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 ... 5You 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.
4This 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}}} 1You 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> 1I was looking for a solution to this as well and hit some hiccups.
- Didn't want to use an external app
- 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#
4Posted 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.
0I 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.
1I'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 } 2If 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