Cómo administrar identificadores de archivos abiertos con PowerShell

Contenidos

Personas de la línea de comando

Uno de los errores más frustrantes con los que puede lidiar un usuario final o un administrador de TI es el de los archivos bloqueados dentro de Windows. Cuando borras una carpeta, mueves un archivo o editas una configuración y encuentras un mensaje de error de archivo bloqueado, es mejor lidiar con eso de manera rápida y eficiente.

Microsoft introdujo PowerShell como un shell de reemplazo, pero tiene mucha más funcionalidad que eso y es un lenguaje complejo y capaz. Veamos en este post cómo puede usar PowerShell para lidiar con archivos bloqueados.

El problema del archivo bloqueado

¿Cómo se bloquea exactamente un archivo? A lo largo del uso normal, un procedimiento crea muchos identificadores de recursos como un archivo. Al hacerlo, los procesos a menudo bloquean el archivo para evitar que se produzcan cambios de configuración no deseados u otros daños. El problema a menudo es que es difícil determinar qué procedimiento ha bloqueado el archivo y, posteriormente, cómo borrar ese bloqueo del archivo.

Desafortunadamente, no hay un cmdlet integrado para probar un archivo y saber si está bloqueado o por qué procedimiento. Por eso, debe crear sus propias funciones o empaquetar otras herramientas útiles que existen para ayudarlo a obtener más información sobre estos archivos.

Prueba de archivos bloqueados

Dentro de Windows, puede probar para ver si un archivo individual está bloqueado. Con el siguiente bloque de código, puede probar para ver si un archivo determinado está bloqueado. los $Item La variable debe establecerse en una ruta de archivo completa. Al probar para ver si el archivo se puede abrir para escritura, como se ve con el [System.IO.File]::Open($Item,'Open','Write') comando, puede saber si el archivo está bloqueado.

If ([System.IO.File]::Exists($Item)) {
  Try {
      $FileStream = [System.IO.File]::Open($Item,'Open','Write')

      $FileStream.Close()
      $FileStream.Dispose()

      $IsLocked = $False
  } Catch [System.UnauthorizedAccessException] {
      $IsLocked = 'AccessDenied'
  } Catch {
      $IsLocked = $True
  }
}

Get-SMBOpenFile

Dije que Windows no cuenta con una función incorporada, pero hay un caso en el que existe una función. Si tiene un recurso compartido remoto o inclusive administrativos (como c$), entonces puede utilizar el Get-SMBOpenFile cmdlet para informar sobre esos archivos abiertos.

PS C:> Get-SMBOpenFile

FileId       SessionId    Path  ShareRelativePath
------       ---------    ----  -----------------
154618822665 154618822657 C:

PS C:> 

La desventaja es que esto solo funciona para archivos a los que se accede de forma remota. No se informará sobre ningún archivo bloqueado que esté en uso en su sistema local, por lo que en la mayoría de los casos esta no es una solución viable. Para cerrar, puede canalizar los archivos abiertos devueltos al Close-SMBOpenFile mando.

Get-SMBOpenFile | Close-SMBOpenFile

Utilidad OpenFiles

Windows cuenta con una utilidad incorporada llamada openfiles que puede ayudar a enumerar qué archivos están en uso y desconectarlos. ¡A primera vista, se ve perfecto para tus necesidades! Inclusive puede envolver esto dentro de una función de PowerShell para facilitar la consulta y desconexión de archivos.

Abra un indicador administrativo de PowerShell y ejecute el comando openfiles /query. De inmediato, debería recibir un mensaje de error que indica que la marca global «mantener lista de objetos» debe estar activada.

PS C:/> openfiles /query

INFO: The system global flag 'maintain objects list' needs
      to be enabled to see local opened files.
      See Openfiles /? for more information.


Files opened remotely via local share points:
---------------------------------------------

INFO: No shared open files found.

Esta lista de objetos es lo que verdaderamente mantiene la lista de identificadores que están en uso y habilita openfiles para consultar esa información. Para activar esto, ingrese en openfiles /local on y después reinicie su computadora. La desventaja de activar esta función es que hay un ligero impacto en el rendimiento, que dependiendo de su sistema, puede que no valga la pena usar esta herramienta. Una vez dicho esto, veamos cómo podemos hacer que esto funcione dentro de PowerShell.

PS C:> openfiles /Query /fo csv /nh

Files opened remotely via local share points:
---------------------------------------------
"ID","Accessed By","Type","Open File (Pathexecutable)"
"608","user","Windows","C:"

