gpt4 book ai didi

windows - powershell 2.0重定向文件句柄异常

转载 作者:可可西里 更新时间:2023-11-01 13:14:52 25 4
gpt4 key购买 nike

我正在寻找解决 操作系统句柄的位置不是 FileStream 所期望的。不要在一个 FileStream 和 Win32 代码或另一个 FileStream 中同时使用句柄。 异常也适用于包含 "the fix" 的脚本中调用的脚本。 .

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

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)继承。当 bar.ps1 尝试写入时,它会崩溃。如果我不在 foo.ps1 中以某种方式防范它,它也会严重崩溃。在调用 bar.ps1 之前/期间,我可以做什么来防止 bar.ps1 在尝试写入时崩溃?

约束:

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

更新

下面是一个半可接受的解决方案。我说一半是因为它只能防止“父”脚本崩溃。 “子”脚本在尝试写入时仍然会失败。从好的方面来说,它可以识别该栏失败。

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

通过 more 管道输出隐藏了一个事实,即它最终会从 Powershell 的子实例转到文件,从而绕过了错误。

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

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

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

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

.\bar.ps1

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

关于windows - powershell 2.0重定向文件句柄异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8978052/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com