2009-06-05 14 views

Respuesta

28

Puede hacerlo con el SysInternals tool handle.exe. Intentar algo como esto:

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 
... 
+7

Gracias, puedo usar handle [filename], para hacerlo más simple. –

+0

¿Dónde está la diversión en eso? :-) Pero sí, eso sería mucho más simple. –

+0

:(todavía tiene problemas ... no es tan poderoso para mostrar si hay archivos (es decir, archivos de texto) abiertos por un proceso determinado. –

9

Debería poder usar el openfiles command desde la línea de comando normal o desde PowerShell.

La herramienta integrada de archivos abiertos se puede usar para compartir archivos o para archivos locales. Para los archivos locales, debe encender la herramienta y reiniciar la máquina (nuevamente, solo para usarla por primera vez). Creo que el comando para activar esta función es:

openfiles /local on 

Por ejemplo (Funciona en Windows Vista x64  ):

openfiles /query | find "chrome.exe" 

Eso devuelve correctamente los identificadores de archivo asociado con Chrome. También puede pasar un nombre de archivo para ver el proceso que actualmente está accediendo a ese archivo.

+0

Por lo que veo ese comando simplemente enumera los archivos que se abren por un usuario de remoto a través de acciones SMB. No le dirá nada sobre el proceso que lo usa. – Joey

+0

No puede decirlo desde el enlace, pero parece que Johannes tiene razón. No funciona en Vista x64 para mí, dice "INFO: no se han encontrado archivos abiertos compartidos". –

+0

Joe/Johannes: Primero, ¿tiene activada la "lista global de objetos mantenidos" (creo que la sintaxis es "openfiles/local on" IIRC)? Luego, ¿está pasando el argumento "/ query", como en el ejemplo anterior (se requiere para Vista, parece)? – Garrett

3

que he visto una buena solución a Locked file detection que utiliza sólo PowerShell y .NET clases del 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 
} 
+0

Lo siento, le di una respuesta a un escenario diferente :( – Jordij

+0

Esto solo muestra si el archivo está bloqueado o no, no muestra qué proceso lo está usando. – KERR

0

Si modifica la función de arriba ligeramente, como a continuación se devolverá verdadero o falso (deberá ejecutar con todos los derechos de administrador) por ej. Uso:

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 
} 
+3

Esto indica si el archivo está bloqueado o no, pero no da la aplicación que está bloqueando el archivo. – CJBS

+2

Además: en realidad * creará * un nuevo archivo si no existe – monojohnny

8

Esto podría ayudarle a: Use PowerShell to find out which process locks a file. Se analiza la propiedad System.Diagnostics.ProcessModuleCollection Módulos de cada proceso y busca la ruta de archivo del archivo bloqueado:

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

Habría sido la respuesta perfecta para mí, pero parece que esto solo funcionaría para dlls, y no para cualquier archivo, como archivos de texto bloqueado. –

0

me gusta lo que tiene el símbolo del sistema (CMD), y se puede utilizar en PowerShell así:

tasklist /m <dllName> 

Sólo tenga en cuenta que no se puede introducir la ruta completa del archivo DLL. Solo el nombre es lo suficientemente bueno.

+0

Desafortunadamente esto muestra solo archivos DLL ... – KERR

4

Puede encontrar una solución usando Sysinternal's Handle utilidad.

tuve que modificar el código (un poco) para trabajar con 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>.*)" 
    [regex]$matchPattern = "(?<Name>\w+\.\w+)\s+pid:\s+(?<PID>\d+)\s+type:\s+(?<Type>\w+)\s+(?<User>\.+)\s+\w+:\s+(?<Path>.*)" 

    $data = &$handle -u $path 
    $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 

Ejemplo:

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> 
+0

¡Bien, gracias por escribir esta sencilla función! – Denis

Cuestiones relacionadas