powershell 2.0 Umleitung von Datei-handle-Ausnahme
Ich bin auf der Suche nach einer Lösung für das 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.
Ausnahme, dass würde auch die Arbeit an Aufgabenstellungen innerhalb des Skripts mit "the fix".
Für die Zwecke dieser Frage, ich sage, dass ich zwei Skripte:
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"
Sowie foo.ps1
wird ausgeführt, wie diese:
powershell .\foo.ps1 > C:\temp\redirecct.log 2>&1
Der erwartete output sollte sein:
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
Jedoch, aufgrund der bekannten Fehler, der Ausgang ist eigentlich:
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
Also das beobachtete Verhalten ist, dass die änderungen durch den "fix" nicht geerbt wird von der 'Kind' - Skript (bar.ps1
, in diesem Fall). Wenn bar.ps1 versucht zu schreiben, es stürzt schwer. Wenn ich nicht Wache gegen es irgendwie in foo.ps1
es werden auch crash-hart. Was kann ich vor/bei der Berufung von bar.ps1
um zu verhindern, dass bar.ps1
abstürzt, wenn er versucht zu schreiben?
Einschränkungen:
- Powershell 2.0
- Das Skript muss ausgeführt werden, wie oben
- Ich kann es nicht ändern bar.ps1 (und es sollte nicht Abstürzen, wenn das schreiben auf stderr).
UPDATE
Unten ist eine halbe akzeptable Lösung. Ich sage halb, weil es verhindert nur, dass das 'parent' - Skript abstürzt. Die 'Kind' - Skript immer noch nicht hart, wenn er versucht zu schreiben. Auf der plus-Seite, es kann so weit gehen, wie die Erkenntnis, dass bar ist fehlgeschlagen.
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"
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie dies tun, foo.ps1 es das problem löst:
Piping die Ausgabe über mehr verbirgt die Tatsache, dass es letztlich geht, um eine Datei aus der untergeordneten Instanz von Powershell, unter Umgehung des bug.
In der Tat, wenn Sie ein Großelternteil Skript foobar.ps1 die läuft einfach foo.ps1:
Dann brauchen Sie nicht "fix", und foo.ps1 kann nur
weil die Rohrleitungen löst das problem für alle untergeordneten Skripts.