¿Cómo cerrar todos los identificadores de archivos en una carpeta determinada mediante programación?

18

Me preguntaba si hay una herramienta de línea de comandos que me permita cerrar todos los controladores de archivo que están abiertos en una carpeta específica.

He probado ProcessExplorer , Unlocker y herramientas similares, pero ofrecen una interfaz GUI y no son útiles en un entorno de programación.

Una solución en Python, cmd o PowerShell sería ideal.

Amelio Vazquez-Reina
fuente
Recuerde que cerrar por la fuerza un identificador de archivo puede hacer que el programa que usa ese identificador se bloquee.
Harry Johnston
1
@HarryJohnston Peor aún, podría terminar causando todo tipo de corrupción de archivos mientras el programa esté abierto: technet.microsoft.com/en-us/magazine/…
Bob

Respuestas:

7

Unlocker afirma que te da esta habilidad:

  1. Simplemente haga clic derecho en la carpeta o archivo y seleccione Desbloqueador

    Paso 1

  2. Si la carpeta o el archivo está bloqueado, aparecerá una lista de ventanas de casilleros

    Paso 2

  3. Simplemente haga clic Unlock Ally listo.

No estoy seguro de si es compatible con el uso de la línea de comandos.

FileASSASSIN de Malwarebyte realiza acciones similares, y lo hace de soporte el uso de línea de comandos, por lo que debe ser capaz de guión muy fácilmente.

FileAssassin's Switches

Ƭᴇcʜιᴇ007
fuente
Gracias techie007, supongo que me perdí eso. Me di cuenta de que Unlocker a veces pierde mis archivos (ProcessExplorer no lo hace). Un segundo problema es si quiero desbloquear o liberar archivos mediante programación (por ejemplo, una herramienta de línea de comandos ayudaría en esta dirección).
Amelio Vazquez-Reina
@intrpc Ahí tienes, agregué otra sugerencia (amigable con la línea de comandos). :)
Ƭᴇcʜιᴇ007
1
Cuidado, Unlocker viene incluido con malware en estos días.
Joshua Hanley
10

Gracias por esto. Hemos tenido algunos problemas con los identificadores de archivos abiertos que hacen que los pagos de git fallen en nuestros trabajos de Jenkins basados ​​en Windows y esto ayudó a corregir el problema fácilmente. Explicaré los conceptos básicos de la técnica:

  1. Instale Handle.exe en el nodo de compilación. Lo descargué desde aquí http://technet.microsoft.com/en-us/sysinternals/bb896655 , lo descomprimí y solté Handle.exe en C: \ Windows \ System32 para asegurarme de que estaría disponible en el% PATH% predeterminado

  2. Instale el complemento Jenkins pre-scm-buildstep: https://wiki.jenkins-ci.org/display/JENKINS/pre-scm-buildstep . Esto nos permite definir operaciones antes de que el complemento git comience a alcanzar archivos potencialmente bloqueados.

  3. Implementé el siguiente comando por lotes como un paso de compilación pre-scm:

    @echo off
    echo Cleaning up open file handles from %NODE_NAME%:%WORKSPACE%...
    for /f "tokens=3,6,8 delims=: " %%i in ('Handle /accepteula %WORKSPACE% ^| grep workspace') do echo Releasing file lock on E:%%k & handle -c %%j -y -p %%i
    

Parece funcionar bien y definitivamente reduce las fallas espurias. También notaré un par de problemas con los que trabajé:

  • Handler.exe tiene un EULA que debe aceptarse la primera vez que se ejecuta. Si está ejecutando su agente Jenkins como un servicio en el contexto del Sistema local, esto es problemático porque no puede iniciar sesión como ese usuario y aceptarlo a mano. Cuando intentamos ejecutarlo desde el trabajo de Jenkins, el proceso simplemente se detuvo a la espera de la entrada del usuario y tardó unos minutos en descubrir por qué. Resolví esto ejecutándolo desde el trabajo de Jenkins usando el indicador / acceptteula y recomiendo que cualquiera que implemente esto como un proceso automatizado haga lo mismo. Esto pasa a ser una configuración de registro en HKEY_CURRENT_USER \ Software \ Sysinternals \ Handle y también puede configurarlo y desactivarlo a través de regedit.exe si necesita manipularlo para un usuario específico, pero la opción de línea de comandos parecía más fácil.

  • El complemento de paso de Jenkins Batch ejecuta el código de lote como si estuviera en un script en lugar de como una directiva de línea de comando. Observe los escapes (por ejemplo, %% i, ^ |).

¡Gracias!

Thomas Boyles
fuente
Luchando por obtener la sintaxis de esto, ¿alguien puede proporcionar más detalles sobre qué es %% i, j, etc.?
c4sh
Esto podría ayudar a comprender la sintaxis del comando por lotes: robvanderwoude.com/ntfortokens.php
c4sh
¿Cómo resolvieron el hecho de que handle.exe debe ejecutarse como administrador, mientras lo ejecutamos desde un usuario de Jenkins que no es administrador?
c4sh
8

Utilizamos el siguiente fragmento para cerrar el identificador de archivo de los usuarios a nuestro servidor. Es posible que pueda modificarlo para su uso.

