Compartir a través de


about_Parsing

Descripción breve

Describe cómo PowerShell analiza los comandos.

Descripción larga

Al escribir un comando en el símbolo del sistema, PowerShell divide el texto del comando en una serie de segmentos denominados tokens y, a continuación, determina cómo interpretar cada token.

Por ejemplo, si escribe:

Write-Host book

PowerShell divide el comando en dos tokens y Write-Host book, e interpreta cada token de forma independiente mediante uno de los dos modos de análisis principales: el modo de expresión y el 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- el 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. Process es y no se puede resolver 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
  • Los literales de cadena de caracteres deben incluirse entre comillas.
  • Los números se tratan como valores numéricos en lugar de como una serie de caracteres (a menos que se escapen).
  • Los operadores, incluidos los operadores unarios como - y -not los operadores binarios como + y , -gtse interpretan como operadores y aplican sus respectivas operaciones en 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 de variable se evalúan en sus valores, pero la expansión está prohibida y produce un error de analizador.
  • Todo lo demás se trata como un comando que se va a invocar.

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:

  • El signo de dólar ($) seguido de un nombre de variable comienza una referencia de variable; de lo contrario, se interpreta como parte de la cadena expandible. La referencia de variable puede incluir el acceso a miembros o la indexación.

    • 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 y el literal -morede $HOME.Length cadena .
  • Comillas (' y ") comienzan las cadenas

  • Llaves ({}) comienzan un nuevo bloque de script

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

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

  • Operador Subexpression ($()) comienza una expresión incrustada

  • 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 principio de un token, se crea un nuevo contexto de análisis que puede contener expresiones o comandos anidados.

    • Cuando va seguido de caracteres adicionales, el primer carácter adicional se considera el inicio de un nuevo argumento independiente.
    • Cuando un literal $() no comillado funciona como una cadena expandible, () inicia un nuevo argumento que es una expresión y @() se toma como literal @ con () el inicio de un nuevo argumento que es una expresión.
  • Todo lo demás se trata como una cadena expandible, excepto metacharacters que todavía necesitan escapar. Consulte Control 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 detención del análisis (--%) cambia la interpretación de todos los argumentos restantes. Para obtener más información, consulte la sección token de detención del análisis a continuación.

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 Mode Resultado
2 Expression 2 (entero)
`2 Expression "2" (comando)
Write-Output 2 Expression 2 (entero)
2+2 Expression 4 (entero)
Write-Output 2+2 Argument "2+2" (cadena)
Write-Output(2+2) Expression 4 (entero)
$a Expression 4 (entero)
Write-Output $a Expression 4 (entero)
$a+2 Expression 6 (entero)
Write-Output $a+2 Argument "4+2" (cadena)
$- Argument "$-" (comando)
Write-Output $- Argument "$-" (cadena)
a$a Expression "a$a" (comando)
Write-Output a$a Argument "a4" (cadena)
a'$a' Expression "a$a" (comando)
Write-Output a'$a' Argument "a$a" (cadena)
a"$a" Expression "a$a" (comando)
Write-Output a"$a" Argument "a4" (cadena)
a$(2) Expression "a$(2)" (comando)
Write-Output a$(2) Argument "a2" (cadena)

Cada token se puede interpretar como un tipo de objeto, como Boolean 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 Mode Resultado
Write-Output !1 argument "!1" (cadena)
Write-Output (!1) expression False (booleano)
Write-Output (2) expression 2 (entero)
Set-Variable AB A,B argument 'A','B' (matriz)
CMD /CECHO A,B argument 'A,B' (cadena)
CMD /CECHO $AB expression 'A B' (matriz)
CMD /CECHO :$AB argument ':A B' (cadena)

Tratamiento de caracteres especiales

El carácter de barra inversa (`) se puede usar para escapar cualquier carácter especial en una expresión. Esto resulta más útil para escapar de los metacharacters en modo de argumento que se quieren usar como caracteres literales en lugar de como metacaracter. 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 barra trasera también se puede usar al final de una línea para permitir 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 el uso de la continuación de línea.

  • Los caracteres versos pueden ser difíciles de ver y fáciles de olvidar.
  • Un espacio adicional después de que la barra trasera rompa la continuación de la 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 los caracteres de canalización (|)
  • Después de los operadores binarios (+, -, -eq, etc.)
  • Después de comas (,) en una matriz
  • Después de abrir caracteres como [, {, (

En el caso del conjunto de parámetros grandes, use la 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

Paso de 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 siguiente comando llama al icacls.exe programa.

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

Token de detención del análisis

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

Nota:

El token de detención del análisis solo está pensado para usar 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 detención del análisis, PowerShell trata los caracteres restantes de la línea como 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 icacls.exe programa:

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

El token de detención del análisis solo es efectivo hasta el siguiente carácter de nueva línea o canalización. 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% las referencias de variables de entorno, no puede insertar ningún otro elemento dinámico en el comando. No se admite el escape de un % carácter como %%, la forma en que puede hacerlo dentro de los archivos por lotes. %<name>% los tokens se expanden invariablemente. Si <name> no hace referencia a una variable de entorno definida, el token se pasa tal como está.

No puede usar el redireccionamiento de secuencias (como >file.txt) porque se pasan textualmente como argumentos al comando de destino.

En el ejemplo siguiente, el primer paso ejecuta un comando sin usar el token de detención del 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 detención del 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.

Paso de argumentos que contienen caracteres de 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 del 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. Use el token de detención del análisis (--%) o el cmdlet para evitar que el Start-Process argumento nativo pase cuando sea necesario.

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

Legacy es el comportamiento que se ha usado hasta ahora. El comportamiento de los modos Windows y Standard es el mismo con la excepción de que, en modo Windows, las invocaciones de los archivos siguientes usan automáticamente el paso de argumentos de estilo Legacy.

  • cmd.exe
  • cscript.exe
  • wscript.exe
  • termina en .bat
  • termina en .cmd
  • termina en .js
  • termina en .vbs
  • termina en .wsf

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

Nota:

Los ejemplos siguientes usan la herramienta TestExe.exe. Puede compilar TestExe a partir del código fuente. Consulte TestExe en el repositorio de origen de PowerShell.

Nuevos comportamientos disponibles con 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 Windows el modo 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 Legacy modo, debe escapar las comillas o usar el token de detención del 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 el carácter de barra diagonal inversa (\) como carácter de escape. Es el carácter de escape que usa la API subyacente para ProcessStartInfo.ArgumentList.

PowerShell 7.3 también agregó 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.

Token de fin de parámetros

El token de fin de parámetros (--) indica que todos los argumentos que siguen deben pasarse en su forma real como si las comillas dobles se colocaran alrededor de ellos. Por ejemplo, el uso -- de 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 siguientes al -- token como expresiones.

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

Este comportamiento solo se aplica a los comandos de PowerShell. Si usa el -- token 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 de 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 de acceso con el carácter 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