Octubre de 2016

Volumen 31, número 10

Essential .NET: PowerShell sigue mejorando

Por Mark Michaelis | Octubre de 2016

Mark MichaelisEn una desviación de mi reciente enfoque en .NET Core, en la columna de Essential .NET de este mes, me centraré en un conjunto de nuevas características que aumentan considerablemente la eficacia de Windows PowerShell. Para mí, las mejoras más importantes son las relacionadas con la compatibilidad multiplataforma. Sí, es cierto, PowerShell se ejecuta ahora en Linux. Además, cambió al código abierto en GitHub (github.com/PowerShell/PowerShell) para que toda la comunidad pueda empezar a reforzar sus características. ¡Genial!

No obstante, los anuncios más recientes no nos lo cuentan todo. En febrero, se lanzó PowerShell 5.0, que incluye compatibilidad nueva o mejorada para las declaraciones de clase y enumeración, la detección de módulos y scripts, la administración e instalación de paquetes, el acceso al punto de conexión de OData, la transcripción y el registro mejorados, etc. En este artículo, revisaré cada una de estas características e incluiré ejemplos.

PowerShell cambia a multiplataforma

Para empezar, echemos un vistazo al siguiente script de comandos, que instala PowerShell en Ubuntu 14.04 desde el host de Windows PowerShell, junto con una captura de pantalla de la sesión de ejecución desde el Bash de Windows en la Figura 1 (si no está familiarizado con Bash en Ubuntu en la Actualización de aniversario de Windows 10, consulte "Instalación de Bash en Windows 10"):

wget -O powershell.deb https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.9/powershell_6.0.0-alpha.9-1ubuntu1.14.04.1_amd64.deb
sudo apt-get install libunwind8 libicu52
sudo dpkg -i powershell.deb
powershell

Instalación y ejecución de Windows PowerShell en Ubuntu 14.04 desde Bash en Ubuntu en Windows
Figura 1 Instalación y ejecución de Windows PowerShell en Ubuntu 14.04 desde Bash en Ubuntu en Windows

Observe que el script de comandos es para Ubuntu 14.04 específicamente. Para otras plataformas, la URL del paquete de depuración y las versiones de requisitos previos variarán. Consulte bit.ly/2bjAJ3H para obtener instrucciones sobre su plataforma específica.

Hace muchos años, Jeffrey Snover tuiteó la probabilidad razonable de que PowerShell apareciera en Linux, pero ha tardado tanto y existen tan pocos informes del progreso que, aún hoy cuando lo uso, estoy alucinado. ¿Es cierto? Ejecuto Bash sobre Ubuntu en Windows (sin usar ninguna tecnología de virtualización) y, suponiendo que no quiera instalar PowerShell directamente en la misma instancia de Bash, con SSH para la conexión a una sesión de Bash remota donde pueda instalar PowerShell y objetos .NET de canalización entre los comandos en el shell de Bash.

Si hubiese sugerido esta posibilidad hace un par de años, dudo que mucha gente me hubiese creído.

Instalación de Bash en Windows 10

A partir de Windows 10 Anniversary Edition, puede instalar Bash de forma nativa en Windows con el siguiente comando de Windows PowerShell:

Get-WindowsOptionalFeature -Online -FeatureName *linux* | Enable-WindowsOptionalFeature -NoRestart -all –online

Sin embargo, tenga en cuenta que la versión aún es beta y que, por tanto, solo se habilita en modo de desarrollador (use "Get-Help-WindowsDeveloper" para ver cómo explorar el modo de desarrollador).

Lamentablemente, esta característica no requiere un reinicio, pero incluyo la opción -NoRestart para que al activar la característica no se desencadene directamente el reinicio.

Repositorios de PowerShell y Galería de PowerShell

Aunque es genial que pueda escribir sus propios scripts y bibliotecas, quizás otro miembro de la comunidad creó algo similar que puede aprovechar y mejorar. No obstante, hasta la llegada de la Galería de PowerShell (PowerShellGallery.com), era necesario examinar Internet para buscar scripts y módulos que pudieran servir, ya fuesen contribuciones de la comunidad o versiones de productos PowerShell oficiales, como PSCX o el módulo Posh-Git. Una de las mejoras más recientes de PowerShell (parte de PowerShell 5.0) que me resulta totalmente imprescindible es la compatibilidad con los nuevos repositorios, en especial la Galería de PowerShell. Imagine, por ejemplo, que hace tiempo que escribe PowerShell y que, al hacerlo, se da cuenta de que existen muchos obstáculos, si solo hubiese un solo modo de analizar el código y encontrarlos. Teniendo esto en cuenta, podría examinar la Galería de PowerShell y buscar y analizar el módulo que quiere instalar. O, aún mejor (dado que se supone que tiene una ventana de PowerShell abierta), puede usar el comando Find-Module del módulo PowerShellGet (incluido con PowerShell 5.0):

