Históricamente, las utilidades de línea de comandos en sistemas Unix han estado más desarrolladas que en Windows, sin embargo, con la llegada de nuevas soluciones, la situación ha cambiado.
Para PowerShell, se pueden escribir scripts en un lenguaje de múltiples paradigmas interpretado, que incluye elementos de programación procedural clásica, orientada a objetos e incluso funcional: estructuras de control, bucles, variables, arrays, tablas hash, clases, manejo de errores, así como funciones, cmdlets y canalizaciones. estaba dedicada a las bases del trabajo en el entorno, y ahora ofrecemos a los lectores una pequeña guía para programadores.
Contenido:
Se puede escribir código en cualquier editor de texto o utilizando un entorno de desarrollo integrado; lo más sencillo es utilizar Windows PowerShell ISE del paquete de sistemas operativos de servidor de Microsoft. Esto solo es necesario para scripts suficientemente complejos: conjuntos cortos de comandos son más fáciles de ejecutar en modo interactivo.
Comentarios
El uso de comentarios se considera parte de un buen estilo de programación junto con sangrías y espacios correctos:
# Для строчных комментариев используется символ решетки — содержимое строки интерпретатор не обрабатывает.
<#
Так обозначаются начало и конец блочного комментария.
Заключенный между ними текст интерпретатор игнорирует.
#>
Variables y sus tipos
Las variables en PowerShell son objetos nombrados. Sus nombres pueden incluir un guión bajo, así como letras y números. Siempre se utiliza el símbolo $, y para declarar una variable, solo es necesario proporcionarle al intérprete un nombre válido:

