¿Qué es Windows PowerShell y qué come? Parte 3: pasar parámetros a scripts y funciones, crear cmdlets



La segunda parte de la serie cubrió los conceptos básicos del lenguaje de programación PowerShell, pero ahora vale la pena descubrir cómo usar el código escrito en él para tareas administrativas. La forma más obvia de hacer esto es ejecutar el script. Además, es posible crear sus propios cmdlets.

Tabla de contenido:


Parámetros posicionales
Bloque Param ()
Atributos de parámetros adicionales
Pasando parámetros a través de la tubería
Estructura del cuerpo de la función
Atributo [CmdletBinding ()] y funciones avanzadas
Módulos de secuencias de comandos y creación de cmdlets

Parámetros posicionales


En scripts y funciones, puede pasar parámetros posicionales (argumentos) cuyos valores se escriben en la variable incorporada $ args. Esta matriz unidimensional no requiere declaración previa, y su alcance está limitado a un script o función. Por ejemplo, ejecute el script más simple:

Write-Host " :" $args.count
Write-Host ":" $args


imagen

En las funciones, los parámetros posicionales se usan de la misma manera:

function Print-Args {
    Write-Host " :" $args.count
    Write-Host " 0:" $args[0]
    Write-Host " 1:" $args[1] 
}

Print-Args "Zero" "One"

Tenga en cuenta que al llamar a Print-Args no ponemos una coma entre los parámetros: no se trata de una matriz que se pasa a la función, sino de valores individuales que se escriben en la matriz unidimensional $ args: su alcance está limitado por el cuerpo de la función.

imagen

El método descrito anteriormente le permite pasar cualquier número de parámetros a un script o función, pero al llamar debe seguir el orden de su secuencia, y puede acceder a ellos solo por el índice de la matriz; esto no siempre es conveniente.

Bloque de parámetros ()


En scripts y funciones, es mucho más conveniente usar parámetros con nombre. En un artículo anterior, hablamos sobre una forma de describirlos:

function test ($arg0, ..., $argN)
{
       
}

Los desarrolladores conocen una sintaxis similar, pero cuando se llama a una función, los parámetros (si los hay) están separados por espacios y no están encerrados entre paréntesis; surge una cierta disonancia. Esta es la especificidad de los lenguajes de shell: para trabajar con el shell en modo interactivo, los espacios entre valores son mucho más convenientes. La llamada de prueba ($ value0) también es correcta, pero el parámetro en este caso es la expresión completa entre paréntesis, es decir ($ value0) en lugar de $ value0 . Al pasar de esta manera, varios parámetros no funcionarán. Como resultado de llamar a la prueba ($ value0, $ value1), la función recibirá solo uno: una matriz de dos elementos con los valores $ value0 y $ value1 .

Microsoft recomienda usar el bloque Param (): esta sintaxis es más universal y le permite establecer no solo argumentos de función, sino también parámetros de script:

param (
    $arg0, $arg1
)

Write-Host $arg0 $arg1


imagen

En el cuerpo de la función, se ve así:

function test {
     param (
           $arg0, $arg1
     )
}

Si la lista de argumentos de la función es pequeña, el bloque Param () solo saturará la construcción, pero en muchos casos hace que el código sea más legible y es, entre otras cosas, un elemento de un buen estilo de programación.

Atributos de parámetros adicionales


Al describir argumentos de funciones o parámetros de script, se pueden establecer sus atributos adicionales. El ejemplo más simple es una instalación forzada del tipo:

param([int]$arg0)

o

function test ([int]$arg0) {
}

Además de la conversión de tipos, puede usar el atributo [parámetro ()]:

param(
    [parameter(Argument1=value1, Argument2=value2)]
    $ParameterName
)

Con su ayuda, es fácil hacer que el parámetro sea obligatorio. Preste atención al uso simultáneo de varios atributos; en este caso, se siguen entre sí:

param([parameter(Mandatory=$true)][int]$arg0)

