PowerShell 2.0redirect文件句柄exception

我正在寻找一个解决schemeThe OS handle's position is not what FileStream expected. Do not use a handle simultaneously in one FileStream and in Win32 code or another FileStream. The OS handle's position is not what FileStream expected. Do not use a handle simultaneously in one FileStream and in Win32 code or another FileStream. 这个exception也可以用在包含“修复”的脚本中调用的脚本上。

为了这个问题的目的,说我有两个脚本:

foo.ps1

 # <fix> $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" $objectRef = $host.GetType().GetField( "externalHostRef", $bindingFlags ).GetValue( $host ) $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty" $consoleHost = $objectRef.GetType().GetProperty( "Value", $bindingFlags ).GetValue( $objectRef, @() ) [void] $consoleHost.GetType().GetProperty( "IsStandardOutputRedirected", $bindingFlags ).GetValue( $consoleHost, @() ) $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" $field = $consoleHost.GetType().GetField( "standardOutputWriter", $bindingFlags ) $field.SetValue( $consoleHost, [Console]::Out ) $field2 = $consoleHost.GetType().GetField( "standardErrorWriter", $bindingFlags ) $field2.SetValue( $consoleHost, [Console]::Out ) # </fix> write-host "normal" write-error "error" write-host "yay" .\bar.ps1 

bar.ps1

 write-host "normal" write-error "error" write-host "yay" 

foo.ps1正在像这样运行:

 powershell .\foo.ps1 > C:\temp\redirecct.log 2>&1 

预期产出应该是:

 normal C:\foo.ps1 : error At line:1 char:10 + .\foo.ps1 <<<< + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,foo.ps1 yay normal C:\bar.ps1 : error At C:\foo.ps1:17 char:6 + .\bar <<<< 2>&1 + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,bar.ps1 yay 

但是,由于已知的错误,输出实际上是:

 normal C:\foo.ps1 : error At line:1 char:10 + .\foo.ps1 <<<< + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,foo.ps1 yay normal out-lineoutput : The OS handle's position is not what FileStream expected. Do not use a handle simultaneously in one FileStream and in Win3 2 code or another FileStream. This may cause data loss. + CategoryInfo : NotSpecified: (:) [out-lineoutput], IOException + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.OutLineOutputCommand 

所以观察到的行为是“修正”所做的更改不被“子”脚本(在本例中为bar.ps1 )inheritance。 当bar.ps1尝试写入时,它崩溃很难。 如果我在foo.ps1没有防范,它也会崩溃。 在调用bar.ps1之前/之前我可以做些什么来防止bar.ps1在尝试写入时崩溃?

约束:

  • Powershell 2.0
  • 脚本必须如上运行
  • 我无法修改bar.ps1(写入stderr时不会崩溃)。

UPDATE

以下是一个可以接受的解决scheme。 我说了一半,因为它只能防止“父母”脚本崩溃。 “孩子”脚本在写入时仍然很难。 从好的方面来说,它可以尽可能地承认吧台失败。

foo.ps1

 function savepowershellfromitself { $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" $objectRef = $host.GetType().GetField( "externalHostRef", $bindingFlags ).GetValue( $host ) $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty" $consoleHost = $objectRef.GetType().GetProperty( "Value", $bindingFlags ).GetValue( $objectRef, @() ) [void] $consoleHost.GetType().GetProperty( "IsStandardOutputRedirected", $bindingFlags ).GetValue( $consoleHost, @() ) $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" $field = $consoleHost.GetType().GetField( "standardOutputWriter", $bindingFlags ) $field.SetValue( $consoleHost, [Console]::Out ) $field2 = $consoleHost.GetType().GetField( "standardErrorWriter", $bindingFlags ) $field2.SetValue( $consoleHost, [Console]::Out ) } savepowershellfromitself write-host "normal" write-error "error" write-host "yay" $output = .\bar.ps1 2>&1 savepowershellfromitself write-host "$output" if( $errors = $output | ?{$_.gettype().Name -eq "ErrorRecord"} ){ write-host "there were errors in bar!" } write-error "error2" write-host "done" 

如果你在foo.ps1中这样做,它解决了这个问题:

 # <fix> $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" $objectRef = $host.GetType().GetField( "externalHostRef", $bindingFlags ).GetValue( $host ) $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty" $consoleHost = $objectRef.GetType().GetProperty( "Value", $bindingFlags ).GetValue( $objectRef, @() ) [void] $consoleHost.GetType().GetProperty( "IsStandardOutputRedirected", $bindingFlags).GetValue( $consoleHost, @() ) $bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField" $field = $consoleHost.GetType().GetField( "standardOutputWriter", $bindingFlags ) $field.SetValue( $consoleHost, [Console]::Out ) $field2 = $consoleHost.GetType().GetField( "standardErrorWriter", $bindingFlags ) $field2.SetValue( $consoleHost, [Console]::Out ) # </fix> write-host "normal" write-error "error" write-host "yay" powershell .\bar.ps1 2>&1 | more 

通过更多的输出来隐藏最终将从Powershell的子实例转到文件的事实,绕过bug。

事实上,如果你创建一个只运行foo.ps1的祖父母脚本foobar.ps1:

 powershell .\foo.ps1 2>&1 | more 

那么你根本不需要“修正”,而foo.ps1就可以

 write-host "normal" write-error "error" write-host "yay" .\bar.ps1 

因为管道解决了所有后代脚本的问题。