PowerShell para administradores de sistemas

imagen¡Hola, habitantes! PowerShell es un lenguaje de secuencias de comandos y un shell de comandos que le permite administrar y automatizar casi cualquier tarea. En PowerShell para administradores de sistemas, el propietario de Microsoft MVP, Adam Bertram, también conocido como "el Automator", le muestra cómo usar PowerShell para que el lector finalmente tenga tiempo para los juguetes, el yoga y los gatos. Aprenderá a: -Combinar comandos, controlar el flujo de ejecución, manejar errores, escribir scripts, ejecutarlos de forma remota y probarlos usando el marco de prueba Pester. -Analizar datos estructurados como XML y JSON, trabajar con servicios populares (como Active Directory, Azure y Amazon Web Services), crear sistemas de monitoreo de servidores. -Crear y diseñar módulos PowerShell. -Utilice PowerShell para mayor comodidad,instalación de Windows totalmente automatizada. -Cree un bosque de Active Directory con solo un host Hyper-V y algunos archivos ISO. -Cree innumerables servidores web y SQL con solo unas pocas líneas de código. Los ejemplos de la vida real ayudan a cerrar la brecha entre la teoría y el trabajo en un sistema real, y el humor ligero del autor facilita la lectura. ¡Deje de depender de software costoso y vagos consejos de la web!



Para quién es este libro
- , . DevOps, , / (CI/CD).



, PowerShell . PowerShell « Windows» — Microsoft, PowerShell . , , .



Flujo de control



Repitamos un poco. En el Capítulo 3, aprendimos cómo se pueden combinar comandos mediante una canalización y scripts externos. El Capítulo 2 cubrió las variables y cómo usarlas para almacenar valores. Una de las principales ventajas de trabajar con variables es la capacidad de usarlas para escribir código que no funciona con valor, sino con "significado". En lugar de trabajar con el número 3, por ejemplo, trabajará con el concepto general de $ serverCount. Esto le permite escribir código que funciona igual si tiene uno, dos o mil servidores. Combine esta capacidad con la capacidad de guardar su código en scripts que se pueden ejecutar en diferentes computadoras, y puede comenzar a resolver problemas a una escala mucho mayor.



Sin embargo, en la vida, a veces importa si trabaja con un servidor, con dos o con mil. Hasta ahora, no tiene una forma adecuada de dar cuenta de esto, y sus scripts simplemente se ejecutan de arriba a abajo, incapaces de adaptarse en función de ciertos valores. En este capítulo, usaremos el flujo de control y la lógica condicional para escribir scripts que ejecutarán diferentes comandos dependiendo de los valores en los que operan. Al final del capítulo, aprenderá cómo usar las sentencias if / then y switch, así como varios bucles, para darle a su código la flexibilidad que tanto necesita.



Un poco sobre el flujo de control



Escribiremos un script que lea el contenido de un archivo almacenado en varias computadoras remotas. Para continuar, descargue un archivo llamado App_configuration.txt de los materiales del libro en github.com/adbertram/PowerShellForSysadmins/ y colóquelo en la raíz de la unidad C: \ en varias computadoras remotas. Si no tiene computadoras remotas, siga leyendo por ahora. Para este ejemplo, usaré los servidores llamados SRV1, SRV2, SRV3, SRV4 y SRV5.



Para acceder al contenido del archivo, use el comando Get-Content y especifique la ruta al archivo en el valor del argumento del parámetro Path, como se muestra a continuación:



Get-Content -Path "\\ servername \ c $ \ App_configuration.txt "



Primero, guardemos todos los nombres de nuestros servidores en una matriz y ejecutemos este comando para cada servidor. Abra un nuevo archivo .ps1 e ingrese el código del Listado 4.1 en él.



Listado 4.1. Extraer contenido de archivos de varios servidores



$servers = @('SRV1','SRV2','SRV3','SRV4','SRV5')
Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"
Get-Content -Path "\\$($servers[1])\c$\App_configuration.txt"
Get-Content -Path "\\$($servers[2])\c$\App_configuration.txt"
Get-Content -Path "\\$($servers[3])\c$\App_configuration.txt"
Get-Content -Path "\\$($servers[4])\c$\App_configuration.txt"
      
      





En teoría, este código debería funcionar sin problemas. Pero este ejemplo asume que algo te va mal. ¿Qué pasa si el servidor SRV2 no funciona? ¿Qué pasa si alguien olvidó poner App_configuration.txt en SRV4? ¿O tal vez alguien cambió la ruta del archivo? Puede escribir una secuencia de comandos separada para cada servidor, pero esta solución no se escalará, especialmente a medida que comience a agregar más y más servidores. Necesita un código que funcione según la situación.



