Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net PowerShell调用命令行_.net_Powershell_Pipeline_Powershell 4.0 - Fatal编程技术网

.net PowerShell调用命令行

.net PowerShell调用命令行,.net,powershell,pipeline,powershell-4.0,.net,Powershell,Pipeline,Powershell 4.0,PowerShell的进程调用是不稳定的,充其量也充满了bug,所以当您需要一些不偶尔挂起的东西时,比如启动进程,或者捕获到管道的输出,同时仍然保留$lastexitcode,大多数人似乎都使用process/ProcessStartInfo。有些进程会向输出写入大量数据,或者可能会长时间运行,因此我们不希望等到它们完成后才看到输出流(不一定是主机…可能是日志文件)。所以我做了这个函数 function Invoke-Cmd { <# .SYNOPSIS Executes a comm

PowerShell的进程调用是不稳定的,充其量也充满了bug,所以当您需要一些不偶尔挂起的东西时,比如启动进程,或者捕获到管道的输出,同时仍然保留$lastexitcode,大多数人似乎都使用process/ProcessStartInfo。有些进程会向输出写入大量数据,或者可能会长时间运行,因此我们不希望等到它们完成后才看到输出流(不一定是主机…可能是日志文件)。所以我做了这个函数

function Invoke-Cmd {
<# 
.SYNOPSIS 
Executes a command using cmd /c, throws on errors and captures all output. Writes error and info output to pipeline (so uses .NET process API).
#>
    [CmdletBinding()]
    param(
        [Parameter(Position=0,Mandatory=1)][string]$Cmd,
        [Parameter(Position=1,Mandatory=0)][ScriptBlock]$ErrorMessage = ({"Error executing command: $Cmd - Exit Code $($p.ExitCode)"}),
        [Parameter()][int[]]$ValidExitCodes = @(0)
    )
    begin {
        $p = New-Object System.Diagnostics.Process    
        $pi = New-Object System.Diagnostics.ProcessStartInfo
        $pi.FileName = "cmd.exe"
        $pi.Arguments = "/c $Cmd 2>&1"
        $pi.RedirectStandardError = $true
        $pi.RedirectStandardOutput = $true
        $pi.UseShellExecute = $false
        $pi.CreateNoWindow = $true        
        $p.StartInfo = $pi

        $outputHandler = {  
           if ($EventArgs.Data -ne $null) { Write-Output $EventArgs.Data } 
        }

        Write-Output "Executing..."

        $stdOutEvent = Register-ObjectEvent -InputObject $p `
            -Action $outputHandler -EventName 'OutputDataReceived'
        $stdErrEvent = Register-ObjectEvent -InputObject $p `
            -Action $outputHandler -EventName 'ErrorDataReceived'
    }
    process {
        $p.Start() | Out-Null

        $p.BeginOutputReadLine()
        $p.BeginErrorReadLine()

        $p.WaitForExit() | Out-Null

    }
    end {    
        Unregister-Event -SourceIdentifier $stdOutEvent.Name
        Unregister-Event -SourceIdentifier $stdErrEvent.Name

        if (!($ValidExitCodes -contains $p.ExitCode)) {
            throw (& $ErrorMessage)
        }
    }
}
函数调用Cmd{
[CmdletBinding()]
param(
[参数(位置=0,强制=1)][string]$Cmd,
[Parameter(Position=1,Mandatory=0)][ScriptBlock]$ErrorMessage=({“执行命令时出错:$Cmd-Exit Code$($p.ExitCode)”}),
[参数()][int[]$ValidExitCodes=@(0)
)
开始{
$p=新对象System.Diagnostics.Process
$pi=新对象System.Diagnostics.ProcessStartInfo
$pi.FileName=“cmd.exe”
$pi.Arguments=“/c$Cmd 2>&1”
$pi.RedirectStandardError=$true
$pi.RedirectStandardOutput=$true
$pi.UseShellExecute=$false
$pi.CreateNoWindow=$true
$p.StartInfo=$pi
$outputhHandler={
if($EventArgs.Data-ne$null){写入输出$EventArgs.Data}
}
写入输出“正在执行…”
$stdOutEvent=注册对象事件-InputObject$p`
-操作$outputHandler-事件名称“OutputDataReceived”
$stdErrEvent=注册对象事件-InputObject$p`
-操作$outputHandler-事件名称'ErrorDataReceived'
}
过程{
$p.Start()|输出为空
$p.BeginOutputReadLine()
$p.BeginErrorReadLine()
$p.WaitForExit()|输出为空
}
结束{
注销事件-源标识符$stdOutEvent.Name
注销事件-SourceIdentifier$stdErrEvent.Name
if(!($ValidExitCodes-包含$p.ExitCode)){
抛出(&$ErrorMessage)
}
}
}
问题是我的事件处理程序中的写入输出与Invoke Cmd本身在同一执行上下文中不起作用。。。如何让事件处理程序将输出写入父函数输出流


谢谢

这应该可以满足您的要求:

cmd /c ... '2>&1' [ | ... ]
要捕获变量中的输出,请执行以下操作:

$captured = cmd /c ... '2>&1' [ | ... ]
这个成语:

  • 同步执行传递给
    cmd/c
    的外部命令
  • 当输出可用时,通过管道传递stdout和stderr
  • 如果指定,则在变量
    $captured
    中捕获组合输出
  • $LASTEXITCODE
    中保留外部命令的退出代码
$LASTEXITCODE
是一种外部程序运行结束时自动设置的代码,并设置为该程序的退出代码。它是一个全局单例变量,您可以从任何范围访问它,而无需使用范围说明符(就好像它是用
-scope global-Option AllScope
声明的,即使
Get variable LASTEXITCODE | Format List
没有反映这一点)。这意味着只有最近运行的程序的退出代码才会反映在
$LASTEXITCODE
中,而不管它在什么范围内运行。
但是,请注意,在会话中启动的第一个外部命令完成运行之前,不会创建该变量

注意事项:由于是
cmd
处理
2&1
重定向(由于它周围的引用),stdout和stderr在源代码处合并,因此您将无法分辨哪些输出行来自哪个流;如果您确实需要知道,请使用PowerShell的
2&1
重定向(省略引用)。
有关这两种方法的不同之处的讨论,请参阅我的

如果除了捕获变量(假设最后一个管道段调用cmdlet)之外,还希望输出到控制台:


示例:

> cmd /c ver '&&' dir nosuch '2>&1' > out.txt
> $LASTEXITCODE
1
> Get-Content out.txt

Microsoft Windows [Version 10.0.10586]
 Volume in drive C has no label.
 Volume Serial Number is 7851-9F0B

 Directory of C:\

File Not Found
该示例演示退出代码正确地反映在
$LASTEXITCODE
中,并且stdout和stderr都被发送到输出流,并由PowerShell在文件
out.txt
中捕获

> cmd /c ver '&&' dir nosuch '2>&1' > out.txt
> $LASTEXITCODE
1
> Get-Content out.txt

Microsoft Windows [Version 10.0.10586]
 Volume in drive C has no label.
 Volume Serial Number is 7851-9F0B

 Directory of C:\

File Not Found