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:
gmaggiw@gmaggiw-Lenovo-G40-80:~/midirectorio$ ls -la
total 8
drwxr-xr-x 2 gmaggiw gmaggiw 4096 nov 11 19:06 .
drwxr-xr-x 105 gmaggiw gmaggiw 4096 nov 11 19:05 ..
-rw-r--r-- 1 gmaggiw gmaggiw 0 nov 11 19:05 arch1
-rw-r--r-- 1 gmaggiw gmaggiw 0 nov 11 19:06 arch2
En PowerShell podemos ejecutar:
PS /home/gmaggiw/midirectorio> Get-ChildItem
Directory: /home/gmaggiw/midirectorio
Mode LastWriteTime Length Name
---- ------------- ------ ----
------ 11/11/18 7:05 p. m. 0 arch1
------ 11/11/18 7:06 p. m. 0 arch2
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()
Delete Method 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)
Open Method System.IO.FileStream Open(System.IO...
OpenRead Method System.IO.FileStream OpenRead()
OpenText Method System.IO.StreamReader OpenText()
OpenWrite Method System.IO.FileStream OpenWrite()
Refresh Method void Refresh()
Replace Method System.IO.FileInfo Replace(string d...
ToString Method 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...
Attributes Property System.IO.FileAttributes Attributes...
CreationTime Property datetime CreationTime {get;set;}
CreationTimeUtc Property datetime CreationTimeUtc {get;set;}
Directory Property System.IO.DirectoryInfo Directory {...
DirectoryName Property string DirectoryName {get;}
Exists Property bool Exists {get;}
Extension Property 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;}
Length Property 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/18 7:05:59 p. m. False
arch2 11/11/18 7: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/18 7:05:59 p. m.
IsReadOnly : False
BaseName : arch2
CreationTime : 11/11/18 7: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!
Curso de Administración de Servidores Linux 2017