PS C:> openfiles /Query /fo csv | Select-Object -Skip 4 | ConvertFrom-CSV

ID  Accessed By  Type    Open File (Pathexecutable)
--  -----------  ----    ---------------------------
608 user         Windows C:

PS C:> openfiles /disconnect /id 608

SUCCESS: The connection to the open file "C:" has been terminated.

Con los ejemplos anteriores, puede ver cómo importar la salida CSV de openfiles en PowerShell. Con esa información, puede disconnect un archivo para desbloquearlo. Debido al impacto en el rendimiento en el que puede incurrir al habilitar el maintain objects list capacidad, puede que no valga la pena para sus necesidades. Es por esto que, es factible que se necesiten otras soluciones.

La aplicación de la manija

Sysinternals es conocido por las muchas herramientas de TI útiles y casi esenciales que fabrica. Hace tiempo, Microsoft adquirió Sysinternals y usted puede descargar y usar estas herramientas bien soportadas por usted mismo. Convenientemente, hay una aplicación llamada handles que proporciona exactamente lo que está buscando.

Primero, debes descargar la aplicación, descomprima los archivos y coloque los ejecutables en una ubicación que haya incluido su variable de entorno Path. Al hacerlo, puede hacer referencia a la aplicación fácilmente donde la necesite. Con una consulta simple para archivos abiertos, puede ver que obtiene muchos resultados (truncados para facilitar la lectura).

PS C:/> handle64 -NoBanner
...
------------------------------------------------------------------------------
RuntimeBroker.exe pid: 9860 User
   48: File          C:WindowsSystem32
  188: Section       BaseNamedObjects__ComCatalogCache__
  1EC: Section       BaseNamedObjects__ComCatalogCache__
------------------------------------------------------------------------------
chrome.exe pid: 4628 User
   78: File          C:Program Files (x86)GoogleChromeApplication78.0.3904.108
  1C4: Section       Sessions1BaseNamedObjectswindows_shell_global_counters
...

Parece que obtiene lo que desea, al menos una forma de averiguar qué archivos se están usando, y puede probarlos usando su código de archivo bloqueado de antes. Pero, ¿cómo hace que esto sea más fácil de utilizar? El siguiente código lee cada procedimiento y recupera solo los archivos bloqueados. La desventaja es que esto lleva un tiempo en ejecutarse dado que hay muchos procesos.

$Processes = Get-Process

$results = $Processes | Foreach-Object {
    $handles = (handle64 -p $_.ID -NoBanner) | Where-Object { $_ -Match " File " } | Foreach-Object {
            [PSCustomObject]@{
        "Hex"  = ((($_ -Split " ").Where({ $_ -NE "" })[0]).Split(":")[0]).Trim()
        "File" = (($_ -Split " ")[-1]).Trim()
        }
    }

    If ( $handles ) {
        [PSCustomObject]@{
            "Name"    = $_.Name
            "PID"     = $_.ID
            "Handles" = $handles
        }
    }
}

A pesar de esto, en última instancia, lo que obtiene es una colección procesable de archivos, enumerados por procedimiento, que sabe que están en uso y que se pueden filtrar más. Si descubre que necesita cerrar uno de ellos, puede hacer lo siguiente (como administrador):

PS C:> $results |
>>  Where-Object Name -EQ 'Notepad' |
>>  Where-Object { $_.Handles.File -Match "test.txt" }

Name                      PID Handles
----                      --- -------
Notepad                   12028 {@{Hex=44; File=C:test.txt}


PS C:> handle64 -p 12028 -c 44 -y -nobanner

44: File  (R-D)   C:test.txt

Handle closed.

Puede envolver aún más todo esto en una función para que sea aún más fácil analizar y buscar según sea necesario. Existen muchas alternativas, especialmente en la combinación de varios métodos en una solución que se adapte a su entorno.

Conclusión

Tratar con archivos bloqueados puede ser un desafío, especialmente cuando detiene lo que necesita hacer rápidamente. Hay varias alternativas para hallar y desbloquear esos archivos, pero necesita un poco de trabajo dado que Windows no tiene un método integrado verdaderamente completo para tratar esos archivos bloqueados. Las soluciones descritas deberían hacer que el problema sea breve y permitirle pasar a tareas mucho más importantes.

Suscribite a nuestro Newsletter

No te enviaremos correo SPAM. Lo odiamos tanto como tú.