加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

windows – powershell 2.0重定向文件处理异常

发布时间:2020-12-13 20:40:05 所属栏目:Windows 来源:网络整理
导读:我正在寻找一个解决方案,OS句柄的位置不是FileStream所期望的.不要在一个FileStream和Win32代码或另一个FileStream中同时使用句柄.异常,也适用于包含 “the fix”的脚本中调用的脚本. 出于这个问题的目的,假设我有两个脚本: foo.ps1 # fix$bindingFlags = [
我正在寻找一个解决方案,OS句柄的位置不是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,GetProperty"
$consoleHost = $objectRef.GetType().GetProperty( "Value",$bindingFlags ).GetValue( $objectRef,@() )
[void] $consoleHost.GetType().GetProperty( "IsStandardOutputRedirected",$bindingFlags ).GetValue( $consoleHost,@() )
$bindingFlags = [Reflection.BindingFlags] "Instance,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:tempredirecct.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],bar.ps1

yay

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

normal
C:foo.ps1 : error
At line:1 char:10
+ .foo.ps1 <<<< 
    + CategoryInfo          : NotSpecified: (:) [Write-Error],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时不应该崩溃).

UPDATE

以下是半可接受的解决方案.我说一半,因为它只会阻止’父’脚本崩溃. ‘child’脚本在尝试写入时仍然很难.从好的方面来说,它可以认识到酒吧失败了.

foo.ps1:

function savepowershellfromitself {
    $bindingFlags = [Reflection.BindingFlags] "Instance,GetField"
    $objectRef = $host.GetType().GetField( "externalHostRef",$bindingFlags ).GetValue( $host )
    $bindingFlags = [Reflection.BindingFlags] "Instance,GetProperty"
    $consoleHost = $objectRef.GetType().GetProperty( "Value",@() )
    [void] $consoleHost.GetType().GetProperty( "IsStandardOutputRedirected",@() )
    $bindingFlags = [Reflection.BindingFlags] "Instance,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,$bindingFlags ).GetValue(     $objectRef,$bindingFlags).GetValue( $consoleHost,[Console]::Out )
# </fix>

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

powershell .bar.ps1 2>&1 | more

通过更多管道输出隐藏了它最终从Powershell的子实例转到文件的事实,绕过了这个bug.

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

powershell .foo.ps1 2>&1 | more

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

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

.bar.ps1

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读