用于检查锁定文件的应用程序的 PowerShell 脚本?

发布于 2024-07-23 11:26:31 字数 81 浏览 3 评论 0原文

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

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

Using in PowerShell, how can I check if an application is locking a file?

I like to check which process/application is using the file, so that I can close it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

沫雨熙 2024-07-30 11:26:31

您可以使用SysInternals 工具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
...

You can do this with the SysInternals tool handle.exe. Try something like this:

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
...
墨小沫ゞ 2024-07-30 11:26:31

这可以帮助您: 使用 PowerShell 找出哪个进程锁定了文件。 它解析每个进程的 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}}}

简化:

Get-Process | Where-Object { $_.Modules.FileName -icontains "C:\windows\System32\CRYPT32.dll" } | select Name, ID

This could help you: Use PowerShell to find out which process locks a file. It parses the System.Diagnostics.ProcessModuleCollection Modules property of each process and it looks for the file path of the locked file:

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

Simplified:

Get-Process | Where-Object { $_.Modules.FileName -icontains "C:\windows\System32\CRYPT32.dll" } | select Name, ID
妄司 2024-07-30 11:26:31

您应该能够使用 openfiles 命令常规命令行或 PowerShell。

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

openfiles /local on

例如(适用于 Windows Vista x64):

openfiles /query | find "chrome.exe"

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

You should be able to use the openfiles command from either the regular command line or from PowerShell.

The openfiles built-in tool can be used for file shares or for local files. For local files, you must turn on the tool and restart the machine (again, just for first time use). I believe the command to turn this feature on is:

openfiles /local on

For example (works on Windows Vista x64):

openfiles /query | find "chrome.exe"

That successfully returns file handles associated with Chrome. You can also pass in a file name to see the process currently accessing that file.

霞映澄塘 2024-07-30 11:26:31

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

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

经过广泛的搜索我发现了。

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

感谢 Paul DiMaggio

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

I was looking for a solution to this as well and hit some hiccups.

  1. Didn't want to use an external app
  2. Open Files requires the local ON attribute which meant systems had to be configured to use it before execution.

After extensive searching I found.

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

Thanks to Paul DiMaggio

This seems to be pure powershell and .net / C#

层林尽染 2024-07-30 11:26:31

您可以使用 Sysinternal句柄实用程序。

我必须(稍微)修改代码才能使用 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>

You can find a solution using Sysinternal's Handle utility.

I had to modify the code (slightly) to work with 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

Example:

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>
等待我真够勒 2024-07-30 11:26:31

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

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

具有管理权限:

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

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

You can find for your path on handle.exe.

I've used PowerShell but you can do with another command line tool.

With administrative privileges:

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

Down the lines and search for "Thread: ...", you should see there the name of the process using your path.

无边思念无边月 2024-07-30 11:26:31

在 PsGallery 中发布了一个 PowerShell 模块来发现和使用 杀死打开文件或文件夹句柄的进程。
它公开了以下功能:1) 查找锁定进程,2) 终止锁定进程。
该模块在第一次使用时会自动下载handle.exe。

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

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

PsGallery 链接:https:/ /www.powershellgallery.com/packages/LockingProcessKiller
要安装,请运行:
安装模块-名称 LockingProcessKiller

Posted a PowerShell module in PsGallery to discover & kill processes that have open handles to a file or folder.
It exposes functions to: 1) find the locking process, and 2) kill the locking process.
The module automatically downloads handle.exe on first usage.

Find-LockingProcess()
Retrieves process information that has a file handle open to the specified path.
Example: Find-LockingProcess -Path $Env:LOCALAPPDATA
Example: Find-LockingProcess -Path $Env:LOCALAPPDATA | Get-Process

Stop-LockingProcess()
Kills all processes that have a file handle open to the specified path.
Example: Stop-LockingProcess -Path $Home\Documents

PsGallery Link: https://www.powershellgallery.com/packages/LockingProcessKiller
To install run:
Install-Module -Name LockingProcessKiller

水染的天色ゝ 2024-07-30 11:26:31

我遇到了这个问题并编写了一个完全独立的脚本,因为我不想依赖 SysInternals。 在进行完整的递归复制之前,脚本将识别并终止锁定文件的任何进程。

https://github.com/Tikinsin/ForceCopy.ps1/blob/ main/ForceCopy.ps1

这利用了 Zachery Fischer 和 Paul DiMaggio 的 Github 解决方案的答案。

I ran into this issue and wrote an entirely self contained script because I didn't want to depend on SysInternals. Script will identify and kill any process locking a file before making a full recursive copy.

https://github.com/Tikinsin/ForceCopy.ps1/blob/main/ForceCopy.ps1

This leverages the answer by Zachery Fischer and Paul DiMaggio's Github solution.

水中月 2024-07-30 11:26:31

这是一个完全工作的独立 Powershell 解决方案,无需任何外部工具/依赖项。

它使用函数“NtQueryInformationFile" 带有参数 FileInformationClass=47 获取 FILE_PROCESS_IDS_ USING_FILE_INFORMATION 数据。

# script to get all PIDs of processes accessing/blocking a given file

cls
remove-variable * -ea 0
$errorActionPreference = 'stop'

Add-Type -TypeDefinition @"
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

public static class ProcessUtils {