Para inicializar una variable (asignarle un valor) se utiliza el operador de asignación (símbolo =):
$test = 100Se puede declarar una variable indicando su tipo en corchetes (operador de conversión de tipo) antes del nombre o el valor:
[int]$test = 100
$test = [int]100Es importante entender que las variables en PowerShell son objetos completos (clases) con propiedades y métodos, cuyos tipos se basan en los existentes en .NET Core. Enumeremos los principales:
Tipo (clase .NET)
Descripción
Ejemplo de código
[string]
System.String
cadena Unicode
$test = "test"
$test = 'test'
[char]
System.Char
carácter Unicode (16 bits)
[char]$test = 'c'
[bool]
System.Boolean
tipo booleano (valor lógico True o False)
[bool]$test = $true
[int]
System.Int32
número entero de 32 bits
[int]$test = 123456789
[long]
System.Int64
número entero de 64 bits
[long]$test = 12345678910
[single]
System.Single
número de punto flotante de 32 bits
[single]$test = 12345.6789
[double]
System.Double
número de punto flotante de 64 bits (8 bytes)
[double]$test = 123456789.101112
[decimal]
System.Decimal
número de punto flotante de 128 bits (debe incluir d al final)
[decimal]$test = 12345.6789d
[DateTime]
System.DateTime
fecha y hora
$test = Get-Date
[array]
System.Object[]
arreglo cuyas posiciones de elementos comienzan desde 0
$test_array = 1, 2, "test", 3, 4
[hashtable]
System.Collections.Hashtable
las tablas hash son arreglos asociativos con claves nombradas construidas con la estructura: @{clave = "valor"}
$test_hashtable = @{one="uno"; two="dos"; three="tres"}
PowerShell admite la conversión implícita de tipos; además, el tipo de la variable puede cambiar dinámicamente (por ejemplo, mediante el operador de asignación), si no se especifica de forma explícita, en cuyo caso el intérprete generará un error. El tipo de la variable del ejemplo anterior se puede determinar usando el método GetType():
$test.GetType().FullName 
Hay varios cmdlets para administrar variables. Su lista se muestra de manera conveniente usando el comando:
Get-Command -Noun Variable | ft -Property Name, Definition -AutoSize -Wrap 
Para ver las variables declaradas y sus valores, se puede usar un cmdlet especial:
Get-Variable | moreEste enfoque puede parecer excesivamente engorroso; es mucho más conveniente trabajar con variables a través de operadores o accediendo directamente a sus propiedades y métodos. Sin embargo, los cmdlets tienen derecho a existir, ya que permiten establecer algunos parámetros adicionales. Es importante entender que las variables de usuario se definen solo dentro de la sesión actual. Después de cerrar la consola o finalizar el script, se eliminan.
Variables del sistema
Además de las variables declaradas por el usuario, existen variables integradas (sistémicas) que no se eliminan tras finalizar la sesión actual. Se dividen en dos tipos, y los datos sobre el estado de PowerShell se almacenan en variables automáticas que no se pueden asignar valores arbitrarios. Un ejemplo de esto es $PWD:
$PWD.Path 
Para almacenar la configuración del usuario, se necesitan variables de preferencias cuyos valores se pueden modificar. Por ejemplo, mediante $ErrorActionPreference se establece la reacción del intérprete de comandos ante la aparición de errores no fatales.
Además de los operadores y cmdlets para acceder a las variables declaradas, existe un pseudo-almacenador Variable:. Se puede trabajar con él de manera similar a otros almacenadores, y en este caso las variables se asemejan a objetos del sistema de archivos:
Get-ChildItem Variable: | moreo
ls Variable: | more 
Ámbitos de visibilidad
Para las variables en PowerShell existe el concepto de ámbito (Scope). La acción del ámbito global (Global) se extiende a toda la sesión actual; por ejemplo, incluye variables del sistema. Las variables locales (Local) están disponibles solo en el ámbito en el que fueron definidas: digamos dentro de una función. También hay un concepto de ámbito de script (Script), que, para los comandos de script, es esencialmente local. Por defecto, al declarar variables se les asigna un ámbito local, y para cambiar esto se necesita una construcción especial del tipo: $Global: variable = valor.
Por ejemplo, así:
$Global:test = 100
Variables de entorno
Desde PowerShell hay otro pseudo-almacenador Env:, que permite acceder a las variables de entorno. Al iniciar la consola, se copian desde el proceso padre (es decir, desde el programa que inició la sesión actual) y, por lo general, sus valores iniciales coinciden con los valores en el panel de control. Para ver las variables de entorno se utiliza el cmdlet Get-ChildItem o sus pseudónimos (alias): ls y dir.
dir Env: 
Estas variables representan secuencias de bytes (o caracteres, si lo prefieres), cuya interpretación depende únicamente del programa que las utiliza. Los cmdlets *-Variable no funcionan con las variables de entorno. Para acceder a ellas, tendrás que usar el prefijo del disco:
$env:TEST = "Hello, World!" 
Operadores aritméticos y operadores de comparación
PowerShell tiene los siguientes operadores aritméticos: + (suma), — (resta), * (multiplicación), / (división) y % (módulo o residuo). El resultado de una expresión aritmética se calcula de izquierda a derecha de acuerdo con el orden de operaciones convencional, y se utilizan paréntesis para agrupar partes de la expresión. Los espacios entre los operadores son ignorados, y se usan únicamente para facilitar la lectura. El operador + también concatena, mientras que el operador * repite cadenas. Al intentar sumar un número a una cadena, este se convertirá en cadena. Además, en PowerShell hay numerosos operadores de comparación que verifican la correspondencia entre dos valores y devuelven verdadero lógico o falso:
El operador
Descripción
Ejemplo de código
-eq
Igual / Equality (similar a = o == en otros lenguajes)
$test = 100
$test -eq 123
-ne
No igual / Not equal (similar a o !=)
$test = 100
$test -ne 123
-gt
Mayor que / Greater than (similar a >)
$test = 100
$test -gt 123
-ge
Mayor o igual / Greater than or equal (similar a >=)
$test = 100
$test -ge 123
-lt
Menor que / Less than (similar a <)
$test = 100
$test -lt 123
-le
Menor o igual / Less than or equal (similar a <=)
$test = 100
$test -le 123
Existen otros operadores similares que permiten, por ejemplo, comparar cadenas considerando caracteres comodín o utilizar expresiones regulares para buscar coincidencias. Los veremos en detalle en los siguientes artículos. Los símbolos y = no se utilizan para la comparación, ya que están asignados a otros propósitos.
Operadores de asignación
Además del operador más común =, existen otros operadores de asignación: +=, -=, *=, /= y %= que modifican el valor antes de la asignación. De manera similar, se comportan los operadores unarios ++ y —, que incrementan o decrementan el valor de la variable, y también se consideran operadores de asignación.
Operadores lógicos
Para describir condiciones complejas, solo la comparación no es suficiente. Cualquier expresión lógica se puede escribir usando los operadores: -and, -or, -xor, -not y!.. Funcionan como en otros lenguajes de programación, y se pueden usar paréntesis para especificar el orden de la evaluación:
("Test" -eq "Test") -and (100 -eq 100)
-not (123 -gt 321)
!(123 -gt 321)
Estructura de control
Los operadores de ramificación en PowerShell son estándar: IF(IF…ELSE, IF…ELSEIF…ELSE) y SWITCH. Analicemos su uso con ejemplos:
[int]$test = 100
if ($test -eq 100) {
Write-Host "test = 100"
}
[int]$test = 50
if ($test -eq 100) {
Write-Host "test = 100"
}
else {
Write-Host "test 100"
}
[int]$test = 10
if ($test -eq 100) {
Write-Host "test = 100"
}
elseif ($test -gt 100) {
Write-Host "test > 100"
}
else {
Write-Host "test 5 o valor no está definido"}
}
Bucles
En PowerShell hay varios tipos de bucles: WHILE, DO WHILE, DO UNTIL, FOR y FOREACH.
Un bucle con condición previa funciona si/ mientras se cumple:
[int]$test = 0
while ($test -lt 10) {
Write-Host $test
$test = $test + 1
}
Los bucles con condición posterior siempre se ejecutan al menos una vez, ya que la condición se verifica después de la iteración. DO WHILE funciona mientras la condición sea verdadera, y DO UNTIL funciona mientras sea falsa:
[int]$test = 0
do {
Write-Host $test
$test = $test + 1
}
while ($test -lt 10)
[int]$test = 0
do {
Write-Host $test
$test = $test + 1
}
until ($test -gt 9)
El número de iteraciones en el bucle FOR es conocido de antemano:
for ([int]$test = 0; $test -lt 10; $test++) {
Write-Host $test
}
En el bucle FOREACH se hace una iteración sobre los elementos de un array o colección (tablas hash):
$test_collection = "item1", "item2", "item3"
foreach ($item in $test_collection)
{
Write-Host $item
}
Arrays
En PowerShell, las variables pueden almacenar no solo objetos únicos (números, cadenas, etc.), sino también múltiples. La variante más simple de tales variables son los arrays. Un array puede contener varios elementos, un solo elemento o estar vacío, es decir, no contener elementos. Para su declaración se utiliza el operador @(), que necesitaremos en el siguiente artículo, ya que es muy importante para agregar otros arrays a un array (crear arrays multidimensionales), pasar arrays a funciones como argumentos y tareas similares:
$test_array = @() #creamos un array vacíoAl inicializar un array, sus valores se enumeran separados por comas (operador especial ,):
$test_array = @(1, 2, 3, 4) # creamos un array de cuatro elementos En la mayoría de los casos, se puede omitir el operador @():
$test_array = 1, 2, 3, 4En este caso, un array de un solo elemento se inicializa de la siguiente manera
$test_array = , 1Para acceder a los elementos de un array, se utiliza un índice entero que comienza en cero y el operador de índice (corchetes):
$test_array[0] = 1Se pueden especificar varios índices separados por comas, incluidos los repetidos:
$test_array = "uno", "dos", "tres", "cuatro"
$test_array[0,1,2,3]
$test_array[1,1,3,3,0] 
El operador .. (dos puntos — operador de rango) devuelve un array de enteros en un intervalo definido por un límite superior e inferior. Por ejemplo, la expresión 1..4 devuelve un array de cuatro elementos @(1, 2, 3, 4), y la expresión 8..5 — un array @(8, 7, 6, 5).

