1

I am trying to create a script that appends (or creates, then appends) to an existing file. This file is being interfaced to from another system, so in order to avoid a situation where the file is being read while I'm appending to it, I'm creating a no-share lock on it. Script seems to work perfectly with one exception that I cannot understand. Here's a code sample:

$ErrorActionPreference = "Stop"
try
{
    [System.IO.FileStream]$file1 = [System.IO.File]::Open("test.txt", [System.IO.FileMode]::Append,[System.IO.FileAccess]::Write, [System.IO.FileShare]::None)
}
catch
{
    Write-Host "Unable to create a lock on this file"
}

There's one condition that does NOT trigger the catch block - if the file is already locked via a powershell console AND if this code is ran from a script and not directly typed in the window. If I open the file first in Excel, the catch block always works. If I execute this code by typing it into the console, it also always works. But if I lock a file first by typing this into the console, and then run a script that attempts to do the same thing, there's no exception thrown and the catch block does not trigger.

What am I missing here?

Update: I did additional troubleshooting and here's my findings. First, how to reproduce this:

  • Create a file named test.txt
  • Create a script named test1.ps1, place the above code in it
  • Run this command in console:

    [System.IO.FileStream]$file2 = [System.IO.File]::Open("test.txt", [System.IO.FileMode]::Append,[System.IO.FileAccess]::Write, [System.IO.FileShare]::None)
    
  • Now execute the test1.ps1 script

And the catch block of the script does not trigger... in my work environment! I tested at home, and it works as expected. So I went back to work and tested it again, this time using a file on the PC's local drive and it worked. The one difference that made it not work was the fact that the file I was working on was located on my company's DFS namespace. I tried it on a local network's drive mapped on my PC and it worked fine.

So, for whatever reason, PowerShell does not react to files locked by PowerShell on a DFS namespace like it is supposed to. Every other app I tried does detect the lock: Notepad and Excel refused to read the file, and when I tested it on a PDF document, Acrobat wouldn't open it either. But PowerShell does not complain, and even processes all the subsequent methods without an error - which have no effect; CopyTo() and Flush() methods do not fail, but the file is unchanged.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
Cpu1
  • 77
  • 8
  • And another comment: if I replace Append method with either Open, CreateNew, or Truncate, it does trigger the catch block. Append, Create, and OpenOrCreate methods do not. – Cpu1 Oct 11 '16 at 15:36

1 Answers1

2

When you run the above code as a script the file/handle is automatically closed when the script (or, more precisely, the PowerShell process) terminates. You need to keep the script running to keep the handle open, e.g. by adding an infinite loop after the Open() call:

$ErrorActionPreference = "Stop"
try {
    $writeStream = [IO.File]::Open($FilePath,[IO.FileMode]::Append,[IO.FileAccess]::Write, [IO.FileShare]::None)
    do {
        Start-Sleep -Milliseconds 100
    } while ($true)
} catch {
    Write-Host "Unable to create a lock on this file"
}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • Sorry, this is my first script, so maybe I'm not understanding your answer... My problem is not keeping the lock on the file, the issue is: if the file is already locked by the powershell, the script instance does not detect it. The Open statement does not fail like I expect it to. – Cpu1 Oct 11 '16 at 00:55
  • Can't reproduce. Please describe what *exactly* you do, and how *exactly* you do it. – Ansgar Wiechers Oct 11 '16 at 03:01
  • I did some more testing and I think it's either a bug or maybe it's designed that way. I'm adding my findings to the original post. – Cpu1 Oct 11 '16 at 15:02