运行 通过远程 运行 空间时 PowerShell RemoteException 不一致

PowerShell RemoteException incosistency when run via remote runspace

我有这个演示脚本,我将其放入 Jenkins 作业中:

Write-Host "##############################################"
$ErrorActionPreference = "Stop"

Write-Host "ErrorActionPreference: $ErrorActionPreference"
Write-Host "whoami: $(whoami)"
$PSVersionTable | Format-Table

try {
 cmd /c "comanddoesnotexist c:/foo c:/bar"
} catch {
 Write-Host "### Exception! ###"
}

Write-Host "################### TRACE ###########################"

Trace-Command -Name errorrecord  -Expression { cmd /c "comanddoesnotexist c:/foo c:/bar" }  -PSHost

Write-Host "##############################################"

当我在本地 运行 时,我得到以下结果:

##############################################
ErrorActionPreference: Stop
whoami: td\builder

Name                           Value
----                           -----
PSVersion                      5.1.17763.1
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17763.1
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1


Der Befehl "comanddoesnotexist" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
################### TRACE ###########################
Der Befehl "comanddoesnotexist" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
##############################################

然而,当我通过 Jenkins 运行 完全相同的事情时,我确实得到了以下信息:

[PowerShell_DummyChecks] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Users\BUILDE~1\AppData\Local\Temp\jenkins5194440861464562005.ps1'"
##############################################
ErrorActionPreference: Stop
whoami: td\builder

Name                           Value                                                                                   
----                           -----                                                                                   
PSVersion                      5.1.17763.1                                                                             
PSEdition                      Desktop                                                                                 
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                 
BuildVersion                   10.0.17763.1                                                                            
CLRVersion                     4.0.30319.42000                                                                         
WSManStackVersion              3.0                                                                                     
PSRemotingProtocolVersion      2.3                                                                                     
SerializationVersion           1.1.0.1                                                                                 


### Exception! ###
################### TRACE ###########################
cmd : Der Befehl "comanddoesnotexist" ist entweder falsch geschrieben oder
In C:\Users\builder\AppData\Local\Temp\jenkins5194440861464562005.ps1:16 Zeichen:48
+ ... cord  -Expression { cmd /c "comanddoesnotexist c:/foo c:/bar" }  -PSH ...
+                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Der Befehl "com...eschrieben oder:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Build step 'Windows PowerShell' marked build as failure
Finished: FAILURE

这个 'RemoteException' 来自哪里 - 为什么会被抓到? 请注意,Jenkins 服务正在使用与本地 运行 时相同的帐户执行。

更糟糕的是,这个问题似乎只存在于上述 Win10 + PowerShell 组合中,当我 运行 在另一台(较旧的)服务器上执行相同的作业时,我得到以下(预期的) ) 结果:

[PowerShell_DummyChecks] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Users\BUILDE~1\AppData\Local\Temp\jenkins5640455886657276493.ps1'"
##############################################
ErrorActionPreference: Stop
whoami: td\builder

Name                           Value                                                                                   
----                           -----                                                                                   
PSVersion                      5.1.14393.3053                                                                          
PSEdition                      Desktop                                                                                 
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                 
BuildVersion                   10.0.14393.3053                                                                         
CLRVersion                     4.0.30319.42000                                                                         
WSManStackVersion              3.0                                                                                     
PSRemotingProtocolVersion      2.3                                                                                     
SerializationVersion           1.1.0.1                                                                                 


Der Befehl "comanddoesnotexist" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
################### TRACE ###########################
Der Befehl "comanddoesnotexist" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
##############################################
Build step 'Windows PowerShell' marked build as failure
Finished: FAILURE

现在,再添一层疯狂:

when I run this script remotely via Enter-PSSession, it always fails with the "weird" behavior as on the new server. (also on the old hosts)

有人知道这是怎么回事吗?

注意:所有这些仅适用于 tested/verified Windows PowerShell 5.1

当没有附加控制台的 PowerShell 运行s 时,STDERR 会生成 'RemoteException'。 (在 PS 远程会话中也是如此)。 当 powershell "sees" 一个控制台(即 CREATE_NEW_CONSOLE 或没有特定标志)时,它 will not generate any exception or error,相反它会 只需将来自子进程的 STDERR 输出通过管道传输到它自己的 STDERR 流。此 STDERR 输出将依次显示在控制台 window 上,而无需 任何红色高亮或 PS 异常。

当 运行从使用 'CREATE_NO_WINDOW' 或 'DETACHED_PROCESS' 标志。

在 Windows 10 1809: 当 运行ning powershell.exe 没有 Console 时,只是 like Jenkins does it (Java Runtime.exec), 它的行为就像在远程会话中 运行ning (Enter-PSSession)(参见 #3996)。

在Windows 10 1607 1903: 在 STDERR 处理方面,没有控制台的本地启动的 powershell.exe 就好像它有一个控制台(就像 cmd.exe 中的 运行)。 (没有生成异常,而是子进程在 STDERR 上的所有输出都通过 powershell.exe 的 STDERR 传递)

旁注:明确使用 Enter-PSSession 时,PoSh 在 1607、1809 和 1903 上的行为相同。

一个可行的解决方案是通过使用 'CREATE_NEW_CONSOLE' 标志执行 CreateProcess 的应用程序包装所有 powershell.exe 调用,并将 stdout 以及 stderr 重定向到它的父流。 MSDN example 可以很容易地修改为 "proxy application".