Powershell: Get-Content without locking file

7

5

I need to read a file on a remote pc which is frequently modified. As it so happens, it appears that my script is sometimes colliding with a write on the file, rendering it inaccessible. I cannot change the way the file is written to so I have to work with what I have.

I ran a test by having a script continuously reading a file with Get-Content and subsequently starting another script which writes to the file at frequent intervals. At times, the write operation was not possible.

Is it possible that I use get-content on a remote pc without locking the file?

lcam

Posted 2017-03-03T11:24:54.567

Reputation: 85

Answers

4

[System.IO.FileStream]$fileStream = [System.IO.File]::Open("\\remote\share\Text Document.txt", [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
$byteArray = New-Object byte[] $fileStream.Length
$encoding = New-Object System.Text.UTF8Encoding $true
while ($fileStream.Read($byteArray, 0 , $byteArray.Length)) {
    $encoding.GetString($byteArray)
}
$fileStream.Dispose()

t1meless

Posted 2017-03-03T11:24:54.567

Reputation: 291

Thank you for your input, however this still locks the file to a write, if my testing is correct. – lcam – 2017-03-06T13:19:39.793

How do you perform your testing? I didn't get any locks while testing this code snippet. – t1meless – 2017-03-12T19:44:25.933

Never mind, my testing was in fact incorrect. I researched a bit so I could modify your code to read the last couple of lines of the file rather than read the whole lot of it as that was taking some time and conflicting with a write. This seemed to have solved the issue, thanks! – lcam – 2017-03-16T15:53:55.740

8

The content that is being written cannot be read on the same time.

As a solution for you, you could read the file using shadow copy. For that, you will need to mount a shadow copy.

$s1 = (Get-WmiObject -List Win32_ShadowCopy).Create("X:\", "ClientAccessible")
$s2 = Get-WmiObject Win32_ShadowCopy | Where-Object { $_.ID -eq $s1.ShadowID }
$d  = $s2.DeviceObject + "\"   # 
cmd /c mklink /d X:\tmpshacpy "$d"

After this, you can access the mounted location ( X:\tmpshacpy) and read the file just fine.

To unmount the shadow copy after the read is done, use $s2.Delete().

Overmind

Posted 2017-03-03T11:24:54.567

Reputation: 8 562

Thanks for your input. I read about this feature and it looks amazing, however I forgot to mention that I need to this on a remote computer. – lcam – 2017-03-03T13:45:42.207

"I forgot to mention that I need to this on a remote computer" Use Invoke-Command for that. – Ƭᴇcʜιᴇ007 – 2017-03-03T14:01:40.543

You can use remote commands just fine (with invoke) and you will have to provide credentials (just another additional parameter). – Overmind – 2017-03-06T09:43:39.733

Thanks all. Unfortunately it understandably is taking some time to create and mount the shadow copy on the remote pc, and I need this script to go over 100 pc's after each other... but perhaps I am asking for the impossible now. If only there was some way to kind of get a shadow copy of a single file... Thanks anyway! – lcam – 2017-03-06T13:17:00.893

If the shadow is mounted, you can copy a single file from that mount, should be no issue here. – Overmind – 2017-03-07T08:18:39.130

Overmind, thanks a lot for your input as it is definitely a sure-fire way of copying/restoring and will definitely have it in my arsenal for the future. However it understandably takes a few seconds.. in this case, lowering the access time seemed to have worked for me. Thanks! – lcam – 2017-03-16T15:58:04.133

Glad it worked. – Overmind – 2017-03-21T08:59:27.320