Introducción a PowerShell (Parte 1: Generalidades)

  En otras entradas de la presente bitácora se ha mencionado la interfaz de usuario de Windows llamada PowerShell.
  Se trata de  una solución de automatización de tareas multiplataforma formada por un intérprete de órdenes de línea de comandos, un lenguaje de guiones y un marco de administración de configuración. PowerShell funciona en Windows, Linux y macOS.
  A diferencia de la mayoría de los intérpretes de órdenes, que solo aceptan y devuelven texto, PowerShell acepta y devuelve objetos .NET. El intérprete de órdenes incluye las siguientes características:
  •    Historial de línea de comandos sólido.
  •    Finalización con tabulación y predicción de comandos.
  •    Admisión de alias de comando y parámetro.
  •   Canalización para encadenar comandos.
  •   Sistema de ayuda en la consola, similar a las páginas “man” de UNIX.
   Como lenguaje de guiones, PowerShell se usa normalmente para automatizar la administración de sistemas, aunque también compilar, probar e implementar soluciones, a menudo en entornos de CI/CD (integración continua/despliegue continuo; tiene como objetivo optimizar y acelerar el ciclo de vida del desarrollo de soporte lógico). PowerShell se basa en entorno en tiempo de ejecución de lenguaje común .NET ["Common Language Runtime" ("CLR"), en inglés; entorno de ejecución para los códigos de los programas que corren sobre la plataforma Microsoft .NET]. Todas las entradas y salidas son objetos de .NET. No es necesario analizar la salida de texto para extraer información de la salida. El lenguaje de guiones de PowerShell incluye las siguientes características:
  •   Extensible mediante funciones, clases, guiones y módulos.
  •    Sistema de formato extensible para una salida fácil.
  •    Sistema de tipos extensible para crear tipos dinámicos.
  •    Compatibilidad integrada con formatos de datos comunes, como CSV, JSON y XML.
 

