Исключение дескриптора перенаправления файла powershell 2.0

Я ищу решение проблемы Положение дескриптора ОС не соответствует ожиданиям FileStream. Не используйте дескриптор одновременно в одном FileStream и в коде Win32 или другом FileStream. исключение, которое также будет работать со сценариями, вызываемыми внутри сценария, содержащего «исправление» .

Для целей этого вопроса предположим, что у меня есть два скрипта:

foo.ps1

# 
$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 )
# 

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"

7
задан Christopher Neylan 30 January 2012 в 15:16
поделиться