PsExec 仅返回 BackgroundJob 中标准输出的第一行

PsExec returning only the first line of stdout inside of a BackgroundJob

我遇到一个问题,PsExec 的标准输出在 BackgroundJob 内部不同。

关于我工作环境的一些信息:

我有大量 Windows 没有 WinRM 的 XP 机器,我无法使用 WMI 调用,但是 PsExec 可以工作。我需要从所有 XP 机器获取命令的标准输出。我能够在 BackgroundJob 之外获得我期望的标准输出,但是当我尝试在 BackgroundJob 内部执行 PsExec 时,我只收到标准输出的第一行。

这是我看到的差异的示例:

# 1.2.3.4 = IP Address of an XP Machines
# 123.123.123.123 = IP of a server I want to compare the time against.

$output = & "path\to\psexec\psexec.exe" "\1.2.3.4" -accepteula -u "$($creds.Username)" -p "$($creds.GetNetworkCredential().Password)" w32tm /stripchart /computer:123.123.123.123 /samples:1 /dataonly

Write-Host $output

此代码输出:Tracking 123.123.123.123 [123.123.123.123]. Collecting 1 samples. The current time is 6/30/2021 2:41:51 PM (local time). 14:41:51, +00.0059682s

但是,这段代码输出了一些不同的东西:


Start-Job -Name "1.2.3.4" -ScriptBlock {
    # 1.2.3.4 = IP Address of an XP Machines
    # 123.123.123.123 = IP of a server I want to compare the time against.

    $output = & "path\to\psexec\psexec.exe" "\1.2.3.4" -accepteula -u "$($using:creds.Username)" -p "$($using:creds.GetNetworkCredential().Password)" w32tm /stripchart /computer:123.123.123.123 /samples:1 /dataonly
    
    return $output
}

$returnValue = Get-Job "1.2.3.4" | Receive-Job -Wait -AutoRemoveJob

Write-Host $returnValue

这输出:Tracking 123.123.123.123 [123.123.123.123]. 这是 w32tm /stripchart /computer:123.123.123.123 /samples:1 /dataonly.

标准输出的第一行

我做错了吗?我的理解是 BackgroundJob 内部和外部的标准输出不应该有区别。

我对 PowerShell 比较陌生。如果我的理解不正确,请赐教。你能给我的任何信息或建议都会有所帮助。

谢谢!

更新:阅读 Iconiu 对此的回答后 Whosebug Thread

这似乎是 PowerShell 的限制。我目前正在为此寻找解决方法。当我有一个有效的问题时,我会再次更新这个问题。

更新 2:我找到了适合我的目的的解决方法,我想我会分享它。


$ip = '1.2.3.4' # IP of an XP Machine
$otherip = '123.123.123.123' # Machine I want use for w32tm

# Create the temp Folder outside of the job if it does not exist.
if(!(Test-Path "\$ip\c`$\temp\")) {
    MKDIR "\$ip\c`$\temp\"
    Start-Sleep -Seconds 1 # Sleep for one second to allow for network lag.
}

Start-Job -Name $ip -ScriptBlock {
    $ip = $using:ip
    $otherip = $using:otherip
    $creds = $using:creds 
    & "path\to\psexec\psexec.exe" \$ip -accepteula -u $creds.Username -p $creds.GetNetworkCredential().Password cmd /c "w32tm /stripchart /computer:$otherip /samples:1 /dataonly > C:\temp\w32tmstripchart.txt"
    if(Test-Path "\$ip\c`$\temp\w32tmstripchart.txt") {
        $stdout = Get-Content -Path "\$ip\c`$\temp\w32tmstripchart.txt" -Raw
        return $stdout
    } else {
        return "ERROR"
    
}

$retVal = Get-Job -Name $ip | Receieve-Job -Wait -AutoRemoveJob

Write-Host $retVal


如果您想从命令中捕获 stderr 和 stdout,请在将输出定向到文件后添加 2>&1。例如,w32tm /stripchart /computer:123.123.123.123 /samples:1 /dataonly > w32tmstripchart.txt 2>&1

如果您希望标准输出是字符串数组而不是单个字符串,请从 Get-Content 命令中删除 -Raw 开关。

希望这对以后遇到类似问题的任何人有所帮助。

确实 Start-Job 报告 first stdout 行似乎有问题psexec 的输出.

Start-Job 创建基于 child-process 的后台作业,但是 有一个更轻量级的,通常更可取的 线程基于 的替代方案 Start-ThreadJob 没有 有同样的问题。

  • Start-ThreadJob 附带 PowerShell (Core) v6+,可以按需安装 Windows PowerShell v3+ - 请参阅

因此,请尝试以下使用 Start-ThreadJob:

Start-ThreadJob -Name 1.2.3.4 -ScriptBlock {
  & 'path\to\psexec\psexec.exe' -nobanner \1.2.3.4 -accepteula -u $using:creds.Username -p ($using:creds).GetNetworkCredential().Password w32tm /stripchart /computer:123.123.123.123 /samples:1 /dataonly 2>$null
}

如果您还想捕获 w32tmstderr 输出:

Start-ThreadJob -Name 1.2.3.4 -ScriptBlock {
  & 'path\to\psexec\psexec.exe' -nobanner \1.2.3.4 -accepteula -u $using:creds.Username -p ($using:creds).GetNetworkCredential().Password cmd /c 'w32tm /stripchart /computer:123.123.123.123 /samples:1 /dataonly 2>&1' 2>$null
}