We’ve all had this. You want to delete or rename some file or folder, and you get the very dreaded following window:
You probably already know about the locked files and checked the Server Manager > Roles > File Services > Share and Storage Management > OpenFiles (this is the path for Win 2K8). Your folder is not to be seen, and it gets you mad, I know.
Then you Google some, and you find some miraculous third-party software which-will-solve-all-your-problem-but-please-click-next-next-next-and-don’t-read.
Delta Toolbar? SRSLY?
Then let’s think: it’s Windows, we are in 2015; what about Powershell?
Beam Us Up Scotty proposes a command for this, let’s try it on that example directory:
1 2 |
$lockedFile="D:\atestdir002" Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq $lockedFile){$processVar.Name + " PID:" + $processVar.id}}} |
It might be actually good for files, but in the case of a directory, it returns nothing 🙁
Out of the box, I haven’t found a way to get what I want: clearly identify what the hell is locking my file or folder.
There is a Sysinternals executable called Handle.exe (which I would love to decompile some day and inject its commands into some PS!) which looks promising.
Note that you can run this executable from a remote location, but not from a certain location, aimed toward a remote machine where the file is locked.
The Lonely Administrator and Stackoverflow propose solutions using this, let’s try:
- Download Handle.exe from the official Sysinternals site. It’s a safe lonely executable, no crappy toolbar, no adware and the like.
- Put it on some network share.
- Write a nice PS function to use Handle.exe. As we won’t reinvent the wheel; just grab the one from the Lonely Administrator (the second “Click to Expand Code”)… it’s well done and works fine (*).
- Put the function in a file (let’s call it Get-LockingProcess.ps1) on a share (e.g. the same as Handle.exe, let’s call it MYSHARE for the example). Be sure to edit the path to the Handle.exe file (variable $Handle in that code) to match your network share.
- From anywhere where a file or folder is locked, as long as you have access to the said share, you open a Powershell window, you include the Get-LockingProcess.ps1 (using the dot command for instance) and then you call the function with the locked directory.
Let’s try this with our example dir. I put Handle.exe and the Get-LockingProcess.ps1 files on \\MYSHARE:
1 2 3 4 5 6 7 8 9 |
PS C:\> . \\MYSHARE\Get-LockingProcess.ps1 PS C:\> Get-LockingProcess D:\atestdir002 FullName : cmd.exe Name : cmd ID : 4896 Type : File Path : D:\atestdir002 |
Pretty clear: you have the directory opened in a cmd window!
This is from a system admin’s point of view and wanting to give any power user a quick and easy way to identify locked files/folders.
Of course you can also do this locally, and/or only output Handle.exe to a file and Ctrl+F into that file, but it isn’t as fancy ! 🙂
(*) For future’s sake, here is a copy, with cited source:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# source http://jdhitsolutions.com/blog/2014/03/friday-fun-find-file-locking-process-with-powershell/ # in remote script/PS window type the following line: # . \\MYSHARE\Get-LockingProcess.ps1 # then call it with: # Get-LockingProcess BLOCKEDFILE 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 = "\\MYSHARE\handle.exe" [regex]$matchPattern = "(?<Name>\w+\.\w+)\s+pid:\s+(?<PID>\b(\d+)\b)\s+type:\s+(?<Type>\w+)\s+\w+:\s+(?<Path>.*)" $data = &$handle $path $MyMatches = $matchPattern.Matches( $data ) if ($MyMatches.value) { $MyMatches | foreach { [pscustomobject]@{ FullName = $_.groups["Name"].value Name = $_.groups["Name"].value.split(".")[0] ID = $_.groups["PID"].value Type = $_.groups["Type"].value Path = $_.groups["Path"].value } #hashtable } #foreach } #if data else { Write-Warning "No matching handles found" } } #end function |
Doesn’t that regex totally PWNS? 🙂