La idea detrás del flujo de control es que le permite ejecutar diferentes conjuntos de instrucciones basadas en una lógica predefinida. Imagine que sus scripts se ejecutan a lo largo de una ruta específica. Hasta ahora, su ruta es simple: desde la primera línea de código hasta la última. Sin embargo, puede agregar bifurcaciones en el camino, regresar a lugares que ya ha visitado o saltar sobre ellos. Al bifurcar las rutas de ejecución de su secuencia de comandos, le da más flexibilidad, lo que le permite manejar muchas situaciones con una sola secuencia de comandos.



Comenzaremos mirando el tipo más simple de flujo de control, la declaración condicional.



Usar declaraciones condicionales



En el Capítulo 2, aprendimos que existen valores lógicos: verdadero y falso. Los booleanos le permiten crear declaraciones condicionales que le dicen a PowerShell que ejecute un bloque específico de código dependiendo de si una expresión (llamada condición) se evalúa como Verdadero o Falso. Una condición es una pregunta de sí / no. ¿Tiene más de cinco servidores? ¿Está funcionando el servidor 3? ¿Existe la ruta del archivo? Para comenzar a usar declaraciones condicionales, veamos cómo convertir tales preguntas en expresiones.



Creación de expresiones con operadores Puede



escribir expresiones lógicas utilizando operadores de comparación que comparan valores. Para utilizar un operador de comparación, debe colocarlo entre dos valores, por ejemplo:



PS> 1 –eq 1
True
      
      





En este caso, el operador –eq le permite determinar la equivalencia de dos valores.

A continuación se muestra una lista de los operadores de comparación más comunes que usaremos:



-eq compara dos valores y devuelve True si son iguales.



-ne compara dos valores y devuelve True si no son iguales.



-gt compara dos valores y devuelve True si el primero es mayor que el segundo.



-ge compara dos valores y devuelve True si el primero es mayor o igual que el segundo.



-lt compara dos valores y devuelve True si el primero es menor que el segundo.



-le compara dos valores y devuelve True si el primero es menor o igual que el segundo.



-contains devuelve True si el segundo valor es parte del primero. Por ejemplo, este operador le permite determinar si un valor está dentro de una matriz.



PowerShell también tiene operadores de comparación más avanzados. No nos detendremos en ellos aquí, pero le recomiendo que lea sobre ellos en la documentación de Microsoft en docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators o en la sección de ayuda de PowerShell (ver capítulo 1).



Puede utilizar los operadores anteriores para comparar variables y valores. Pero la expresión no tiene por qué ser una comparación. A veces, los comandos de PowerShell se pueden usar como condiciones. En el ejemplo anterior, queríamos conocer la disponibilidad del servidor. Puede usar el cmdlet Test-Connection para probar la conexión al servidor. Normalmente, la salida del cmdlet Test-Connection contiene mucha información diferente, pero con el parámetro Quiet puede forzar que el comando devuelva True o False, y el parámetro Count puede limitar la prueba a un intento.



PS> Test-Connection -ComputerName offlineserver -Quiet -Count 1
False
      
      





PS> Test-Connection -ComputerName onlineserver -Quiet -Count 1
True
      
      





Para saber si el servidor está inactivo, puede usar el operador –not para invertir la expresión:



PS> -not (Test-Connection -ComputerName offlineserver -Quiet -Count 1)
True
      
      





Ahora que está familiarizado con las expresiones básicas, veamos el operador condicional más simple.



El enunciado if El enunciado



if funciona simplemente: si X es verdadero, entonces haz Y. ¡Eso es!



Para usar una declaración en una expresión, escriba la palabra clave if seguida de paréntesis que contengan la condición. La expresión va seguida de un bloque de código entre llaves. PowerShell solo ejecutará este bloque de código si la expresión se evalúa como True. Si la expresión if se evalúa como False o no devuelve nada, el bloque de código no se ejecutará. La sintaxis de la instrucción if / then se muestra en el Listado 4.2.



Listado 4.2. Sintaxis de la instrucción if



if () {
   #  ,   
}
      
      





