Назад | Перейти на главную страницу

Закройте заблокированный файл в Windows Share с помощью Powershell и Openfiles

Я работаю с большим количеством общих папок, но есть куча заблокированных файлов, которые были открыты каким-то другим процессом.

Мне нужно закрыть эти файлы. Пока что использую 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.

  1. Перейдите к $env:homepath\Documents\WindowsPowerShell (создайте, если у вас его нет).
    Обычно это сводится к C:\Users\<username>\Documents\WindowsPowerShell.
  2. Создайте файл с именем profile.ps1 (или Microsoft.PowerShell_profile.ps1).
  3. Скопируйте и вставьте все 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