Cómo Escribir Tu Primer Script de PowerShell: Automatización de Limpieza de Archivos

Una de las metodologías de codificación más importantes a seguir es asegurarse de conocer y gestionar cada forma en que su código puede “fluir”. Si piensa en su código como un flujo, puede ramificarse, regresar a varios puntos y encontrar muchas condiciones.

El manejo de errores asegura que configure “redes” o un lugar predeterminado al que su código puede fluir cuando algo inesperado sucede.

Utilicemos un escenario del mundo real en el que podría encontrarse, tratando con el manejo de errores en PowerShell.

Construyendo el Script Inicial para la Limpieza de Archivos

Necesitamos limpiar algunos archivos antiguos. Nuestro servidor de archivos ha estado funcionando desde siempre, y necesitamos liberar espacio. La dirección ha decidido eliminar todos los archivos que tengan más de un número especificado de días. Necesitamos construir un script que busque recursivamente en una carpeta, encuentre todos los archivos que tengan más de un cierto número de días y los elimine.

La tarea suena lo suficientemente fácil, pero esta es la sección de manejo de errores, así que sabe que algunas cosas saldrán mal!

Comencemos a entender el manejo de errores construyendo primero el script de demostración del escenario sin manejo de errores para demostrar el problema que resuelve el manejo de errores.

  1. Primero, abra una nueva pestaña en VS Code.

    Como solo estamos probando algunas cosas ahora, no guardaremos el script todavía. Dígale temporalmente a VS Code que está a punto de escribir algo de PowerShell.

    Presione Ctrl-Shift-P, escriba ‘lang’, seleccione Elegir Modo de Lenguaje, escriba ‘power’ y elija PowerShell. Ahora VS Code sabe que estará escribiendo PowerShell.

  2. A continuación, divide el problema en tareas, resolviendo primero la más obvia.

    Para este caso, la tarea consiste en crear un comando para leer archivos en un directorio.

    Get-ChildItem -Path C:\OldForgottenFolder
    
  3. Get-ChildItem también devuelve directorios que no necesitamos, así que limitemos eso solo a archivos.

    Get-ChildItem -Path C:\OldForgottenFolder -File
    
  4. Si hay archivos en esos subdirectorios, también necesitamos obtenerlos con Recurse.

    Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse
    
  5. Ahora que tenemos el comando y los parámetros, está devolviendo TODOS los archivos. Solo necesitamos encontrar aquellos que sean más antiguos que un cierto número de días.

    Como Get-ChildItem devuelve cada archivo con una propiedad de objeto LastWriteTime, debemos filtrar en esa propiedad. Usaremos el filtro Where para encontrar los archivos con un LastWriteTime menor que una fecha especificada.

    (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le ?????}
    
  6. La fecha necesita ser dinámica porque “antiguo” hoy será diferente a “antiguo” mañana.

    Comenta la línea anterior porque la necesitaremos en algún momento y luego averigua la situación de la fecha.

    ## (Get-ChildItem -Path C:\\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le ?????}
    $Now = Get-Date
    $Now
    
  7. Ahora que tenemos la fecha de hoy, busquemos un número específico de días antes de hoy para encontrar la fecha. Solo pondré 30 aquí temporalmente, ya que sé que algunos archivos tienen más de cinco días de antigüedad para hacer una prueba rudimentaria.

    ## (Get-ChildItem -Path C:\\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le ?????}
    $Ahora = Get-Date
    $ÚltimaEscritura = $Ahora.AddDays(-30)
    $ÚltimaEscritura
    
  8. ¡Hecho! Vamos a juntarlo hasta ahora.

    $Ahora = Get-Date
    $ÚltimaEscritura = $Ahora.AddDays(-30)
    (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le $ÚltimaEscritura}
    

    Ahora tenemos un pequeño script que encuentra todos los archivos en un directorio que son más antiguos que un número específico de días.

  9. A continuación, debemos agregar la capacidad de eliminar esos archivos más antiguos. Esto es trivial usando el cmdlet Remove-Item y la tubería.

    $Ahora = Get-Date
    $ÚltimaEscritura = $Ahora.AddDays(-30)
    (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le $ÚltimaEscritura} | Remove-Item
    
  10. ¡Hecho! Pero espera, no tengo idea de qué archivos eliminó. También hubo algunos errores que abordaremos en unos minutos. Agreguemos algo de funcionalidad básica.

    $VerbosePreference = 'Continuar'
    
    $Ahora = Get-Date
    $ÚltimaEscritura = $Ahora.AddDays(-30)
    $archivosViejos = (Get-ChildItem -Path C:\OldForgottenFolder -File -Recurse).Where{$_.LastWriteTime -le $ÚltimaEscritura}
    foreach ($archivo in $archivosViejos) {
        Remove-Item -Path $archivo.FullName
        Write-Verbose -Message "Eliminado con éxito [$($archivo.FullName)]."
    }
    
  11. Necesitarás incluir un bucle como este para ejecutar algún tipo de código para cada archivo. Aquí no estamos utilizando la canalización y, en su lugar, estamos poniendo todos los archivos encontrados en una variable archivosViejos, un arreglo de objetos de archivo. Luego estamos ejecutando Remove-Item en cada uno como antes, pero esta vez incluyendo un mensaje detallado que nos dice qué archivo se está eliminando.

  12. Ahora ejecutemos este código y veamos qué sucede.

    Ahora puedes ver a través del mensaje detallado que se eliminaron algunos archivos. El código que tenemos ahora es lo esencial que necesitamos para crear el script. Ahora vamos a crear un script real a partir de esto en la siguiente sección.