Este ejemplo tiene un poco de sintaxis nueva: el carácter de almohadilla (#) denota un comentario; este es un texto que PowerShell ignora. Puede utilizar los comentarios para dejar notas y descripciones útiles para usted o para otra persona que luego leerá su código.



Ahora, echemos otro vistazo al código que se muestra en el Listado 4.1. Le mostraré cómo usar una declaración if para evitar intentar llegar a un servidor inactivo. Ya vimos en la sección anterior que el comando Test-Connection se puede usar como una expresión que devuelve True o False, así que por ahora envolvemos Test-Connection en una declaración if y luego usemos el comando Get-Content para evitar intentar acceder un servidor muerto. ... Por ahora, solo cambiaremos el código del primer servidor, como se muestra en el Listado 4.3.



Listado 4.3. Usar una declaración if para acceder de forma selectiva



$servers = @('SRV1','SRV2','SRV3','SRV4','SRV5')
if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {
   Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"
}
Get-Content -Path "\\$($servers[1])\c$\App_configuration.txt"
----
      
      





Dado que tiene Get-Content en su declaración if, no se encontrará con ningún error si intenta acceder a un servidor roto; si la prueba falla, su secuencia de comandos sabe que no debe intentar leer el archivo. El código intentará acceder al servidor solo si ya sabe que está habilitado. Pero tenga en cuenta que este código solo se activa si la condición es verdadera. Muy a menudo, deberá especificar un comportamiento de secuencia de comandos para una condición verdadera y otro para una condición falsa. En la siguiente sección, verá cómo definir el comportamiento de una condición falsa utilizando la instrucción else.



Otra declaración



Para proporcionar una alternativa a su declaración if, puede usar la palabra clave else después del paréntesis de cierre del bloque if, seguida de otro par de llaves que contienen el bloque de código. Como se muestra en el Listado 4.4, usaremos una instrucción else para devolver un error a la consola si el primer servidor no responde.



Listado 4.4. Usar la cláusula else para ejecutar el código si la condición

no es verdadera



if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {
   Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"
} else {
   Write-Error -Message "The server $($servers[0]) is not responding!"
}
      
      





La declaración if / else funciona muy bien cuando tiene dos situaciones mutuamente excluyentes. En este caso, el servidor está conectado o no, es decir, solo necesitamos dos ramas del código. Veamos cómo lidiar con situaciones más complejas.



Declaración de Elseif



La declaración else cubre la situación opuesta: si no funciona, hágalo de todos modos. Este enfoque funciona para condiciones binarias, es decir, cuando el servidor se está ejecutando o no. Pero a veces tienes que lidiar con una gran cantidad de opciones. Por ejemplo, suponga que tiene un servidor que no tiene el archivo que desea y ha almacenado el nombre de ese servidor en la variable $ problemServer (¡agregue esta línea de código a su script!). Esto significa que necesita una verificación adicional para ver si el servidor que está sondeando actualmente es el servidor con problemas. Esto se puede lograr con declaraciones if anidadas, como se muestra en el siguiente código:



if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {
   if ($servers[0] –eq $problemServer) {
      Write-Error -Message "The server $servers[0] does not have the right
         file!"
   } else {
      Get-Content -Path "\\$servers[0]\c$\App_configuration.txt"
   }
} else {
   Write-Error -Message "The server $servers[0] is not responding!"
}
----
      
      





Pero hay una forma más ordenada de implementar la misma lógica, con una instrucción elseif, que le permite verificar una condición adicional antes de regresar al bloque else. La sintaxis del bloque elseif es idéntica a la del bloque if. Entonces, para probar el servidor problemático con la instrucción elseif, ejecute el código del Listado 4.5.



Listado 4.5. Usando el bloque elseif



if (-not (Test-Connection -ComputerName $servers[0] -Quiet -Count 1)) { 
   Write-Error -Message "The server $servers[0] is not responding!"
} elseif ($servers[0] –eq $problemServer) 
   Write-Error -Message "The server $servers[0] does not have the right file!"
} else {
   Get-Content -Path "\\$servers[0]\c$\App_configuration.txt"
}
----
      
      





Tenga en cuenta que no solo agregamos una instrucción elseif, sino que al mismo tiempo cambiamos la lógica del código. Ahora podemos verificar si el servidor está fuera de línea usando el operador –not. Luego, una vez que hemos determinado el estado de la red del servidor, verificamos si es problemático. Si no es así, usamos la instrucción else para activar el comportamiento de extracción del archivo predeterminado. Como puede ver, hay varias formas de estructurar su código de esta manera. Lo importante es que el código funcione y que sea legible para una persona desde el exterior, ya sea que su colega lo vea por primera vez, o usted mismo algún tiempo después de escribirlo.



Puede encadenar tantas declaraciones elseif como desee para adaptarse a una amplia variedad de circunstancias. Sin embargo, las declaraciones elseif son mutuamente excluyentes: cuando uno de los elseif se evalúa como Verdadero, PowerShell solo ejecuta su código y no busca otros casos. En el Listado 4.5, esto no causó ningún problema, ya que solo necesitaba probar el servidor en busca de "problemas" después de verificar el estado, pero en el futuro le aconsejo que tenga esta característica en mente.



Las declaraciones if, else y elseif son excelentes para implementar respuestas de código a preguntas simples de sí / no. En la siguiente sección, aprenderá a trabajar con lógica más compleja.



Declaración de cambio