o

function test ([parameter(Mandatory=$true)][int]$arg0) { 
}

o

function test {
          parameter([parameter(Mandatory=$true)][int]$arg0)
}


imagen

La posición le permite especificar el orden del parámetro (por defecto, corresponde al orden de la declaración):

param(
                    [parameter(Mandatory=$true, Position=0)]
                    [int]
                    $arg0,

                    [parameter(Position=1)]
                    [string]
                    $arg1,

                    [parameter(Position=2)]
                    [array]
                    $arg2
)

El atributo [Parámetro ()] tiene otros argumentos, cuya lista completa está disponible en el sitio web de Microsoft. Allí se describen otros atributos, con la ayuda de los cuales puede validar los valores pasados, verificarlos utilizando expresiones regulares, etc. Aquí hay algunos:

[Alias ​​()] establece un alias para el parámetro:

param(
    [parameter(Mandatory=$true)]
    [alias("ARG","ArgumentName")]
    [string[]]
    $arg0
)

El operador de conversión [cadena []] significa que el valor del parámetro es una matriz de cadenas.

[AllowNull ()] permite $ null como parámetro requerido:

param(
    [parameter(Mandatory=$true)]
    [AllowNull()]
    [string]
    $arg0
)

[AllowEmptyString ()] permite una cadena vacía como parámetro requerido:

param(
    [parameter(Mandatory=$true)]
    [AllowEmptyString()]
    [string]
    $arg0
)

[AllowEmptyCollection ()] permite una matriz vacía como parámetro requerido:

param(
    [parameter(Mandatory=$true)]
    [AllowEmptyCollection()]
    [string[]]
    $arg0
)

Validación [ValidatePattern ()] usando una expresión regular:

param(
    [parameter(Mandatory=$true)]
    [ValidatePattern("[0-9][0-9][0-9][0-9]")]
    [string[]]
    $arg0
)

[ValidateLength ()] comprueba la longitud de un parámetro de cadena:

param(
    [parameter(Mandatory=$true)]
    [ValidateLength(1,10)]
    [string]
    $arg0
)

Pasando parámetros a través de la tubería


En el primer artículo de la serie, hablamos sobre la posibilidad de transferir datos a cmdlets a través de una tubería. En PowerShell, los cmdlets y las funciones devuelven objetos o matrices de objetos (resultados de declaraciones) y también los reciben en la entrada. Para ver esto, preparamos uno de los cmdlets con Get-Help:

Get-Help Stop-Process -Parameter Name


imagen

A través de la canalización, puede aceptar valores de parámetros para los que se establecen los atributos correspondientes (ByValue y / o ByPropertyName). En el primer caso, el parámetro coincidirá con un objeto recibido a través de la canalización, siempre que su tipo corresponda al esperado. En el segundo parámetro, el valor será la propiedad del objeto entrante cuyo nombre corresponde al nombre o alias de este parámetro. Para establecer los atributos, use [parámetro ()] con los argumentos booleanos ValueFromPipeline y ValueFromPipelineByPropertyName, cuyo valor predeterminado es $ false:

param(
    [parameter(Mandatory=$true,
    ValueFromPipeline=$true)]
    [string[]]
    $Name
)

o

param(
    [parameter(Mandatory=$true,
    ValueFromPipelineByPropertyName=$true)]
    [string[]]
    $Name
)

ValueFromPipelineByPropertyName se usa generalmente si es necesario para pasar varios parámetros para que no haya confusión, y el argumento se puede usar simultáneamente con ValueFromPipeline:

param(
    [parameter(Mandatory=$true,
    ValueFromPipeline=$true,
    ValueFromPipelineByPropertyName=$true)]
    [string[]]
    $Name
)

Write-Host $Name


imagen

Como puede ver, los scripts también pueden recibir parámetros a través de la canalización, pero sin embargo, la aplicación práctica de los atributos descritos anteriormente es más probable para funciones avanzadas , que se discutirán a continuación.

Estructura del cuerpo de la función


En PowerShell, una función puede incluir tres bloques opcionales de código encerrados entre corchetes de declaración: Inicio, Proceso y Fin. Se ve algo como esto:

function test
{
   param()
   begin {}
   process {}
   end {}
}

El bloque Begin es el primero en ejecutarse una vez, y si los parámetros se pasan a la función a través de la canalización, el código se ejecutará antes de que llegue el primer objeto para su procesamiento. Las variables $ _ y $ PSItem en el bloque Begin en este caso no contendrán valores. Si se llama a la función utilizando parámetros especificados explícitamente, estarán disponibles en el bloque Begin, ya que no es necesario esperar a que se reciban los objetos de la canalización. A continuación, se ejecuta el bloque Proceso: si los parámetros se pasan a través de la tubería, se lanzará uno por uno para cada objeto. En el caso de parámetros especificados explícitamente, el bloque de Proceso comienza solo una vez. La función finaliza ejecutando el bloque End una vez. Obviamente, el uso de estas construcciones se justifica solo si la función puede recibir objetos de la tubería:

function test
{

    param(
        [Parameter(ValueFromPipeline)]
        [string[]]
        $Param1,

        [string]$Param2
    )

    begin
    {
        Write-Host " Begin"
        Write-Host "       ( pipeline):" $Param1
        Write-Host "       ( ):" $Param2
    }

    process {
        Write-Host " Process"
        Write-Host "       ( pipeline):" $Param1
        Write-Host "       ( ):" $Param2
    }

    end
    {
        Write-Host " End"
        Write-Host "       ( pipeline):" $Param1
        Write-Host "       ( ):" $Param2
    }
}

'uno', 'dos', 'tres' | prueba -Param2 'cuatro'

imagen

[CmdletBinding ()] Atributo y funciones avanzadas


Para crear funciones "avanzadas" (y scripts estrictamente hablando), puede usar el atributo [ CmdletBinding () ]. En particular, le permite definir funciones avanzadas con las capacidades de cmdlets binarios compilados en Visual Studio, que son clases de clases .NET Core. Dado que este atributo se usa principalmente en funciones, nos detendremos en ellas:

function <Name>
{
    [CmdletBinding(ConfirmImpact=<String>,
    DefaultParameterSetName=<String>,
    HelpURI=<URI>,
    SupportsPaging=<Boolean>,
    SupportsShouldProcess=<Boolean>,
    PositionalBinding=<Boolean>)]

    Param ()

    Begin{}
    Process{}
    End{}
}

De hecho, [CmdletBinding ()] inicializa una nueva instancia de la clase CmdletBindingAttribute llamando a un constructor al que se pueden pasar argumentos opcionales. Su descripción detallada está en el sitio web de Microsoft. El atributo CmdletBinding le permite controlar características adicionales de la función avanzada: agregar soporte para -Confirm y -WhatIf (a través de SupportsShouldProcess), -Force, -Verbose y -Debug, así como deshabilitar el enlace de parámetros posicionales, etc. Además, analizaremos el uso de parámetros especiales.

El parámetro -Force se usa para suprimir solicitudes de varias operaciones;

-Y sinecesitaba emular el inicio y mostrar información sobre las consecuencias de ejecutar una función (comando) sin este parámetro. Se usa comúnmente si una función puede realizar acciones destructivas.

Remove-Item C: \ Windows \ notepad.exe -WhatIf

imagen

-Confirm requiere confirmación y también se usa si la función puede realizar acciones destructivas.

function Delete-File {
[CmdletBinding(
    ConfirmImpact = 'High',
    SupportsShouldProcess = $true
)]
    param(
        [string]$File,
        [switch]$Force
    )
    if ($Force -or $PSCmdlet.ShouldProcess($File,"Delete file")) {
        Remove-Item $File
    }
}


imagen

Para procesar -WhatIf y / o -Confirm, se llama al método ShouldProcess (SupportsShouldProcess = $ true), que solicita o emula la ejecución del comando. Para implementar el procesamiento -Force, lo ponemos primero en la condición IF. Primero, se verifica la expresión a la izquierda del operador -o, y si es verdadera, la prueba se detiene; no se llamará al método ShouldProcess. Además, en el atributo [CmdletBinding ()], especificamos el argumento ConfirmImpact, que determina el nivel de influencia del código en el sistema e incluye el controlador de parámetros -Confirm. Este argumento puede tomar los siguientes valores:

Ninguno o no especificado: los mensajes de confirmación no se mostrarán, incluso si se pasa el parámetro -Confirm.

Bajo : la función afecta levemente al sistema y no crea riesgos significativos de pérdida de datos.

Medio - exposición medio con poco riesgo de pérdida de datos como resultado de las acciones destructivas.

Alto : el código crea un alto riesgo de pérdida de datos como resultado de acciones destructivas.

De manera predeterminada, para una sesión de PowerShell, el nivel de exposición se considera Alto. El valor actual se almacena en la variable $ ConfirmPreference, y si el código tiene el mismo o mayor nivel de impacto en el sistema, siempre se mostrará una solicitud de confirmación.

Opciones -Verbose y -Debugnecesario para mostrar información de depuración. Su uso se considera un buen estilo de programación (olvídate de Write-Host, esto no es necesario en funciones avanzadas). El primer parámetro muestra información sobre el progreso y el segundo: información de depuración detallada. También hace posible cambiar a la ejecución de código paso a paso. El comportamiento de -Verbose y -Debug se define así:

function Get-Something {
[CmdletBinding()]
    param()
    if ($PSBoundParameters.Verbose) {$VerbosePreference = "Continue"}
    if ($PSBoundParameters.Debug) {$DebugPreference = "Continue"}
    Write-Verbose "Type some verbose information"
    Write-Debug "Type some debug information"
}

Para trabajar con parámetros especiales, utilizamos la variable $ PSBoundParameters. De forma predeterminada, los valores de $ VerbosePreference y $ DebugPreference son iguales a 'SilentlyContinue', por lo tanto, incluso si se especifican los parámetros correspondientes, no se mostrará la información de depuración; deben transferirse al estado 'Continuar'.

Módulos de script y creación de cmdlet


Comencemos a crear nuestros propios cmdlets. De hecho, estas son funciones avanzadas que se describen en el llamado módulos de script : archivos de texto con la extensión .psm1. Se almacenan en directorios definidos en la variable de entorno PSModulePath. Puede ver las rutas a ellos utilizando el siguiente comando:

Get-ChildItem Env: \ PSModulePath | Format-Table -AutoSize

El conjunto estándar tiene un aspecto similar a este:

C: \ Users \% UserName% \ Documents \ WindowsPowerShell \ Modules
C: \ Program Files \ WindowsPowerShell \ Modules
C: \ Windows \ System32 \ WindowsPowerShell \ v1.0 \ Modules

Después de crear el archivo ModuleName.psm1 con la función extendida Eliminar archivo de la sección anterior, debe guardarlo, por ejemplo, en] C: \ Users \% UserName% \ Documents \ WindowsPowerShell \ Modules \ ModuleName. Tenga en cuenta que el módulo de script debe almacenarse en un subdirectorio separado, cuyo nombre coincide con el nombre base (sin extensión) del archivo .psm1. Después de ejecutar el comando Import-Module ModuleName , la función Eliminar archivo estará disponible para el usuario y, dado que es avanzada, desde el punto de vista práctico, es el mismo cmdlet.

imagen

En este artículo, hemos examinado con suficiente detalle el paso de parámetros a funciones y scripts. La siguiente parte de la serie se centrará en la programación orientada a objetos.

Parte 1: Windows PowerShell Essentials
2: Windows PowerShell
4: ,



All Articles