Compartir a través de


acerca de Parsing

Descripción breve

Describe cómo PowerShell analiza los comandos.

Descripción larga

Cuando introduces un comando en el símbolo del sistema, PowerShell divide el texto del comando en una serie de segmentos llamados tokens y luego determina cómo interpretar cada token.

Por ejemplo, si escribe:

Write-Host book

PowerShell divide el comando en dos tokens, Write-Host y book, e interpreta cada token de forma independiente mediante uno de los dos modos de análisis principales: modo de expresión y modo de argumento.

Nota:

A medida que PowerShell analiza la entrada del comando, intenta resolver los nombres de comando en cmdlets o ejecutables nativos. Si un nombre de comando no tiene una coincidencia exacta, PowerShell antepone Get- al comando como verbo predeterminado. Por ejemplo, PowerShell analiza Service como Get-Service. No se recomienda usar esta característica por los siguientes motivos:

  • Es ineficaz. Esto hace que PowerShell busque varias veces.
  • Los programas externos con el mismo nombre se resuelven primero, por lo que es posible que no ejecute el cmdlet previsto.
  • Get-Help y Get-Command no reconocen nombres sin verbo.
  • El nombre del comando puede ser una palabra reservada o una palabra clave de lenguaje. Processes ambos, y no puede resolverse en Get-Process.

Modo de expresión

El modo de expresión está diseñado para combinar expresiones, necesarias para la manipulación de valores en un lenguaje de scripting. Las expresiones son representaciones de valores en la sintaxis de PowerShell y pueden ser simples o compuestas, por ejemplo:

Las expresiones literales son representaciones directas de sus valores:

'hello'
32

Las expresiones de variable llevan el valor de la variable a la que hacen referencia:

$x
$script:path

Los operadores combinan otras expresiones para la evaluación:

-12
-not $Quiet
3 + 7
$input.Length -gt 1
  • Las cadenas de caracteres literales deben ir entre comillas.
  • Los números se tratan como valores numéricos y no como una serie de caracteres (a menos que se escapen).
  • Operadores, incluidos los operadores unarios como - y -not, y los operadores binarios como + y -gt, se interpretan como operadores y aplican sus respectivas operaciones a sus argumentos (operandos).
  • Las expresiones de atributo y conversión se analizan como expresiones y se aplican a expresiones subordinadas. Por ejemplo: [int] '7'.
  • Las referencias a variables se evalúan según sus valores, pero la fragmentación está prohibida y provoca un error de análisis.
  • Todo lo demás se trata como un comando que será invocado.

Modo de argumento

Al analizar, PowerShell primero busca interpretar la entrada como una expresión. Pero cuando se encuentra una invocación de comando, el análisis continúa en modo de argumento. Si tiene argumentos que contienen espacios, como rutas de acceso, debe incluir esos valores de argumento entre comillas.

