viernes, 5 de noviembre de 2010

PowerShell y el Framework .NET

PowerShell se apoya en Framework.NET. ¿Qué significa esto? Sencillamente que PowerShell se convierte en un lenguaje más de programación como C# o Visual Basic. Aunque PowerShell está pensado como lenguaje de scripting, podemos hacer lo mismo que con cualquier otro lenguaje de programación .NET.

Ejemplo. PowerShell no incluye cmdlets para realizar cálculos matemáticos complejos, pero Framework.NET sí. En un programa hecho en C# podemos acceder a las funciones matemáticas incluyendo el espacio de nombres System.Math ubicado en la DLL mscorlib.dll.

En PowerShell esto lo hacemos con el objeto [System.Math]

Necesito información de métodos y propiedades de [System.Math] para saber qué puedo usar: [System.Math] | gm

Vemos que hay un método llamado GetMembers(). Con esto ya podemos consultar a la clase:

[System.Math].GetMembers()

Y hacer uso de todos los métodos y propiedades estáticas(no hace falta instanciar un objeto):

[System.Math]::PI
[System.Math]::sqrt(25)


Y lo mismo con cualquier otra clase de FrameWork.NET. ¿Os suena esto?:

[System.Console]::WriteLine("Hola Mundo")

¿Y si quiero hacer uso de métodos o propiedades no estáticos? Pues a crear un objeto.

$Ping = New-Object System.Net.NetworkInformation.Ping
$Ping.Send("10.10.10.10")


¿Y si la DLL con las clases que quiero usar no está cargada?

Para ver ensamblados cargados: [System.AppDomain]::CurrentDomain.GetAssemblies()
o mejor

[System.AppDomain]::CurrentDomain.GetAssemblies() | foreach-object { split-path $_.Location -leaf } | sort

Para cargar un ensamblado:

Add-Type -AssemblyName Nombre_del_ensamblado (si está en la GAC)
Add-Type -Path "ruta_completa_al_ensamblado"

Funciones

En PowerShell podemos hacer uso de funciones para evitar la repetición de un conjunto de instrucciones continuamente. Un ejemplo de función es:

Function salida
{
Write-Host "Mensaje"
}


A una función le podemos pasar valores y hay tres maneras de hacerlo.

Primera manera: Podemos pasar a una función todos los parámetros que queramos y hacemos referencia a ellos mediante $args[n]

Function suma
{
[int]$args[0] + [int]$args[1]
}


A esta función la podemos llamar así:

suma 5 10

Segunda manera: Podemos pasar a una función una serie de parámetros especificados

Function suma ([int]$x, [int]$y)
{
$x+$y
}


A esta función le llamamos de una de las siguientes maneras:

suma 5 10

suma -x 5 -y 10


Tercera manera:

Function suma
{
Param ([int]$x, [int]$y)
$x+$y
}


A esta función le llamamos de una de las siguientes maneras:

suma 5 10

suma -x 5 -y 10


Las funciones en PowerShell devuelven cualquier valor que se envíe al stream de salida. En los ejemplos anteriores solo se devuelve un valor, pero no tenemos límite en el número de valores devueltos, todos se van agregando a un array.

Nota. Podemos usar la palabra clave Return para salir inmediatamente de una función devolviendo un único valor.

Versión del sistema operativo

Si en un script de PowerShell necesitamos conocer la versión del sistema operativo para realizar tareas diferentes dependiendo de dicha versión, lo podemos hacer de la siguiente manera:

$maquina = $env:computername
$filtro = "(&(objectCategory=Computer)(Name=$maquina))"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.Filter = $filtro
$objPath = $objSearcher.FindOne()
$objEquipo = $objPath.GetDirectoryEntry()
$objEquipo.operatingSystem

Mapeo de impresoras

El siguiente ejemplo, muestra como mapear impresoras de red con un script de PowerShell basándose en el departamento al que pertenecen los usuarios.

Condiciones:

1) Los usuarios del Directorio Activo tienen que tener el atributo department rellenado con el departamento al que pertenecen.
2) Las impresoras tienen que estar publicadas en el Directorio Activo y el atributo location tiene que contener un nombre de departamento.

El script recorre todas las impresoras y mapea al usuario las impresoras cuyo atributo location coincide con el atributo department del usuario.

###Función que mapea la impresora

function mapear_impresora([string]$ruta)
{

$net = New-Object -com WScript.Network;
$impresoras=$net.EnumPrinterConnections()
if ($impresoras -like $ruta) {$net.RemovePrinterConnection($ruta,$true)}
$net.AddWindowsPrinterConnection($ruta)
}


#Obtenemos el usuario que inicia la sesión.

$usuario = $env:username
$filtro = "(&(objectCategory=User)(samAccountName=$usuario))"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.Filter = $filtro
$objPath = $objSearcher.FindOne()
$objUser = $objPath.GetDirectoryEntry()

###Obtenemos las impresoras del Directorio Activo

$filtroimpresora = "(&(objectCategory=PrintQueue))"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.Filter = $filtroimpresora
$objPath2=$objSearcher.FindAll()


###Mapeos por usuario

for($n=0;$n -lt $objPath2.Count;$n++) { if ( $objPath2[$n].Properties.location -eq $objUser.Properties.department ) { mapear_impresora -ruta $objPath2[$n].Properties.uncname } }

