【问题标题】:How to check if a folder has no files locked by any process?如何检查文件夹是否没有被任何进程锁定的文件?
【发布时间】:2016-08-28 10:15:05
【问题描述】:

我正在尝试编写一个PowerShell 脚本来检查特定文件夹中的文件是否被任何进程锁定;如果为真,则仅删除该文件夹。

一种方法是通过以 RW 模式迭代地打开每个文件来检查每个文件的锁 - 查看是否发生异常。但这太麻烦了。

有没有办法检查文件夹的相同内容?我尝试将Remove-Item-WhatIf 标志一起使用,但它没有用,因为该命令没有返回任何值 - 它也没有检测到锁定的文件。如果我尝试在没有标志的情况下运行 Remove-Item 来查找异常,那么它只会删除空闲文件,而我想要一个 All 或 None 条件。

【问题讨论】:

  • 你总是可以让重启管理器帮你检查锁,但是还是有点麻烦。

标签: powershell process file-locking


【解决方案1】:

只要您不打算分发解决方案,您就可以使用handle.exe。它显示所有正在使用的文件/文件夹以及谁在使用它。

$path = "C:\Users\frode\Desktop\Test folder"

(.\handle64.exe /accepteula $path /nobanner) -match 'File'
explorer.exe       pid: 1888   type: File           F3C: C:\Users\frode\Desktop\Test folder
explorer.exe       pid: 1888   type: File          2E54: C:\Users\frode\Desktop\Test folder
notepad.exe        pid: 2788   type: File            38: C:\Users\frode\Desktop\Test folder
WINWORD.EXE        pid: 2780   type: File            40: C:\Users\frode\Desktop\Test folder
WINWORD.EXE        pid: 2780   type: File           6FC: C:\Users\frode\Desktop\Test folder\New Microsoft Word-dokument.docx

如果您只想要一个是/否的答案,您可以使用 if-test 和 -match 来查看它是否返回任何结果。

if((.\handle64.exe /accepteula $path /nobanner) -match 'File') { "IN USE, ABORT MISSION!" }

即使explorer.exe 正在其中浏览,您通常也可以删除文件夹,因此您通常可以从结果中排除该进程:

if((.\handle64.exe /accepteula $path /nobanner) -match 'File' -notmatch 'explorer.exe') { "IN USE, ABORT MISSION!" }

【讨论】:

    【解决方案2】:

    如果您不想安装句柄,您可以查看给定目录或子目录中正在运行的进程。

    $lockedFolder="C:\Windows\System32" 
    Get-Process | % {
      $processVar = $_
      $_.Modules | %{ 
        if($_.FileName -like "$lockedFolder*"){
            $processVar.Name + " PID:" + $processVar.id + " FullName: " + $_.FileName 
        }
      }
    }
    

    【讨论】:

    • 不适用于文件被未从同一目录运行的外部进程锁定的目录(如 excel 打开工作表 - 目录已锁定但 excel 未在该目录中运行)
    【解决方案3】:

    这不是一个完整的解决方案,而是一个起点,您可以在此基础上进行构建。

    我在“E:\Work\Powershell\scripts\demo”下有一个名为“demo.txt”的 txt 文件。我正在使用 Notepad.exe 打开它。在这种情况下,我将无法删除文件夹“demo”,直到我关闭记事本。

    您必须查询 "Win32_process" 类以了解记事本是否正在使用该文件。

    Get-WmiObject win32_process | where {$_.name -eq 'notepad.exe'}
    

    在上述 cmdlet 的输出中,"CommandLine" 属性将显示该进程当前正在使用哪些文件。

    您可能需要对其进行迭代才能为您的问题找到完整的解决方案。

    像“chrome.exe”这样的某些进程将在“CommandLine”属性下有一个巨大的列表,因为 chrome 或 iExplorer 不会阻止您在打开文件时删除文件夹,您可以忽略这些进程。

    注意:“(Get-Process).Modules”下的“FileName”只为您提供可以找到“notepad.exe”的路径(即,E:\Work\Powershell\scripts\demo)

    【讨论】:

    • 这应该很有效:$location = 'E:\Work\Powershell\scripts\demo' Get-WmiObject Win32_process |其中 {$_.commandline -like "$location"} |选择名称
    【解决方案4】:

    或者您可以尝试重命名 $path 上的项目,如果失败,它会锁定它。扔一点 try{ catch{ 在那里,你会得到一些可能像下面这样的东西。漂亮又简单

    #check for locking handle    
    Function Check-LockedItem {
            param([string]$path)
            $name = Split-Path "$path" -leaf
            $pathorg = Split-Path "$path" -Parent
            try {Rename-Item -Path "$path" -NewName "$name--" -ErrorAction Stop}
            catch {write-host "A process is locking $path. Please close the process and try again"}
            Finally {Rename-Item -path "$pathorg\$name--" -NewName $name -ErrorAction SilentlyContinue}
    }
    

    用法

    Check-LockedItem -Path "C:\Mypathtotest"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-29
      • 2018-11-17
      相关资源
      最近更新 更多