Find-Module *Analyze* | Select-Object Name,Description

La salida del comando se muestra en la Figura 2.

Salida del comando Find-Module
Figura 2 Salida del comando Find-Module

Tenga en cuenta que si no dispone de una versión suficientemente moderna de NuGet instalada, al usar el módulo PowerShellGet se desencadenará una actualización de paquetes de NuGet.

Suponiendo que encuentra el módulo deseado, puede ver su contenido a través del comando Save-Module. Para instalar el módulo, use el comando Install-Module (en este caso, Install-Module PSScriptAnalyzer). Este comando descargará el módulo y lo instalará automáticamente. Todas las funciones incluidas en el módulo estarán disponibles. Después de instalar el módulo PSScriptAnalyzer, puede invocar Invoke-ScriptAnalyzer $profile para examinar su perfil e identificar asuntos que el analizador no considere óptimos. (Tenga en cuenta que ya no es necesario importar un módulo para poder acceder a él. Las funciones del módulo se indexan automáticamente para que, al invocar una función de módulo, el módulo se importe automáticamente y sea accesible a petición).

Tenga en cuenta que la Galería de PowerShell está configurada como un repositorio de forma predeterminada:

>Get-PSRepository
Name         InstallationPolicy   SourceLocation
----         ------------------   --------------
PSGallery    Untrusted            https://www.powershellgallery.com/api/v2/

Como resultado, Find-Module funciona sin problemas. No obstante, Install-Module mostrará una advertencia que indica que el repositorio no es de confianza. Para evitarlo, suponiendo que confía en el repositorio, puede establecerlo como confiable con el comando:

Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

Apt-Get para Windows con administración de paquetes de PowerShell

Aquellos que hayáis trabajado como profesionales de TI en Linux habréis aprovechado sin duda apt-get, probablemente con scripts de instalación que arrancan el entorno nada más iniciar una nueva instancia de Linux. Para aquellos que no, apt-get es un método de línea de comandos para descargar e instalar programas o paquetes, así como sus dependencias, de manera rápida y sencilla a través de Internet directamente desde la línea de comandos. En la Figura 1 se muestra un ejemplo trivial de este tipo de instalación que usa apt-get para instalar libunwind8 libicu52, paquete del que depende PowerShell (en Ubuntu 14.04). Con PowerShell 5.0, la misma funcionalidad se incluye en Windows (no estoy seguro de si gritar "¡Viva!" o suspirar exasperadamente "¡Al fin!", quizás ambas cosas).

Del mismo modo que existen repositorios, como la Galería de PowerShell, para los módulos de PowerShell, PowerShell 5.0 también admite la administración de programas (denominados "paquetes") en Windows. Un administrador de paquetes de este tipo es Chocolatey (chocolatey.org), que se puede agregar como un repositorio de paquetes mediante el comando siguiente:

Get-PackageProvider -Name chocolatey

Esto permite usar PowerShell para encontrar paquetes implementados en Chocolatey. Por ejemplo, si quiere instalar Visual Studio Code, solo tiene que introducir los siguientes comandos:

Find-Package V*S*Code | Install-Package

Como se puede observar, se admiten caracteres comodín.

Otros comandos Package con los que debe familiarizarse están disponibles al usar el siguiente comando (los resultados se muestran en la Figura 3):

Get-Help "-package" | Select-Object Name,Synopsis

Comandos Package de Windows PowerShell disponibles
Figura 3 Comandos Package de Windows PowerShell disponibles

Como puede observar, un paquete se puede obtener y desinstalar. Get-Package muestra todos los programas (y más) disponibles a través de Programas y Características del Panel de control. De este modo, si quiere desinstalar Notepad2, por ejemplo, puede usar el comando:

Get-Package Notepad2* | Uninstall-Package