rem close all network files that are locked
for /f "skip=4 tokens=1" %%a in ('net files') do net files %%a /close
Brendan
fuente
Gracias @Brendan. Creo que su código no fue formateado correctamente. Su respuesta parece interesante, así que si no le importa editarla, le sugiero que seleccione sus líneas de código y luego haga clic en el botón con las dos pulseras rizadas. Eso convertirá tu fragmento en código legible.
Amelio Vazquez-Reina
5

Creo este pequeño archivo por lotes para liberar automáticamente todos los bloqueos al archivo xml con mi eclipse

@echo off
for /f "tokens=3,6,8 delims=: " %%i in ('handle -p eclipse e:\git\ ^| grep .xml') do echo Releasing %%k & handle -c %%j -y -p %%i

Debe descargar la utilidad de manejo del sitio de Microsoft y la utilidad grep de GnuWin32

Si no necesita filtrar por tipo de archivo, puede omitir la parte grep como esta:

@echo off
for /f "tokens=3,6,8 delims=: " %%i in ('handle -p eclipse e:\git\') do echo Releasing %%k & handle -c %%j -y -p %%i

O si no necesita filtrar bloqueos por un programa en particular, simplemente elimine el filtro del proceso de eclipse:

@echo off
for /f "tokens=3,6,8 delims=: " %%i in ('handle e:\git\') do echo Releasing %%k & handle -c %%j -y -p %%i

Recuerde reemplazar e:\git\con la ruta de su carpeta.

Coolersport
fuente
4

Si está utilizando PSTools , esto obligará a cerrar todos los archivos abiertos de forma recursiva:

psfile \\serverName c:\path\toDatabase\ -c

Tenga en cuenta que c:\path\toDatabase\es el C: conduzca \\serverName, no su máquina local. Al principio no estaba claro para mí, así que pensé en señalarlo.

Este es un enfoque de fuerza bruta que casi garantiza la pérdida de datos, así que úselo con precaución.

Tenemos una base de datos de Access mal improvisada que literalmente pone a nuestra empresa de rodillas regularmente (tuve que arreglarlo tres veces ayer).

El tipo que normalmente maneja esto está de vacaciones durante un par de semanas y sus instrucciones usan un enfoque basado en la interfaz de usuario (Inicio> Computadora> Administrar> Administración de la computadora (local)> Conectarse a otra computadora> Herramientas del sistema> Carpetas compartidas> Abrir archivos> Cerrar Abrir archivos). DEMASIADO demasiados clics cuando puedo ejecutar el comando anterior y expulsar a toda la empresa de todos los archivos de la base de datos e iniciar el proceso de Compactar y reparar (que también estoy trabajando en un enfoque de fuerza bruta).

El truco es mantenerse por delante de las personas que inmediatamente comienzan a volver a conectarse a la base de datos tan pronto como se cae. Están tan acostumbrados a esto que no se les ocurre presentar un error contra él, simplemente siguen martillando la base de datos hasta que vuelven a entrar. Simplemente sigo arrancándolos hasta que he compactado y reparado las tres docenas archivos que componen la base de datos.

delliottg
fuente
4

Si está hablando de los identificadores de archivos abiertos a través de un recurso compartido SMB en un servidor de archivos de Windows (Server 2012 o posterior), aquí está la respuesta de PowerShell:

Get-SmbOpenFile | Where-Object { $_.Path -like "D:\Folder\*" } | Close-SmbOpenFile -Force

En un servidor de archivos de Windows anterior, es openfiles.exe /disconnect.

Para un identificador de archivo de sistema local, la mejor manera que he encontrado es utilizar Sysinternals handle.exe

Joshua Hanley
fuente
3

Prefiero http://lockhunter.com porque admite tanto la interfaz gráfica de usuario como la interfaz de línea de comandos, y en muchos casos pude eliminar archivos que Unlocker no pudo eliminar.

Vladimir Reshetnikov
fuente
2

Unlocker también puede ejecutarse en modo silencioso.

Por ejemplo, para desbloquear todos los archivos dentro del espacio de trabajo de Jenkins:

"C:\Program Files\Unlocker\unlocker.exe" "%WORKSPACE%" /S

Luego puede eliminar de forma segura los archivos del espacio de trabajo:

del "%WORKSPACE%\*.*" /s /q
Noam Manos
fuente
0

Puedes usar Powershell para hacer esto:

function KillProcessesWithHandles
{
    param([string]$path)

    $allProcesses = Get-Process

    # Start by closing all notepad processes. Someone may have left a logor config file open
    $allProcesses | Where-Object {$_.Name -eq "notepad"} | Stop-Process -Force -ErrorAction SilentlyContinue

    # Then close all processes running inside the folder we are trying to delete
    $allProcesses | Where-Object {$_.Path -like ($path + "*")} | Stop-Process -Force -ErrorAction SilentlyContinue

    # Finally close all processes with modules loaded from folder we are trying to delete
    foreach($lockedFile in Get-ChildItem -Path $path -Include * -Recurse) {
        foreach ($process in $allProcesses) {
            $process.Modules | Where-Object {$_.FileName -eq $lockedFile} | Stop-Process -Force -ErrorAction SilentlyContinue
        }
    }
}

Para obtener más información, consulte Thomas Ardal aquí: https://thomasardal.com/deleting-contents-of-a-folder-containing-files-with-open-file-handles-using-powershell/

Abhi
fuente