【发布时间】:2009-06-05 21:00:39
【问题描述】:
在 PowerShell 中使用,我如何检查应用程序是否锁定了文件?
我喜欢检查哪个进程/应用程序正在使用该文件,以便我可以关闭它。
【问题讨论】:
标签: powershell scripting filelock
在 PowerShell 中使用,我如何检查应用程序是否锁定了文件?
我喜欢检查哪个进程/应用程序正在使用该文件,以便我可以关闭它。
【问题讨论】:
标签: powershell scripting filelock
您可以使用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 /dir 为我工作。然后我在任务管理器中杀死了锁定文件夹的进程。
您应该能够从常规命令行或 PowerShell 中使用 openfiles command。
openfiles 内置工具可用于文件共享或本地文件。对于本地文件,您必须打开该工具并重新启动机器(同样,仅适用于第一次使用)。我相信打开此功能的命令是:
openfiles /local on
例如(适用于 Windows Vista x64):
openfiles /query | find "chrome.exe"
成功返回与 Chrome 关联的文件句柄。你也可以传入一个文件名来查看当前访问该文件的进程。
【讨论】:
这可以帮助你: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}}}
【讨论】:
您可以使用Sysinternal 的Handle 实用程序找到解决方案。
我不得不(稍微)修改代码以使用 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>
【讨论】:
<# .Description Calls SysInternals handle.exe to get the locking bastard. .Parameter path File or folder #> function lock-handle([string] $path) { . "C:\Program Files\SysInternals\handle64.exe" $path }
我也在寻找解决方案,但遇到了一些问题。
经过大量搜索,我找到了。
感谢保罗·迪马乔
这似乎是纯 powershell 和 .net/C#
【讨论】:
handle.exe 替换为内部编译的 C# 模块来完成这项工作。
handle.exe 可能需要大约 30 秒。
在 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
【讨论】:
我在 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
}
【讨论】:
你可以在handle.exe上找到你的路径。
我使用过 PowerShell,但您可以使用其他命令行工具。
具有管理权限:
handle.exe -a | Select-String "<INSERT_PATH_PART>" -context 0,100
向下搜索“Thread: ...”,您应该会看到使用您的路径的进程名称。
【讨论】:
我喜欢命令提示符 (CMD) 的功能,它也可以在 PowerShell 中使用:
tasklist /m <dllName>
请注意,您不能输入 DLL 文件的完整路径。光是名字就够了。
【讨论】:
如果你稍微修改一下上面的函数,它将返回 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
}
【讨论】: