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

Mantener el espacio libre en disco es crucial al administrar servidores y sistemas. Como administradores, no querrían encontrarse desprevenidos ante una situación de ‘disco lleno’. Para asegurarse de estar cubiertos, 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!

Prerrequisitos

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 Remove-Item cmdlet. 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 el potente pipeline de PowerShell realmente puede hacer las cosas muy fáciles.

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

¿Sabían que el cmdlet Remove-Item tiene un alias llamado del? Cuando trabajan en PowerShell, usar Remove-Item o del ejecutará el mismo comando.

Usando PowerShell para Eliminar un Archivo

El primer ejemplo que sería más útil es el más básico, es decir, eliminar un solo archivo. Para eliminar solo un archivo, solo necesitas usar el siguiente comando. 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 encuentre un error.

Uso de 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 que se incluirá son archivos. Get-ChildItem ignora las carpetas.

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

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

Successfully deleted all files in a folder

Uso de PowerShell para eliminar todos los archivos recursivamente

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

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

Al ejecutar el código anterior, PowerShell busca en todos los subdirectorios y recupera la lista de archivos. La salida a continuación muestra que el código pudo eliminar archivos en la carpeta principal; sin embargo, no pudo recuperar los archivos en los subdirectorios.

Failed to retrieve files in sub-folders

Solución al 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 llegar no existe, lo cual es engañoso.

En este caso, el error se debe a que la ruta que Get-ChildItem está intentando leer excede 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 que un archivo de texto llamado InTooDeep.txt se encuentra en el subdirectorio más profundo. La combinación de todos los caracteres que componen los nombres de directorio anidados crea un problema de ruta larga.

Nested directories creating a long path name

En Windows PowerShell 5.1, hay un método alternativo para el problema del nombre de ruta largo. El método alternativo es utilizar la versión Unicode de la ruta. En lugar de especificar la ruta de esta manera: C:\temp, use la versión Unicode así: ‘\\?\C:\temp’ para carpetas ubicadas localmente, o ‘\\?\UNC\<nombredecomputadora>\<compartido>\Temp’ si la carpeta está ubicada en una ruta UNC.

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

Utilizando el código modificado anterior que se adapta al nombre de ruta largo, la salida a continuación muestra que PowerShell leyó el nombre de ruta profundamente anidado con éxito y eliminó el archivo.

Deleted the file with a long path name

Tenga 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 se necesitan eliminar las carpetas, simplemente elimine 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 mantenimiento del espacio en disco es eliminar archivos que sean más antiguos que un número específico de días. Este ejemplo es útil para eliminar archivos de registro antiguos, como los generados por servidores web 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. Utilizando el script siguiente, 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 se puede ver en la captura de pantalla abajo, 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 a eliminar, puedes crear un script para eliminar solo los archivos que tengan más de un número específico de días de antigüedad, en este caso, más de 14 días.

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

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

La siguiente línea de código después de la variable $threshold realizará 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 más antiguo que el número de días guardado 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

Cuando ejecute 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 que tienen menos de 14 días aún 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

Usando PowerShell para igualar 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.

Este siguiente ejemplo muestra cómo eliminar los archivos que coinciden con el nombre de archivo *.LOG. Una forma de hacerlo es utilizando 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 primero Get-ChildItem 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*

Al excluir 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, puedes enviar 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

Eliminar archivos usando WMI en PowerShell

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

PowerShell viene con soporte para WMI. Y el soporte para WMI significa que se pueden llamar consultas y métodos de WMI desde dentro de 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 e Invoke-CimMethod.

Usando PowerShell y WMI para eliminar un archivo

Este ejemplo asume que conoces la ruta del archivo específico que deseas 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 se escapen 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: \\.

Al ejecutar el código anterior, se 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 mediante 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 puedes ver en la captura de pantalla a continuación, el valor de 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 Delete 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 otros 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, le mostraré cómo eliminar todos los archivos en una carpeta usando PowerShell y WMI. Se utilizarán los mismos cmdlets utilizados en el ejemplo anterior, que son Get-CimInstance y Invoke-CimMethod. Pero, esta vez, la consulta WQL recuperará todos los archivos en la carpeta en lugar de solo uno específico.

En este siguiente código, el cmdlet Get-CimInstance recupera todos los archivos ubicados en C:\temp. Como puede 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\\'"

Ejecutar el código anterior guarda la información recuperada sobre los archivos en C:\temp en la variable $file2delete. Ver el valor o los valores de la variable $file2delete 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 ser enviados al cmdlet Invoke-CimMethod para eliminar todos los archivos en c:\temp.

$file2delete | Invoke-CimMethod -Name Delete

Recuerda, el código ReturnValue de 0 significa exitoso, 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, esta vez la consulta tiene una condición adicional (Name LIKE '%.log). Esta condición adicional 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 archivos *.LOG y solo un archivo *.TXT. Una vez que el código haya terminado de ejecutarse, los archivos *.LOG son eliminados 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 integrado en PowerShell como Get-ChildItem y Remove-Item para recuperar y eliminar archivos es mucho más rápido que cuando se utiliza 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 de WMI
Measure-Command { Get-CimInstance -ClassName Cim_DataFile -Filter "Drive = 'c:' AND Path = '\windows\web\%'"}

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

Get-ChildItem vs. Get-CimInstance with WMI Query

Como puedes ver en la salida mostrada arriba, listar los archivos en C:\windows\web casi tomó diez veces más tiempo usando Get-CimInstance que el tiempo que tomó completar con Get-ChildItem!

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.

Próximos Pasos

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

Recuerda que siempre debes usar el cmdlet 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 tareas de limpieza de espacio en disco por ti. Seguramente ya existan algunos scripts con ese propósito; si estás dispuesto a practicar y aprender, deberías intentar crear el tuyo propio.

Lectura adicional:

Source:
https://adamtheautomator.com/powershell-delete-file/