2008R2: Automatizando tareas administrativas: powershell(4)

Variables, Alias, Ámbitos, perfiles y seguridad.

Variables en powershell

Una variable en un lugar de almacenamiento de datos. En muchos shells los únicos datos que pueden almacenarse en una variable son de tipo texto. En shells avanzados y lenguajes de programación, estos datos pueden ser de cualquier tipo, desde cadenas de texto a secuencias de objetos. Powershell es de los segundos, puede almacenar cualquier tipo.

Para definir una variable en powershell debemos nombrarla con el signo dolar $ como prefijo que nos ayuda a definir variables de álias, cmdlets, archivos y otros elementos que el usuario del shell quiera utilizar. El nombre de una variable puede contener cualquier combinación de carácteres alfanuméricos (a-z, 0-9) y el subrayado (_). Aunque no hay establecida una nomenclatura en los nombres de variables en powershell, no deja de ser interesante utilizar un nombre que refleje el tipo de datos que contiene la variable.

powershellVariable

En el ejemplo he usado el ISE, he definido una variable $Detenido cuyo contenido es una colección de servicios donde su estado es Detenido.

Alias

En Powershell, como en la mayoría de shells de línea de comandos, se pueden definir alias de comandos. Es un método de ejecución de comandos del shell (cmdlets) usando un nombre diferente. En todo caso la razón del uso de alias es por la reducción de carácteres en el nombre a usar y reducir lo que se escribe.

Por ejemplo: en lugar de usar get-process usar sólo gps. Este es un alias predefinido, hay otros: con el cmdlet get-alias obtenemos la lista de los predefinidos.

Pero en Powershell disponemos de varios cmdlets que nos permiten definir nuevos alias, exportarlos, importarlos y como el dicho anteriormente, mostrarnos una lista de los existentes. La lista de estos cmdlets también la podemos obtener con otro cmdlet:

powershellalias

Con get-alias obtenemos una lista de alias disponibles en la sesión actual, todos los predefinidos y los que hayamos creado nosotros, export-alias e import-alias nos servirán tanto para exportar como para importar la lista entre sesiones, mientras new-alias y set-alias nos permiten definir nuevos alias en la sesión actual.

Los alias creados mediante los dos últimos cmdlets son válidos únicamente en la sesión actual. Para disponer de alias persistentes entre sesiones de powershell se han de definir en un archivo de perfil, en cada línea un alias:

set-alias nuevo new-object

set-alias hora get-date

Y aunque el uso de comandos cortos no deja de tener su encanto, un uso indiscriminado no es muy recomendable. Primero porque los alias no son tan portables como los scripts, imaginad: un script lleno de alias, cada uno de ellos debe incluirse mediante set-alias al principio del script para asegurarse que todos los necesarios están presentes, independientemente del equipo o del perfil de la sesión, cuando se ejecute el script. Hay que reconocer que una concentración grande de alias pueden causar confusión en comandos y scripts. Los alias definidos podrían tener sentido para un programador, pero no todos comparten esa lógica en la definición de alias. Así qué, si uno quiere que otros entiendan sus scripts, cuantos menos alias mejor, o en todo caso alias entendibles y claros.

Ámbitos

Un ámbito o alcance es un límite lógico donde Powershell aisla el uso de funciones y variables. Los ámbitos se pueden definir como: global, local, script y private. Funcionan en una jerarquía en que la información del ámbito se hereda descendentemente, es decir, el ámbito local puede leer del ámbito global, pero no al revés.

global

Como su nombre indica, el ámbito global se aplica a toda la instancia de powershell. Los datos se heredan por todos los ámbitos hijo, comandos, funciones o scripts que se ejecutan usando variables definidas en global. Sin embargo, tened en cuenta que no se comparten ámbitos globales entre instancias de powershell.

powershellscopesglobal

local

Un ámbito local se crea dinámicamente cada vez que se ejecuta una función, filtro o script. Después de la ejecución, la información se descarta. Puede leer información del ámbito global, pero no realizar cambios. Veamos el mismo ejemplo anterior pero en forma local.

powershellscopeslocal

script

El ámbito de script se circunscribe a la ejecución del script y acaba cuando éste finaliza. Veamos un ejemplo:

powershellscopescript

Cuando ListaServicio.ps1 se ejecuta, la información guardada en la variable $Servicios (el primer servicio) se muestra en el panel de salida. Pero al intentar acceder a la información de la variable desde la consola con $Servicios[0] se devuelve un error, ya que la variable sólo es válida en el ámbito del script. Cuando finaliza el script, el ámbito y todo su contenido es descartado.

¿Qué pasa si un administrador quiere usar un script en un Pipeline o acceder como a un archivo de biblioteca en busca de funciones comunes? Normalmente esto no es posible ya que powershell descarta el ámbito de script en cuanto éste script finaliza. Por suerte, Powershell admite la técnica del punto-origen (dot-sourcing), un término original de UNIX. Aplicarla a un script hace que Powershell cargue el ámbito de script dentro del ámbito padre de la llamada. Para usarla, simplemente hay que añadir el prefijo (.) punto al nombre del script cuando se ejecute, algo como: PS C:\> ..\script.ps1

private

Parecido al ámbito local pero con una diferencia clave: Las definiciones en el ámbito privado no son heredadas por ningún ámbito hijo. Qué mejor que verlo en un ejemplo, siguiendo el hilo de los anteriores.

powershellscopeprivate

El ejemplo se ejecuta porque usa el operador de llamada &. Con este operador, podemos ejecutar fragmentos de código script en un ámbito local aislado. Esta técnica es útil para aislar un bloque del script y sus variables de un ámbito padre o, como vemos aquí, separar una variable de ámbito privado de un bloque del script.

