Estoy buscando una solución a la excepción 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.
que también funcionaría en scripts llamados dentro del script que contiene "the fix".excepción de controlador de archivo de redirección de powershell 2.0
A los efectos de esta pregunta, decir que tengo dos guiones:
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"
Y SE foo.ps1
ejecute así:
powershell .\foo.ps1 > C:\temp\redirecct.log 2>&1
La salida esperada debe ser:
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
Sin embargo, debido al fallo conocido, la salida es en realidad:
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
lo tanto, el comportamiento observado es que los cambios hechos por " la corrección "no está siendo heredada por el script 'hijo' (bar.ps1
, en este caso). Cuando bar.ps1 intenta escribir, se cuelga con fuerza. Si no lo prevengo de alguna manera en foo.ps1
, también se bloqueará. ¿Qué puedo hacer antes/en llamar al bar.ps1
para evitar que bar.ps1
se bloquee cuando intenta escribir?
Restricciones:
- PowerShell 2.0
- La secuencia de comandos se deben ejecutar como anteriormente
- No puedo modificar bar.ps1 (y no deben bloquearse al escribir en stderr).
ACTUALIZACIÓN
continuación es una solución de medio aceptable. Digo la mitad porque solo evita que el script 'padre' se cuelgue. El script 'hijo' aún falla mucho cuando intenta escribir. En el lado positivo, puede ir tan lejos como reconocer que la barra falló.
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"
Nota: foobar.ps1 probablemente debería comprobar si la salida se redirige o no antes de llamar a foo.ps1; si no se redirige, probablemente no se debe canalizar a más. –
gracias por su respuesta! De hecho, hoy experimenté con la idea de un script padre-envoltura común. en lugar de más, encontré el éxito con algo como '$ output = invoke-command" $ args 2> & 1 "(extendido de lo que mostré arriba). también, le agradezco que eche un vistazo a las 3 preguntas abiertas :) –