重定向stdout和stderr并使用START-PROCESS升级到管理员

时间:2013-11-29 09:40:27

标签: powershell

作为我们使用Powershell完成的服务器构建和配置的一部分,我需要在许多Server 2012机器上远程安装.net framework 4.5.1。 The offline install作为.exe提供,在运行时,解压缩许多MSI安装程序和安装程序。

我们用来运行安装程序的代码可以使用MSI文件或exe。如果我们使用MSI文件,则调用MSIEXEC,如果是EXE,则直接调用该程序。任何所需的参数也可以传递。

出于我们的目的,这是使用Powershell cmdlet Start-Process实现的。

我需要获取返回代码以确定安装是否已正确完成,并且还希望捕获stdout和stderr以帮助诊断安装失败时的任何问题。

我有以下自定义编写函数来包装Start-Process cmdlet。

Function Start-Proc()
{
[CmdletBinding()]
    param (
    [string][ValidateNotNullOrEmpty()][ValidateScript({Test-Path -Path $_ -Type Leaf})] $FilePath,
    [string][ValidateNotNullOrEmpty()]$Arguments,
    [switch] $Hidden,
    [switch] $WaitForExit
    )

#Create files to hold the output to avoid the deadlock issue that seems to arise when we read
#the output and error at the same time http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.110).aspx
$errorFilePath = Join-Path -Path $env:TEMP -ChildPath ([system.guid]::NewGuid().ToString())
$outputFilePath = Join-Path -Path $env:TEMP -ChildPath ([system.guid]::NewGuid().ToString())

$process = Start-Process `
                -FilePath $FilePath `
                -ArgumentList $Arguments `
                -RedirectStandardError $errorFilePath `
                -RedirectStandardOutput $outputFilePath `
                -NoNewWindow:$Hidden `
                -PassThru `
                -Wait:$WaitForExit

$errorOut = Get-Content -Path $errorFilePath
$stdOut = Get-Content -Path $outputFilePath

#Tidy up files
If ($process.HasExited)
{
    Remove-Item $errorFilePath
    Remove-Item $outputFilePath
}

#Create new object to send the messages and exit code back
$output = New-Object -TypeName PSObject
$output | Add-Member –MemberType NoteProperty -Name Message -Value $stdOut
$output | Add-Member –MemberType NoteProperty -Name ErrorMessage -Value $errorOut
$output | Add-Member –MemberType NoteProperty -Name ExitCode -Value $process.ExitCode

return $output
}

注意:我必须使用-RedirectStandardOutput和-RedirectStandardInput Params将输出发送到文件,然后使用Get-Content来避免死锁将属性读取为文本。

调用此函数以安装.NET framework 4.5.1始终失败,错误代码为5,即拒绝访问。

调查一下,看来你需要使用     -Verb RunAs 带有Start-Process的参数以管理员身份提升命令,但是将该参数添加到cmdlet会导致以下错误:

Parameter set cannot be resolved using the specified named parameters.

这是因为-Verb和-RedirectStandardOutput& -RedirectStandardError在不同的参数集中。

因此我的问题是:

如何从Powershell运行执行以下操作的可执行文件:

  1. 捕获退出代码
  2. 捕获输出和错误消息
  3. 以提升管理员身份运行
  4. 我已经尝试过直接使用.NET System.Diagnostics.Process.Start方法,但这会遇到同样的问题。

    感谢您的帮助,因为这被证明是一个难题!

2 个答案:

答案 0 :(得分:0)

我会使用另一个脚本,它具有参数,例如exe路径,参数和输出文件的名称,并让它返回退出代码。使用Start-Process重定向,等待进程并获取退出代码以返回到父脚本。在父脚本中,使用Start-Process -verb runas以脚本路径作为参数启动PowerShell,以及启动脚本提升的脚本参数。

答案 1 :(得分:0)

我没有捕获退出代码-但我确实得到了stdout + stderr。然后,您可以调整“脚本块”以执行此操作……

$output = "c:\temp\psoutput.txt"
$computername = "xxxxxx"
$code = "Stop-WebAppPool -Name `"my.app.pool" 2>&1 >>$output"

$prog = "powershell.exe"
Invoke-Command -ComputerName $computername -ScriptBlock { param($p,$a,$o) 
                                                            Start-Process $p -ArgumentList $a -wait -verb RunAs
                                                            get-content $o
                                                        } -ArgumentList $prog,$code,$output