28

I have a problem with automating a deployment, after I stop the service there is still a lock on the file and I am unable to delete it. I really do not want to start hacking about with sleeps to make something that 'usually works'. Is there a good way to properly resolve the problem of locked files, perhaps some kind of 'wait until file is removable':

Get-ChildItem : Access to the path 'D:\MyDirectory\' is denied.

'Test-Path' is not sufficient in this case as the folder both exists and I have access to it.

Dech
  • 1,582
  • 4
  • 17
  • 32
  • 3
    http://social.technet.microsoft.com/Forums/windowsserver/en-US/74ea3752-9403-4296-ab98-d03fcc12b608/how-to-check-to-see-if-a-file-is-openlocked-before-trying-to-copy-it?forum=winserverpowershell – David Brabant Jul 28 '14 at 10:02

4 Answers4

55

With thanks to David Brabant who posted a link to this solution under the initial question. It appears I can do this by starting off with the following function:

function Test-FileLock {
  param (
    [parameter(Mandatory=$true)][string]$Path
  )

  $oFile = New-Object System.IO.FileInfo $Path

  if ((Test-Path -Path $Path) -eq $false) {
    return $false
  }

  try {
    $oStream = $oFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)

    if ($oStream) {
      $oStream.Close()
    }
    return $false
  } catch {
    # file is locked by a process.
    return $true
  }
}

Then add a 'wait until' function with a timeout.

Thanks for your help!

Arno Peters
  • 675
  • 5
  • 13
Dech
  • 1,582
  • 4
  • 17
  • 32
  • I tried this but it seems to not work unless I add a write-output statement to Test-FileLock, am I doing something wrong? ` If (Test-FileLock -path $file) { Write-Output "skipping locked file $File" } Else { $null = Move-Item -Path $file.FullName -Destination $dir_path\ } ` – Ching Liu Mar 20 '20 at 14:48
26

I use this:

try { [IO.File]::OpenWrite($file).close();$true }
catch {$false}
mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • 2
    a try/catch as a logical if/else feels so nasty, but I guess if there is no other way... – Matthew Bonig Sep 10 '14 at 19:27
  • 3
    `$file` should be an absolute path eg. `[IO.File]::OpenWrite((Resolve-Path $file).Path).close()`, otherwise it will default to the home directory and become a hard to debug logic error. – mvanle Jul 15 '15 at 05:04
  • 4
    Note that this returns false if the file is locked, while @Dech's answer returns true if the file is locked. – 3VYZkz7t Jan 26 '18 at 12:04
  • My gut feeling: If you open a file to write will that not clear down the content? The answer from @Dech at least opens for ReadWrite - so if file exists it wouldn't clear it down. Can someone confirm my suspicions? .. Though I guess if it's locked by another task it may prevent that anyhow. But if it isn't locked will you not wipe out the data? Not a good side effect if that is the case! – JGFMK May 09 '23 at 09:55
2
$fileName = "C:\000\Doc1.docx"
$file = New-Object -TypeName System.IO.FileInfo -ArgumentList $fileName
$ErrorActionPreference = "SilentlyContinue"
[System.IO.FileStream] $fs = $file.OpenWrite(); 
if (!$?) {
    $msg = "Can't open for write!"
}
else {
    $fs.Dispose()
    $msg = "Accessible for write!"
}
$msg
Basati Naveen
  • 323
  • 6
  • 18
1

Simplified:

Function Confirm-FileInUse {
    Param (
        [parameter(Mandatory = $true)]
        [string]$filePath
    )
    try {
        $x = [System.IO.File]::Open($filePath, 'Open', 'Read') # Open file
        $x.Close() # Opened so now I'm closing
        $x.Dispose() # Disposing object
        return $false # File not in use
    }
    catch [System.Management.Automation.MethodException] {
        return $true # Sorry, file in use
    }
}
Krywulf
  • 11
  • 2