Я работаю с большим количеством общих папок, но есть куча заблокированных файлов, которые были открыты каким-то другим процессом.
Мне нужно закрыть эти файлы. Пока что использую MMC - Системные инструменты - Общие папки - Открытые файлы.
Было бы намного удобнее, если бы я мог использовать PowerShell для фильтрации списка / таблицы, полученной OpenFiles.exe и как только я получу идентификатор файла, закройте его net файл / закрыть, или другие родные средства PS с аналогичным эффектом.
Я новичок в PowerShell, поэтому мне интересно, есть ли способ создать сценарий PS, который получает путь к файлу, а затем использует идентификатор файла, чтобы закрыть этот файл?
Get-SmbOpenFile и Close-SmbOpenFile сделает работу за вас.
Войдите на свой файловый сервер, запустите PowerShell. Используйте Get-SmbOpenFile, чтобы отобразить все открытые файлы на вашем файловом сервере. Файлы будут отображаться вместе со следующими заголовками таблиц.
FileId SessionId Path ShareRelativePath ClientComputerName ClientUserName
Используйте Close-SmbOpenFile, чтобы закрыть файл.
Close-SmbOpenFile -FileId 4415226383589
Если вы знаете, что проблема в файле Excel, вы можете сузить область поиска для всех открытых файлов с расширением .XLSX.
Get-SmbOpenFile | Where-Object -Property sharerelativepath -match ".XLSX"
Найдя в результатах проблемный файл, вы можете закрыть его по идентификатору файла.
Если вы хотите закрыть все открытые файлы на файловом сервере:
Get-SmbOpenFile | Close-SmbOpenFile
Если вы хотите закрыть один или несколько открытых файлов с расширением ".XLSX".
Get-SmbOpenFile | Where-Object -Property sharerelativepath -match ".XLSX" | Close-SmbOpenFile -Force
**** ПРИМЕЧАНИЕ **** Согласно статье TechNet "The Close-SMBOpenFile командлет принудительно закрывает файл, открытый одним из клиентов сервера блока сообщений сервера (SMB). Этот командлет следует использовать с осторожностью, поскольку это может привести к потере данных для клиента. для которого файл закрывается, если клиент не сбросил все модификации файла обратно на сервер до закрытия файла ».
Для получения дополнительной информации о 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
Есть ли причина, по которой вам нужно использовать оба openfiles.exe
и net file
?
Ниже приведена функция, использующая только net file
и оборачивает его вокруг сценария PowerShell.
Чтобы использовать его, вы можете скопировать весь код и вставить его в сеанс PowerShell. В качестве примечания, вам нужны права администратора, чтобы использовать net file
и openfiles
.
Как только вы вставите его в свою сессию, вы сможете использовать функцию Close-OpenFile
. Использование очень простое. Вы можете передать пути к файлам в функцию или указать пути к файлам в качестве параметра.
Если вы вставили его как есть, вы действительно можете получить помощь, используя Get-Help Close-OpenFile -Example
чтобы увидеть примеры. Ниже приведены те же примеры для вашего удобства.
# 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"
Теперь предположим, что вы хотите использовать это каждый раз, когда открываете PowerShell. Я предоставил основной способ сделать это (есть и другие способы сделать это) в конце этого ответа.
<#
.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" }
}
Ниже показан базовый способ использования этой функции каждый раз, когда вы открываете PowerShell.
$env:homepath\Documents\WindowsPowerShell
(создайте, если у вас его нет).C:\Users\<username>\Documents\WindowsPowerShell
.profile.ps1
(или Microsoft.PowerShell_profile.ps1
).Close-OpenFiles
функции и сохраните ее.Вот быстрое и грязное использование CMD и OpenFiles.exe. Я уверен, что при необходимости это можно было бы быстро перевести на PoSH. Сохраните его как CloseFile.cmd и поместите в папку на своем пути.
@echo off
if "%1" == "" goto SYNTAX
if "%2" == "" goto SYNTAX
goto RUNIT
:SYNTAX
echo Use:
echo CloseFile.cmd ^<server^> ^<file^>
goto :EOF
:RUNIT
set _server=%1
set _file=%2
openfiles /query /s %_server% /fo csv | findstr /i /c:"%_file%" > _filelist.txt
for /f "tokens=1,4 delims=," %%a in (_filelist.txt) do (
openfiles /disconnect /s %_server% /op %%b /id %%a
)
if exist _filelist.txt del _filelist.txt