powershell 2.0重定向文件句柄异常 [英] powershell 2.0 redirection file handle exception

查看:691
本文介绍了powershell 2.0重定向文件句柄异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个解决方案操作系统句柄的位置不是什么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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