Este comando simplifica la automatización de la configuración del equipo Windows enormemente. Hace años que soy seguidor de Chocolatey y este comando integra compatibilidad con Chocolatey directamente en Windows. Por último, integra la administración de paquetes en Windows de manera muy parecida a Apt-Get en Linux.

Un aspecto a tener en cuenta es que no solo se puede acceder al repositorio de Chocolatey a través de los comandos *-package* de PowerShell, sino que Chocolatey también se puede instalar directamente. Aunque no es necesario, la instalación de Chocolatey directamente proporcionará, en ocasiones, un conjunto de funciones de administración de paquetes más sólido. Afortunadamente (y quizás irónicamente), la instalación de Chocolatey solo requiere invocar Install-Package Chocolatey, pero (y este es un ejemplo de las discrepancias entre Chocolatey y el comportamiento de *-Package) la ubicación de instalación predeterminada dependerá del motor de instalación que se use. Consulte chocolatey.org/install para obtener más información sobre el conjunto de herramientas de Chocolatey, incluidas las instrucciones de instalación para su entorno.

OData con Export-ODataEndpointProxy

Otra característica de PowerShell 5.0 que vale la pena mencionar es la capacidad de generar un conjunto de métodos para acceder a un origen de datos OData, como Visual Studio Team Services (VSTS). La Figura 4 demuestra la ejecución de Export-ODataEndpointProxy en un servicio de OData, en este caso un servicio Northwind OData público de muestra.

Generación e invocación de un proxy de OData
Figura 4 Generación e invocación de un proxy de OData

Si examina los comandos del módulo generados, observará que se han generado comandos aparte para cada entidad (Advertisement, Category, Person, etc.), junto con las acciones correspondientes de cada una (Get, New, Remove y Set).

Un hecho a tener en cuenta en la línea de comandos de la Figura 4 es el uso del parámetro -AllowUnsecureConnection. Es necesario porque el servicio de OData usado en el ejemplo no requiere autenticación ni cifrado.

Conversión de texto en objetos con ConvertFrom-String

Otro nuevo comando que aparece en PowerShell 5.0 es ConvertFrom-String. Está diseñado para tomar texto estructurado como entrada e interpolar la estructura para obtener un objeto basado en el texto analizado. Este se puede usar, por ejemplo, para analizar un archivo plano o (y aquí es donde me parece tremendamente útil) para convertir el texto extraído de un ejecutable en un objeto.

Considere, por ejemplo, el programa handle.exe de SysInternal (que se puede instalar con el comando Install-Package Handle y aprovechar la administración de paquetes como se explica en la sección anterior). Como cabe esperar de una utilidad de línea de comandos, escribe texto en stdout (en este caso, una lista de identificadores abiertos asociados a un nombre). En PowerShell, sin embargo, está acostumbrado a trabajar con objetos. Para convertir el texto extraído en un objeto, se usa la función ConvertFrom-String, como se muestra en la Figura 5.

Uso de ConvertFrom-String para analizar stdout en un objeto
Figura 5 Uso de ConvertFrom-String para analizar stdout en un objeto

La Figura 5 comienza mostrando la salida sin procesar de la utilidad handle.exe. Después, muestra ConvertFrom-String sin ningún parámetro. Como resultado, la utilidad ConvertFrom-String divide el texto de cada línea según el espacio en blanco.

En el tercer ejemplo, demuestro la opción de especificar un patrón de división de expresión regular para ajustar el análisis. No obstante, tenga en cuenta que no se requiere estar familiarizado con las expresiones regulares. En su lugar, puede especificar una plantilla (o una muestra, para más precisión) de un archivo o una cadena, donde analizar los primeros elementos manualmente. A continuación, ConvertFrom-String aprovechará el contenido analizado con la muestra e interpretará cómo analizar el resto de la entrada.

En el último ejemplo, he agregado el parámetro -PropertyNames para asignar nombres con sentido a la salida.

Al final, ConvertFrom-String conecta la discordancia de impedancia del mundo basado en texto del stdout del proceso tradicional con un mundo de Power­Shell basado en objetos. En este caso, puedo canalizar la salida en Stop-Process -Id y asignar el valor PID al valor del parámetro -Id.

Clases y enumeraciones