Este script se puede asociar a una directiva de grupo como script de inicio de los usuarios.

Mapeos unidades de red

PowerShell incluye varios cmdlet para la gestión de unidades ya sean locales o de red. son los cmdlets con nombre PSDrive y verbos Get, New y Remove. El problema de estos cmdlets es que solo actúan en las sesiones de PowerShell, es decir, si creamos un mapeo de red desde PowerShell con el cmdlet New-Psdrive, la unidad mapeada solo es visible en la consola de PowerShell, y no en el explorador de Windows, por ejemplo. Por lo que tenemos que hacer uso de objetos COM para el mapeo correcto de las unidades de red.

El siguiente ejemplo mapea unidades de red a un usuario basándose en la pertenencia a determinados grupos:

#Función que mapea la unidad de red.

function mapear_unidad([string]$unidad, [string]$ruta)
{
$net = New-Object -com WScript.Network;
$unidades=$net.EnumNetworkDrives();
if ($unidades -like $unidad) { $net.removenetworkdrive($unidad,$true)}
$net.mapnetworkdrive($unidad,$ruta)
}


#Obtenemos el usuario que inicia la sesión.

$usuario = $env:username
$filtro = "(&(objectCategory=User)(samAccountName=$usuario))"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.Filter = $filtro
$objPath = $objSearcher.FindOne()
$objUser = $objPath.GetDirectoryEntry()

#Obtenemos los grupos a los que pertenece.
$groups=$objUser.memberOf

#Los grupos están en formato LDAP, vamos a quedarnos con el nombre CN

function new-array {,$args}
$groupCN= new-array
foreach($i in $groups)
{ $groupCN+=($i.split(",")[0]).split("=")[1] }

#Mapeo de unidad personal
$carpetausuario=$objUser.sAMAccountName
mapear_unidad -unidad "K:" -ruta "\\Servidor\Personales\$carpetausuario"


#Mapeo de unidades de grupo

foreach ($group in $groupCN)
{

switch ($group)
{

Grupo1 { mapear_unidad -unidad "T:" -ruta "\\Servidor\CarpetaGrupo1" }
Grupo2 { mapear_unidad -unidad "M:" -ruta "\\Servidor\CarpetaGrupo2" }
default {"No hay mapeos para el grupo $group"}
}
}

jueves, 4 de noviembre de 2010

Logon Scripts con PowerShell

Es habitual tener scripts de inicio de sesión programados en Batch o en Visual Basic Script. Ahora es posible hacerlo también con PowerShell.

Cosas a tener en cuenta:

1) Los scripts de inicio van a estar en una carpeta compartida de un controlador de dominio y las máquinas del dominio acceden al script a través de la red. Es muy importante que las máquinas cliente reconozcan el acceso al DC como si fuera un acceso de Intranet, no un acceso de Internet, ya que entonces saltará el famoso aviso de "Advertencia de seguridad de Abrir archivo" y el script no llegaría a ejecutarse. (Ajustar los sitios de intranet en las propiedades de Internet Explorer, agregando rutas como file://Nombre_DC)

2) Los scripts de PowerShell son archivos con extensión ps1. EStos archivos tienen como acción predeterminada "Abrir" en lugar de "Ejecutar", por lo que el usuario, al iniciar la sesión, se encontrará con el notepad abierto con el código del script en lugar de ejecutarse. La solución es acceder al registro en todas las máquinas cliente:

HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell el valor predeterminado es Open, debemos cambiarlo a 0, que es la acción asociada a ejecutar el script usando el intérprete PowerShell.

3) Lógicamente, PowerShell tiene que estar instalado. (En Windows XP se puede instalar a través de las actualizaciones automáticas o mediante una directiva de grupo en la que asociamos como Script de inicio de máquina el ejecutable: WindowsXP-KB968930-x86-ESN.exe con parámetros /quiet /passive )

Una vez establecidas estas 3 condiciones, podemos crear directivas de grupo que tengan asociados scripts de inicio de sesión realizados con PowerShell.

Propiedad useraccountcontrol

Esta propiedad de los usuario del Directorio Activo contiene información a nivel de bit. A continuación muestro algunos bits de los más útiles (de bit menos significativo a más significativo):


ACCOUNTDISABLE Segundo bit puesto a 1 indica cuenta deshabilitada.
LOCKOUT Cuarto bit puesto a 1 indica cuenta bloqueada.
PASSWD_CANT_CHANGE Sexto bit puesto a 1 indica que no puede cambiar la contraseña.
NORMAL_ACCOUNT Décimo bit puesto a 1 indica cuenta normal.
DONT_EXPIRE_PASSWORD Décimoseptimo bit puesto a 1 indica que la contraseña no caduca.
PASSWORD_EXPIRED Vigésimo tercero bit puesto a uno indica que la contraseña caduca.


Para saber si un determinado bit está puesto a uno o a cero, por ejemplo para el bit número 17:

$numero -band 0x10000

Si el resultado es distinto de cero, el bit número 17 está puesto a 1. Si el resultado es cero, entonces el bit está puesto a cero.


Para el ejemplo de hace dos posts, podemos hacer:


$resultado=$($informacion.Properties.useraccountcontrol) -band 0x10000
if ($resultado -ne 0) { Write-Host " La contraseña no tiene fecha de caducidad"}

Propiedades especiales de fechas

En el Directorio Activo hay una serie de propiedades(atributos) que contienen una fecha en formato de número entero muy grande. Es el caso de:


pwdlastset (Fecha del último cambio de contraseña)
accountexpires (fecha de caducidad de la cuenta)
lastlogon (Fecha del último inicio de sesión)

Estos números están indicando fechas. Concretamente indican (ojo al dato) el número de intervalos de 100 nanosegundos transcurridos desde el 1 de Enero de 1601 (coincidiendo con el comienzo del calendario gregoriano).

Vamos a pasar uno de esos números a una fecha usando la siguiente función:


Function epoch2date($segundos) { [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1601').AddSeconds($segundos)) }

Y la usamos de la siguiente manera:

epoch2date(valor_en_segundos)

Para el ejemplo que veíamos en el post anterior, podemos hacer:

epoch2date($($informacion.Properties.lastlogon)/1E+7)

Y el resultado será algo como:

miércoles, 03 de noviembre de 2010 10:09:51

miércoles, 3 de noviembre de 2010

Información del usuario

Muchas veces necesitamos hacer un script que obtenga información del usuario que ha iniciado la sesión. En PowerShell, lo podemos hacer de varias maneras y quizás una de las más fáciles es la siguiente:

$usuario = $env:username
$consulta = "(&(objectCategory=User)(samAccountName=$usuario))"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.Filter = $consulta
$informacion = $objSearcher.FindOne()


El nombre del usuario que ha iniciado la sesión se almacena en la variable de entorno username. La leemos de la unidad de las variables de entorno (env:) y buscamos el objeto correspondiente en el Directorio Activo. Una vez realizada la consulta, tenemos toda la información en el objeto $informacion. Podemos hacer cosas como:

Ver todas las propiedades:

$informacion.Properties

Acceder a una de ellas (por ejemplo, el nombre completo):

$informacion.Properties.distinguishedname

Suele ser habitual, consultar los grupos a los que pertenece el usuario:

$informacion.Properties.memberof

martes, 21 de septiembre de 2010

Modulos vs. Snapins vs. Providers

Windows Powershell introduce muchos conceptos nuevos. Voy a describir tres conceptos que pueden causar confusión.

Módulo

Es un paquete de cmdlets, providers, funciones, alias o otro tipo de elementos que se pueden usar en PowerShell. Una vez qué el módulo está en el disco, podemos importarlo para usarlo en PowerShell.

Normalmente los módulos los instalan los programas que instalamos en el servidor, y podemos ver los existentes con el cmdlet get-module -listAvailable.

Pero para poder usarlos hay que importarlos. Los módulos por defecto, hay que instalarlos en c:\Windows\System32\WindowsPowerShell\v1.0\Modules\ActiveDirectory y consisten en una dll ( o un archivo psm1) y una serie de archivos de configuración.

Snap-ins (Complementos)

Un complemento de Windows PowerShell es un ensamblado de Microsoft .NET Framework que contiene proveedores y/o cmdlets de PowerShell.

Para ver la lista de Snap-ins: get-pssnapin


Según vemos en las definiciones de módulo y complemento, parece que son muy similares. Realmente es lo mismo, lo que pasa es que en PowerShell v1 se definieron los Complementos y en PoweShell v2 se definen los módulos que facilitan la ampliación de PowerShell. En PowerShell v2 se siguen soportando los complementos por compatibilidad hacia atrás, pero se recomienda hacer uso de los módulos.

Provider

Los proveedores de Windows PowerShell son programas basados en Microsoft .NET Framework que permiten que los datos de un almacén de datos especializado estén disponibles en Windows PowerShell para poder verlos y administrarlos fácilmente. Los datos que un proveedor expone aparecen en una unidad y se obtiene acceso a los datos a través de una ruta de acceso, al igual que en una unidad del disco duro.

Es decir, un provider permite el acceso a la configuración de determinados elementos (registro, almacén de certificados, Servicios de escritorio remoto, alias, funciones, etc) de la misma manera que usamos para acceder a las carpetas y archivos de un disco.

Se pueden ver los proveedores con el cmdlet get-psprovider

miércoles, 15 de septiembre de 2010

Desinstalación Masiva

¿Tenéis un equipo de pruebas con mucho software instalado, y queréis desinstalar todo?

Con PowerShell muy fácil:


$programas=Get-Wmiobject -class win32_product
foreach($prog in $programas){
$cadena="Name='" + $prog.name + "'"
$prog1=Get-Wmiobject -class win32_product -filter "$cadena"
$prog1.uninstall()
}

miércoles, 1 de septiembre de 2010

Bucle WHILE

La sintaxis de este tipo de bucle es:

while (condicion)
{
instrucciones
}


Este bucle funciona de la siguiente manera:

1) Se evalúa la condición.
2) Si la condición es True, se ejecuta el bloque de instrucciones y se vuelve a 1). Si la condición es False se sale del bucle.

Nota. Este bucle puede que no se ejecute ninguna vez. Si la primera evaluación de la condición es False, se sale del bucle sin haber ejecutado ninguna iteración.

Ejemplo

$i=11
while ($i -lt 20 -and $i -gt 10)
{
Write-Host "Iteración: $i"
$i++
}

lunes, 30 de agosto de 2010

Bucle FOR

El bucle for se usa cuando sabemos el número de iteraciones a realizar. La sintaxis es la siguiente:

for (inicializar;condicion;repeticion)
{
instrucciones
}


Inicializar: Se usa para inicializar variables. Esta parte se ejecuta una sola vez antes de la primera iteración.
Condición: Se evalúa a True o False, si es True se ejecuta una iteración del bucle. Si es False se sale del bucle.
Repetición: Se ejecuta después de cada iteración del bucle y se usa para actualizar el valor de las variables de control del bucle.

El funcionamiento de este bucle es el siguiente:

1) Se ejecuta la parte de inicialización.
2) Se evalúa la condición.
3) Si la condición es cierta, se ejecuta el bloque de instrucciones, se ejecuta la parte de repetición y se vuelve a 2).
4) Si la condición es falsa se sale del bucle.


Ejemplo:

for ($i=0;$i -lt 10;$i++)
{
Write-Host "iteración número: $i"
}



Bucle infinito

Podemos realizar un bucle infinito, estableciendo una condición que sea siempre cierta, por ejemplo:

for (;;)
{
Write-Host "Bucle infinito"
}

Lo podemos cortar con Control + C.

Sentencia break

En cualquier momento podemos salir de un bucle haciendo uso de la sentencia break. Por ejemplo:

for ($i=0;;$i++)
{
Write-Host "iteración número: $i"
if ($i -eq 10) {break}
}

Sentencia Continue

Se usa para forzar una nueva iteración sin haber llegado al final del bloque de instrucciones.

for ($i=0;$i -lt 30;$i++)
{
if ($i%2) {continue}
Write-Host "iteración número: $i"
}

miércoles, 11 de agosto de 2010

Cómo quitar comentarios de los archivos

Si queremos eliminar de un archivo todas las líneas que sean comentarios (es decir, que empiecen por el caracter #), con PowerShell se haría de la siguiente manera:

get-content archivo_entrada | foreach { if ($_ -notmatch "^#") {$_}} |out-File archivo_salida

P.D.: También vale esto:

get-content archivo_entrada | select-string -pattern "^#" -notmatch |out-File archivo_salida
Aunque aparecen saltos de línea donde no deben.

Análisis de archivos de logs

PowerShell facilita el trabajo con archivos de registros. Por ejemplo, imaginemos que necesitamos saber qué direcciones IP han accedido a nuestro servidor IIS.
Con PowerShell lo podemos hacer fácilmente, pero previamente debemos realizar unos cambios sobre el archivo de registro de IIS.

1) Hacemos una copia del archivo que queremos analizar.

2) Borramos todas las líneas de comentarios, salvo la que establece los nombres de los campos.

Las dos siguientes imágenes, muestran parte del archivo original de IIS y del que vamos a analizar nosotros:









3) Importamos los datos a PowerShell.

$a=import-csv -Delimiter " " archivo.log

Podemos ver el número de líneas importado: $a.count
Para acceder a una línea, por ejemplo a la 0: $a[0]
Para ver las propiedades de cada línea: $a[0]| Get-Member. Se crea una propiedad por cada columna existente en el archivo.
Para ver el archivo importado: $a[0]| Format-Table

4) Almacenamos todas las IPs en un array:

$col=@()
foreach ($i in $a) {$col+=$i."s-ip"}


5) Ordenamos el array y quitamos los duplicados:

$col | sort-object | get-unique

martes, 10 de agosto de 2010

Trabajos en Segundo Plano

Cuando ejecutamos un cmdlet en el consola host de PowerShell, la consola espera a que el cmdlet termine su ejecución. Mientras un cmdlet está en ejecución, la consola no permite introducir más cmdlets. Sin embargo, a partir de la versión 2.0 de PowerShell, disponemos de un conjunto de cmdlets que nos permtien la ejecución de cmdlets en segundo plano, de tal manera que podemos realizar varias tareas simultaneamente en una única consola.

Los cmdlets para la gestión de trabajos en segundo plano son:

Get-Job. Nos muestra una lista de todos los trabajos que se han ejecutado (o se están ejecutando) en segundo plano en la instancia de PowerShell actual.
Receive-Job. Se usa para acceder a la salida producida por un trabajo en segundo plano.
Remove-Job. Se elimina un trabajo en segundo plano.
Start-Job. Se lanza un trabajo en segundo plano.
Stop-Job. Se para un trabajo en segundo plano
Wait-Job. Suprime el símbolo del sistema hasta que uno o todos los trabajos en segundo plano de Windows PowerShell que se ejecutan en la sesión se completen.

Nota. Algunos cmdlets disponen del parámetro AsJob, que hace lo mismo que Start-Job.


Ejemplo. Lanzar un trabajo en segundo plano:

start-job {Start-Sleep 90}

Nota. Este trabajo se ejecuta en una nueva instancia de PoweShell.


Ejemplo. Para ver todos los procesos en segundo plano:

get-job


Si un trabajo tiene el estado "Failed", podemos ver la razón del fallo en:

$job.ChildJobs[0].JobStateInfo.Reason


Ejemplo.Vamos a lanzar ahora el siguiente proceso en segundo plano:

$job1=Start-Job { for ($i=0;$i -lt 10;$i++) { Start-Sleep 10; Write-Host "Bucle número: $i"} }


Este proceso está sacando por pantalla una serie de información. Sin embargo, al estar en segundo plano, no vamos a ver la salida, sino que se está almacenando en una caché de procesos de segundo plano. Si queremos acceder a esa información, haremos uso del cmdlet Receive-Job.

Ejemplo. Para ver si hay datos en la caché para nuestro trabajo en segundo plano:

$job1.HasMoreData. Si el resultado es True, significa que hay datos.

Para obtenerlos: Receive-Job $job1

Nota. Una vez que hemos accedido a los datos, estos se eliminan de la caché. Para consultarlos y no eliminarlos de la caché, haremos:
Receive-Job $job1 -Keep

Nota. Si al crear el trabajo, no lo hemos asociado a una variable, podemos acceder a nuestro trabajo mediante el id:

$trabajo1=Get-Job -Id 3
Receive-Job -Id 4


etc.

viernes, 6 de agosto de 2010

Acceso remoto con PowerShell - III

Una vez que ya tenemos habilitado WinRM 2.0 en el servidor al que queremos conectarnos, desde un cliente solo tenemos que ejecutar esto:

Enter-PSSession 'Nombre_Servidor'

Ya tenemos establecida una conexión interactiva con el servidor remoto y todos los cmdlets que ejecutemos se harán en el servidor remoto.

Condiciones para que funcione bien:

1) El usuario con el que hemos iniciado la sesión en el cliente debe tener privilegios administrativos en la máquina remota.

2) Las dos máquinas pertenecen al mismo dominio o hay establecida una relación de confianza.

Si no se cumple alguna de las condiciones anteriores:

Enter-PSSession 'Nombre_Servidor' -Credential:'dominio\usuario'

Para salir de la sesión interactiva:

Exit-PSSession



Ejecución de comandos en modo no interactivo:

Disponemos del cmdlet Invoke-Command para ejecutar comandos en remoto de manera no interactiva:

Invoke-Command -computerName servidor1 {Get-Process}

Invoke-Command -computerName servidor1, servidor2 {Get-Process}

Podemos también ejecutar scripts. El script tiene que estar accesible en la máquina cliente:

Invoke-Command -computername Server01, Server02 -filepath c:\Scripts\script.ps1


Pero de esta manera no mantenemos la sesión.Si queremos mantener la sesión, haremos:

$s = New-PSsession -computername Servidor1, Servidor2

Ahora podemos hacer:

Invoke-Command -session $s {$h = get-Process}
Invoke-Command -session $s {$h | where {$_.Status -eq "Stopped"}

Más información en:

about_remote_requirements
about_remote_troubleshooting

Acceso remoto con PowerShell - II

WinRM significa Windows Remote Management.Es el nuevo estándar de Microsoft para la administración remota. En lugar de usar RPC, usa HTTP o HTTPS.

Windows Server 2008 R2 y Windows 7 hacen uso de WinRM 2.0. Por defecto, esta herramienta está instalada, pero no habilitada.

WinRM se basa en los estandares WS-Management (Web Services for Management). WS-Management usa peticiones SOAP(Simple Object Access Protocol) para enviar y recibir instrucciones a máquinas remotas. Las peticiones SOAP se envían y reciben usando XML.

La versión WinRM 1.1 hace uso del puerto 80 para HTTP y 443 para HTTPS. La versión WinRM 2.0 hace uso del puerto 5985 para HTTP y 5986 para HTTPS.

PowerShell hace uso de WinRM para el acceso máquinas remotas.

Nota. Aunque usemos el protocolo HTTP, todas las conexiones están cifradas, siempre y cuando el mecanismo de autenticación sea "Integrated Windows Authentication".

Cuando los accesos sean entre máquinas del mismo dominio, podemos hacer uso de HTTP. Si el acceso es entre máquinas de dominios diferentes, es mejor habilitar HTTPS. Por
defecto, la configuración de WinRM hace uso del transporte HTTP.


Para saber si WinRM está funcionando en una máquina, hacemos:

winrm enumerate winrm/config/listener

Si no está habilitado, la forma más fácil de hacerlo es:

winrm quickconfig

Una vez habilitado, podemos comprobar que funciona bien, accediendo a otra máquina y ejecutando:

winrs -r:http://nombre_servidor:5985 comando o winrs -r:nombre_servidor comando

Si hemos iniciado la sesión con un usuario que no tiene privilegios sobre la máquina remota, hacerlo así:

winrs -r:nombre_servidor -u:dominio\usuario -p:contraseña comando

Por ejemplo: winrs -r:dc01 ipconfig

En varios sitios de Internet he visto que se puede llamar a PowerShell así:

winrs -r:dc01 powershell.exe

Pues esto a mi no me funciona, se llega a conectar, pero no muestra el prompt y no responde a los cmdlets. Lo que si funciona es lo siguiente:

winrs -r:dc01 powershell.exe cmdlet

Esto ejecuta el cmdlet de PowerShell en la máquina remota.

Si alguien sabe cómo hacer una conexión interactiva de esta manera, que me lo cuente.

Si queremos habilitar el transporte HTTPS en WinRM, hacer esto:

1) Solicitar un certificado web con nombre común el nombre DNS de la máquina.

