Eliminación eficiente de archivos con PowerShell: Remove-Item y WMI

Mantener espacio libre en el disco es crucial al gestionar servidores y sistemas. Como administradores, no querrían sorprenderse con una situación de ‘disco lleno’. Para asegurarse de que todo esté en orden, ¡deberían aprender a usar PowerShell para eliminar archivos!

En este artículo, aprenderán prácticamente todas las formas de eliminar archivos de sus sistemas con PowerShell.

¡Comencemos!

Requisitos previos

Este artículo presenta ejemplos utilizando PowerShell, y si planean seguirlo, necesitarán lo siguiente.

Usando el cmdlet Remove-Item para eliminar archivos

Cuando simplemente necesiten usar PowerShell para eliminar un archivo, probablemente aprenderán de inmediato sobre el cmdlet Remove-Item. Este cmdlet es el estándar de facto para eliminar archivos con PowerShell.

Usar Remove-Item combinado con el cmdlet Get-ChildItem para leer archivos y carpetas, y la potente canalización de PowerShell realmente facilita las cosas.

Relacionado: Get-ChildItem: Listar archivos, registros, certificados y más

¿Sabían que el cmdlet Remove-Item tiene un alias con el nombre de del? Al trabajar en PowerShell, usar Remove-Item o del ejecutará el mismo comando.

Usar PowerShell para eliminar un archivo

El primer ejemplo que sería más útil es el más básico, es decir, eliminar un único archivo. Para eliminar solo un archivo, solo necesitas usar el comando a continuación. El código a continuación elimina el archivo C:\temp\random.txt.

Remove-Item -Path C:\temp\random.txt

Ejecutar el código anterior en PowerShell no mostraría nada en la pantalla a menos que se produjera un error.

Usar PowerShell para eliminar todos los archivos en una carpeta

En este ejemplo, el código a continuación elimina todos los archivos en una carpeta. El cmdlet Get-ChildItem apunta a C:\temp con el parámetro -Path. El parámetro -File indica que el único tipo de elemento a incluir son archivos. Get-ChildItem ignora las carpetas.

Get-ChildItem -Path C:\temp -File | Remove-Item -Verbose

La salida debería verse como en la captura de pantalla a continuación.

Successfully deleted all files in a folder

Usar PowerShell para eliminar todos los archivos de forma recursiva

El ejemplo anterior solo eliminó archivos en la carpeta C:\temp. Si también necesitas eliminar los archivos dentro de cada subdirectorio, necesitas agregar el interruptor -Recurse al cmdlet Get-ChildItem para obtener todos los archivos de forma recursiva.

Get-ChildItem -Path C:\temp -File -Recurse | Remove-Item -Verbose

Ejecutar el código anterior obliga a PowerShell a buscar en todos los subdirectorios y recuperar toda la lista de archivos. La salida a continuación muestra que el código pudo eliminar archivos en la carpeta principal; sin embargo, falló al recuperar los archivos en los subdirectorios.

Failed to retrieve files in sub-folders

Trabajando alrededor del Problema de la Ruta Larga

El error mostrado anteriormente indica que PowerShell “no pudo encontrar una parte de la ruta”. Ese error indica que la ruta a la que el cmdlet está intentando acceder no existe, lo cual es engañoso.

En este caso, el error se debe a que la ruta que el comando Get-ChildItem está intentando leer supera la longitud máxima de la ruta de 260 caracteres.

La captura de pantalla a continuación muestra que la ruta o directorio y sus subdirectorios existen, y un archivo de texto llamado InTooDeep.txt se encuentra en el subdirectorio más profundo. La combinación de todos los caracteres que conforman los nombres de directorios anidados crea un problema de ruta larga.

Nested directories creating a long path name

En Windows PowerShell 5.1, hay una solución temporal para el problema del nombre de ruta largo. La solución consiste en utilizar la versión Unicode de la ruta. En lugar de especificar la ruta así: C:\temp, utiliza la versión Unicode así: ‘\\?\C:\temp’ para carpetas ubicadas localmente, o ‘\\?\UNC\<nombredecomputadora>\<compartir>\Temp’ si la carpeta está en una ruta UNC.

Get-ChildItem -Path '\\?\C:\temp' -File -Recurse | Remove-Item -Verbose

