Scripting en PowerShell
Habilitar la ejecución de scripts PowerShell
Para poder ejecutar scripts .ps1
debemos abrir PowerShell como Administrador y ejecutar el siguiente comando:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass -Force;
El comando anterior deshabilitará las políticas de ejecución de scripts PowerShell (Bypass
) para el usuario actual (CurrentUser
).
OJO: Se debe hacer esto con precaución.
El primer script
Script “Hola Mundo” (HolaMundo.ps1):
Write-Host "Hola Mundo"
Los scripts PowerShell deben tener extensión .ps1
.
Para ejecutar el script:
PS> .\HolaMundo.ps1
Hola Mundo
Hay que añadir
.\
porqueHolaMundo.ps1
no está en el PATH.
El cmdlet
Write-Host
es equivalente aecho
.
El segundo script
Los comentarios simples en PowerShell se definen con #
(almohadilla).
Desde la versión 2 de PowerShell se pueden usar bloques de comentarios con <#
y #>
.
Script “ComentariosSimples.ps1”:
# Soy un comentario simple en PowerShell
Get-Date
<#
Y you soy un
bloque de comentarios
#>
(Get-WmiObject Win32_OperatingSystem).Caption
Los bloques de comentarios se suelen utilizar para incluir ayuda en nuestros scripts, que luego podrá ser consultada con Get-Help <script.ps1>
.
Script “ComentariosComplejos.ps1”:
<#
.SYNOPSIS
Breve descripción de lo que hace nuestro script.
.DESCRIPTION
Descripción detallada de nuestro script.
.NOTES
File Name : <script.ps1>
Author : Fran Vargas (mi@email.com)
Prerequisite : PowerShell vX sobre Windows X o superior.
Copyright 2018 - Fran Vargas (IES Domingo Pérez Minik)
.LINK
Script publicado en:
http://fvarrui.github.io/ADD
.EXAMPLE
Ejemplo 1
.EXAMPLE
Ejemplo 2
#>
Write-Host "Sólo sirvo para mostrarte como se usan los comentarios"
Si consultamos la ayuda del script anterior obtendremos los siguiente:
PS> Get-Help .\ComentariosComplejos.ps1
NOMBRE
ComentariosComplejos.ps1
SINOPSIS
Breve descripción de lo que hace nuestro script.
SINTAXIS
ComentariosComplejos.ps1 [<CommonParameters>]
DESCRIPCIÓN
Descripción detallada de nuestro script.
VÍNCULOS RELACIONADOS
Script publicado en:
http://fvarrui.github.io/ADD
NOTAS
Para ver los ejemplos, escriba: "get-help ComentariosComplejos.ps1 -examples".
Para obtener más información, escriba: "get-help ComentariosComplejos.ps1 -detailed".
Para obtener información técnica, escriba: "get-help ComentariosComplejos.ps1 -full".
Para obtener ayuda disponible en línea, escriba: "get-help ComentariosComplejos.ps1 -online"
El tercer script
El script “Educado.ps1”:
$nombre = Read-Host -Prompt "¿Cómo te llamas?"
Write-Host "Hola $nombre"
Write-Host "¿Cómo estás?"
El cmdlet
Read-Host -Prompt <mensaje>
muestra elmensaje
al usuario, luego espera a que se introduzca un dato desde teclado y éste es devuelto como unString
, el cuál se almacena en la variable$nombre
.
Es posible implementar el ejemplo anterior sin usar la variable:
Write-Host "Hola $(Read-Host -Prompt "¿Cómo te llamas?")"
Write-Host "¿Cómo estás?"
Paso de parámetros
Es posible pasar parámetros a un script cuando lo ejecutamos, como si se tratara de un comando más.
Bloque param
Es recomendable declarar los parámetros al principio del script mediante la directiva Param
.
Sintaxis:
Param(
[<tipo>] $<nombre> [ = <valor> ],
[...]
)
Donde:
Elemento | Descripción |
---|---|
tipo | Tipo de datos del parámetros (string, bool, int, …). |
nombre | Nombre del parámetro (es como una variable más dentro del script). |
valor | Valor por defecto que tomará el parámetro si no se especifica al ejecutar el script. |
Script “Parametros.ps1”:
Param(
[string] $Primero,
[string] $Segundo = "valor por defecto",
[switch] $Tercero = $false,
[bool] $Cuarto,
[int] $Quinto
)
Write-Host $Primero
Write-Host $Segundo
Write-Host $Tercero
Write-Host $Cuarto
Write-Host $Quinto
Ejemplo de ejecución del script anterior:
PS> Get-Help .\Parametros.ps1
Parametros.ps1 [[-Primero] <string>] [[-Segundo] <string>] [[-Cuarto] <bool>] [[-Quinto] <int>] [-Tercero]
PS> .\Parametros.ps1
valor por defecto
False
False
0
PS> .\Parametros.ps1 -Primero "hola" -Tercero
hola
valor por defecto
True
False
0
PS> .\Parametros.ps1 -Primero "hola" -Segundo "don pepito"
hola
don pepito
False
False
0
PS> .\Parametros.ps1 -Primero "hola" -Tercero -Quinto 123 -Desconocido
hola
valor por defecto
True
False
123
Parámetro con conjunto de valores limitado
Para hacer que un parámetro sólo pueda recibir un conjunto limitado de valores (Limitado.ps1):
Param(
[ValidateSet("word","excel","powerpoint")][string] $Parametro
)
Write-Host $Parametro
Uso del script:
PS> .\Limitado.ps1 -parametro word
word
PS> .\Limitado.ps1 -parametro access
.\Limitado.ps1 : No se puede validar el argumento del parámetro 'Parametro'. El argumento "access" no pertenece al conjunto
"word;excel;powerpoint" especificado por el atributo ValidateSet. Proporcione un argumento que pertenezca al conjunto e intente ejecutar el comando de nuevo.
En línea: 1 Carácter: 16
+ .\Limitado.ps1 access
+ ~~~~~~
+ CategoryInfo : InvalidData: (:) [Limitado.ps1], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Limitado.ps1
Parámetros obligatorios
Es posible hacer que un parámero sea obligatorio (Mandatory.ps1):
Param(
[string] $Primero,
[Parameter(Mandatory=$true)][string] $Segundo
)
Write-Host $Primero
Write-Host $Segundo
En el ejemplo anterior, el parámetro
Segundo
es obligatorio (mandatory).
Si no especificamos el valor de los parámetros obligatorios, al ejecutar el script nos pedirá dichos valores:
PS> .\Mandatory.ps1
cmdlet Mandatory.ps1 en la posición 1 de la canalización de comandos
Proporcione valores para los parámetros siguientes:
Segundo: hola
hola
Tipos de datos de los parámetros
Tipo | Descripción |
---|---|
[int] | Entero de 32 bits. |
[long] | Entero de 64 bits. |
[string] | Cadena de caracteres. |
[char] | Carácter. |
[bool] | Verdadero ($true ) o falso ($false ). |
[double] | Número de coma flotante de 64 bits. |
[single] | Número de coma flotante de 32 bits. |
[switch] | Verdadero si se especifica el parámetro o falso en caso contrario. |
Variables especiales
Dentro de los scripts podemos usar las siguientes variables especiales:
Variable | Descripción |
---|---|
$args | Array con todos los parámetros pasados al script (excluyendo los especificados en el bloque Param ). Podemos acceder a los elementos del array con $args[0] , $args[1] , $args[2] , …, $args[n] . |
$args.Count | Número de parámetros pasados al script (excluyendo los especificados en el bloque Param ). |
$LASTEXITCODE | Código de retorno de la última orden ejecutada (si es <> 0 indica que hubo un error). |
Script “Especiales.ps1”:
Write-Host "Primero:" $args[0]
Write-Host "Segundo:" $args[1]
Write-Host "Tercero:" $args[2]
Write-Host "Cuarto :" $args[3]
Write-Host "Número total de parámetros:" $args.Count
Get-Date
Write-Host "Valor de retorno del último comando:" $LASTEXITCODE
El cmdlet Read-Host
Sintaxis:
$variable = Read-Host [[-Prompt] <prompt>] [-AsSecureString]
Donde:
-Prompt <prompt>
muestra un mensaje antes de esperar a que se introduzca texto.variable
es la variable donde se guardará el texto introducido (string).-AsSecureString
hace que el texto introducido sea seguro (una contraseña, por ejemplo).
Se utiliza para leer información desde el teclado (entrada estándar) y guardarla en variables.
Script “Leer-Variable.ps1”:
<#
Ejemplo de uso de Read-Host
#>
$var = Read-Host -Prompt "Introduce un valor"
Write-Host "El valor introducido es:" $var
Script “Nueva-Contraseña.ps1”:
$password = Read-Host -Prompt "Introduce la contraseña" -AsSecureString
Write-Host "La contraseña introducida es" $password
# Extraer la contraseña encriptada de un SecureString
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
$plainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
Write-Host "La contraseña introducida es" $plainPassword
Operaciones aritméticas
PowerShell integra de forma natural las operaciones aritméticas.
Operador | Descripción | Ejemplo |
---|---|---|
+ | Suma. | 12 + 34 |
- | Resta. | 12 - 34 |
* | Multiplicación. | 12 * 34 |
/ | División. | 34 / 12 |
% | Resto de la división. | 34 % 12 |
() | Altera la precedencia de los operadores. | ( 12 + 34 ) * 5 |
++ | Incrementa en 1 el operando. | $variable++ |
– | Decrementa en 1 el operando. | $variable-- |
Más información:
Get-Help about_Arithmetic_Operators
Script “Aritmetica.ps1”:
$x = [int] (Read-Host -Prompt "Introduce el valor de la variable")
$y = ($x * 3)
$z = ($y / 2) + 5
Write-Host $z
Casting
El cmdlet Read-Host
devuelve valores de tipo cadena de caracteres (string) y para poder operar con esos valores debemos convertirlos primero a entero (int).
Para ello se especifica el tipo al que queremos convertir el valor entre corchetes ([int]
). Este proceso de cambiar un valor de un tipo de datos a otro se llama casting.
La clase Math
Math
es una clase que ofrece funciones y constantes matemáticas (raíz cuadrada, potencia, número PI, …).
Para acceder a sus miembros usamos [Math]::<miembro>
.
Miembro | Tipo | Descripción |
---|---|---|
[Math]::PI | Constante | Devuelve el valor del número PI (3.1416…). |
[Math]::Pow(base, exponente) | Función | Devuelve la base elevada al exponente . |
[Math]::Sqrt(valor) | Función | Devuelve la raíz cuadrada de valor . |
[Math]::Max(valor1, valor2) | Función | Devuelve el mayor de valor1 y valor2 . |
[Math]::Min(valor1, valor2) | Función | Devuelve el menor de valor1 y valor2 . |
Script “Radio.ps1”:
$radio = [double] (Read-Host -Prompt "Introduce el radio de la circunferencia")
$area = [Math]::PI * [Math]::pow($radio, 2) # area = PI * radio^2
Write-Host "El área de la circunferencia de radio" $radio "es" $area
Operadores relacionales
Los operadores relacionales se utilizan para comparar valores y devuelven un valor de tipo booleano (True o False).
Operador | Descripción | Ejemplo |
---|---|---|
-eq |
¿Son los operandos iguales? | 4 -eq 5 |
-ne |
¿Son los operandos distintos? | 4 -ne 5 |
-gt |
¿Es el primer operando mayor que el segundo operando? | 4 -gt 5 |
-ge |
¿Es el primer operando mayor o igual que el segundo operando? | 4 -ge 5 |
-lt |
¿Es el primer operando menor que el segundo operando? | 4 -lt 5 |
-le |
¿Es el primer operando menor o igual que el segundo operando? | 4 -le 5 |
Para obtener más información podemos ejecutar el siguiente cmdlet:
Get-Help about_Comparison_Operators
Script “Comparacion.ps1”:
Write-Host
Write-Host "Compara de dos variables"
Write-Host "------------------------"
Write-Host
$arg1 = [int] (Read-Host "Introduce la primera variable")
$arg2 = [int] (Read-Host "Introduce la segunda variable")
$resultado = $arg1 -eq $arg2
Write-Host "El resultado es" $resultado
También se pueden comparar otros tipos de datos:
Script “Comparar-Strings.ps1”:
# Compara dos strings
$a = "chuck"
$b = "norris"
$resultado = $a -eq $b
Write-Host "¿" $a "es igual a" $b "?" $resultado
Otros operadores relacionales:
Operador | Descripción |
---|---|
-in |
Comprueba si un elemento está dentro de un array. |
-notin |
Comprueba si un elemento NO está dentro de un array. |
-like |
Compara una cadena con otra usando el metacarácter *. Si casa devuelve True. |
-notlike |
Compara una cadena con otra usando el metacarácter *. Si casa devuelve False. |
-match |
Compara una cadena de caracteres con una expresión regular. Si casa devuelve True. |
-notmatch |
Compara una cadena de caracteres con una expresión regular. Si casa devuelve False. |
-contains |
Comprueba si un array contiene un elemento. |
-notcontains |
Comprueba si un array NO contiene un elemento. |
-is |
Comprueba si un valor es de un tipo de datos determinado (int, double, string, …) |
-isnot |
Comprueba si un valor NO es de un tipo determinado. |
Ejemplos:
# -in / -notin
PS> $miArray = "hola","don","pepito"
PS> "hola" -in $miArray
True
PS> "jose" -in $miArray
False
PS> "jose" -notin $miArray
True
# -like / -notlike
PS> "juan" -like "ju*"
True
PS> "pepe" -like "ju*"
False
PS> "pepe" -notlike "ju*"
True
# -match / -notmatch
PS> "12345678Z" -match "^[0-9]{8}\-?[a-zA-Z]$" # exp. regular para validar un DNI
True
PS> "12345678-Z" -match "^[0-9]{8}\-?[a-zA-Z]$"
True
PS> "922102030" -match "^[0-9]{8}\-?[a-zA-Z]$"
False
PS> "922102030" -match "^[0-9]{9}$" # exp. regular para validar teléfono con 9 dígitos
True
PS> "78560432E" -match "^[0-9]{9}$"
False
PS> "78560432E" -notmatch "^[0-9]{9}$"
True
# -contains / -notcontains
PS> $miArray = "hola","don","pepito"
PS> $miArray -contains "pepito"
True
PS> $miArray -contains "jose"
False
PS> $miArray -notcontains "jose"
True
# -is / -notis
PS> $a = 123
PS> $a -is [int]
True
PS> $a -is [string]
False
PS> $b = "hola"
PS> $b -is [int]
False
PS> $b -isnot [double]
True
PS> $b -is [string]
True
Operadores lógicos
Los operadores lógicos permiten crear expresiones de comparación más complejas.
Operador | Descripción | Ejemplo |
---|---|---|
-or |
“O” lógico. Si alguno de los operandos es Verdadero, devuelve Verdadero. | $False -or $True |
-and |
“Y” lógico. Si alguno de los operandos es Falso, devuelve Falso. | $False -and $True |
-not |
Negación. Si el operando es Verdadero, devuelve Falso, y viceversa. | -not $True |
Más ejemplos:
PS> $a = $True
PS> $b = $False
PS> $a -or $b
True
PS> $a -and $b
False
PS> -not $a
False
PS> ($a -or $b) -and -not $true
False
Estructuras de control
if
Sintaxis:
if (condicion1) {
ordenes
} elseif (condicion2) {
ordenes
} else {
ordenes
}
Nos permite tomar decisiones según se cumplan o no unas condiciones (expresiones booleanas).
El script “Temperatura.ps1”:
$temperatura = [double] (Read-Host -Prompt "¿Cuál es la temperatura del paciente?")
if ($temperatura -lt 35) {
"Hipotermia"
} elseif ($temperatura -gt 37 -and $temperatura -lt 38) {
"Febrícula"
} elseif ($temperatura -ge 38 -and $temperatura -le 39) {
"Fiebre"
} elseif ($temperatura -gt 39 -and $temperatura -lt 40.5) {
"Fiebre alta"
} elseif ($temperatura -ge 40.5) {
"Hipertermia"
} else {
"Normal"
}
switch
Sintaxis:
switch (expresion) {
patron1 {
ordenes
break
}
patron2 {
ordenes
break
}
[...]
default {
ordenes
}
}
Controla el flujo de ejecución basándose en la expresión dada. La expresión se compara, en orden, con todos los patrones. Cuando la expresión coincide con un patrón, se ejecutan todas las órdenes que vayan a continuación, hasta encontrar break
.
Ejemplo “Obtener-DiaSemana.ps1”:
$dia = Get-Date -UFormat "%a"
switch ($dia) {
"lu." { "Hoy es lunes :_("; break }
"ma." { "Hoy es martes :-|"; break }
"mi." { "Hoy es miércoles :-)"; break }
"ju." { "Hoy es juernes :-D"; break }
"vi." { "Hoy es viernes ;-P"; break }
"sá." { "Hoy es sábado ;-D"; break }
"do." { "Hoy es domingo :-("; break }
default { "No sé que día es hoy" }
}
Ejemplo “TemperaturaConSwitch.ps1”:
$temperatura = [double] (Read-Host -Prompt "¿Cuál es la temperatura del paciente?")
switch ($temperatura) {
{ $_ -lt 35 } # si la temperatura < 35
{
"Hipotermia"
break
}
{ $_ -gt 37 -and $_ -lt 38 } # si la temperatura > 37 y temperatura < 38
{
"Febrícula"
break
}
{ $_ -ge 38 -and $_ -le 39 } # si la temperatura >= 38 y temperatura <= 39
{
"Fiebre"
break
}
{ $_ -gt 39 -and $_ -lt 40.5 } # si la temperatura > 39 y temperatura < 40.5
{
"Fiebre alta"
break
}
{ $_ -ge 40.4 } # si la temperatura >= 40.5
{
"Hipertermia"
break
}
default # resto de los casos
{
"Normal"
}
}
La variable
$_
se corresponde con el valor de la expresión. En el ejemplo anterior$_
es igual a$temperatura
.
Ejemplo “Menu.ps1”:
Write-Host "1) Mostrar la fecha"
Write-Host "2) Mostrar la hora"
Write-Host "3) Comprobar conexión a Internet"
$opcion = [int] (Read-Host -Prompt "Elija una opción")
switch ($opcion) {
1 { Get-Date -DisplayHint Date ; break }
2 { Get-Date -DisplayHint Time ; break }
3 { Test-Connection 8.8.8.8 ; break }
default { "Opción desconocida" }
}
Para obtener más información:
Get-Help about_Switch
while
Sintaxis:
while (condición) {
orden(es)
}
Se ejecutan las órdenes una y otra vez mientras se cumpla la condición. La condición se evalúa al principio del bucle, y debe ser una expresión booleana (debe devolver verdadero o falso).
Script “Mientras.ps1”:
<#
Ejemplo de uso de while
#>
$a = 42
while ( $a –le 53 ) {
Write-Host "Contador = $a"
$a++ # $a = $a + 1
}
Script “LineasConWhile.ps1”:
<#
Va leyendo línea a línea el fichero indicado por parámetro
#>
Param([Parameter(Mandatory=$true)][string]$fichero)
$contenido = Get-Content $fichero # devuelve un array de string con el contenido de fichero
$numero = 0
while ($numero -lt $contenido.Length) {
Write-Host ($numero + 1) ":" $contenido[$numero]
$numero++
}
Write-Host "El fichero tiene $numero líneas"
do..while
Sintaxis:
do {
orden(es)
} while (condicion)
Se ejecutan las órdenes una y otra vez mientras se cumpla la condición. La condición se evalúa al final del bucle.
do..until
Sintaxis:
do {
orden(es)
} until (condicion)
Es similar a do..while
sólo que en vez de ejecutar las órdenes “mientras” se cumpla la condición, las ejecuta HASTA (until) que se cumpla. La condiución se evalúa al final del bucle.
Script “Hasta.ps1”:
do {
$palabra = Read-Host -Prompt "¿De qué color es el caballo blanco de Santiago?"
} until ($palabra -eq "blanco")
Write-Host -ForegroundColor Black -BackgroundColor White "¡Qué list@ eres!"
for
Sintaxis:
for (inicializacion; condicion; actualizacion) {
orden(es)
}
El bucle se repite mientras se cumpla la condición. El bloque de inicialización se ejecuta una vez al principio. Se utiliza para inicializar variables, normalmente usadas como contadores. El bloque de actualización se ejecuta al final de cada iteración, después de ejecutar las órdenes.
Script “Bucle-For.ps1”:
<#
Ejemplo de uso de for:
Cuenta desde el 42 hasta el 53
#>
for ($a = 42; $a –le 53 ; $a++) {
Write-Host "Contador = $a"
}
Script “LineasConFor.ps1”:
<#
Va leyendo línea a línea el fichero indicado por parámetro
#>
Param([Parameter(Mandatory=$true)][string]$fichero)
$contenido = Get-Content $fichero # devuelve array de string del contenido de fichero
for ($numero = 0; $numero -lt $contenido.Length; $numero++) {
Write-Host ($numero + 1) ":" $contenido[$numero]
}
Write-Host "El fichero tiene $numero líneas"
Para obtener más información:
Get-Help about_For
.
foreach
Sintaxis:
foreach (elemento in lista) {
orden(es)
}
El bucle se repite tantas veces como elementos tiene la lista. En cada iteración, elemento
toma el valor de un elemento de la lista. El bucle termina cuando se hayan recorrido todos los elementos de la lista.
Script “Ficheros.ps1”:
Param([string] $directorio = ".")
$ficheros = Get-ChildItem $directorio
foreach ($fichero in $ficheros) {
Write-Host "El fichero" $fichero.Name "fue modificado el día" $fichero.LastWriteTime
}
Script “LineasConForEach.ps1”:
<#
Va leyendo línea a línea el fichero indicado por parámetro
#>
Param([Parameter(Mandatory=$true)][string]$fichero)
$numero=0
foreach ($linea in Get-Content $fichero) {
Write-Host ($numero + 1) ":" $linea
$numero++
}
Write-Host "El fichero tiene $numero líneas"
Para obtener más información:
Get-Help about_ForEach
.
ForEach-Object
Sintaxis:
cmdlet | ForEach-Object { orden(es) }
Es un cmdlet, no una estructura de control. Permite usarlo en combinación con otros cmdlets mediante tuberías. El bloque de órdenes se ejecuta por cada objeto devuelto por el cmdlet previo. Para recoger el elemento en cada iteración usamos la variable $_
.
Script “FicherosConForEach-Object.ps1”:
Param([string] $directorio = ".")
Get-ChildItem $directorio | ForEach-Object {
Write-Host "El fichero" $_.Name "fue modificado por última vez el día" $_.LastWriteTime
}
Script “Enumera-Lineas.ps1”:
<#
Va leyendo línea a línea el fichero indicado por parámetro
#>
Param([Parameter(Mandatory=$true)][string]$fichero)
$numero = 0
Get-Content $fichero | ForEach-Object {
Write-Host ($numero + 1) ":" $_
$numero++
}
Write-Host "El fichero tiene $numero líneas"
try..catch
Mediante el bloque try..catch
podemos capturar errores que ocurran en nuestro script.
Sintaxis:
try {
orden(es) controladas
} catch [<excepción>] {
orden(es) que se ejecutan en respuesta a la <excepción>
} catch {
orden(es) que se ejecutan en respuesta a cualquier excepción no capturada antes
} finally {
orden(es) que se ejecutan tanto si hay error como si no
}
Cuando una de las instrucciones de nuestro script produce un error (por el motivo que sea), éste lanza (throw) una excepción (error).
Las excepciones pueden ser de muchos tipos, y podemos capturarlas todas
catch {
orden(es)
}
O sólo alguna concreta:
catch [<excepción>] {
orden(es)
}
Por ejemplo, para capturar la excepción ItemNotFoundException
lanzada por un cmdlet cuando no existe un archivo o carpeta:
catch [System.Management.Automation.ItemNotFoundException] {
orden(es)
}
Para capturar las excepciones que pueden lanzar una o varias instrucciones las metemos dentro del bloque try
, y mediante los bloques catch
indicamos lo que se hará en caso de que se produzca un error.
Script “Crea-Dir.ps1”:
<#
Comprueba si el directorio especificado por
parámetro existe, y si no lo crea.
#>
Param([Parameter(Mandatory=$true)][string] $directorio)
$ErrorActionPreference = "Stop" # Hace que se pueda capturar la excepción
try {
# Obtiene el directorio indicado (lanza excepción si el directorio no existe)
Get-Item $directorio
} catch [System.Management.Automation.ItemNotFoundException] {
# Crea el directorio porque no se encontró
New-Item -ItemType Directory $directorio
} finally {
Write-Host "El directorio" $directorio "ya existía o ha sido creado"
}
break, continue y exit
break
Hace que cualquier bucle termine y pase el control a la siguiente línea después del bloque de órdenes.
continue
Hace que termine la iteración actual de cualquier bucle y pase directamente a la siguiente iteración, saltádose la ejecución de las órdenes restantes de la iteración actual.
exit
Termina la ejecución del script.
Funciones
Las funciones permiten agrupar un conjunto de órdenes que se ejecutan con una cierta frecuencia, para poder reutilizarlas.
Sintaxis de definición de una función:
function nombre([parametro]...) {
orden(es)
[[return] valor]
}
Donde:
-
nombre
es el nombre de la función. Lo utilizaremos para ejecutarla.Es recomendable usar nombres formados por “Verbo-Sujeto” (por ejemplo:
Saludar-Persona
) y que el verbo utilizado sea alguno de los devueltos por el comandoGet-Verb
. -
valor
es el resultado devuelto por la función, si es que devuelve algo.
Las funciones se usan dentro del script como si fueran cmdlets.
Para devolver un valor desde una función se puede hacer enviando el resultado a la salida estándar (con un Write-Host
por ejemplo) o usando la orden return
seguida del valor a devovler.
Podemos declarar tantas funciones como queramos dentro de un script, así como es posible invocar unas funciones desde dentro de otras para crear funciones más complejas.
Script “Saludar.ps1”:
# Declaración de la función
function Saludar-Persona() {
"Hola Don Pepito"
}
# Ejecución o invocación de la función
$saludo = Saludar-Persona
# Muetra el resultado devuelto por la función
Write-Host $saludo
Parámetros
La función puede recibir parámetros al ejecutarla, y estos hay que declararlos entre los paréntesis (...)
.
La sintaxis para definir los parámetros de una función es idéntica al bloque param
utilizado para especificar los parámetros de un script.
Debemos tener en cuenta que los parámetros son variables locales dentro de la función, lo que significa que no se puede acceder a ellas desde fuera de la función.
Ejemplo “Saludar2.ps1”:
<#
Declara una función para recoger un nombre desde la consola
#>
function Obtener-Nombre() {
return Read-Host -Prompt "Introduce un nombre"
}
<#
Declara la función que saluda a la persona con el nombre
especificado por parámetro.
#>
function Saludar-Persona([string] $nombre) {
return "Hola " + $nombre
}
<#
Invoca a la función Obtener-Nombre y guarda el resultado
en la variable $nombre
#>
$nombre = Obtener-Nombre
<#
Invoca a la función Saludar pasándole el nombre
almacenado en la variable $nombre
#>
$saludo = Saludar-Persona $nombre
# Muetra el resultado devuelto por la función
Write-Host $saludo
Más ejemplos de funciones
Ejemplo “Sumar.ps1”:
function Calcular-AreaCirculo([double] $radio) {
$area = [Math]::PI * $radio * $radio
return $area
}
$radio = 25
$area = Calcular-AreaCirculo $radio
Write-Host "El área de una circunferencia de radio $radio es $area"
Ejemplo “Espacio-Libre.ps1”:
# Devuelve la cantidad de bytes libres de la unidad indicada
function Obtener-EspacioLibre([string] $unidad) {
return (Get-PSDrive -Name $unidad).Free
}
# Convierte la cantidad de bytes indicada en gigabytes
function Convertir-BytesAGigas([uint64] $cantidad) {
return $cantidad / 1GB
}
$libre = Obtener-EspacioLibre "C"
$gigas = Convertir-BytesAGigas $libre
Write-Host "La unidad $unidad dispone de $gigas GB libres"
Módulos
Es posible crear módulos o librerías con elementos (llamados miembros) que podemos reutilizar desde otros scripts (variables, funciones, alias, cmdlets, …).
Los módulos son scripts con extensión .psm1
.
Módulo “Trigonometria.psm1”:
function Calcular-AreaRectangulo([double] $ancho, [double] $alto) {
return $ancho * $alto
}
function Calcular-AreaTriangulo([double] $base, [double] $altura) {
return $base * $altura / 2
}
function Calcular-AreaCircunferencia([double] $radio) {
return [Math]::PI * $radio * $radio
}
Exportar miembros de un módulo
Es posible decidir lo que es accesible dentro de un módulo mediante el cmdlet Export-ModuleMember
.
Script “Trigonometria-Limitado.psm1”:
function Calcular-AreaRectangulo([double] $ancho, [double] $alto) {
return $ancho * $alto
}
function Calcular-AreaTriangulo([double] $base, [double] $altura) {
return $base * $altura / 2
}
function Calcular-AreaCircunferencia([double] $radio) {
return [Math]::PI * $radio * $radio
}
Export-ModuleMember -Function Calcular-AreaRectangulo,Calcular-AreaTriangulo
En el ejemplo anterior, los scripts que usen el módulo sólo podrán acceder a las funciones
Calcular-AreaRectangulo
yCalcular-AreaTriangulo
, pero no aCalcular-AreaCircunferencia
. Esta última será una función sólo para uso interno del módulo.
Usar un módulo
Para usar un módulo desde un script es necesario importarlo con el cmdlet:
Import-Module <modulo>
Donde:
modulo
es el nombre del fichero del módulo con o sin la extensión.
Para importar un módulo es necesario que se encuentre en alguna de las rutas de la variable de entorno $env:PSModulePath
o especificar la ruta completa del módulo.
El cmdlet Import-Module
comprueba si los nombres de las funciones utilizan verbos válidos para PowerShell. Para conocer estos verbos disponemos del cmdlet Get-Verb
. Se mostrarán unos avisos en caso de que alguna función exportada no cumpla con este requisito. Para deshabilitar esta comprobación usamos el parámetro -DisableNameChecking
.
Import-Module -DisableNameChecking <modulo>
Por ejemplo, en el script “usar-modulo.ps1” vemos como importar y usar las funciones exportadas por el módulo “trigonometria.psm1”:
Import-Module -DisableNameChecking "x:\ruta\al\modulo\trigonometria"
$area = Calcular-AreaRectangulo 12 34
Write-Host "Área = $area"
Arrays (vectores)
Definición de un array de cuatro elementos:
PS> $miArray = "primero","segundo","tercero","cuarto"
El array puede contener cuaquier tipo de elemento.
Definición de un array fuertemente tipado:
# Crea un array de enteros (int) con 4 elementos (del 0 al 3)
# Este array sólo podrá contener enteros
PS> $otroArray = New-Object int[] 4
PS> $otroArray[0] = 123
PS> $otroArray[1] = "hola"
No se puede convertir el valor "hola" al tipo "System.Int32". Error: "La cadena de entrada no tiene el formato correcto."
En línea: 1 Carácter: 1
+ $otroArray[1] = "hola"
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
Acceder a uno de los elementos del array:
PS> $miArray[1]
segundo
PS> $miArray[0] + " blablabla " + $miArray[2]
primero blablabla tercero
Acceder a TODOS los elementos del array:
PS> $miArray
primero
segundo
tercero
cuarto
Conocer el número de elementos del array:
PS> $miArray.Length
4
- Anterior
- Siguiente