使用 Powershell 和 Openfiles 关闭 Windows 共享中的锁定文件

使用 Powershell 和 Openfiles 关闭 Windows 共享中的锁定文件

我使用了很多文件夹共享,但有一堆被其他进程打开的锁定文件。

我需要关闭这些文件。到目前为止,我一直在使用 MMC - 系统工具 - 共享文件夹 - 打开文件。

如果我可以使用 PowerShell 来过滤通过以下方式检索的列表/表,那就方便多了:打开文件一旦我得到文件 ID,就关闭它网络文件/关闭或者其他一些 PS 原生的类似效果的方法。

我是 PowerShell 新手,所以我想知道是否有办法创建一个 PS 脚本来接收文件的路径,然后使用文件 ID 来关闭该文件?

答案1

获取SmbOpenFile关闭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"

在结果中找到问题文件后,您可以通过 fileID 关闭该文件。

如果要关闭文件服务器上所有打开的文件:

Get-SmbOpenFile | Close-SmbOpenFile

如果您想关闭一个或多个打开的且文件扩展名与“.XLSX”匹配的文件。

Get-SmbOpenFile | Where-Object -Property sharerelativepath -match ".XLSX" | Close-SmbOpenFile -Force

****注意**** 根据 TechNet 文章“关闭-SMBOpenFile命令强行关闭某个客户端打开的文件服务器消息块 (SMB) 服务器。应谨慎使用此 cmdlet,因为它可能会导致客户端数据丢失如果客户端在关闭文件之前没有将所有文件修改刷新回服务器,则文件将被关闭。”

有关 CMDlet 的更多信息

获取SmbOpenFile https://technet.microsoft.com/en-us/library/jj635701(v=wps.620).aspx

关闭SmbOpenFile https://technet.microsoft.com/en-us/library/jj635721(v=wps.620).aspx

答案2

你需要同时使用两者吗?openfiles.exe net file?下面是一个仅使用并包装 PowerShell 脚本的
函数。net file

要使用它,您可以复制整个代码,并将其粘贴到 PowerShell 会话中。附带说明一下,您需要管理员权限才能使用net fileopenfiles

将其粘贴到会话中后,您将能够使用该函数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函数并保存。

答案3

这是使用 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

相关内容