Perfiles

Un perfil de powershell no es más que una colección de valores guardados para personalizar el entorno de powershell. Hay varios tipos de perfiles, cargados en un orden específico cada vez que powershell se inicia.

todos los usuarios todos los hosts

Debe ubicarse en %windir%\system32\windowspowershell\v1.0\profile.ps1 (1). Los valores de este perfil se aplicarán a todos los usuarios de powershell en el quipo actual.

todos los usuarios host actual

Debe ubicarse en %windir%\system32\windowspowershell\v1.0\ShellID_profile.ps1 (2). Se aplican a todos los usuarios del shell actual (de forma predeterminada la consola).

usuario actual todos los hosts

Debe ubicarse en %userprofile%\My Documents\windowspowershell\profile.ps1 (3). Aquéllos usuarios que desean controlar su propio perfil pueden utilizar este tipo. Se aplica sólo al usuario actual de la sesión de powershell y no afecta al resto.

usuario actual host actual

 Debe ubicarse en %userprofile%\My Documents\windowspowershell\ShellID_profile.ps1 (4). Como el perfil todos de host específico, este tipo carga valores para el shell actual, aunque los valores son de usuario específico.

Hay otros perfiles, por ejemplo para el ISE, usuario actual ISE(5) o todos los usuarios ISE(6).

Antes de crear un perfil: get-help about profiles

(1) if (!(test-path $profile.AllUsersAllHosts)) {new-item -type file -path $profile.AllUsersAllHosts-force}

(2) if (!(test-path $profile )) {new-item -type file -path $profile -force} Desde la consola de Powershell.

(3) if (!(test-path $profile.CurrentUserAllHosts)) {new-item -type file -path $profile.CurrentUserAllHosts -force}

(4) if (!(test-path $profile.AllUsersAllHosts)) {new-item -type file -path $profile.AllUsersAllHosts-force} Desde la consola de Powershell.

(5) if (!(test-path $profile )) {new-item -type file -path $profile -force} Desde el ISE.

(6) if (!(test-path $profile.AllUsersAllHosts)) {new-item -type file -path $profile.AllUsersAllHosts-force} Desde el ISE.

Si deseamos editar el perfil desxe el ISE: psEdit $profile

powershellprofile

Aunque en este caso no me lo edita porque no existe.

SEGURIDAD

Cuando se liberó WSH con Windows 98 (ufffff), fue un regalo para los administradores que buscaban capacidades de automatización como sus hermanos UNIX. Pero al mismo tiempo, los viruseros descubrieron rápidamente que abría un gran frente de ataque contra los Windows.

Casi cualquier cosa de un sistema Windows puede automatizarse o controlarse con WSH, lo cual es una ventaja para administradores. Pero WSH no aporta ningún tipo de seguridad en la ejecución de scripts. Le das un script y lo ejecuta. De donde proviene o cual es su propósito no importa. Con este comportamiento WSH es más conocido como una vulnerabilidad que como una herramienta.

Con todas las críticas contra la seguridad de WSH, el equipo de diseño de powershell decidió incluir una directiva de ejecución para mitigar las amenazas de seguridad que plantea el código malicioso. Una directiva de ejecución define restricciones en cuanto a Cómo permite ejecutar los scripts o que archivos de configuración se cargan. Powershell tenía cuatro directivas de ejecución principales: Restricted, AllSigned, RemoteSigned y Unrestricted. Algo como: Restringida, Todos firmados, Remotos firmados y Sin restricción.

De forma predeterminada Powershell está configurado para ejecutarse bajo la Restringida. La más segura y qué sólo le permite ejecutarse en modo interactivo. Nada de scripts, y archivos de configuración firmados digitalmente por un emisor de confianza.

Todos firmados es la inmediatamente inferior a Restringida. Significa que los scripts y archivos de configuración deben ir firmados digitalmente por un emisor de confianza para ser cargados o ejecutados.

La directiva de Remotos firmados está pensada para evitar la ejecución de scripts y archivos de configuración remotos que no estén firmados digitalmente, pero que no será necesario si los mismos son locales.

Y la última y como su propio nombre sugiere: Sin restricción, permite la ejecución y/o carga de scripts y archivos de configuración. Locales y firmados, aunque a los remotos les antecede una opción para elegir si se ejecuta o no.

Con la liberación de powershell 2.0, se añadieron las directivas Bypass y Undefined.

Con la primera, Bypass, no se bloquea nada y además no hay avisos ni preguntas para elegir.

Undefined que no existe ninguna directiva definida en el ámbito actual, y si esta es la que hay para todos los ámbitos entonces la directiva es la Restringida.

Configurar la directiva de ejecución

De forma predeterminada la directiva es la Restringida, si queremos cambiarla usaremos el cmdlet Set-executionPolicy. (También podemos usar la Directiva de Grupo para establecer la directiva de ejecución en varios equipos).

Vamos a cambiar la directiva mediante el ISE, primero vemos la que hay get-executionpolicy, y el resultado es Unrestricted. Vamos a establecerla en Set-executionpolicy AllSigned… Por seguridad nos envía una ventana de confirmación, le damos al Sí y …¿qué pasa?

cambiarexecutionpolicy

cambiarexecutionpolicyNODEJA

No la cambia y nos lanza una serie de mensajes y advertencias. El acceso es denegado. Bien, lo que sucede es que hemos de iniciar el ISE con el comando Ejecutar como Administrador, veamos ahora:

cambiarexecutionpolicy02

Sin ningún problema, está cambiada sin errores.