【问题标题】:PowerShell script to check an application that's locking a file?用于检查锁定文件的应用程序的 PowerShell 脚本?
【发布时间】:2009-06-05 21:00:39
【问题描述】:

在 PowerShell 中使用,我如何检查应用程序是否锁定了文件?

我喜欢检查哪个进程/应用程序正在使用该文件,以便我可以关闭它。

【问题讨论】:

    标签: powershell scripting filelock


    【解决方案1】:

    您可以使用SysInternals tool handle.exe 执行此操作。试试这样的:

    PS> $handleOut = handle
    PS> foreach ($line in $handleOut) { 
            if ($line -match '\S+\spid:') {
                $exe = $line
            } 
            elseif ($line -match 'C:\\Windows\\Fonts\\segoeui\.ttf')  { 
                "$exe - $line"
            }
         }
    MSASCui.exe pid: 5608 ACME\hillr -   568: File  (---)   C:\Windows\Fonts\segoeui.ttf
    ...
    

    【讨论】:

    • 谢谢,我可以使用句柄[文件名],让它更简单。
    • 这有什么好玩的? :-) 但是,是的,那会简单得多。
    • :(虽然还是有问题...显示某个进程是否打开了文件(即文本文件)并不是那么强大。
    • 虽然不幸的是,handle 是一个外部工具
    • handle /dir 为我工作。然后我在任务管理器中杀死了锁定文件夹的进程。
    【解决方案2】:

    您应该能够从常规命令行或 PowerShell 中使用 openfiles command

    openfiles 内置工具可用于文件共享或本地文件。对于本地文件,您必须打开该工具并重新启动机器(同样,仅适用于第一次使用)。我相信打开此功能的命令是:

    openfiles /local on
    

    例如(适用于 Windows Vista x64):

    openfiles /query | find "chrome.exe"
    

    成功返回与 Chrome 关联的文件句柄。你也可以传入一个文件名来查看当前访问该文件的进程。

    【讨论】:

    • 据我所见,该命令仅枚举用户通过 SMB 共享从远程打开的文件。它不会告诉您有关使用它的过程的任何信息。
    • 您无法从链接中看出这一点,但看起来 Johannes 是对的。对我来说,它在 Vista x64 上不起作用——显示“信息:未找到共享的打开文件。”
    • Joe/Johannes:首先,您是否打开了全局“维护对象列表”(我认为语法是“openfiles /local on”IIRC)?接下来,您是否像上面的示例一样传入“/query”参数(似乎是 Vista 的要求)?
    【解决方案3】:

    这可以帮助你:Use PowerShell to find out which process locks a file。它解析每个进程的 System.Diagnostics.ProcessModuleCollection Modules 属性并查找锁定文件的文件路径:

    $lockedFile="C:\Windows\System32\wshtcpip.dll"
    Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq $lockedFile){$processVar.Name + " PID:" + $processVar.id}}}
    

    【讨论】:

    • 对我来说是完美的答案,但似乎这仅适用于 dll,而不适用于任何文件,例如锁定的文本文件。
    【解决方案4】:

    您可以使用SysinternalHandle 实用程序找到解决方案。

    我不得不(稍微)修改代码以使用 PowerShell 2.0:

    #/* http://jdhitsolutions.com/blog/powershell/3744/friday-fun-find-file-locking-process-with-powershell/ */
    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 = "G:\Sysinternals\handle.exe"
        $Handle = "C:\tmp\handle.exe"
    
        # //[regex]$matchPattern = "(?<Name>\w+\.\w+)\s+pid:\s+(?<PID>\b(\d+)\b)\s+type:\s+(?<Type>\w+)\s+\w+:\s+(?<Path>.*)"
        # //[regex]$matchPattern = "(?<Name>\w+\.\w+)\s+pid:\s+(?<PID>\d+)\s+type:\s+(?<Type>\w+)\s+\w+:\s+(?<Path>.*)"
        # (?m) for multiline matching.
        # It must be . (not \.) for user group.
        [regex]$matchPattern = "(?m)^(?<Name>\w+\.\w+)\s+pid:\s+(?<PID>\d+)\s+type:\s+(?<Type>\w+)\s+(?<User>.+)\s+\w+:\s+(?<Path>.*)$"
    
        # skip processing banner
        $data = &$handle -u $path -nobanner
        # join output for multi-line matching
        $data = $data -join "`n"
        $MyMatches = $matchPattern.Matches( $data )
    
        # //if ($MyMatches.value) {
        if ($MyMatches.count) {
    
            $MyMatches | foreach {
                [pscustomobject]@{
                    FullName = $_.groups["Name"].value
                    Name = $_.groups["Name"].value.split(".")[0]
                    ID = $_.groups["PID"].value
                    Type = $_.groups["Type"].value
                    User = $_.groups["User"].value.trim()
                    Path = $_.groups["Path"].value
                    toString = "pid: $($_.groups["PID"].value), user: $($_.groups["User"].value), image: $($_.groups["Name"].value)"
                } #hashtable
            } #foreach
        } #if data
        else {
            Write-Warning "No matching handles found"
        }
    } #end function
    

    例子:

    PS C:\tmp> . .\Get-LockingProcess.ps1
    PS C:\tmp> Get-LockingProcess C:\tmp\foo.txt
    
    Name                           Value
    ----                           -----
    ID                             2140
    FullName                       WINWORD.EXE
    toString                       pid: 2140, user: J17\Administrator, image: WINWORD.EXE
    Path                           C:\tmp\foo.txt
    Type                           File
    User                           J17\Administrator
    Name                           WINWORD
    
    PS C:\tmp>
    

    【讨论】:

    • 这对我有用:&lt;# .Description Calls SysInternals handle.exe to get the locking bastard. .Parameter path File or folder #&gt; function lock-handle([string] $path) { . "C:\Program Files\SysInternals\handle64.exe" $path }
    【解决方案5】:

    我也在寻找解决方案,但遇到了一些问题。

    1. 不想使用外部应用程序
    2. 打开文件需要本地 ON 属性,这意味着必须将系统配置为在执行之前使用它。

    经过大量搜索,我找到了。

    https://github.com/pldmgg/misc-powershell/blob/master/MyFunctions/PowerShellCore_Compatible/Get-FileLockProcess.ps1

    感谢保罗·迪马乔

    这似乎是纯 powershell 和 .net/C#

    【讨论】:

    • 在 PowerShell 代码中包含 C# 非常棒,但在某种程度上它似乎是在作弊...... 将外部程序 handle.exe 替换为内部编译的 C# 模块来完成这项工作。
    • 更不用说这快了 100 倍。这对我来说需要半秒钟,而 handle.exe 可能需要大约 30 秒。
    • 似乎不适用于目录:/
    • 我最终打开了 resmon -> CPUs -> Associated Handles 并搜索了我的目录名称。
    【解决方案6】:

    在 PsGallery 中发布了一个 PowerShell 模块,用于发现和终止对文件或文件夹具有打开句柄的进程。 它将函数暴露于:1) 找到锁定进程,以及 2) 终止锁定进程。 模块首次使用时会自动下载handle.exe。

    Find-LockingProcess()
    检索具有打开到指定路径的文件句柄的进程信息。
    示例:Find-LockingProcess -Path $Env:LOCALAPPDATA
    示例:Find-LockingProcess -Path $Env:LOCALAPPDATA |获取进程

    Stop-LockingProcess()
    杀死所有文件句柄打开到指定路径的进程。
    示例:Stop-LockingProcess -Path $Home\Documents

    PsGallery 链接:https://www.powershellgallery.com/packages/LockingProcessKiller 安装运行:
    Install-Module -Name LockingProcessKiller

    【讨论】:

      【解决方案7】:

      我在 Locked file detection 看到了一个很好的解决方案,它只使用 PowerShell 和 .NET 框架类:

      function TestFileLock {
          ## Attempts to open a file and trap the resulting error if the file is already open/locked
          param ([string]$filePath )
          $filelocked = $false
          $fileInfo = New-Object System.IO.FileInfo $filePath
          trap {
              Set-Variable -name filelocked -value $true -scope 1
              continue
          }
          $fileStream = $fileInfo.Open( [System.IO.FileMode]::OpenOrCreate,[System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None )
          if ($fileStream) {
              $fileStream.Close()
          }
          $obj = New-Object Object
          $obj | Add-Member Noteproperty FilePath -value $filePath
          $obj | Add-Member Noteproperty IsLocked -value $filelocked
          $obj
      }
      

      【讨论】:

      • 对不起,我给了一个不同场景的答案:(
      • 这个只显示文件是否被锁定,不显示哪个进程正在使用它。
      【解决方案8】:

      你可以在handle.exe上找到你的路径。

      我使用过 PowerShell,但您可以使用其他命令行工具。

      具有管理权限:

      handle.exe -a | Select-String "<INSERT_PATH_PART>" -context 0,100
      

      向下搜索“Thread: ...”,您应该会看到使用您的路径的进程名称。

      【讨论】:

        【解决方案9】:

        我喜欢命令提示符 (CMD) 的功能,它也可以在 PowerShell 中使用:

        tasklist /m <dllName>
        

        请注意,您不能输入 DLL 文件的完整路径。光是名字就够了。

        【讨论】:

        • 不能输入DLL文件的完整路径——只输入名字——很好的提示
        【解决方案10】:

        如果你稍微修改一下上面的函数,它将返回 True 或 False (您需要以完全管理员权限执行) 例如用法:

        PS> TestFileLock "c:\pagefile.sys"

        function TestFileLock {
            ## Attempts to open a file and trap the resulting error if the file is already open/locked
            param ([string]$filePath )
            $filelocked = $false
            $fileInfo = New-Object System.IO.FileInfo $filePath
            trap {
                Set-Variable -name Filelocked -value $true -scope 1
                continue
            }
            $fileStream = $fileInfo.Open( [System.IO.FileMode]::OpenOrCreate, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None )
            if ($fileStream) {
                $fileStream.Close()
            }
            $filelocked
        }
        

        【讨论】:

        • 这表明文件是否被锁定,但不给锁定文件的应用程序。
        • 另外:如果新文件不存在,它实际上会创建一个新文件
        • 更不用说是复制 Jordijs 的答案了。
        猜你喜欢
        • 1970-01-01
        • 2011-03-26
        • 1970-01-01
        • 2013-12-14
        • 2017-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-04
        相关资源
        最近更新 更多