Workaround: The OS handle’s position is not what FileStream expected
Wednesday, 30 July 2008
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 that this code must be placed at the top of your script before any other code.
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)
$field2 = $consoleHost.GetType().GetField(“standardErrorWriter”, $bindingFlags)
$field2.SetValue($consoleHost, [Console]::Out)
V2
$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)
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.
[Edit 03/12/09 - Updated to also fix Standard Error, as mentioned in the PowerShellWizard Blog]


Subscribe to this blog.
No. 1 — November 29th, 1999 at 4:00 pm
Bug is still there in server 2008 R2 SP1! Microsoft fix this, please!!!
No. 2 — September 2nd, 2009 at 7:27 pm
The workarounds are quite useful, but will this ever get fixed?
No. 3 — October 30th, 2009 at 11:09 am
Many thanks for this: I had a script running in an automation tool that was failing because of this
bug, and now it works without error. It would be great for the issue to be fixed in Powershell though.
No. 4 — November 18th, 2009 at 3:30 pm
Many thanks for this fix, it saved me lots of digging through msdn and it would have taken a while to spot the actual bug in my environment.
As for this getting fixed in a later version… I’m going to go ahead and say doubtful. It would need to change the way that powershell handles being called from elsewhere, insofar as it acquires output streams.
What I think is more likely is cmd.exe getting phased out and powershell ending up as the lowest-possible-level user of those streams.
No. 5 — June 1st, 2010 at 9:17 am
Hello
I used your fix for PowerShell 1.0, and it worked perfectly. Does anybody have any experience with this fix in relation to PowerShell 2.0, is it still needed?
Robert
No. 6 — November 4th, 2010 at 6:12 am
Still there as f today in V2.0 on a recently patched server; for u it comes up when running from AutoSys. The fix for v2 above works ok.
No. 7 — December 22nd, 2010 at 8:18 am
Same here, it causes problems in Autosys Jobs.
No. 8 — January 3rd, 2011 at 1:28 pm
Same problem with Powershell V2 script called through Autsosy
No. 9 — October 6th, 2011 at 4:50 am
Hard to believe that on 10/6/11 on Windows 2008 R2 that this is STILL an issue. But it is. And this page was a life saver. Thanks!
No. 10 — October 6th, 2011 at 8:29 am
Also experience this issue. This is VERY annoying!
No. 11 — October 7th, 2011 at 9:03 pm
We hear you about this being very annoying. We had seen the bug once in a while in PowerShell version 1, but didn’t have a good example of what caused it (and didn’t see that it was impacting many people) We finally nailed down the cause late in PowerShell version 2, but were so close to releasing Windows 7 (still without evidence that it was impacting people) that we decided to not risk a fix. If you download the Windows 8 Developer Preview, you’ll see that we’ve fixed this now :)
Lee
No. 12 — October 10th, 2011 at 5:04 am
I reported this error to Microsoft years ago, and after a while it war recognized as an error. MS said it would NOT be fixed, it was too complicated. MS Case no. 110081742134557. It has cost us hundreds of hours, and still is, right now I am working on a new server, where PowerShell still fails with this error (2008 server). We are calling PowerShell from within a product called UC4, and the way they have integrated PowerShell makes this problem VERY big. I have spend hundreds of hours rewriting PowerShell code, in order to avoid this situation.
No. 13 — October 18th, 2011 at 1:33 am
Ditto the hundreds of hours – this sort of nonsense makes people rewrite log maintenance code in freaking Windows Workflow. I simply do not buy the nobody seeing it nonsense. I saw it in week 1 of using the product. You guys did too and these sorts of bugs are the ones we want fixed – global ones that only you can do. Any issue with a Task can be routed around – this is the single most painful issue I’ve experienced with MS products since the bad days of Visual C++ and it’s toolery in the last century
No. 14 — November 23rd, 2011 at 11:24 am
I really appreciate your posting of this article. I am running PowerShell from within UC4 (a scheduler product), and I continually fought this. I always seemed to find something that worked for each scenario, but what worked for one did not work for the other.
I probably spent more time trying to fix this issue than on trying solve any other single problem with PowerShell. Your work-around works great. Thanks!
No. 15 — December 6th, 2011 at 10:01 pm
Wow, thanks for writing up an explanation of this that confirms an intuitive guess at was happening. And a workaround makes this 10 times better. Really appreciate it!
No. 16 — December 13th, 2011 at 1:44 pm
No dice – the V2 fix doesn’t work. Like many of the other users, I’m seeing this issue when calling PowerShell scripts from CA Autosys.
The error I’m seeing with the V2 fix listed above:
You cannot call a method on a null-valued expression.
At C:\Program Files\PowerGUI\actimize_daily_run.ps1:17 char:96
+ [void] $consoleHost.GetType().GetProperty(“IsStandardOutputRedirected”, $bindingFlags).GetValue <<<< ($consoleHost, @())
+ CategoryInfo : InvalidOperation: (GetValue:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\Program Files\PowerGUI\actimize_daily_run.ps1:20 char:16
+ $field.SetValue <<<< ($consoleHost, [Console]::Out)
+ CategoryInfo : InvalidOperation: (SetValue:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\Program Files\PowerGUI\actimize_daily_run.ps1:22 char:17
+ $field2.SetValue <<<< ($consoleHost, [Console]::Out)
+ CategoryInfo : InvalidOperation: (SetValue:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
No. 17 — December 13th, 2011 at 1:51 pm
While the V2 fix listed above doesn’t work, I found what appears to be a solution to my specific problem.
Basically I was using Powershell as a wrapper around a vendor-provided batch file, in order to pass it some parameters. I’m using CA Autosys R11 to call “powershell.exe -f “x:\path\script.ps1″. In the batch file itself, a line containing “x:\path\script.bat $parm1 $parm2″ (no quotes) called the batch file. I appended the line to “x:\path\script1.bat $parm1 $parm2 | Out-Default” (no quotes) and all output appeared correctly in the CA Autosys R11 STDOUT log.
YMMV, of course. I haven’t tested this with embedded code that creates STDERR yet.
No. 18 — February 13th, 2012 at 1:23 pm
As another option, you could create a parent script to run the child script using this syntax:
powershell .\child.ps1 2>&1 | more
Hiding the fact that the output is going to a file should prevent the bug from happening. (You’re going to want to check whether output is actually redirected first.)
It may well be possible to avoid invoking more.com, perhaps by making the parent script do the piping itself, but I’ll leave this to someone else to investigate. :-)
No. 19 — January 16th, 2013 at 2:25 pm
For anyone still using this code it might be worth noting that this will not run in ISE. Wrap inside an if statement $host.Name -eq ‘ConsoleHost’ for console or $host.Name -ne ‘PowerShell’ to exclude ISE. Additionally I was still getting the error for Standard Error Redirection and had to add [void] $consoleHost.GetType().GetProperty(“IsStandardErrorRedirected”, $bindingFlags).GetValue($consoleHost, @()). I also updated $field2.SetValue($consoleHost, [Console]::Out) to $field2.SetValue($consoleHost, [Console]::Error) but have seen no difference in functionality.
No. 20 — May 1st, 2013 at 8:00 pm
Another workaround
Before piping to a file you can redirect output to find and reprint again
for example
PowerShell -Command ‘”start”‘; Write-Error “Foo”; ‘”end”‘ | find /v “” > c:\temp\redirect.log 2>&1