A continuación, se incluye un detalle de la compatibilidad de las nuevas clases y enumeraciones. En PowerShell 5.0, se incluyen dos nuevas palabras clave correspondientes a las dos estructuras, de modo que ahora se puede declarar una clase o una enumeración directamente en PowerShell (en lugar de usar Add-Type y pasar el código de C# o crear una instancia de PSCustom­Object). La sintaxis es la prevista (véase la Figura 6).

Figura 6 Declaración de clases y enumeraciones en Windows PowerShell

enum CustomProcessType {
  File
  Section
}
class CustomProcess {
  [string]$ProcessName;
  hidden [string]$PIDLabel;
  [int]$PID;
  hidden [string]$TypeLabel;
  [CustomProcessType]$Type;
  [int]$Handle;
  [string]$Path;
  CustomProcess(
    [string]$processName,[string]$pidLabel,[int]$pid,
    [string]$typeLabel,[string]$type,[int]$handle,[string]$path) {
    $this.ProcessName = $processName;
    $this.PIDLabel=$pidLabel;
    $this.PID=$pid;
    $this.TypeLabel=$typeLabel;
    $this.Type=$type;
    $this.Handle=$handle;
    $this.Path=$path;
  }
  CustomProcess() {}
  GetProcess() {
    Get-Process -Id $this.PID
  }
  static StopProcess([CustomProcess]$process) {
    Stop-Process -Id $process.PID
  }
}

Observe, en especial, que se admiten tanto las propiedades como los métodos. Además, existen modificadores de declaraciones, como static y hidden, que designan la construcción asociada en consecuencia. Además, se admite la herencia con una sintaxis muy similar a C#:

class Employee : Person {}

Por último, lo que también se demuestra en la Figura 6, los constructores se pueden declarar. En este ejemplo, declaro un constructor predeterminado (sin parámetros) y un segundo constructor que toma todos los parámetros. Los constructores se invocan a través del comando New-Object mediante la especificación del parámetro -ArgumentList (donde se enumera una matriz de argumentos de constructor) o, como alternativa, se pasa un argumento HashTable a través del parámetro -Property.

Resumen

De ninguna manera, constituye una lista completa de las nuevas características de PowerShell 5.0. Otros elementos destacados son:

  • Integración del archivo (compatibilidad con archivos .zip) a través de los comandos Compress-Archive y Expand-Archive.
  • Comandos Get-Clipboard y Set-Clipboard, que también funcionan con el operador de barra vertical.
  • Los comandos Out-File, Add-Content y Set-Content incluyen un parámetro –NoNewline, que permite contenido de archivo que omita el carácter de nueva línea.
  • El comando New-TemporaryFile funciona de manera similar a [System.IO.Path]::GetTempFileName (aunque no idéntica). Igual que es equivalente de .NET, New-TemporaryFile no elimina el archivo temporal, por lo que debe asegurarse de guardar la salida para poder quitar el archivo cuando termine de usarlo.
  • Los vínculos simbólicos se pueden administrar ahora directamente desde los cmdlets New-Item y Remove-Item de PowerShell.
  • PowerShell Integrated Scripting Environment (ISE) admite ahora el registro a través de las funciones Start/Stop/Search-Transcript, que generaban errores anteriormente cuando se llamaban desde PowerShell ISE.

Además, aunque no se admite inmediatamente en la versión de código abierto de PowerShell, Microsoft pretende ofrecer total compatibilidad con Open SSH, de modo que sea una opción de transporte remoto en PowerShell y en Administración remota de Windows poco después de la publicación de este artículo.

Con todo esto, solo quiero decir que PowerShell mejora constantemente. Si todavía lo desconoce, continúe.


Mark Michaelis es el fundador de IntelliTect y trabaja de arquitecto técnico como jefe y formador. Durante casi dos décadas, ha sido MVP de Microsoft y director regional de Microsoft desde 2007. Michaelis trabaja con varios equipos de revisión de diseño de software de Microsoft, como C#, Microsoft Azure, SharePoint y Visual Studio ALM. Realiza ponencias en conferencias para desarrolladores y ha escrito varios libros, como "Essential C# 6.0 (5th Edition)", que es su publicación más reciente.  Póngase en contacto con él en Twitter: @markmichaelis o por correo electrónico a la dirección mark@IntelliTect.com.

Gracias a los siguientes expertos técnicos de IntelliTect por revisar este artículo: Kevin Bost, Phil Spokas y Michael Stokesbary