    [StructLayout(LayoutKind.Sequential)]
    private struct IO_STATUS_BLOCK {
        public IntPtr Information;
        public IntPtr Status;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct FILE_PROCESS_IDS_USING_FILE_INFORMATION {
        public ulong NumberOfProcessIdsInList;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
        public ulong[] ProcessIdList;
    }

    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationFile(SafeFileHandle FileHandle, ref IO_STATUS_BLOCK IoStatusBlock,
        IntPtr FileInformation, uint Length, int FileInformationClass);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern SafeFileHandle CreateFile(string lpFileName, FileAccess dwDesiredAccess,
        FileShare dwShareMode, IntPtr lpSecurityAttributes, FileMode dwCreationDisposition,
        FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);

    public static ulong[] GetProcessesUsingFile(string filePath) {
        var processIds = new ulong[0];
        var ioStatusBlock = new IO_STATUS_BLOCK();
        var fileInfo = new FILE_PROCESS_IDS_USING_FILE_INFORMATION();

        using (var fileHandle = CreateFile(filePath, FileAccess.Read, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero)) {
            if (!fileHandle.IsInvalid) {
                var fileInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(fileInfo));
                if (NtQueryInformationFile(fileHandle, ref ioStatusBlock, fileInfoPtr, (uint)Marshal.SizeOf(fileInfo), 47) == 0) {
                    fileInfo = Marshal.PtrToStructure<FILE_PROCESS_IDS_USING_FILE_INFORMATION>(fileInfoPtr);
                    if (fileInfo.NumberOfProcessIdsInList > 0) {
                        processIds = new ulong[fileInfo.NumberOfProcessIdsInList];
                        Array.Copy(fileInfo.ProcessIdList, processIds, (int)fileInfo.NumberOfProcessIdsInList);
                    }
                }
                Marshal.FreeHGlobal(fileInfoPtr);
            }
        }
        return processIds;
    }
}
"@

# Get the PIDs of all processes using a file:
[ProcessUtils]::GetProcessesUsingFile("C:\temp\test.txt")

Here is a fully working standalone Powershell solution without any external tools/dependencies.

It uses the function "NtQueryInformationFile" with parameter FileInformationClass=47 to get FILE_PROCESS_IDS_USING_FILE_INFORMATION data.

# script to get all PIDs of processes accessing/blocking a given file

cls
remove-variable * -ea 0
$errorActionPreference = 'stop'

Add-Type -TypeDefinition @"
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

public static class ProcessUtils {

    [StructLayout(LayoutKind.Sequential)]
    private struct IO_STATUS_BLOCK {
        public IntPtr Information;
        public IntPtr Status;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct FILE_PROCESS_IDS_USING_FILE_INFORMATION {
        public ulong NumberOfProcessIdsInList;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
        public ulong[] ProcessIdList;
    }

    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationFile(SafeFileHandle FileHandle, ref IO_STATUS_BLOCK IoStatusBlock,
        IntPtr FileInformation, uint Length, int FileInformationClass);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern SafeFileHandle CreateFile(string lpFileName, FileAccess dwDesiredAccess,
        FileShare dwShareMode, IntPtr lpSecurityAttributes, FileMode dwCreationDisposition,
        FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);

    public static ulong[] GetProcessesUsingFile(string filePath) {
        var processIds = new ulong[0];
        var ioStatusBlock = new IO_STATUS_BLOCK();
        var fileInfo = new FILE_PROCESS_IDS_USING_FILE_INFORMATION();

        using (var fileHandle = CreateFile(filePath, FileAccess.Read, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero)) {
            if (!fileHandle.IsInvalid) {
                var fileInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(fileInfo));
                if (NtQueryInformationFile(fileHandle, ref ioStatusBlock, fileInfoPtr, (uint)Marshal.SizeOf(fileInfo), 47) == 0) {
                    fileInfo = Marshal.PtrToStructure<FILE_PROCESS_IDS_USING_FILE_INFORMATION>(fileInfoPtr);
                    if (fileInfo.NumberOfProcessIdsInList > 0) {
                        processIds = new ulong[fileInfo.NumberOfProcessIdsInList];
                        Array.Copy(fileInfo.ProcessIdList, processIds, (int)fileInfo.NumberOfProcessIdsInList);
                    }
                }
                Marshal.FreeHGlobal(fileInfoPtr);
            }
        }
        return processIds;
    }
}
"@

# Get the PIDs of all processes using a file:
[ProcessUtils]::GetProcessesUsingFile("C:\temp\test.txt")
深海夜未眠 2024-07-30 11:26:31

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

tasklist /m <dllName>

请注意,您无法输入 DLL 文件的完整路径。 只要名字就足够了。

I like what the command prompt (CMD) has, and it can be used in PowerShell as well:

tasklist /m <dllName>

Just note that you can't enter the full path of the DLL file. Just the name is good enough.

阳光下的泡沫是彩色的 2024-07-30 11:26:31

我在 锁定文件检测< 中看到了一个很好的解决方案/a> 仅使用 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
}

I've seen a nice solution at Locked file detection that uses only PowerShell and .NET framework classes:

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
}
[旋木] 2024-07-30 11:26:31

如果你稍微修改上面的函数,如下所示,它将返回 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
}

If you modify the above function slightly like below it will return True or False
(you will need to execute with full admin rights)
e.g. Usage:

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文