Я ищу решение для исключения 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.
, которое также будет работать со скриптами, вызываемыми в скрипте, содержащем "исправление" .
Для целей этого вопросаскажем, что у меня есть два сценария:
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
Таким образом, наблюдаемое поведение состоит в том, что изменения, внесенные "исправлением", не наследуются скриптом 'child' (bar.ps1
, в данном случае).Когда bar.ps1 пытается писать, он сильно падает.Если я не буду защищаться от этого как-то в foo.ps1
, он тоже сильно рухнет.Что я могу сделать до / при вызове bar.ps1
, чтобы предотвратить сбой bar.ps1
при попытке записи?
Ограничения:
- Powershell 2.0
- скрипт должен быть запущен как указано выше
- Я не могу изменить bar.ps1 (и он не должен падать при записи в stderr).
UPDATE
Ниже приведено полуоприемлемое решение.Я говорю «половина», потому что это только предотвращает сбой «родительского» сценария.«Дочерний» сценарий все еще терпит неудачу, когда пытается писать.С положительной стороны, это может пойти так далеко, как признание того, что бар не удалось.
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"