Close locked file in Windows Share using Powershell and Openfiles
I work with a lot of folder shares, but there are a bunch of locked files which have been opened by some other process.
I need to close those files. So far I've been using MMC - System Tools - Shared Folders - Open Files.
It would be far more convenient if I could use PowerShell to filter the list/table retrieved by OpenFiles.exe and once I get the file ID close it with net file /close, or some other PS native means to similar effect.
I am new to PowerShell, so I wonder if there is a way to create a PS script that receives the file's path and then used the file ID to close that file?
Get-SmbOpenFile and Close-SmbOpenFile will get the job done for you.
Logged into your file server, start PowerShell. Use Get-SmbOpenFile to display all of the open files on your file server. The files will display along with the following table headers
FileId SessionId Path ShareRelativePath ClientComputerName ClientUserName
Use Close-SmbOpenFile to close a file.
Close-SmbOpenFile -FileId 4415226383589
If you know an Excel file is the issue, you can narrow your search for all open files with a .XLSX extension.
Get-SmbOpenFile | Where-Object -Property sharerelativepath -match ".XLSX"
After finding your problem file in the results, you can then close the file by the fileID.
If you want to close all open files on your file server:
Get-SmbOpenFile | Close-SmbOpenFile
If you want to close one or more files that are open and that match the file extension ".XLSX".
Get-SmbOpenFile | Where-Object -Property sharerelativepath -match ".XLSX" | Close-SmbOpenFile -Force
****NOTE**** Per the TechNet article "The Close-SMBOpenFile cmdlet forcibly closes a file that is open by one of the clients of the Server Message Block (SMB) server. This cmdlet should be used with care as it may result in data loss to the client for which the file is being closed if the client has not flushed all of the file modifications back to the server before the file is closed."
For more information on the CMDlets
Get-SmbOpenFile https://technet.microsoft.com/en-us/library/jj635701(v=wps.620).aspx
Close-SmbOpenFile https://technet.microsoft.com/en-us/library/jj635721(v=wps.620).aspx
Is there a reason that you need to use both openfiles.exe
and net file
?
Below is a function that uses only net file
and wraps it around a PowerShell Script.
To use it, you can copy the whole code, and paste it into a PowerShell session. As a side note, you need Administrator privilege to use net file
and openfiles
.
Once you paste it into your session, you will be able to use the function Close-OpenFile
. The usage is very simple. You can either pipe the file paths into the function, or to specify the file paths as a parameter.
If you pasted it as is, you can actually get help by using Get-Help Close-OpenFile -Example
to see examples. Below are the same examples for your convenience.
# Method 1 : Pipeline
@("file\path\1", "file\path\2") | Close-OpenFile
"file\path\1" | Close-OpenFile
# Method 2 : Parameter
Close-OpenFile @("file\path\1", "file\path\2")
Close-OpenFile "file\path\2"
Now, suppose you want to use this every time you open PowerShell. I've provided a basic way to do this (there are other ways to do it) at the end of this answer.
<#
.Synopsis
Closes Files Opened in Network Share
.EXAMPLE
@("file\path\1", "file\path\2") | Close-OpenFile
Attempts to close "file\path\1" and "file\path\2" if they are open.
.EXAMPLE
Close-OpenFile @("file\path\1", "file\path\2")
Attempts to close "file\path\1" and "file\path\2" if they are open.
.EXAMPLE
"file\path\1" | Close-OpenFile
Attempts to close "file\path\1" if it is open.
.EXAMPLE
Close-OpenFile "file\path\2"
Attempts to close "file\path\2" if it is open.
#>
function Close-OpenFile {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[String[]]$filesToClose
)
Begin {
$netFile = net file
if($netFile.length -lt 7) { Throw "No Files are Open" }
$netFile = $netFile[4..($netFile.length-3)]
$netFile = $netFile | ForEach-Object {
$column = $_ -split "\s+", 4
New-Object -Type PSObject -Property @{
ID = $column[0]
FilePath = $column[1]
UserName = $column[2]
Locks = $column[3]
}
}
$count = 0
} Process {
ForEach ($file in $filesToClose) {
ForEach ($openFile in $netFile) {
if($openFile.FilePath -eq $file) {
$count++
net file $openfile.ID /close > $null
}
}
}
} End { Write-Output "Closed $count Files" }
}
Below illustrates a basic way to have this function every time you open PowerShell.
- Navigate to
$env:homepath\Documents\WindowsPowerShell
(create it if you don't have it).
This typically resolves toC:\Users\<username>\Documents\WindowsPowerShell
. - Create a file called
profile.ps1
(orMicrosoft.PowerShell_profile.ps1
). - Copy and Paste the entire
Close-OpenFiles
function and save it.