Сценарий PowerShell для проверки приложения, блокирующего файл?

StackOverflow https://stackoverflow.com/questions/958123

  •  12-09-2019
  •  | 
  •  

Вопрос

Как с помощью PowerShell проверить, блокирует ли приложение файл?

Мне нравится проверять, какой процесс/приложение использует файл, чтобы можно было его закрыть.

Это было полезно?

Решение

Вы можете сделать это с помощью Инструмент 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
...

Другие советы

Вы должны уметь использовать команда открытых файлов либо из обычной командной строки, либо из PowerShell.

Встроенный инструмент openfiles можно использовать для общих файловых ресурсов или для локальных файлов.Для локальных файлов необходимо включить инструмент и перезагрузить компьютер (опять же, только при первом использовании).Я считаю, что команда для включения этой функции:

openfiles /local on

Например (работает на Windows Vista x64):

openfiles /query | find "chrome.exe"

Это успешно возвращает дескрипторы файлов, связанные с Chrome.Вы также можете передать имя файла, чтобы увидеть процесс, который в данный момент обращается к этому файлу.

Это может помочь вам: Используйте 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}}}

Вы можете найти решение, используя Сисинтернал's Ручка полезность.

Мне пришлось (немного) изменить код для работы с 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>

Я видел хорошее решение на Обнаружение заблокированных файлов который использует только классы PowerShell и .NET Framework:

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
}

Мне нравится командная строка (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
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top