Modifiquemos un poco nuestro ejemplo. Digamos que tenemos cinco servidores, y en cada servidor la ruta al archivo requerido es diferente. Según lo que sabe ahora, deberá crear una declaración elseif separada para cada servidor. Esto funcionará, pero hay un método más conveniente.



Tenga en cuenta que ahora trabajaremos con un tipo diferente de condición. Si antes necesitábamos respuestas a preguntas como "sí / no", ahora queremos obtener el significado específico de una cosa. ¿Es un servidor SRV1? SRV2? Etc. Si solo estuviera trabajando con uno o dos valores específicos, una instrucción if funcionaría, pero en este caso, una instrucción switch funciona mucho mejor.



La instrucción de cambio le permite ejecutar diferentes piezas de código dependiendo de algún valor. Consiste en la palabra clave switch seguida de una expresión entre paréntesis. Dentro del bloque de interruptores hay una serie de declaraciones, estructuradas así: primero especifica el valor, seguido de un conjunto de llaves que contienen el bloque de código y finalmente el bloque predeterminado, como se muestra en el Listado 4.6.



Listado 4.6. Cambiar plantilla de declaración



switch () {
    {
      # 
   }
    {
   }
   default {
     # ,     
   }
}
      
      





Una sentencia de cambio puede contener un número casi ilimitado de valores. Si la expresión se evalúa como un valor, se ejecuta el código correspondiente dentro del bloque. Lo importante es que, a diferencia de elseif, después de ejecutar un bloque de código, PowerShell continuará verificando el resto de condiciones, a menos que se indique lo contrario. Si ninguno de los valores coincide, PowerShell ejecutará el código en el bloque predeterminado. Para dejar de iterar sobre las condiciones en una declaración de cambio, use la palabra clave break al final del bloque de código, como se muestra en el Listado 4.7.



Listado 4.7. Usar la palabra clave break en una declaración de cambio



switch () {
    {
      # 
      break
   }
----
      
      





La palabra clave break le permite hacer que las condiciones en una declaración de cambio se excluyan mutuamente. Volvamos a nuestro ejemplo con cinco servidores y el mismo archivo con diferentes rutas. Usted sabe que el servidor con el que está trabajando solo puede tener un valor (es decir, no se puede nombrar SRV1 y SRV2 al mismo tiempo), por lo que debe usar declaraciones de interrupción. Su secuencia de comandos debe verse como la que se muestra en el Listado 4.8.



Listado 4.8. Comprobación de varios servidores con una declaración de cambio



$currentServer = $servers[0]
switch ($currentServer) {
   $servers[0] {
      # Check if server is online and get content at SRV1 path.
      break
   }
   $servers[1] {
      ## Check if server is online and get content at SRV2 path.
      break
   }
   $servers[2] {
      ## Check if server is online and get content at SRV3 path.
      break
   }
----
      
      





Puedes reescribir este código usando solo las declaraciones if y elseif (¡y realmente te recomiendo que pruebes esto!). En cualquier caso, sea cual sea el método que elija, necesita la misma estructura para todos los servidores de la lista, lo que significa que su escenario será bastante largo; solo imagine probar quinientos servidores en lugar de cinco. En la siguiente sección, aprenderá cómo deshacerse de este problema utilizando una de las estructuras de flujo de control más fundamentales: un bucle.



Usando bucles



Existe una buena regla general para el trabajo con la computadora: no se repita (SECO). Si se encuentra haciendo el mismo trabajo, es probable que haya una forma de automatizarlo. Es lo mismo con la codificación: si usa las mismas líneas una y otra vez, probablemente haya una solución mejor.



Una forma de evitar las repeticiones es utilizar bucles. Un bucle le permite ejecutar código repetidamente hasta que cambie alguna condición específica. La condición de parada puede iniciar el ciclo un número específico de veces, ya sea hasta que cambie algún valor booleano, o definir el ciclo para que se ejecute indefinidamente. Llamaremos a cada paso del bucle una iteración.



PowerShell ofrece cinco tipos de bucles: foreach, for, do / while, do / until y while. En esta sección, discutiremos cada tipo de bucle, resaltaremos sus características únicas y resaltaremos las mejores situaciones para usarlas.



Acerca del autor



Adam Bertram es un experto en negocios de Internet y TI con 20 años de experiencia. Emprendedor, Influencer de TI, MVP de Microsoft, Blogger, Gerente de capacitación y Autor de marketing de contenido, que trabaja con muchas empresas de TI. Adam también fundó la popular plataforma TechSnips para desarrollar las habilidades de los profesionales de TI (techsnips.io).



Se pueden encontrar más detalles sobre el libro en el sitio web de la editorial

» Tabla de contenido

» Extracto



Para los residentes, un 25% de descuento en el cupón - PowerShell



Tras el pago de la versión impresa del libro, se envía un libro electrónico al correo electrónico.



All Articles