Utilizando el código modificado anterior que aborda el problema del nombre de ruta largo, el resultado a continuación muestra que PowerShell leyó con éxito la ruta profundamente anidada y eliminó el archivo.

Deleted the file with a long path name

Ten en cuenta que el problema del nombre de ruta largo no afecta a PowerShell 7.0. Con PowerShell 7.0, no es necesario utilizar la versión Unicode de la ruta porque ya tiene soporte incorporado para nombres de ruta largos.

Si también es necesario eliminar las carpetas, simplemente elimina el parámetro -File del cmdlet Get-ChildItem, y PowerShell debería eliminar todos los elementos, incluidos archivos y carpetas.

Usando PowerShell para eliminar archivos más antiguos que x días

Otro ejemplo típico de limpieza de espacio en disco es eliminar archivos que tengan más de un número específico de días. Este ejemplo es útil para eliminar archivos de registro antiguos, como los generados por servidores web de IIS, para liberar espacio en disco.

En este ejemplo, hay archivos en c:\temp que tienen más de 14 días de antigüedad. Usando el script a continuación, se muestra el Nombre, HoraCreación y EdadEnDías de cada archivo en c:\temp.

Get-ChildItem c:\temp | Select-Object Name,CreationTime,@{n='AgeInDays';e={(New-TimeSpan -Start $PSItem.CreationTime).Days}}

Como puedes ver en la captura de pantalla siguiente, hay archivos que tienen 15 días de antigüedad, 7 días de antigüedad y 0 días de antigüedad.

List of files in c:\temp

Ahora que conoces los archivos que quieres eliminar, puedes crear un script para eliminar solo los archivos que tengan más de un número específico de días, en este caso, más de 14 días.

En el siguiente script de ejemplo, se eliminarán los archivos en C:\temp cuyo valor de HoraCreación sea mayor que el umbral establecido.

La primera línea define la ruta para que Get-ChildItem la busque. La ruta se guarda en la variable $path. Luego, la segunda línea es donde se especifica el umbral. El valor de $threshold es la cantidad de días que debe tener el archivo a eliminar.

La siguiente línea de código después de la variable $threshold hará lo siguiente:

  • Obtener la colección de archivos ubicados en la carpeta especificada en la variable $path. En este ejemplo, la ruta es C:\temp.
  • Filtrar la salida para incluir solo archivos cuyo valor de HoraCreación sea mayor que el número de días guardados en la variable $threshold. En este ejemplo, el umbral es de 14 días.
  • Pase la lista filtrada de archivos al valor Remove-Item para realizar la eliminación de esos archivos.
$path = 'C:\Temp'
$threshold = 14
Get-ChildItem -Path $path -File | Where-Object {$PSItem.CreationTime -lt (Get-Date).AddDays(-$threshold)} |Remove-Item -Verbose

Al ejecutar el código anterior, verá una salida como se muestra a continuación.

The script deleted the files older than 14 days

Observe que, en la captura de pantalla anterior, según el mensaje detallado, el script solo eliminó cinco archivos más antiguos de 14 días. Para confirmar que los archivos más nuevos de 14 días todavía existen, ejecute el código a continuación para listarlos nuevamente.

Get-ChildItem c:\temp | Select-Object Name,CreationTime,@{n='AgeInDays';e={(New-TimeSpan -Start $PSItem.CreationTime).Days}}

El resultado a continuación confirma que Remove-Item no eliminó los archivos más nuevos.

Newer files are left untouched

Usar PowerShell para Coincidir y Eliminar Patrones de Archivos

Eliminar todos los archivos, independientemente del nombre, tipo o extensión, no siempre es el mejor enfoque. A veces, es necesario excluir o incluir explícitamente ciertos archivos en el proceso de eliminación.

El siguiente ejemplo muestra cómo eliminar los archivos que coinciden con el nombre de archivo *.LOG. Una forma de hacerlo es usando directamente el cmdlet Remove-Item con el uso del parámetro -Include, como se muestra a continuación.

Remove-Item -Path C:\temp\* -Include *.log

Otra forma, quizás, el enfoque cauteloso es usar Get-ChildItem primero para recopilar la lista de archivos a eliminar. Solo cuando esté satisfecho con la lista de archivos para eliminar, finalmente puede pasar la colección al cmdlet Remove-Item.

Por ejemplo, el código a continuación obtiene los archivos *.LOG en c:\temp.

Get-ChildItem -Path C:\temp\* -Include *.log

