PowerShell script to check an application that's locking a file?

Using in PowerShell, how can I check if an application is locking a file?

I like to check which process/application is using the file, so that I can close it.

10 Answers

You can do this with the SysInternals tool handle.exe. Try something like this:

PS> $handleOut = handle PS> foreach ($line in $handleOut) { if ($line -match '\S+\spid:') { $exe = $line } elseif ($line -match 'C:\\Windows\\Fonts\\segoeui\.ttf') { "$exe - $line" } } MSASCui.exe pid: 5608 ACME\hillr - 568: File (---) C:\Windows\Fonts\segoeui.ttf ... 
5

You should be able to use the openfiles command from either the regular command line or from PowerShell.

The openfiles built-in tool can be used for file shares or for local files. For local files, you must turn on the tool and restart the machine (again, just for first time use). I believe the command to turn this feature on is:

openfiles /local on 

For example (works on Windows Vista x64):

openfiles /query | find "chrome.exe" 

That successfully returns file handles associated with Chrome. You can also pass in a file name to see the process currently accessing that file.

4

This could help you: Use PowerShell to find out which process locks a file. It parses the System.Diagnostics.ProcessModuleCollection Modules property of each process and it looks for the file path of the locked file:

$lockedFile="C:\Windows\System32\wshtcpip.dll" Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq $lockedFile){$processVar.Name + " PID:" + $processVar.id}}} 
1

You can find a solution using Sysinternal's Handle utility.

I had to modify the code (slightly) to work with PowerShell 2.0:

#/* */ Function Get-LockingProcess { [cmdletbinding()] Param( [Parameter(Position=0, Mandatory=$True, HelpMessage="What is the path or filename? You can enter a partial name without wildcards")] [Alias("name")] [ValidateNotNullorEmpty()] [string]$Path ) # Define the path to Handle.exe # //$Handle = "G:\Sysinternals\handle.exe" $Handle = "C:\tmp\handle.exe" # //[regex]$matchPattern = "(?<Name>\w+\.\w+)\s+pid:\s+(?<PID>\b(\d+)\b)\s+type:\s+(?<Type>\w+)\s+\w+:\s+(?<Path>.*)" # //[regex]$matchPattern = "(?<Name>\w+\.\w+)\s+pid:\s+(?<PID>\d+)\s+type:\s+(?<Type>\w+)\s+\w+:\s+(?<Path>.*)" # (?m) for multiline matching. # It must be . (not \.) for user group. [regex]$matchPattern = "(?m)^(?<Name>\w+\.\w+)\s+pid:\s+(?<PID>\d+)\s+type:\s+(?<Type>\w+)\s+(?<User>.+)\s+\w+:\s+(?<Path>.*)$" # skip processing banner $data = &$handle -u $path -nobanner # join output for multi-line matching $data = $data -join "`n" $MyMatches = $matchPattern.Matches( $data ) # //if ($MyMatches.value) { if ($MyMatches.count) { $MyMatches | foreach { [pscustomobject]@{ FullName = $_.groups["Name"].value Name = $_.groups["Name"].value.split(".")[0] ID = $_.groups["PID"].value Type = $_.groups["Type"].value User = $_.groups["User"].value.trim() Path = $_.groups["Path"].value toString = "pid: $($_.groups["PID"].value), user: $($_.groups["User"].value), image: $($_.groups["Name"].value)" } #hashtable } #foreach } #if data else { Write-Warning "No matching handles found" } } #end function 

Example:

PS C:\tmp> . .\Get-LockingProcess.ps1 PS C:\tmp> Get-LockingProcess C:\tmp\foo.txt Name Value ---- ----- ID 2140 FullName WINWORD.EXE toString pid: 2140, user: J17\Administrator, image: WINWORD.EXE Path C:\tmp\foo.txt Type File User J17\Administrator Name WINWORD PS C:\tmp> 
1

I was looking for a solution to this as well and hit some hiccups.

  1. Didn't want to use an external app
  2. Open Files requires the local ON attribute which meant systems had to be configured to use it before execution.

After extensive searching I found.

Thanks to Paul DiMaggio

This seems to be pure powershell and .net / C#

4

Posted a PowerShell module in PsGallery to discover & kill processes that have open handles to a file or folder. It exposes functions to: 1) find the locking process, and 2) kill the locking process. The module automatically downloads handle.exe on first usage.

Find-LockingProcess()
Retrieves process information that has a file handle open to the specified path.
Example: Find-LockingProcess -Path $Env:LOCALAPPDATA
Example: Find-LockingProcess -Path $Env:LOCALAPPDATA | Get-Process

Stop-LockingProcess()
Kills all processes that have a file handle open to the specified path.
Example: Stop-LockingProcess -Path $Home\Documents

PsGallery Link: To install run:
Install-Module -Name LockingProcessKiller

You can find for your path on handle.exe.

I've used PowerShell but you can do with another command line tool.

With administrative privileges:

handle.exe -a | Select-String "<INSERT_PATH_PART>" -context 0,100 

Down the lines and search for "Thread: ...", you should see there the name of the process using your path.

0

I like what the command prompt (CMD) has, and it can be used in PowerShell as well:

tasklist /m <dllName> 

Just note that you can't enter the full path of the DLL file. Just the name is good enough.

1

I've seen a nice solution at Locked file detection that uses only PowerShell and .NET framework classes:

function TestFileLock { ## Attempts to open a file and trap the resulting error if the file is already open/locked param ([string]$filePath ) $filelocked = $false $fileInfo = New-Object System.IO.FileInfo $filePath trap { Set-Variable -name filelocked -value $true -scope 1 continue } $fileStream = $fileInfo.Open( [System.IO.FileMode]::OpenOrCreate,[System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None ) if ($fileStream) { $fileStream.Close() } $obj = New-Object Object $obj | Add-Member Noteproperty FilePath -value $filePath $obj | Add-Member Noteproperty IsLocked -value $filelocked $obj } 
2

If you modify the above function slightly like below it will return True or False (you will need to execute with full admin rights) e.g. Usage:

PS> TestFileLock "c:\pagefile.sys"

function TestFileLock { ## Attempts to open a file and trap the resulting error if the file is already open/locked param ([string]$filePath ) $filelocked = $false $fileInfo = New-Object System.IO.FileInfo $filePath trap { Set-Variable -name Filelocked -value $true -scope 1 continue } $fileStream = $fileInfo.Open( [System.IO.FileMode]::OpenOrCreate, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None ) if ($fileStream) { $fileStream.Close() } $filelocked } 
3

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like