Maximizando la Flexibilidad y la Reusabilidad con Parámetros

Has construido tu script, pero todavía tiene el potencial de ser flexible y reutilizable. ¿Cómo? Los parámetros nos permitirán especificar el directorio y la antigüedad de los archivos que queremos objetivos, haciendo que el script sea más flexible.

  1. Antes de avanzar mucho más, guardemos nuestro trabajo. Llámalo Remove-FileOlderThan.ps1.

    Nota el formato verbo/sustantivo con un guion. Si es posible, intenta siempre crear nombres de scripts de la misma manera que los comandos de PowerShell para consistencia y legibilidad.

  2. Primero, los scripts están destinados a ser reutilizables. Es probable que quieras usar este script en diferentes directorios y diferentes edades. Necesitaremos introducir algunos parámetros. Para hacerlo, averiguamos qué cambiará. El directorio y el número de días. Entendido.

    param (
        [Parameter(Mandatory)]
        [string]$RutaDeCarpeta,
    [Parameter(Mandatory)]
    [int]$DiasAntiguos
    

    )

    $Ahora = Get-Date
    $UltimaEscritura = $Ahora.AddDays(-30)
    $archivosAntiguos = (Get-ChildItem -Path C:\CarpetaOlvidadaAntigua -File -Recurse).Where{$_.LastWriteTime -le $UltimaEscritura}
    foreach ($archivo in $archivosAntiguos) {
    Remove-Item -Path $archivo.FullName
    Write-Verbose -Message "Se eliminó correctamente [$($archivo.FullName)]."
    }

    Agrega un bloque param en la parte superior y define cada parámetro como obligatorio ya que debemos tener una ruta y un número para que el script funcione. Además, especifica el tipo aquí como una buena práctica.

  3. Reemplaza los elementos estáticos que teníamos en el código anterior con los valores de los parámetros.

    param (
        [Parameter(Mandatory)]
        [string]$FolderPath,
    [Parameter(Mandatory)]
    [int]$DaysOld
    

    )

    $Now = Get-Date
    $LastWrite = $Now.AddDays(-$DaysOld)
    $oldFiles = (Get-ChildItem -Path $FolderPath -File -Recurse).Where{$_.LastWriteTime -le $LastWrite}
    foreach ($file in $oldFiles) {
    Remove-Item -Path $file.FullName
    Write-Verbose -Message "Eliminado con éxito [$($file.FullName)]."
    }

  4. Ahora ejecutemos el script y veamos qué sucede.

    C:\Scripts\Remove-FileOlderThan.ps1 -FolderPath C:\OldForgottenFolder -DaysOld 30 -Verbose
    

    Puedes ver cómo tenemos que especificar la ruta de la carpeta y el número de días como parámetros. Usa el parámetro Verbose para ver esa línea de Write-Verbose.

    PowerShell ejecutó el script exactamente como antes, ¡pero ahora tenemos un script parametrizado que podemos usar en cualquier directorio o en cualquier antigüedad de archivos!

    Al observar la salida, encontramos un texto en rojo. O no tienes permisos, o el archivo es de solo lectura. Pero, ¿en qué archivos falló? ¿Y cómo aseguras que esos archivos también sean eliminados?

    Conclusión

    En este tutorial, construimos un script para limpiar archivos antiguos de un directorio, asegurando flexibilidad al agregar parámetros. Aunque el script funciona como se esperaba, vimos que el manejo de errores aún no se había abordado, lo cual es crucial al tratar con escenarios del mundo real.

    A medida que avancemos, agregar gestión de errores nos permitirá manejar problemas, como cmdlets que lanzan errores o archivos que son inaccesibles, ayudándonos a evitar la terminación del script y proporcionando información detallada sobre lo que salió mal.

    ¡Mantente atento para la próxima demostración! PowerShell 101: Errores terminantes, no terminantes, y Try/Catch.

Source:
https://adamtheautomator.com/powershell-file-cleanup-script/