Como resultado del código anterior, Get-ChildItem devuelve una lista de archivos que coinciden con el nombre de archivo *.LOG.

Only files matching the *.log filename is returned

Pero, ¿qué pasa si quieres excluir un archivo que contiene el número 5 en su nombre? Puedes hacerlo agregando el parámetro -Exclude como se muestra en el siguiente código.

Get-ChildItem -Path C:\temp\* -Include *.log -Exclude *5*

Como excluiste el archivo con el número 5, el resultado ahora es diferente. Específicamente, el archivo File_5.log ya no está en la lista, como se muestra a continuación.

The file File_5.log was excluded

Cuando ya estés satisfecho con la colección de archivos que tu código crea, entonces puedes canalizar la colección de archivos al cmdlet Remove-Item para finalmente eliminar esos archivos.

Get-ChildItem -Path C:\temp\* -Include *.log -Exclude *5* | Remove-Item -Verbose

Después de ejecutar tu código final, habrás logrado tu objetivo de eliminar solo los archivos que seleccionaste.

Deleting selected files

Eliminación de archivos usando WMI en PowerShell

Ahora que tienes una buena comprensión de cómo usar el cmdlet común Remove-Item para eliminar archivos, pasemos a un caso de uso más avanzado; usar WMI.

PowerShell viene con soporte para WMI. Y el soporte para WMI significa que se pueden llamar consultas y métodos de WMI desde PowerShell. Sí, WMI no es solo para scripts de Visual Basic que los administradores solían usar en los primeros días de Windows.

Microsoft lanzó cmdlets CIM específicos de WMI en PowerShell 3.0. Los cmdlets CIM que se usarán para eliminar archivos son Get-CimInstance y Invoke-CimMethod.

Usando PowerShell y WMI para eliminar un archivo

Este ejemplo asume que conoces la ruta del archivo específico a eliminar. El cmdlet Get-CimInstance con la clase Cim_DataFile se utiliza para recuperar la información sobre el archivo a eliminar, que es C:\Temp\random.txt.

$file2delete = Get-CimInstance -ClassName Cim_DataFile -Filter "Name = 'C:\Temp\random.txt'"
 $file2delete

En el código anterior, el parámetro -Filter acepta una consulta en formato WQL. Usar WQL requiere que escapes algunos caracteres, incluida la barra invertida. Y, dado que el carácter de escape de WQL también es la barra invertida, resultan los caracteres de doble barra invertida – \\.

Ejecutar el código anterior produce el resultado mostrado en la demostración a continuación. La información sobre C:\Temp\random.txt se guarda en la variable $file2delete

Getting a file using WMI query and PowerShell

Ahora que se ha recuperado la información del archivo C:\Temp\random.txt, el objeto resultante en la variable $file2delete puede enviarse por canalización al cmdlet Invoke-CimMethod. El cmdlet Invoke-CimMethod tiene un parámetro llamado -Name, que representa el nombre del método de la clase Cim_DataFile.

$file2delete | Invoke-CimMethod -Name Delete

Como se ve en la captura de pantalla a continuación, el ReturnValue muestra 0, lo que significa que el comando se ejecutó correctamente.

File successfully deleted using WMI and PowerShell

Para conocer los posibles códigos de ReturnValue, consulte este enlace: Método de eliminación de la clase CIM_DataFile

Además, la captura de pantalla a continuación muestra que después de ejecutar el método Invoke-CimMethod Delete(), CIM solo eliminó el archivo C:\Temp\random.txt. No eliminó los demás archivos.

C:\Temp\random.txt file was deleted

Usando PowerShell y WMI para eliminar todos los archivos en una carpeta

En este próximo ejemplo, te mostraré cómo eliminar todos los archivos en una carpeta utilizando PowerShell y WMI. Se utilizarán los mismos cmdlets que en el ejemplo anterior, que son Get-CimInstance e Invoke-CimMethod. Pero, en esta ocasión, la consulta WQL recuperará todos los archivos en la carpeta en lugar de solo uno específico.

En este código siguiente, el cmdlet Get-CimInstance recupera todos los archivos ubicados en C:\temp. Como puedes ver a continuación, la consulta filtra las propiedades Drive y Path de la clase Cim_DataFile.

$file2delete = Get-CimInstance -ClassName Cim_DataFile -Filter "Drive = 'c:' AND Path = '\\temp\\'"