LENGUAJE ORIENTADO A OBJETOS

   En términos generales, se trata de un lenguaje de programación que implementa los conceptos definidos por la programación orientada a objetos [paradigma de programación que parte del concepto de "objetos" como base, los cuales contienen información en forma de campos (a veces también referidos como atributos, cualidades o propiedades) y código en forma de métodos]. Dichos conceptos son para definir que un lenguaje es orientado a objetos, aunque existen conceptos que pueden estar ausentes en un lenguaje dado y sin embargo, no invalidar su definición como lenguaje orientado a objetos.
  En este tipo de lenguaje se considera un objeto una entidad que tiene un determinado estado, comportamiento e identidad (su identificador). Por otra parte, los métodos y campos están estrechamente relacionados por la propiedad de conjunto. Esta propiedad destaca que una clase requiere de métodos para poder tratar los campos con los que cuenta.
  De este modo, la programación orientada a objetos difiere de la programación estructurada tradicional, en la que los datos y los procedimientos están separados y sin relación, ya que lo único que se busca es el procesamiento de unos datos de entrada para obtener otros de salida. La programación estructurada prima el concepto de procedimientos o funciones sobre el de estructuras (se emplean principalmente funciones que procesan datos). La programación orientada a objetos, en cambio, primero se definen los objetos o estructuras para posteriormente solicitar la ejecución de sus métodos.
  Los conceptos de este tipo de lenguaje son:
  •   Clase: Especie de "plantilla" en la que se definen los atributos y métodos predeterminados de un tipo de objeto. Esta plantilla se crea para poder crear objetos fácilmente. Al método de crear nuevos objetos mediante la lectura y recuperación de los atributos y métodos de una clase se le conoce como instanciación.
  •   Herencia: Relación entre una clase general y otra clase más específica. De este modo, una clase se deriva de otra de manera que extiende su funcionalidad. La clase de la que se hereda se suele denominar clase base, clase padre, superclase, clase ancestro (el vocabulario que se utiliza suele depender, en gran medida, del lenguaje de programación).
  •   Objeto: Instancia de una clase. Entidad provista de un conjunto de propiedades o atributos (datos) y de comportamiento o funcionalidad (métodos), los mismos que consecuentemente reaccionan a eventos. Se corresponden con los objetos reales del mundo que nos rodea, o con objetos internos del sistema (del programa).
  •   Método: Algoritmo asociado a un objeto (o a una clase de objetos), cuya ejecución se desencadena tras la recepción de un "mensaje". Desde el punto de vista del comportamiento, es lo que el objeto puede hacer.
  •   Evento: Suceso en el sistema (tal como una interacción del usuario con la máquina, o un mensaje enviado por un objeto). El sistema maneja el evento enviando el mensaje adecuado al objeto pertinente.
  •   Atributos: Características de la clase.
  •   Mensaje: Comunicación dirigida a un objeto, que le ordena que ejecute uno de sus métodos con ciertos parámetros asociados al evento que lo generó.
  •   Propiedad: Contenedor de un tipo de dato asociado a un objeto (o a una clase de objetos), que hace los datos visibles desde fuera del objeto y esto se define como sus características predeterminadas, y cuyo valor puede ser alterado por la ejecución de algún método.
  •   Estado interno: Variable que se declara privada, que puede ser únicamente accedida y alterada por un método del objeto, y que se utiliza para indicar distintas situaciones posibles para el objeto (o clase de objetos). No es visible al programador que maneja una instancia de la clase.
  •   Miembros de un objeto: Atributos, identidad, relaciones y métodos.
  •   Identificación de un objeto: Un objeto se representa por medio de una tabla o entidad que esté compuesta por sus atributos y funciones correspondientes.
   Además, las características más relevantes de este tipo de lenguaje son:
  •   Abstracción: Denota las características esenciales de un objeto, donde se capturan sus comportamientos. Cada objeto en el sistema sirve como modelo de un "agente" abstracto que puede realizar trabajo, informar y cambiar su estado, y "comunicarse" con otros objetos en el sistema sin revelar "cómo" se implementan estas características. Los procesos, las funciones o los métodos pueden también ser abstraídos, y, cuando lo están, se requiere una variedad de técnicas para ampliar una abstracción. El proceso de abstracción permite seleccionar las características relevantes dentro de un conjunto e identificar comportamientos comunes para definir nuevos tipos de entidades en el mundo real. La abstracción es clave en el proceso de análisis y diseño orientado a objetos, ya que mediante ella podemos llegar a armar un conjunto de clases que permitan modelar la realidad o el problema que se quiere atacar.
  •   Encapsulamiento: Reunir todos los elementos que pueden considerarse pertenecientes a una misma entidad, al mismo nivel de abstracción. Esto permite aumentar la cohesión (diseño estructurado) de los componentes del sistema.
  •   Polimorfismo: Comportamientos diferentes, asociados a objetos distintos, pueden compartir el mismo nombre; al llamarlos por ese nombre se utilizará el comportamiento correspondiente al objeto que se esté usando. Esto es, las referencias y las colecciones de objetos pueden contener objetos de diferentes tipos, y la invocación de un comportamiento en una referencia producirá el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto ocurre en "tiempo de ejecución", esta última característica se llama asignación tardía o asignación dinámica. Algunos lenguajes proporcionan medios más estáticos (en "tiempo de compilación") de polimorfismo.
  •   Herencia: Las clases no se encuentran aisladas, sino que se relacionan entre sí, formando una jerarquía de clasificación. Los objetos heredan las propiedades y el comportamiento de todas las clases a las que pertenecen. La herencia organiza y facilita el polimorfismo y el encapsulamiento, permitiendo a los objetos ser definidos y creados como tipos especializados de objetos preexistentes. Estos pueden compartir (y extender) su comportamiento sin tener que volver a implementarlo. Esto suele hacerse habitualmente agrupando los objetos en clases, y éstas en árboles o enrejados que reflejan un comportamiento común. Cuando un objeto hereda desde más de una clase, se dice que hay herencia múltiple; siendo de alta complejidad técnica por lo cual suele recurrirse a la herencia virtual para evitar la duplicación de datos.
  •   Modularidad: Propiedad que permite subdividir una aplicación en partes más pequeñas (módulos), cada una de las cuales debe ser tan independiente como sea posible de la aplicación en sí y de las restantes partes. Estos módulos se pueden compilar por separado, pero tienen conexiones con otros módulos. Al igual que la encapsulación, los lenguajes soportan la modularidad de diversas formas.
  •   Principio de ocultación: Cada objeto está aislado del exterior, es un módulo natural, y cada tipo de objeto expone una "interfaz" a otros objetos que detalla cómo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas; solamente los propios métodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no puedan cambiar el estado interno de un objeto de manera inesperada, eliminando efectos secundarios e interacciones inesperadas. Algunos lenguajes relajan esto, permitiendo un acceso directo a los datos internos del objeto de una manera controlada y limitando el grado de abstracción. La aplicación entera se reduce a un agregado o rompecabezas de objetos.
  •   Recolección de basura: Técnica por la cual el entorno de objetos se encarga de destruir automáticamente, y, por tanto, desvincular la memoria asociada, los objetos que hayan quedado sin ninguna referencia a ellos. Esto significa que el programador no debe preocuparse por la asignación o liberación de memoria, ya que el entorno la asignará al crear un nuevo objeto y la liberará cuando nadie lo esté usando.
   Por lo tanto, para que un lenguaje se pueda tratar como orientado a objetos, debe cumplir lo siguiente:
  •   Estar basado en objetos, es decir, que tenga el concepto de objeto incluido dentro del lenguaje base como colección de atributos y métodos que reaccionan a eventos.
  •   Estar basado en clases, es decir, que tenga el concepto de clase.
  •   Permitir la aplicación de herencia y polimorfismo.
