PowerShell Cookbook

Search

Categories

 

On this page

Archive

Blogroll

Disclaimer
I work for Microsoft.

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 222
This Year: 0
This Month: 0
This Week: 0
Comments: 536

Sign In

 Wednesday, July 30, 2008
Wednesday, July 30, 2008 7:15:16 PM (Pacific Daylight Time, UTC-07:00) ( )

If you have a PowerShell script that you are calling from cmd.exe, you might run into the following error:

Write-Host : 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. This may cause data loss.

This is bug in PowerShell, and happens when:

  • a PowerShell command generates both regular and error output
  • you have used cmd.exe to redirect the output to a file
  • you have used cmd.exe to merge the output and error streams

For example:

PowerShell -Command '"start"'; Write-Error "Foo"; '"end"' > c:\temp\redirect.log 2>&1

One workaround is to use Start-Transcript for file logging (rather than cmd.exe) or have PowerShell do the error stream redirection.

However, if you don't have control over your logging, you can add the following snippet to any scripts that get launched this way.

Note: this is an unsupported workaround. It will almost definitely break as future versions of PowerShell are released.

 

V1

$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField"
$consoleHost = $host.GetType().GetField("externalHost", $bindingFlags).GetValue($host)
[void] $consoleHost.GetType().GetProperty("IsStandardOutputRedirected", $bindingFlags).GetValue($consoleHost, @())
$field = $consoleHost.GetType().GetField("standardOutputWriter", $bindingFlags)
$field.SetValue($consoleHost, [Console]::Out)

V2 CTP2

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

 

How does this work, and why does this happen in the first place? When PowerShell sends output to its output stream the first time, it keeps a reference to the output stream for future use. However, this output stream is really a wrapper around a lower-level stream. When cmd.exe writes to the output stream, it writes to the lower-level stream. This makes the .NET wrapper complain that the underlying stream has changed from beneath it.

This workaround modifies some private engine state to not keep a reference to the output stream -- but instead to re-examine the output stream on every use.

Comments [0] | | # 
Name
E-mail
Home page

Comment (Some html is allowed: b, blockquote@cite, em, i, strike, strong, sub, super, u)  

Enter the code shown (prevents robots):