Al ejecutar el código anterior, se guarda la información recuperada sobre los archivos en C:\temp en la variable $file2delete. Viendo el valor o valores de la variable $file2delete, se muestra la salida a continuación.

List of all folders found in c:\temp using WMI

Ahora, los valores almacenados en la variable $file2delete pueden enviarse al Invoke-CimMethod para eliminar todos los archivos en c:\temp.

$file2delete | Invoke-CimMethod -Name Delete

Recuerda, el código ReturnValue de 0 significa éxito, y para cada archivo en el que se llamó al método de eliminación tendrá su propio código ReturnValue.

All files in c:\temp deleted using WMI

Uso de PowerShell y WMI para eliminar archivos por extensión

Has visto en el ejemplo anterior cómo eliminar todos los archivos en una carpeta independientemente de la extensión. Sin embargo, también puedes controlar qué archivos se eliminan según la extensión.

Notarás en el código a continuación, que esta vez la consulta tiene una condición añadida (Name LIKE '%.log). Esta condición añadida significa que solo se devuelven los archivos que coinciden con la extensión .LOG. El signo de porcentaje (%) es un operador LIKE de WQL que significa “Una cadena de cero o más caracteres”. En términos de programación, el % es equivalente a un comodín, que es el carácter asterisco (*).

$file2delete = Get-CimInstance -ClassName cim_datafile `
-Filter "Drive = 'c:' AND Path = '\\temp\\' AND Name LIKE '%.log'"

$file2delete | Invoke-CimMethod -Name Delete

La demostración a continuación muestra que antes de que se ejecute el código anterior, hay nueve *.LOG archivos y solo un archivo *.TXT. Una vez que el código haya terminado de ejecutarse, los archivos *.LOG se eliminan y el archivo *.TXT es el único archivo que queda en la carpeta.

Deleting files by extension using WMI

Comparación entre WMI y Remove-Item

Hasta ahora en este tutorial, has obtenido una visión general de cómo usar PowerShell para eliminar archivos. Has aprendido sobre Remove-Item y también sobre WMI. Ambos realizan funciones similares pero de manera muy diferente.

¿Qué método deberías usar para eliminar archivos; Remove-Item o WMI?

Usar un cmdlet incorporado en PowerShell como Get-ChildItem y Remove-Item para recuperar y eliminar archivos es mucho más rápido que cuando se usa WMI.

El ejemplo a continuación muestra la comparación al usar WMI y el cmdlet integrado de PowerShell para obtener la lista de archivos en el directorio C:\windows\web y sus subdirectorios.

## Listar todos los archivos en C:\Windows\Web\ de forma recursiva usando Get-ChildItem
Measure-Command { Get-ChildItem C:\Windows\Web\ -Recurse}

## Listar todos los archivos en C:\Windows\Web\ de forma recursiva usando Get-CimInstance y consulta WMI
Measure-Command { Get-CimInstance -ClassName Cim_DataFile -Filter "Drive = 'c:' AND Path = '\windows\web\%'"}

Al ejecutar el código anterior en PowerShell, verás una salida similar a la siguiente.

Get-ChildItem vs. Get-CimInstance with WMI Query

Como se puede ver en la salida mostrada anteriormente, listar los archivos en C:\windows\web casi tomó diez veces más tiempo usando Get-CimInstance que el tiempo que tomó para que Get-ChildItem completara la operación!

Además, ¿notaste cómo la línea de Get-ChildItem es mucho más corta que Get-CimInstance? No solo obtienes una ejecución más rápida usando Get-ChildItem, sino que también te beneficias de un código más limpio y corto.

Pasos siguientes

En este artículo, has visto las dos formas diferentes en que puedes usar PowerShell para eliminar archivos con cmdlets integrados y WMI/CIM.

Sabe que siempre debes usar los cmdlets Get-ChildItem y Remove-Item para eliminar archivos. Estos cmdlets integrados son más flexibles, más fáciles y más rápidos de usar que cuando se utiliza WMI.

Intenta crear un script que pueda realizar mantenimiento del espacio en disco por ti. Seguramente ya existan algunos scripts con ese propósito; no dudes en usarlos como referencia, pero si estás dispuesto a practicar y aprender, deberías intentar crear el tuyo propio.

Lectura adicional

Source:
https://adamtheautomator.com/powershell-to-delete-files/