Con el operador de rango se puede inicializar un array ($test_array = 1..4) o obtener un slice, es decir, una secuencia de elementos de un array con índices de otro. Un número negativo -1 representa el último elemento del array, -2 el penúltimo, etc.
$test_array = "uno", "dos", "tres", "cuatro"
$test_array[0..2]
$test_array[2..0]
$test_array[-1..0]
$test_array[-2..1]Tenga en cuenta que los valores de un array de enteros pueden ser mayores que el valor máximo del índice de un array de datos. En este caso, se devuelven todos los valores hasta el último:
$test_array[0..100]Si se intenta acceder a un único elemento inexistente del array, se devuelve el valor $null.

En PowerShell, los arrays pueden contener elementos de diferentes tipos o ser estrictamente tipados:
$test_array = 1, 2, "prueba", 3, 4
for ([int]$i = 0; $i -lt $test_array.count; $i++)
{
Write-Host $test_array[$i]
}
Donde la propiedad $test_array.count — representa el número de elementos del array.
Ejemplo de creación de un array estrictamente tipado:
[int[]]$test_array = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Tablas hash
Otro tipo básico de variable en PowerShell — son las tablas hash, que también se conocen como arrays asociativos. Hashtable se asemejan a un objeto JSON y se construyen en base a la idea de clave-valor. A diferencia de los arrays comunes, el acceso a sus elementos se realiza mediante claves nombradas, que son propiedades del objeto (también se puede utilizar el operador de índice — corchetes).
Una tabla hash vacía se declara mediante el carácter especial @ y los corchetes:
$test_hashtable = @{}Al declarar, puede crear inmediatamente claves y asignarles valores:
$test_hashtable = @{one="uno"; two="dos"; three="tres"; "some key"="some value"}Para agregar un elemento a la tabla hash, necesita asignarle una clave que aún no exista o utilizar el método Add(). Si la asignación se hace con una clave existente, su valor cambiará. Para eliminar un elemento de la tabla hash, se utiliza el método Remove().
$test_hashtable."some key"
$test_hashtable["some key"]
$test_hashtable.Add("four", "cuatro")
$test_hashtable.five = "cinco"
$test_hashtable['five'] = "reemplazar valor"
$test_hashtable.Remove("one") 
Las variables de este tipo se pueden pasar como argumentos a funciones y cmdlets; en el siguiente artículo estudiaremos cómo se hace esto, así como otro tipo similar: PSCustomObject.
Funciones
En el lenguaje PowerShell, hay todos los elementos necesarios para la programación procedimental, incluidas las funciones. Para describirlas, se utiliza la palabra clave Function, seguida del nombre de la función y del cuerpo entre paréntesis. Si es necesario pasar argumentos a la función, se pueden indicar justo después del nombre entre paréntesis.
function nombre-función (argumento1, ..., argumentoN)
{
cuerpo-función
}
La función siempre devuelve un resultado; este es un array de resultados de todas sus declaraciones si hay más de una. Si hay solo una declaración, se devuelve un único valor del tipo correspondiente. La construcción return $value añade un elemento con el valor $value al array de resultados y detiene la ejecución de la lista de declaraciones, mientras que una función vacía devuelve $null.
Por ejemplo, crearemos una función que eleva un número al cuadrado:
function sqr ($number)
{
return $number * $number
}
Es importante señalar que en el cuerpo de la función se pueden usar cualquier variable declarada antes de su llamada, y la llamada a funciones en PowerShell puede parecer poco habitual: los argumentos (si los hay) no se colocan entre paréntesis y se separan por espacios.
sqr 2o así:
sqr -number 2Debido a la forma en que se pasan los argumentos, a veces es necesario encerrar la función entre paréntesis:
function test_func ($n) {}
test_func -eq $null # la función no ha sido llamada
(test_func) -eq $null # el resultado de la expresión es $true 
Al describir la función, se pueden asignar valores predeterminados a los argumentos:
function func ($arg = value) {
#cuerpo de la función
}
También existe otra sintaxis para describir los argumentos de la función; además, los parámetros pueden leerse desde el pipeline; todo esto será útil en el siguiente artículo, cuando analizaremos los módulos exportados y la creación de nuestros propios cmdlets.
Manejo de errores
En PowerShell existe un mecanismo Try…Catch…Finally que permite manejar situaciones excepcionales. En el bloque Try se coloca el código donde puede surgir un error, y en el bloque Catch, su manejador. Si no hubo error, no se ejecuta. El bloque Finally se ejecuta después del bloque Try independientemente de si ocurrió un error, y puede haber varios bloques Catch para diferentes tipos de excepciones. La excepción misma se guarda en una variable de obligación ($_) y puede ser extraída fácilmente. En el siguiente ejemplo implementamos una protección contra la entrada de valores incorrectos:
try {
[int]$test = Read-Host "Ingrese un número"
100 / $test
} catch {
Write-Warning "Número incorrecto"
Write-Host $_
}

Con esto, concluimos la revisión de los fundamentos de programación en PowerShell. En los próximos artículos, exploraremos en detalle el trabajo con variables de diferentes tipos, colecciones, expresiones regulares, creación de funciones, módulos y nuestros propios cmdlets, así como la programación orientada a objetos.
Fuente: habr.com