El modo de argumento está diseñado para analizar argumentos y parámetros para comandos en un entorno de shell. Toda la entrada se trata como una cadena expandible a menos que use una de las sintaxis siguientes:

  • Símbolo de dólar ($) seguido de un nombre de variable inicia una referencia de variable; de lo contrario, se interpreta como parte de la cadena expandida. La referencia a una variable puede incluir un acceso a un miembro o un índice.

    • Los caracteres adicionales siguientes a referencias de variables simples, como $HOME, se consideran parte del mismo argumento. Incluya el nombre de la variable entre llaves ({}) para separarlo de los caracteres posteriores. Por ejemplo: ${HOME}.
    • Cuando la referencia de variable incluye el acceso a miembros, el primero de los caracteres adicionales se considera el inicio de un nuevo argumento. Por ejemplo $HOME.Length-more da como resultado dos argumentos: el valor de $HOME.Length y el literal de cadena -more.
  • Las comillas (' y ") inician las cadenas de caracteres

  • Los corchetes ({}) inician un nuevo bloque de script

  • Las comas (,) introducen listas pasadas como arrays, a menos que el comando llamado sea una aplicación nativa, en cuyo caso se interpretan como parte de la cadena expandible. No se admiten las comas iniciales, consecutivas o finales.

  • Paréntesis (()) comienzan una nueva expresión

  • Operador de subexpresión ($()) que inicia una expresión embebida.

  • Inicial en signo (@) comienza sintaxis de expresión como la expansión (), matrices (@args@(1,2,3)) y literales de tabla hash (@{a=1;b=2}).

  • (), $()y @() al comienzo de un token crean un nuevo contexto de análisis que puede contener expresiones y/o comandos anidados.

    • Cuando va seguido de caracteres adicionales, el primer carácter adicional se considera el inicio de un nuevo argumento independiente.
    • Cuando va precedido de un literal sin comillas, $() funciona como una cadena expandible; () inicia un nuevo argumento que es una expresión, y @() se interpreta como el literal @, con () iniciando un nuevo argumento que es una expresión.
  • Todo lo demás se trata como una cadena expandible, excepto los metacaracteres, que aún necesitan escaparse. Consulte Tratamiento de caracteres especiales.

    • Los metacaractores en modo de argumento (caracteres con significado sintáctico especial) son: <space> ' " ` , ; ( ) { } | & < > @ #. De estos, < > @ # solo son especiales al principio de un token.
  • El token de interrupción del análisis (--%) cambia la interpretación de todos los argumentos restantes. Para obtener más información, consulte la sección sobre los tokens de parada.

Ejemplos

En la tabla siguiente se proporcionan varios ejemplos de tokens procesados en modo de expresión y modo de argumento y la evaluación de esos tokens. Para estos ejemplos, el valor de la variable $a es 4.

Ejemplo Modo Resultado
2 Expresión 2 (entero)
`2 Expresión "2" (comando)
Write-Output 2 Expresión 2 (entero)
2+2 Expresión 4 (entero)
Write-Output 2+2 Argumento "2+2" (cadena)
Write-Output(2+2) Expresión 4 (entero)
$a Expresión 4 (entero)
Write-Output $a Expresión 4 (entero)
$a+2 Expresión 6 (entero)
Write-Output $a+2 Argumento "4+2" (cadena)
$- Argumento "$-" (comando)
Write-Output $- Argumento "$-" (cadena)
a$a Expresión "a$a" (comando)
Write-Output a$a Argumento "a4" (cadena)
a'$a' Expresión "a$a" (comando)
Write-Output a'$a' Argumento "a$a" (cadena)
a"$a" Expresión "a$a" (comando)
Write-Output a"$a" Argumento "a4" (cadena)
a$(2) Expresión "a$(2)" (comando)
Write-Output a$(2) Argumento "a2" (cadena)

Cada token se puede interpretar como algún tipo de objeto, como booleano o string. PowerShell intenta determinar el tipo de objeto de la expresión. El tipo de objeto depende del tipo de parámetro que espera un comando y de si PowerShell sabe cómo convertir el argumento al tipo correcto. En la tabla siguiente se muestran varios ejemplos de los tipos asignados a los valores devueltos por las expresiones.

Ejemplo Modo Resultado
Write-Output !1 argumento "!1" (cadena)
Write-Output (!1) expresión False (booleano)
Write-Output (2) expresión 2 (entero)
Set-Variable AB A,B argumento "A","B" (matriz)
CMD /CECHO A,B argumento 'A,B' (cadena de texto)
CMD /CECHO $AB expresión "A B" (matriz)
CMD /CECHO :$AB argumento ":A B" (cadena)

Control de caracteres especiales

El carácter (`) puede utilizarse para escapar cualquier carácter especial de una expresión. Resulta muy útil para escapar los metacaracteres del modo argumento que desee utilizar como caracteres literales en lugar de como metacaracteres. Por ejemplo, para usar el signo de dólar ($) como literal en una cadena expandible:

"The value of `$ErrorActionPreference is '$ErrorActionPreference'."
The value of $ErrorActionPreference is 'Continue'.

Continuación de línea

El carácter de retroceso también puede utilizarse al final de una línea para continuar la entrada en la línea siguiente. Esto mejora la legibilidad de un comando que toma varios parámetros con nombres largos y valores de argumento. Por ejemplo:

New-AzVm `
    -ResourceGroupName "myResourceGroupVM" `
    -Name "myVM" `
    -Location "EastUS" `
    -VirtualNetworkName "myVnet" `
    -SubnetName "mySubnet" `
    -SecurityGroupName "myNetworkSecurityGroup" `
    -PublicIpAddressName "myPublicIpAddress" `
    -Credential $cred

Sin embargo, debe evitar utilizar la continuación de línea.

  • Los caracteres backtick pueden ser difíciles de ver y fáciles de olvidar.
  • Un espacio adicional después de la marca rompe la continuación de línea. Dado que el espacio es difícil de ver puede ser difícil encontrar el error.