C#
   Se trata de un lenguaje de programación multiparadigma desarrollado y estandarizado por la empresa Microsoft como parte de su plataforma .NET. Se trata de uno de los lenguajes de programación diseñados para la infraestructura de lenguaje común, y es en el que está basado el lenguaje de PowerShell.
  Su sintaxis básica deriva de C/C++ y utiliza el modelo de objetos de la plataforma .NET, similar al de Java, aunque incluye mejoras derivadas de otros lenguajes.
  Como lenguaje de programación orientado a objetos, posee los 4 principios básicos de la misma: Abstracción, encapsulación, herencia y polimorfismo.
  Los programas de C# constan de uno o varios archivos. Cada archivo contiene cero o más espacios de nombres, que, a su vez, contiene tipos como clases, estructuras, interfaces, enumeraciones y delegados, u otros espacios de nombres. Un guión de PowerShell posee una estructura similar.

CMDLETS

  Además de los comandos disponibles en el sistema, este intérprete de órdenes posee un comando específico conocido como cmdlet.
  Este tipo de comando es una herramienta simple de línea de comandos de una sola función incluida en el intérprete de órdenes, cuya finalidad es manipular objetos. Los cmdlets se recopilan en módulos de PowerShell que se pueden cargar a petición. Los cmdlets se pueden escribir en cualquier lenguaje .NET compilado o en el mismo lenguaje de guiones de PowerShell.
   Los cmdlets realizan una acción y, por lo general, devuelven un objeto Microsoft .NET al siguiente comando de la secuencia de comandos. Un cmdlet es un comando único que participa en la semántica de la secuencia de comandos de PowerShell. Esto incluye cmdlets binarios (C#), funciones de guión avanzadas, CDXML (análogo XML del tipo de archivo binario CDX) y flujos de trabajo.
  La sintaxis de un cmdlet consiste en un término verbo-nombre (el verbo expresa acciones específicas de PowerShell, mientras que el nombre describe tipos específicos de objetos) para asignarle un nombre, seguido de un parámetro:
<verbo>-<nombre> <parámetro 1> <parámetro 2>...

    Además, los cmdlets están diseñados para utilizarlos en combinación con otros cmdlets.
  Los principales términos de los cmdlets son:
  •   Atributo: Atributo .NET que se utiliza para declarar una clase de cmdlet como un cmdlet. Aunque PowerShell utiliza varios otros atributos que son opcionales, el atributo Cmdlet es obligatorio.
  •    Parámetro:  Propiedades públicas que definen los parámetros que están disponibles para el usuario o la aplicación que ejecuta el cmdlet. Los cmdlets pueden tener parámetros obligatorios, con nombre, posicionales y de conmutación (permiten definir parámetros que se evalúan sólo si se especifican en la llamada).
  •    Conjunto de parámetros: Grupo de parámetros que se pueden utilizar en el mismo comando para realizar una acción específica. Un cmdlet puede tener varios conjuntos de parámetros, pero cada conjunto de parámetros debe tener al menos un parámetro que sea único. Un buen diseño de cmdlet sugiere enfáticamente que el parámetro único también sea un parámetro obligatorio.
  •    Parámetro dinámico: Parámetro que se agrega al cmdlet en tiempo de ejecución. Normalmente, los parámetros dinámicos se agregan al cmdlet cuando otro parámetro se establece en un valor específico.
  •    Métodos de procesamiento de entrada: La clase System.Management.Automation.Cmdlet proporciona los siguientes métodos virtuales que se utilizan para procesar registros. Todas las clases de cmdlet derivadas deben anular uno o más de los tres primeros métodos:
    •   System.Management.Automation.Cmdlet.BeginProcessing : Se utiliza para proporcionar una funcionalidad de preprocesamiento única y opcional para el cmdlet.
    •   System.Management.Automation.Cmdlet.ProcessRecord : Se emplea para proporcionar la funcionalidad de procesamiento registro por registro para el cmdlet. El método System.Management.Automation.Cmdlet.ProcessRecord se puede llamar cualquier cantidad de veces, o no llamarse en absoluto, según la entrada del cmdlet.
    •   System.Management.Automation.Cmdlet.EndProcessing : Se utiliza para proporcionar una funcionalidad opcional de posprocesamiento única para el cmdlet.
    •   System.Management.Automation.Cmdlet.StopProcessing : Se emplea para detener el procesamiento cuando el usuario detiene el cmdlet de forma asincrónica.
  •   Función ShouldProcess: PowerShell permite crear cmdlets que solicitan comentarios al usuario antes de que el cmdlet realice un cambio en el sistema. Para utilizar esta función, el cmdlet debe declarar que admite la ShouldProcessfunción cuando declara el atributo Cmdlet y el cmdlet debe llamar a los métodos System.Management.Automation.Cmdlet.ShouldProcess y System.Management.Automation.Cmdlet.ShouldContinue desde dentro de un método de procesamiento de entrada.
  •   Transacción: Grupo lógico de comandos que se tratan como una sola tarea. La tarea falla automáticamente si falla cualquier comando del grupo y el usuario tiene la opción de aceptar o rechazar las acciones realizadas dentro de la transacción. Para participar en una transacción, el cmdlet debe declarar que admite transacciones cuando se declara el atributo Cmdlet.
 

GUIONES

  El método para crear guiones con lenguaje de objetos en PowerShell es muy similar al del lenguaje batch. El resultado produce un archivo con extensión “.ps1”.
  Las características del lenguaje de guiones de PowerShell poseen ciertas similitudes con las de otros lenguajes de guiones, aunque también las hay propias:
  •    Variables: Pueden usarse variables para almacenar valores. También es posible usar variables como argumentos para los comandos.
  •    Funciones: Una función es una lista con nombre de instrucciones. Las funciones generan una salida que se muestra en la consola. También pueden usarse funciones como entrada para otros comandos.
  •   Control del flujo: El control del flujo consiste en controlar varias rutas de ejecución mediante construcciones como If, ElseIf y Else.
  •   Bucles: Los bucles son construcciones que permiten trabajar en matrices, inspeccionar cada elemento y realizar algún tipo de operación en cada elemento. Pero los bucles van más allá de la iteración de la matriz. También es posible continuar condicionalmente con la ejecución de un bucle mediante bucles Do-While.
  •   Control de errores: Es importante escribir guiones que sean sólidos y puedan controlar varios tipos de errores. Se debe conocer la diferencia entre los errores de terminación y de no terminación. Es necesario utilizar construcciones como Try y Catch.
  •   Expresiones: A menudo, se usarán expresiones en los guiones de PowerShell. Las expresiones son representaciones de valores en la sintaxis de PowerShell.
  •   Integración de .NET y .NET Core: PowerShell proporciona una integración eficaz con .NET y .NET Core.
  Al igual que con los guiones en lenguaje bash, en Linux o macOS, se puede colocar el par de caracteres shebang (nombre que recibe el par de caracteres #! que se encuentran al inicio de los guiones de tipo Unix) en la parte superior del archivo de guión para establecer PowerShell como el intérprete de guiones.
  Una vez creado el archivo de guión de PowerShell (bien desde un bloc de notas, mediante el PowerShell ISE, u otro programa de edición de texto que permita la creación de guiones) puede ejecutarse de manera gráfica  pulsando sobre él con el botón derecho del ratón y, en el menú emergente, marcando la opción “Ejecutar con PowerShell”.
  Otro modo básico de ejecutarlo es abriendo el propio PowerShell como administrador, para lo que se buscará en el menú de inicio de Windows.
  Y se escoge la opción “Ejecutar como administrador” del PowerShell en dicho menú.
  Una vez en la consola de PowerShell, se cambia la política de ejecución (“Execution Policy”, en inglés; ver más abajo) mediante el cmdlet
Set-ExecutionPolicy RemoteSigned (respondiendo “s” cuando pregunte).
  Después se escribe la ruta del archivo (incluyendo el nombre entero del archivo) y se pulsa la tecla de entrar.

  Dado que hay guiones poco fiables, PowerShell posee dos maneras de proteger al usuario para que no realice ninguna acción de forma involuntaria (¡Ojo!, no son un sistema de seguridad):
  •   Obligación de ejecutar guiones mediante una ruta de acceso completa o una ruta de acceso relativa. Al ejecutar un guión, siempre se debe proporcionar su ruta de acceso. De esta manera, se sabrá exactamente qué se está ejecutando. Al incluir la ruta de acceso, se realiza una comprobación adicional para asegurarse de que se ejecuta exactamente lo que se quiere.
  •   Directiva de ejecución: Se trata de una característica de seguridad. Al igual que el requisito de proporcionar la ruta de acceso de un guión, una directiva puede impedir que se realicen acciones de forma involuntaria. La directiva se puede establecer en varios niveles, como el equipo local, el usuario actual o una sesión determinada. También es posible usar una configuración de directiva de grupo para establecer directivas de ejecución para equipos y usuarios, para lo que se utilizan los siguientes cmdlets:
    •   Get-ExecutionPolicy: Devuelve la directiva de ejecución actual. En Linux y macOS, el valor que se devuelve es Unrestricted. Para estos sistemas operativos, no se puede cambiar el valor. Esta limitación no hace que Linux o Mac sean menos seguros, ya que una directiva de ejecución es una característica de seguridad, no un mecanismo de seguridad.
    •   Set-ExecutionPolicy: En un equipo Windows se puede usar este cmdlet para cambiar el valor de una directiva de ejecución. Requiere un parámetro “-ExecutionPolicy”. Hay varios valores posibles. Se recomienda usar “Default” como valor, ya que establece la directiva en “Restricted” en los clientes de Windows y en “RemoteSigned” en Windows Server. “Restricted” significa que no se pueden ejecutar guiones, sólo se pueden ejecutar comandos, lo que tiene sentido en un cliente. “RemoteSigned” significa que se pueden ejecutar los guiones que se han escrito en el equipo local. Los guiones descargados de Internet deben estar firmados con una firma digital de un publicador de confianza.
Variables
  Ciertos valores se pueden almacenar en variables, que también son definibles en la consola, para que se puedan usar más adelante. Para definir una variable se antepone el carácter $.
  Al generar texto mediante
Write-Host o Write-Output, se pueden usar comillas simples o dobles. La elección depende de si se quiere interpolar los valores. Existen tres mecanismos:
  •   Comillas simples: Las comillas simples especifican literales; lo que se escribe es lo que se obtiene.
  •   Comillas dobles: Cuando se usan comillas dobles, las variables de las cadenas se interpolan.
  •    $(): También es posible escribir una expresión entre comillas dobles. Para ello, se usa la construcción $(). Una manera de usar esta construcción consiste en interpolar propiedades de objetos.

Ámbito
  Se trata de la forma en que PowerShell define dónde se pueden leer y cambiar construcciones como variables, alias y funciones. Al aprender a escribir guiones, es importante saber a qué se tiene acceso, qué puede cambiar y dónde se puede cambiar. Si no se entiende cómo funciona el ámbito, es posible que el código no funcione de la forma esperada.
  Existen 3 tipos de ámbito:
  •   Ámbito global: Al crear construcciones en este ámbito, como variables, seguirán existiendo una vez que se finalice la sesión. Todo lo que esté presente al iniciar una nueva sesión de PowerShell se considera dentro del ámbito.
  •   Ámbito de guión: Al ejecutar un archivo de guión, se crea un ámbito de guión. Todo lo definido en dicho archivo se encuentra en el ámbito de guión, por lo que dejará de existir una vez que el archivo termine de ejecutarse. Si se pretende crear algo en el archivo de guión y establecer como destino el ámbito global, se debe definir explícitamente ese ámbito, para lo cual se debe anteponer la palabra clave global a la variable.
  •   Ámbito local: El ámbito local es el ámbito actual y puede ser el ámbito global o cualquier otro ámbito.
  Existen ciertas reglas de ámbito que ayudan tanto a entender qué valores son visibles en un momento dado, como a comprender cómo se cambia un valor:
  •   Los ámbitos pueden anidarse. Un ámbito puede tener un ámbito primario (ámbito externo, fuera de aquel en el que se encuentra). A su vez, un ámbito puede tener un ámbito anidado, también conocido como ámbito secundario.
  •    Los elementos son visibles en los ámbitos actual y secundarios. Un elemento (como una variable o una función) es visible en el ámbito en el que se ha creado. De forma predeterminada, también es visible en todos los ámbitos secundarios. Es posible cambiar este comportamiento si se hace que el elemento sea privado dentro del ámbito.
  •    Los elementos solo se pueden cambiar en el ámbito en el que se crearon. De forma predeterminada, solo puede cambiar un elemento en el ámbito en el que se creó. Se puede cambiar este comportamiento si especifica explícitamente un ámbito diferente.
 
Perfiles
  Se trata de un guión que se ejecuta cuando se inicia PowerShell, que aplicará sus efectos a cada nueva sesión que inicie.
  PowerShell admite varios archivos de perfil, aplicables en los siguientes niveles: Todos los usuarios, todos los nodos (ruta "$PSHOME\Profile.ps1"); todos los usuarios, nodo actual (ruta "$PSHOME\Microsoft.PowerShell_profile.ps1"); usuario actual, todos los nodos (ruta "$Home[My ]Documents\PowerShell\Profile.ps1") y usuario actual, nodo actual (ruta "$Home[My ]Documents\PowerShell\Microsoft.PowerShell_profile.ps1").
   Mientras $PSHOME y $Home. $PSHOME apuntan al directorio de instalación de PowerShell, $Home es el directorio principal del usuario actual.
Otros programas también admiten perfiles, como Visual Studio Code.
  Como la primera vez que instala PowerShell, no hay perfiles, aunque existe una variable
$Profile (objeto que apunta a la ruta de acceso donde se debe colocar cada perfil que se va a aplicar), se deben crear del siguiente modo:
  1.   Se decide el nivel en el que se pretende crear el perfil. Es posible ejecutar $Profile | Select-Object * para ver los tipos de perfil y las rutas de acceso asociadas a ellos.
  2.    Se selecciona un tipo de perfil y se crea un archivo de texto en su ubicación mediante un comando como este: New-Item -Path $Profile.CurrentUserCurrentHost.
  3.   Se agregan las personalizaciones deseadas al archivo de texto y se guarda. La próxima vez que se inicie una sesión, se aplicarán los cambios.
 
  Aguardo que la presente entrada haya sido interesante al lector. De ser así, espero que el lector la comente y/o la comparta, por favor.

No hay comentarios:

Publicar un comentario

Deje aquí su comentario, si no puede comentar, pruebe a hacerlo desde otro navegador de red u otro equipo.