2) winrm create winrm/config/listener?Address=*+Transport=HTTPS

3) Probarlo desde otra máquina: winrs -r:https://dc02.smb.local:5986 comando


Nota: En el caso de estar accediendo entre máquinas de dominios diferentes, tenemos que dar de alta a los clientes que se vayan a conectar, de la siguiente manera:

1) Habilitar autenticación básica en el servidor: WinRM set winrm/config/service/auth @{Basic="true"}
2) Agregar nombre de equipo que se va a poder conectar: WinRM set winrm/config/client @{TrustedHosts="Nombre_equipo"}
3) Habilitar autenticación básica en el cliente: WinRM set winrm/config/service/auth @{Basic="true"}
4) Agregar al cliente el nombre del servidor al que se va a conectar: WinRM set winrm/config/client @{TrustedHosts="Nombre_equipo"}
5) Recomendable habilitar en el servidor el transporte HTTPS.

Acceso remoto con PowerShell - I

PowerShell permite la ejecución en remoto de determinados comandos. Algunos de los cmdlets de PowerShell disponen del parámetro "ComputerName" que permiten la ejecución del cmdlet en un equipo remoto. Para ver un listado de todos los cmdlets con ese parámetro, ejecutar:

get-command | where { $_.parameters.keys -contains "ComputerName" -and $_.parameters.keys -notcontains "Session"}

Estos cmdlets no se basan en la comunicación remota de Windows PowerShell, por lo que podemos ejecutar estos cmdlets en máquinas remotas incluso si el equipo no está configurado para la ejecución de comandos remotos.

Ahora, se tienen que cumplir dos condiciones para poder ejecutar estos cmdlets sobre una máquina remota.

1) La persona que ejecuta el cmdlet tiene que tener permisos adminsitrativos en la máquina remota.
2) Se hace uso del protocolo RPC, por lo que se necesita el puerto TCP 135 abierto en la máquina remota.

Ejemplos:

Restart-Computer -computerName DC01

Para reiniciar varios equipos a la vez:

$pcs=@("Pc1",Pc2","Pc3")
Restart-Computer -computerName $pcs


Aunque esta posibilidad de ejecutar comandos en máquinas remotas es interesante, el número de cmdlets que podemos usar es muy pequeño, por lo que pocas veces haremos uso de esta funcionalidad (quizás el cmdlet más interesante aquí es Get-WmiObject).

Si queremos ejecutar cmdlets en remoto haremos uso de WinRM y estableceremos sesiones remotas.

miércoles, 4 de agosto de 2010

Directiva de ejecución y firma de scripts

Por defecto, PowerShell no permite la ejecución de ningún Script. Esto es debido a la directiva de ejecución.

La directiva de ejecución dispone de 6 niveles:

Restricted. No permite la ejecución de scripts (.ps1, .psm1, .ps1.xml) (Directiva predeterminada)
Allsigned. Permite solo la ejecución de scripts firmados.
RemoteSigned. Permite la ejecución de scripts locales sin firmar. Los remotos tienen que estar firmados.
Unrestricted. Permite la ejecución de scripts sin firmar, pero da advertencias si el script se ha descargado de Internet.
Bypass. Permite la ejecución de scripts sin firmar sin dar advertencias.
Undefined. No hay definida una directiva de ejecución. Se aplica la directiva Restricted.

Vamos a cambiar la directiva de ejecución al nivel AllSigned:

Set-ExecutionPolicy AllSigned

A partir de ahora, cualquier script que queramos ejecutar, tendrá que estar firmado por un editor de confianza.

¿Cómo se firma un script?

Primero, la persona que va a firmar los scripts, debe obtener un certificado con propósito Firma de Código.Lo podemos solicitar a nuestra CA usando el navegador de Internet.

Segundo, debemos almacenar el certificado en una variable:

$cert = Get-ChildItem -path cert:\CurrentUser\my -CodeSigningCert

Tercero, firmamos el script:

Set-AuthenticodeSignature script.ps1 -cert $cert

Cuarto, en la máquina en la que vamos a ejecutar el script, tiene que estar dado de alta el editor de confianza usado para la firma. El editor de confianza se puede distribuir a toda la organización a través de una directiva de grupo. Agregamos a la directiva de grupo, la exportación del certificado sin la clave privada, lógicamente.

Ahora ya podemos ejecutar scripts que hayan sido firmados digitalmente por la persona que solicitó el certificado de firma de código.

Notas

Si no hacemos el paso cuatro, al ejecutar el script firmado, dará una advertencia de seguridad, pero nos dejará ejecutarlo.

Para ver la directiva actual de ejecución, usaremos el cmdlet Get-ExecutionPolicy.

Para ver la ayuda de los diferentes niveles de ejecución y más ayuda, usaremos Help about_Execution_Policies.

Para ver quién ha firmado un script: Get-AuthenticodeSignature script.ps1 | Format-List

Para más información en: Help about_signing

Ayuda en PowerShell

PowerShell cuenta con más de 200 cmdlets. Aprenderse de memoria la sintaxis de todos los cmdlets es una tarea titánica....aunque no necesaria. PowerShell incluye una amplia y sencilla ayuda, que nos asistirá en todo momento.


El cmdlet para acceder a la ayuda es Get-Help, y para saber como usarlo, ejecutamos:

Get-Help Get-Help

Básicamente, se usa poniendo a continuación el nombre del cmdlet del que queremos la ayuda. Por ejemplo, para ver la ayuda del cmdlet Get-command:

Get-Help Get-Command

Siempre podemos ver más información, ejemplos e información técnica ejecutando:

Get-Help Get-Command -detailed
Get-Help Get-Command -examples
Get-Help Get-Command -full

Nota. En lugar de usar Get-Help, podemos usar su alias Help, que además nos muestra la información en páginas.

Además de la ayuda de los cmdlets, PowerShell dispone de ayuda en unos archivos llamados "about", para verlos:

Help about*

y para acceder a cualquiera de ellos, usar su nombre, por ejemplo:

Help about_functions

Nota. Para ver una lista de todos los cmdlets:
get-command | where-object {$_.commandtype -eq "Cmdlet"}
Nota. Para contarlos:
get-command | where-object {$_.CommandType -eq "Cmdlet"} | Measure-Object -Line

martes, 3 de agosto de 2010

Unidades en PowerShell

Estamos acostumbrados a trabajar con letras de unidad en los sistemas Windows (C:, D:, etc.), PowerShell amplia este concepto.

Ejecutar el cmdlet Get-PSDrive y obtendremos algo similar a lo siguiente:




Para PowerShell, el registro es otra unidad, podemos hacer dir HKLM:, o cd HKLM: por lo que el acceso al registro será igual que el acceso a cualquier unidad.

Descripción de las unidades disponibles.

Alias. Contiene todos los alias definidos en PowerShell.
Function. Contiene todas las funciones definidas en PowerShell.
HKLM. Acceso a la rama del registro HKEY_LOCAL_MACHINE.
HKCU. Acceso a la rama del registro HKEY_CURRENT_USER.
Env. Contiene todas las variables de entorno disponibles en PowerShell.
cert. Acceso al almacén de certificados.
Variable. Contiene todas las variables definidas en PowerShell.

Podemos ampliar el número de unidades con el cmdlet New-PSDrive, por ejemplo, para conectarnos a un recurso compartido de un servidor remoto, haremos:

new-psdrive -name S -psprovider FileSystem -root \\DC02\Software

De esta manera disponemos de una nueva unidad llamada S:

Perfiles en PowerShell (Profiles)

Ya sabemos que en PowerShell podemos definir nuestras propias funciones, alias, etc. Sin embargo, los elementos creados en PowerShell se eliminan una vez que salgamos de PowerShell. La siguiente vez que accedemos los elementos definidos anteriormente no aparecen. ¿Qué podemos hacer para que nuestras definiciones estén disponibles siempre?

PowerShell permite hacer uso de perfiles. Estos perfiles no son más que scripts que se ejecutan al iniciar PowerShell. Podemos aprovechar los perfiles para definir elementos que queremos que estén disponibles en todas las sesiones de PowerShell.

Existen cuatro perfiles:

Perfil que afecta a todos los usuarios y todos los Shells:

$env:Systemroot\System32\WindowsPowershell\v1.0\profile.ps1

Perfil que afecta a todos los usuarios, pero solo al shell PowerShell (por ejemplo, no se aplicaría al shell Exchange Management Shell):

$env:Systemroot\System32\WindowsPowershell\v1.0\Microsoft.PowerShell_profile.ps1

Perfil que afecta un usuario y todos los Shells:

$env:UserProfile\Documents\WindowsPowershell\profile.ps1

Perfil que afecta a un usuario y solo al shell PowerShell:

$env:UserProfile\Documents\WindowsPowershell\Microsoft.PowerShell_profile.ps1


Los perfiles son Scripts, por lo que se ven afectados por la directiva de ejecución. La directiva de ejecución, por defecto, solo permite la ejecución de scripts firmados digitalmente. Para realizar pruebas de perfiles sin tener que firmarlos digitalmente, ejecutar el siguiente cmdlet:

Set-ExecutionPolicy RemoteSigned

Una vez hecho esto, crear los archivos anteriores con líneas Write-Host y verificar que se cargan correctamente. La siguiente imagen muestra PowerShell recien arrancado:

lunes, 2 de agosto de 2010

¿Qué puedo administar con PowerShell?

Ya sabéis que PowerShell está incluido en la mayoría de productos de Microsoft, como Exchange, SharePoint, Virtual Machine Manager, IIS, etc. Pero, ¿puedo abrir cualquier consola de PowerShell y administrar cualquier producto instalado en la máquina?

La respuesta es: Por defecto, no. Para poder administrar un producto, la consola tiene que incluir el Snapin correspondiente. Cuando instalamos Exchange, por ejemplo, dispondremos de una consola llamada, Exchange Management Shell, que permite la administración de Exchange. Pero la herramienta PowerShell que viene con el sistema operativo no me permitirá administrar Exchange...a no ser que cargue previamente el Snapin de Exchange.

¿Que Snapin vienen con PowerShell?

Ejecutar el cmdlet Get-PSSnapin para verlo. En un servidor Windows Server 2008 R2 obtendremos los siguientes Snapin:

Get-PSSnapin | Select-Object name
Microsoft.PowerShell.Diagnostics
Microsoft.WSMan.Management
Microsoft.PowerShell.Core
Microsoft.PowerShell.Utility
Microsoft.PowerShell.Host
Microsoft.PowerShell.Management
Microsoft.PowerShell.Security


Estos Snapin permiten la administración del sistema operativo.
En una consola de PowerShell de SharePoint además aparecerá:

Microsoft.SharePoint.PowerShell

En un servidor Exchange 2010, desde Exchange Management Shell aparecerá:

Microsoft.Exchange.Management.PowerShell.E2010

¿Cómo agregar un Snapin a cualquier consola de PowerShell?

Lógicamente solo podemos agregar Snapin que estén registrados en el sistema. En un servidor Exchange, podemos ejecutar desde PowerShell:

Get-PsSnapin -Registered |Select-Object Name

y obtendremos:

Microsoft.Exchange.Management.PowerShell.E2010
Microsoft.Exchange.Management.PowerShell.Setup


Entonces, podemos hacer ahora:

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010

y ya tenemos una Consola de PowerShell, en la que podemos ejecutar cmdlets de Exchange.

PowerShell ISE

La nueva herramienta PowerShell ISE (Integrated Scripting Environment) nos facilita la creación de scripts de PowerShell. Esta herramienta nos aporta un editor e incluye capacidades de depuración.

Por defecto PowerShell ISE no está instalado. En un servidor Windows Server 2008 R2, esta herramienta se instala a través de una característica. Accediendo al Administrador de Servidores, seleccionamos las características y le damos a Agregar Característica. La siguiente imagen muestra la característica seleccionada para la instalación:



Una vez instalada, accedemos al menú Inicio, Todos los programas, Accesorios, Windows PowerShell y veremos PowerShell ISE tanto en 32 bits como en 64 bits. La siguiente imagen muestra el programa abierto:

PowerShell V2

La nueva versión de PowerShell V2, se incluye de manera predeterminada en Windows 7 y Windows Server 2008 R2. Entre las novedades caben destacar las siguientes:

Nuevos cmdlets. Windows PowerShell incluye más de 100 nuevos cmdlets, como Get-Hotfix, Send-MailMessage, Get-ComputerRestorePoint, New-WebServiceProxy, Debug-Process, Add-Computer, Rename-Computer, Reset-ComputerMachinePassword y Get-Random.

Administración remota. Se pueden ejecutar comandos en uno o en cientos de equipos con un único comando. También se puede establecer una sesión interactiva con un solo equipo o establecer una sesión que reciba comandos procedentes de varios equipos.

Windows PowerShell Integrated Scripting Environment (ISE). Windows PowerShell ISE es una interfaz gráfica de usuario para Windows PowerShell que permite ejecutar comandos, así como escribir, editar, ejecutar, probar y depurar scripts en la misma ventana. Ofrece hasta ocho entornos de ejecución independientes e incluye un depurador integrado, funciones de edición de varias líneas, ejecución selectiva, sintaxis de colores, numeración de líneas y columnas y ayuda contextual.

Trabajos en segundo plano. Gracias a los trabajos en segundo plano de Windows PowerShell, se pueden ejecutar comandos de forma asincrónica "en segundo plano", lo cual permite seguir trabajando en la sesión actual. Estos trabajos en segundo plano se pueden ejecutar en equipos locales o remotos y, de igual modo, los resultados obtenidos se pueden almacenar tanto local como remotamente.

Depurador. El depurador de Windows PowerShell ayuda a depurar funciones y scripts. Podrá definir y quitar puntos de interrupción, recorrer el código paso a paso, comprobar el valor de las variables y visualizar un seguimiento de la pila de llamadas.

Módulos. Los módulos de Windows PowerShell permiten organizar los scripts y funciones de Windows PowerShell en unidades con almacenamiento independientes, con lo cual podrá empaquetar cmdlets, proveedores, scripts, funciones y otros tipos de archivo en módulos que se pueden distribuir a otros usuarios. Los módulos son más fáciles de instalar y usar que los complementos de Windows PowerShell, pueden contener cualquier tipo de archivo, incluidos archivos de audio, imágenes, archivos de Ayuda e iconos, y se pueden ejecutar en otra sesión a fin de evitar que surjan conflictos de nombres.

Transacciones. Ahora Windows PowerShell admite las transacciones, por lo que podrá administrar un conjunto de comandos como si se tratara de una unidad lógica. Una transacción se puede confirmar o incluso deshacer completamente para que los datos afectados no experimenten ningún cambio.

Eventos. Windows PowerShell presenta una nueva infraestructura de eventos que permite crear eventos y suscribirse a eventos de sistema y aplicación para, a continuación, identificarlos, reenviarlos o actuar sobre ellos, ya sea sincrónica o asincrónicamente.

Funciones avanzadas. Las funciones avanzadas tienen el mismo comportamiento que los cmdlets, con la diferencia de que se escriben en el lenguaje de scripting de Windows PowerShell y no en C#.

Internacionalización de scripts. Los scripts y las funciones pueden mostrar mensajes y texto de la Ayuda en distintos idiomas.

Ayuda en pantalla. Aparte de la Ayuda en la línea de comandos, el cmdlet Get-Help tiene un nuevo parámetro Online con el que se abre una versión completa y actualizada de cada uno de los temas de la Ayuda de Microsoft TechNet