PowerShell proporciona varias formas de interrumpir líneas en puntos naturales en la sintaxis.

  • Después de caracteres de pipeline (|)
  • Después de los operadores binarios (+, -, -eq, etc.)
  • Después de comas (,) en una matriz
  • Después de caracteres de apertura como [, {, (

Para conjuntos de parámetros grandes, utilice expansión en su lugar. Por ejemplo:

$parameters = @{
    ResourceGroupName = "myResourceGroupVM"
    Name = "myVM"
    Location = "EastUS"
    VirtualNetworkName = "myVnet"
    SubnetName = "mySubnet"
    SecurityGroupName = "myNetworkSecurityGroup"
    PublicIpAddressName = "myPublicIpAddress"
    Credential = $cred
}
New-AzVm @parameters

Pasar argumentos a comandos nativos

Al ejecutar comandos nativos desde PowerShell, PowerShell analiza primero los argumentos. A continuación, los argumentos analizados se combinan en una sola cadena con cada parámetro separado por un espacio.

Por ejemplo, el comando siguiente llama al programa icacls.exe.

icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

Para ejecutar este comando en PowerShell 2.0, debe usar caracteres de escape para evitar que PowerShell malinterprete los paréntesis.

icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F

El símbolo de parada

A partir de PowerShell 3.0, puede usar el token de detención del análisis (--%) para impedir que PowerShell interprete la entrada como comandos o expresiones de PowerShell.

Nota:

El token stop-parsing solo está pensado para comandos nativos en plataformas Windows.

Al llamar a un comando nativo, coloque el token de detención del análisis antes de los argumentos del programa. Esta técnica es mucho más fácil que usar caracteres de escape para evitar errores de interpretación.

Cuando encuentra un token de parada, PowerShell trata los caracteres restantes de la línea como un literal. La única interpretación que realiza es sustituir los valores de las variables de entorno que usan la notación estándar de Windows, como %USERPROFILE%.

icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F

PowerShell envía la siguiente cadena de comandos al programa icacls.exe:

X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

El token de detención de análisis solo es efectivo hasta la siguiente nueva línea o carácter de pipeline. No puede usar el carácter de continuación de línea (`) para extender su efecto o usar un delimitador de comandos (;) para finalizar su efecto.

Aparte de %variable% referencias a variables de entorno, no puede insertar ningún otro elemento dinámico en el comando. Escapar un carácter % como %%, la forma en que se puede hacer dentro de los archivos por lotes, no es compatible. %<name>% se expanden invariablemente. Si <name> no hace referencia a una variable de entorno definida, el token se pasa a través de as-is.

No puede usar la redirección de flujo (como >file.txt) porque se pasan literalmente como argumentos al comando de destino.

En el ejemplo siguiente, el primer paso ejecuta un comando sin usar el token de parada de análisis. PowerShell evalúa la cadena entre comillas y pasa el valor (sin comillas) a cmd.exe, lo que produce un error.

PS> cmd /c echo "a|b"
'b' is not recognized as an internal or external command,
operable program or batch file.
PS> cmd /c --% echo "a|b"
"a|b"

Nota:

El token de parada de análisis no es necesario cuando se usan cmdlets de PowerShell. Sin embargo, podría resultar útil pasar argumentos a una función de PowerShell diseñada para llamar a un comando nativo con esos argumentos.

Pasar argumentos que contienen comillas

Algunos comandos nativos esperan argumentos que contienen caracteres de comillas. PowerShell 7.3 cambió la forma en que se analiza la línea de comandos para los comandos nativos.

Precaución

El nuevo comportamiento es un cambio importante con respecto al comportamiento de Windows PowerShell 5.1. Puede provocar la interrupción de los scripts y la automatización que se usan como soluciones alternativas para diferentes problemas al invocar aplicaciones nativas. Utilice el token stop-parsing (--%) o el cmdlet Start-Process para evitar el paso de argumentos nativos cuando sea necesario.

La nueva variable de preferencia $PSNativeCommandArgumentPassing controla este comportamiento. Esta variable permite seleccionar el comportamiento en tiempo de ejecución. Los valores válidos son Legacy, Standardy Windows. El comportamiento predeterminado es específico de la plataforma. En las plataformas Windows, la configuración predeterminada es Windows y en las plataformas no Windows, la configuración predeterminada es Standard.

Legacy es el comportamiento histórico. El comportamiento de los modos Windows y Standard es el mismo, excepto que en el modo Windows, las invocaciones de los siguientes archivos pasan argumentos al estilo Legacy automáticamente.

  • cmd.exe
  • cscript.exe
  • wscript.exe
  • terminar con .bat
  • terminar con .cmd
  • terminar con .js
  • terminar con .vbs
  • terminar con .wsf

Si el $PSNativeCommandArgumentPassing se establece en Legacy o Standard, el analizador no comprueba si hay estos archivos.

Nota:

En los ejemplos siguientes se usa la herramienta TestExe.exe. Puede compilar TestExe desde el código fuente. Consulte TestExe en el repositorio de origen de PowerShell.

Nuevos comportamientos disponibles mediante este cambio:

  • Las cadenas literales o expandibles con comillas insertadas ahora se conservan:

    PS> $a = 'a" "b'
    PS> TestExe -echoargs $a 'c" "d' e" "f
    Arg 0 is <a" "b>
    Arg 1 is <c" "d>
    Arg 2 is <e f>
    
  • Las cadenas vacías usadas como argumentos ahora se conservan:

    PS> TestExe -echoargs '' a b ''
    Arg 0 is <>
    Arg 1 is <a>
    Arg 2 is <b>
    Arg 3 is <>
    

El objetivo de estos ejemplos es pasar la ruta de acceso del directorio (con espacios y comillas) "C:\Program Files (x86)\Microsoft\" a un comando nativo para que reciba la ruta de acceso como una cadena entre comillas.

En modo Windows o Standard, los ejemplos siguientes generan los resultados esperados:

TestExe -echoargs """${env:ProgramFiles(x86)}\Microsoft\"""
TestExe -echoargs '"C:\Program Files (x86)\Microsoft\"'

Para obtener los mismos resultados en modo Legacy, debe escapar las comillas o utilizar el token de detención de análisis (--%):

TestExe -echoargs """""${env:ProgramFiles(x86)}\Microsoft\\"""""
TestExe -echoargs "\""C:\Program Files (x86)\Microsoft\\"""
TestExe -echoargs --% ""\""C:\Program Files (x86)\Microsoft\\"\"""
TestExe -echoargs --% """C:\Program Files (x86)\Microsoft\\""
TestExe -echoargs --% """%ProgramFiles(x86)%\Microsoft\\""

Nota:

PowerShell no reconoce la barra invertida (\) como carácter de escape. Es el carácter de escape que usa la API subyacente para ProcessStartInfo.ArgumentList.

PowerShell 7.3 también ha agregado la capacidad de realizar un seguimiento del enlace de parámetros para comandos nativos. Para más información, vea Trace-Command.

Pasar argumentos a comandos de PowerShell

A partir de PowerShell 3.0, puede usar el token "" de fin de parámetros "" (--) para impedir que PowerShell interprete la entrada como parámetros de PowerShell. Se trata de una convención especificada en la especificación de utilidades y shell de POSIX.

El token de fin de parámetros

El token de fin de parámetros (--) indica que todos los argumentos siguientes deben pasarse en su forma real como si se colocaran comillas dobles alrededor de ellos. Por ejemplo, con -- puede generar la cadena -InputObject sin usar comillas ni interpretarla como parámetro:

Write-Output -- -InputObject
-InputObject

A diferencia del token de detención del análisis (--%), PowerShell puede interpretar los valores que siguen al token de -- como expresiones.

Write-Output -- -InputObject $env:PROCESSOR_ARCHITECTURE
-InputObject
AMD64

Este comportamiento solo se aplica a los comandos de PowerShell. Si usa el token de -- al llamar a un comando externo, la cadena -- se pasa como argumento a ese comando.

TestExe -echoargs -a -b -- -c

La salida muestra que -- se pasa como argumento a TestExe.

Arg 0 is <-a>
Arg 1 is <-b>
Arg 2 is <-->
Arg 3 is <-c>

Tilde (~)

El carácter de tilde (~) tiene un significado especial en PowerShell. Cuando se usa con comandos de PowerShell al principio de una ruta de acceso, el carácter tilde se expande al directorio principal del usuario. Si el carácter de tilde se usa en cualquier otro lugar de una ruta de acceso, se trata como un carácter literal.

PS D:\temp> $PWD

Path
----
D:\temp

PS D:\temp> Set-Location ~
PS C:\Users\user2> $PWD

Path
----
C:\Users\user2

En este ejemplo, el parámetro Name del New-Item espera una cadena. El carácter de tilde se trata como un carácter literal. Para cambiar al directorio recién creado, debe calificar la ruta con el carácter de tilde.

PS D:\temp> Set-Location ~
PS C:\Users\user2> New-Item -Type Directory -Name ~

    Directory: C:\Users\user2

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----            5/6/2024  2:08 PM                ~

PS C:\Users\user2> Set-Location ~
PS C:\Users\user2> Set-Location .\~
PS C:\Users\user2\~> $PWD

Path
----
C:\Users\user2\~

Cuando se usa el carácter de tilde con comandos nativos, PowerShell pasa la tilde como un carácter literal. El uso de la tilde en una ruta de acceso provoca errores para comandos nativos en Windows que no admiten el carácter tilde.

PS D:\temp> $PWD

Path
----
D:\temp

PS D:\temp> Get-Item ~\repocache.clixml

    Directory: C:\Users\user2

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           4/29/2024  3:42 PM          88177 repocache.clixml

PS D:\temp> more.com ~\repocache.clixml
Cannot access file D:\temp\~\repocache.clixml

Consulte también