6

PowerShell ¿La evolución de Bash?

En el mundo de la Infraestructura Tecnológica, siempre hubo una gran rivalidad entre los Administradores de Sistemas *nix como GNU/Linux y los sistemas basados en Microsoft Windows.

Los Administradores GNU/Linux comentan que una de las grandes debilidades del sistema operativo Windows es no contar con una herramienta de administración remota por consola, sólida y robusta como lo es Bash sobre ssh.

Los Administradores de Windows comentan que si bien es muy poderoso la consola como sistema de administración, la mayoría de tareas del día a día se pueden realizar muy fácilmente con la interfaz gráfica, aumentando así la productividad, y con una herramienta como el Active Directory se pueden administrar cientos de servidores sin necesidad de escribir una línea en una terminal.

La respuesta de Microsoft a esto fue la contratación de Jeffrey Snover en el año 1999, un Arquitecto con amplia experiencia en automatización, en empresas como IBM, quien en el 2002 publica el Monad Manifesto (https://www.jsnover.com/Docs/MonadManifesto.pdf), un documento que considero debe ser leído por todo administrador de sistemas que quiera seguir siendo competitivo en la próxima década.

En este documento, Jeffrey Snover expone claramente que ciertamente hay una tecnología que falta en el stack de soluciones de Microsoft y propone una solución basada en los nuevos enfoques de la administración de sistemas: una plataforma de próxima generación para la automatización administrativa.

Del Monad Manifesto nace PowerShell, pero ¿cuál es la gran novedad dentro de esta tecnología?

La diferencia más notable es la siguiente: Bash y otros Shells anteriores aceptan y devuelven texto, mientras que PowerShell acepta y devuelve objetos.

Pongamos un ejemplo práctico para ilustrar este nuevo enfoque:

Para listar los archivos y carpetas del directorio donde estamos parados, en Bash ejecutamos:

[email protected]80:~/midirectorio$ ls -la
total 8
drwxr-xr-x2 gmaggiw gmaggiw 4096 nov 1119:06 .
drwxr-xr-x105 gmaggiw gmaggiw 4096 nov 1119:05 ..
-rw-r--r--   1 gmaggiw gmaggiw    0 nov 1119:05 arch1
-rw-r--r--   1 gmaggiw gmaggiw    0 nov 1119:06 arch2

En PowerShell podemos ejecutar:

PS/home/gmaggiw/midirectorio> Get-ChildItemDirectory:/home/gmaggiw/midirectorioModeLastWriteTimeLengthName---------------------------------11/11/187:05p.m.0arch1------11/11/187:06p.m.0arch2

Ambas salidas son muy parecidas, vemos que en el directorio existen dos archivos arch1 y arch2.

La diferencia es que en la salida de Bash, lo que vemos en un texto, y en caso de querer obtener sólo un dato de esa salida nos tocaría “parsear” la salida probablemente con una herramienta como awk, que básicamente sería crear un microprograma que pudiera producir la salida que nosotros necesitamos.

Con PowerShell, la salida que obtenemos es una representación en texto de los objetos que tenemos. Para ilustrar esto de una forma inequívoca observe la salida del siguiente comando:

PS /home/gmaggiw/midirectorio> Get-ChildItem | Get-Member                       


   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
LinkType                  CodeProperty   System.String LinkType{get=GetLinkT...
Mode                      CodeProperty   System.String Mode{get=Mode;}
Target                    CodeProperty   System.Collections.Generic.IEnumera...
AppendText                Method         System.IO.StreamWriter AppendText()
CopyTo                    Method         System.IO.FileInfo CopyTo(string de...
Create                    Method         System.IO.FileStream Create()
CreateText                Method         System.IO.StreamWriter CreateText()
Decrypt                   Method         void Decrypt()
DeleteMethod         void Delete()
Encrypt                   Method         void Encrypt()
Equals                    Method         bool Equals(System.Object obj)
GetHashCode               Method         int GetHashCode()
GetLifetimeService        Method         System.Object GetLifetimeService()
GetObjectData             Method         void GetObjectData(System.Runtime.S...
GetType                   Method         type GetType()
InitializeLifetimeService Method         System.Object InitializeLifetimeSer...
MoveTo                    Method         void MoveTo(string destFileName)
OpenMethod         System.IO.FileStream Open(System.IO...
OpenReadMethod         System.IO.FileStream OpenRead()
OpenText                  Method         System.IO.StreamReader OpenText()
OpenWriteMethod         System.IO.FileStream OpenWrite()
RefreshMethod         void Refresh()
ReplaceMethod         System.IO.FileInfo Replace(string d...
ToStringMethod         string ToString()
PSChildName               NoteProperty   string PSChildName=arch1
PSDrive                   NoteProperty   PSDriveInfo PSDrive=/
PSIsContainer             NoteProperty   bool PSIsContainer=False
PSParentPath              NoteProperty   string PSParentPath=Microsoft.Power...
PSPath                    NoteProperty   string PSPath=Microsoft.PowerShell....
PSProvider                NoteProperty   ProviderInfo PSProvider=Microsoft.P...
AttributesProperty       System.IO.FileAttributes Attributes...
CreationTime              Property       datetime CreationTime {get;set;}
CreationTimeUtc           Property       datetime CreationTimeUtc {get;set;}
DirectoryProperty       System.IO.DirectoryInfo Directory {...
DirectoryName             Property       string DirectoryName {get;}
ExistsProperty       bool Exists {get;}
ExtensionProperty       string Extension {get;}
FullName                  Property       string FullName {get;}
IsReadOnly                Property       bool IsReadOnly {get;set;}
LastAccessTime            Property       datetime LastAccessTime {get;set;}
LastAccessTimeUtc         Property       datetime LastAccessTimeUtc {get;set;}
LastWriteTime             Property       datetime LastWriteTime {get;set;}
LastWriteTimeUtc          Property       datetime LastWriteTimeUtc {get;set;}
LengthProperty       long Length {get;}
Name                      Property       string Name {get;}
BaseName                  ScriptProperty System.Object BaseName {get=if ($th...
VersionInfo               ScriptProperty System.Object VersionInfo {get=[Sys...

La salida que observamos es una tabla con los métodos y atributos o propiedades que tiene el set de objetos obtenidos por Get-ChildItem.
Esto me permite hacer los siguiente:

PS /home/gmaggiw/midirectorio> Get-ChildItem | Select-Object BaseName, CreationTime, IsReadOnly                                        

BaseName CreationTime IsReadOnly
-------- ------------           ----------
arch1    11/11/187:05:59 p. m.      False
arch2    11/11/187:06:01 p. m.      False

No sé si se llega a observar el poder increíble que esto nos da. Pude crear una salida totalmente personalizada de la misma información sin tener que usar nada más que los Cmdlets disponibles.

Podemos ir más allá aun, yo pudiera guardar esto en una variable:

PS /home/gmaggiw/midirectorio> $mis_archivos = Get-ChildItem | Select-Object BaseName, CreationTime, IsReadOnly

Y obtener sólo el nombre de los archivos:

PS /home/gmaggiw/midirectorio> $mis_archivos.BaseName                                                                                  
arch1
arch2

O pudiera formatear los objetos en formato lista:

PS /home/gmaggiw/midirectorio> $mis_archivos | Format-List                                                                             


BaseName     : arch1
CreationTime :11/11/187:05:59 p. m.
IsReadOnly   : False

BaseName     : arch2
CreationTime :11/11/187:06:01 p. m.
IsReadOnly   : False

Si se dan cuenta, el prompt y directorio que utilicé para los ejemplos, tanto en bash como en powershell son el mismo, es decir, lo hice en la misma máquina, que la tengo con la distribución Linux Mint.
En 2016 Microsoft anuncia que PowerShell pasa a ser un proyecto open source multiplataforma sobre .Net core. El repositorio de PoweShell se encontra en este link: https://github.com/PowerShell/PowerShell.

Si quieren saber más, o tienen algún comentario sobre el tutorial por favor no duden en dejarlo en los comentarios o escribirme por privado.

Espero les haya podido ilustrar lo que nos permite hacer PowerShell como Administradores de Sistemas, y sembrar la semilla para que sigan aprendiendo sobre esta Power Herramienta!

Escribe tu comentario
+ 2
3
5212Puntos

Saludos,

He probado lo que mencionas, ciertamente es interesante lo que ofrece powershell con el tema de objetos, pero en un entorno unix existen muchas opciones que reemplazan a bash, que soportan multiples paradigmas no solamente la programacion orientada a objectos. Un caso claro es utilizar python, nodejs o go para escribir tareas asincronas y concurrentes, los tres lenguajes proporcionan las librerias necesarias para hacer tareas rutinarias de un Sysadmin o incluso avanzadas como las de un DevOps.

Gracias por compartir, jugar un tiempo con powershell.

1
4 años

Hola Johan,

Muchas gracias por tomarte el tiempo de leer el post y comentar!

Estoy de acuerdo contigo. Python, NodeJS y Go deben estar en el set de herramientas por excelencia de todo SysAdmin, de hecho Python nació como un lenguaje de scripting.

Lo que me parece interesante de PowerShell es que tienes la posibilidad de utilizar el paradigma orientado a objetos sobre el prompt.

Por ejemplo, si yo quisiera hacer un reporte rápido de los procesos que se están ejecutando en la máquina, ordenados en forma descendente por CPU en formato CSV directamente en el prompt, sin necesidad de hacer un script para ello.

Con PowerShell sería simplemente ejecutar esto:

PS /home/gmaggiw> Get-Process | Sort-Object CPU -Descending | Export-Csv ./reporte.csv

Entonces en resumen, yo he visto en PowerShell una herramienta muy poderosa para obtener y manipular información de nuestro sistema al vuelo, sin necesidad de entrar al script.

Si tienes otra solución para generar este reporte compártenos cómo lo harías 😃

Saludos y gracias a ti por el feedback

2
5212Puntos
4 años

Saludos,

En python podría ser utilizanzo un interprete avanzado como ipython y un fragmento de codigo usando psutil :

process_names = [proc.name() forprocin psutil.process_iter()]
process_names.sort()

En nodejs podrias usar el repl utilizando las librerias estandar de nodejs, especificamente las mencionadas en [1], He leido el manifesto que mencionas, es muy interesante sobre todo esto:

When you step back and examine what is really going on when someone uses a pipelined command like“$ a | b | c”,you concludethat the first command “a” did notaccomplishwhat the admin wanted to do. Ifithad, theadminwouldhavejust type “a” and beendone with it.So then the question is why didn’t“a”do what the admin wanted?The answer is thatin this traditional model, thestand-alone executablestightly bindthreeoperationstogether: 1)getting objects; 2)processing objects; 3)outputtingresultsastext. One of thoseoperationsdoes not do what the admin needsso the rest of the pipeline isan attempttofix that.

Es claro de todo el manifiesto que el hecho de poder reusar las salidas de objetos, el acceso a los cmdlets. Solo por curiosidad leí sobre poo para bash y encontre que ya lo habia estado haciendo 😛 si saberlo, [2]

[1] https://nodejs.org/api/os.html
[2] http://hipersayanx.blogspot.com/2012/12/object-oriented-programming-in-bash.html