【问题标题】:Redirecting stdout and stderr and elevate to administrator using START-PROCESS使用 START-PROCESS 重定向 stdout 和 stderr 并提升为管理员
【发布时间】:2013-12-15 11:05:45
【问题描述】:

作为我们使用 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 参数将输出发送到文件,然后使用 Get-Content 以避免将属性作为文本读取时出现死锁。

调用此函数来安装 .NET Framework 4.5.1 总是失败,错误代码为 5,即拒绝访问。

对此进行调查,您似乎需要使用 -动词 RunAs 带有 Start-Process 的参数以将命令提升为管理员,但是将该参数添加到 cmdlet 会导致以下错误:

Parameter set cannot be resolved using the specified named parameters.

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

因此我的问题是:

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

  1. 捕获退出代码
  2. 捕获输出和错误消息
  3. 以提升的管理员身份运行

我已经尝试过直接使用 .NET System.Diagnostics.Process.Start 方法,但是这遇到了同样的问题。

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

【问题讨论】:

    标签: powershell


    【解决方案1】:

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

    【讨论】:

    • 感谢您的回复,您介意对 Keith 的这个建议进行详细说明吗?我已经看到了 Start-Process 调用另一个版本的 Powershell 的示例,但是我不清楚您将在“父”脚本中使用哪些参数,以及您将在子脚本中使用哪些参数以获得提升和输出重定向的正确组合。
    • 在父脚本中使用 -verb runas 启动另一个提升的 PowerShell 进程,使用参数 -ArgumentList "-File c:\child.ps1" 将传递给子脚本传递给 PowerShell.exe .在子脚本中,使用重定向参数启动要运行的进程,并让它返回进程的 ExitCode。在这两个脚本中,您将使用 -PassThru 和 -Wait 参数来等待启动的进程完成并获取退出代码。
    • 我已经尝试了你的建议,这似乎做了它应该做的但是在使用这个过程安装 .net framework 4.5.1 时我仍然收到“错误 0x05 访问被拒绝”。我开始认为这与 start-process 无关,因为如果我在本地运行相同的代码,它就可以工作。它一定是远程会话(使用调用命令)或者因为源文件位于 UNC 共享上。任何关于我为什么被拒绝访问的想法表示赞赏。我的下一步是使用 SysInterals Process Monitor 查看拒绝访问的用途。谢谢。
    • 听起来您可能遇到了凭据的第二个跃点问题。使用 Invoke-Command 参数-Authentication CredSSP
    • 感谢您对 Keith 的持续关注。我现在已经尝试了启动过程的所有变体,我相信这是可能的。 CREDSSP 已经被用作安装 .net 4.5.1 的任务,这只是我们自动化管道中的众多任务之一,我们已经使用 CREDSSP 打开会话,效果很好。但是,我仍然无法安装 .net 4.5.1.install。我总是收到 0x05 的退出代码,拒绝访问。其他需要管理员的程序似乎可以工作。如果其他人有任何远程安装的经验,我很想听听他们是如何做到的。
    【解决方案2】:

    我没有捕获退出代码 - 但我确实得到了 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         
    

    【讨论】:

      猜你喜欢
      • 2014-07-22
      • 2018-01-25
      • 1970-01-01
      • 2015-06-21
      • 2012-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多