powershell 2.0重定向文件句柄异常 [英] powershell 2.0 redirection file handle exception
问题描述
我正在寻找一个解决方案操作系统句柄的位置不是什么FileStream预期。不要在一个FileStream和Win32代码或另一个FileStream中使用一个句柄。
异常也可以在包含修复。
对于这个问题,假设我有两个脚本:
foo.ps1 / p>
#< fix>
$ bindingFlags = [Reflection.BindingFlags]Instance,NonPublic,GetField
$ objectRef = $ host.GetType()。GetField(externalHostRef,$ bindingFlags).GetValue
indingFlags = [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>
写主机正常
写错误错误
写主机yay
.\bar.ps1
bar.ps1
write-hostnormal
write-errorerror
write-hostyay
并且 foo.ps1
正在运行:
powershell .\foo.ps1> C:\temp\redirecct.log 2>& 1
预期输出应为:
正常
C:\foo.ps1:错误
在行:1个字符:10
+。\foo.ps1<<<
+ CategoryInfo:NotSpecified:(:) [Write-Error],WriteErrorException
+ FullyQualifiedErrorId:Microsoft.PowerShell.Commands.WriteErrorException,foo.ps1
yay
正常
C:\bar.ps1:错误
在C:\foo.ps1:17字符:6
+ .\bar<< 2& 1
+ CategoryInfo:NotSpecified:(:) [Write-Error],WriteErrorException
+ FullyQualifiedErrorId:Microsoft.PowerShell.Commands.WriteErrorException,bar.ps1
yay
但是,由于已知的错误,输出实际上是:
正常
C:\foo.ps1:错误
在行:1个字符:10
+。\ foo.ps1<<<<
+ CategoryInfo:NotSpecified:(:) [Write-Error],WriteErrorException
+ FullyQualifiedErrorId:Microsoft.PowerShell.Commands.WriteErrorException,foo.ps1
yay
normal
out-lineoutput:操作系统句柄的位置不是FileStream所期望的。不要在一个FileStream和Win3
2代码或另一个FileStream中同时使用句柄。这可能会导致数据丢失。
+ CategoryInfo:NotSpecified:(:) [out-lineoutput],IOException
+ FullyQualifiedErrorId:System.IO.IOException,Microsoft.PowerShell.Commands.OutLineOutputCommand
所以观察到的行为是修复所做的更改不是由'child'脚本继承的( bar.ps1
,在这种情况下)。当bar.ps1尝试写入时,它会崩溃。如果我不在 foo.ps1
中防止它,它也会崩溃。我在调用 bar.ps1
之前/之前可以做什么以防止 bar.ps1
在尝试写入时崩溃?
限制:
- Powershell 2.0
-
- 我无法修改bar.ps1(写入stderr时不应该崩溃)。
ul>
UPDATE
下面是一个可以接受的解决方案。我说一半,因为它只防止父脚本崩溃。 child脚本在尝试写入时仍然失败。
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)
$ fieldHost, ] :: Out)
}
savepowershellfromitself
write-hostnormal
write-errorerror
write-hostyay
$ output = .\bar.ps1 2>& 1
savepowershellfromitself
write-host$ output
if($ errors = ?{$ _。gettype()。Name -eqErrorRecord}){
write-hostbar中有错误!
}
写错误error2
写主机完成
解决方案如果你在foo.ps1中这样做,它会解决问题:
#< fix>
$ bindingFlags = [Reflection.BindingFlags]Instance,NonPublic,GetField
$ objectRef = $ host.GetType()。GetField(externalHostRef,$ bindingFlags).GetValue
indingFlags = [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-hostnormal
write-errorerror
write-hostyay
powershell .\bar.ps1 2> ;& 1 |更多
通过更多的管道输出隐藏了它最终从子实例到文件的事实
事实上,如果你创建一个祖父母脚本foobar.ps1,它只运行foo.ps1:
powershell .\foo.ps1 2& 1 |更多
然后你不需要修复,foo.ps1只是
写主机正常
写错误错误
写主机yay
.\bar.ps1
因为管道解决了问题所有后代脚本。
I'm looking for a solution to the 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 that would also work on scripts called within the script containing "the fix".
For the purposes of this question, say that I have two scripts:
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"
And foo.ps1
is being run like this:
powershell .\foo.ps1 > C:\temp\redirecct.log 2>&1
The expected output should be:
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
However, due to the known bug, the output is actually:
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
So the observed behavior is that the changes made by "the fix" aren't being inherited by the 'child' script (bar.ps1
, in this case). When bar.ps1 tries to write, it crashes hard. If I don't guard against it somehow in foo.ps1
, it will also crash hard. What can I do before/in calling bar.ps1
to prevent bar.ps1
from crashing when it tries to write?
Constraints:
- Powershell 2.0
- The script must be run as above
- I can't modify bar.ps1 (and it should not crash when writing to stderr).
UPDATE
Below is a half-acceptable solution. I say half because it only prevents the 'parent' script from crashing. The 'child' script still fails hard when it tries to write. On the plus side, it can go as far as recognizing that bar failed.
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"
解决方案 If you do this in foo.ps1 it solves the problem:
# <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
Piping the output through more hides the fact that it is ultimately going to a file from the child instance of Powershell, bypassing the bug.
In fact, if you create a grandparent script foobar.ps1 which just runs foo.ps1:
powershell .\foo.ps1 2>&1 | more
Then you don't need "the fix" at all, and foo.ps1 can just be
write-host "normal"
write-error "error"
write-host "yay"
.\bar.ps1
because the piping solves the problem for all descendent scripts.
这篇关于powershell 2.0重定向文件句柄异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!