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-Hostbook, 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 un 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 verbos.
  • 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á pensado 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 estar incluidos 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 operadores unarios como y operadores binarios como -+ y -not-gt, se 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 variables se evalúan con sus valores, pero la expansión está prohibida y produce un error del analizador.
  • Cualquier otra cosa 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 que siguen a referencias de variables simples, como $HOME, se consideran parte del mismo argumento. Incluya el nombre de la variable entre llaves ({}) para separarla 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, da como resultado $HOME.Length-more dos argumentos: el valor de y el literal -morede $HOME.Length cadena .
  • Comillas (' y ") comienzan las cadenas

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

  • Comas (,) introduce listas que se pasan como matrices, a menos que se llame al comando es 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 (()) comienzan una nueva expresión

  • El operador Subexpression ($()) comienza una expresión incrustada

  • Inicial en el signo (@) comienza las sintaxis de expresión, como la expansión (), las matrices (@args@(1,2,3)) y los 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 $() sin comilla funciona como una cadena expandible, () inicia un nuevo argumento que es una expresión y @() se toma como literal @ al () iniciar un nuevo argumento que es una expresión.
  • Todo lo demás se trata como una cadena expandible, excepto metacaracteres que todavía necesitan escape. Consulte Control de caracteres especiales.

    • Los metacaracteres 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 Argumento "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 Argumento "4+2" (cadena)
$- Argumento "$-" (comando)
Write-Output $- Argumento "$-" (cadena)
a$a Expression "a$a" (comando)
Write-Output a$a Argumento "a4" (cadena)
a'$a' Expression "a$a" (comando)
Write-Output a'$a' Argumento "a$a" (cadena)
a"$a" Expression "a$a" (comando)
Write-Output a"$a" Argumento "a4" (cadena)
a$(2) Expression "a$(2)" (comando)
Write-Output a$(2) Argumento "a2" (cadena)

Cada token se puede interpretar como algún 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 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)
CMD /CECHO $AB expresión 'A B' (matriz)
CMD /CECHO :$AB Argumento ':A B' (cadena)

Control de caracteres especiales

El carácter de acento trasero (`) se puede usar para escapar cualquier carácter especial de una expresión. Esto es más útil para escapar de los metacaracteres de 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 acento trasero también se puede usar al final de una línea para permitirle 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 el verso 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 maneras de interrumpir líneas en puntos naturales de 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 de gran tamaño, 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 stop-parsing (--%) 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 la interpretación incorrecta.

Cuando encuentra un token de detención del análisis, PowerShell trata los caracteres restantes en la línea como un literal. La única interpretación que realiza es sustituir los valores de las variables de entorno que usan 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 se 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 se pueden insertar otros elementos dinámicos en el comando . No se admite el escape de un % carácter como %%, la forma en que se puede realizar 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 se puede usar el redireccionamiento de flujos (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 de análisis. PowerShell evalúa la cadena entrecomillada 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 Start-Process cmdlet para evitar que el 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 siguientes ejemplos 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 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 un 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 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 de 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 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 produce errores para comandos nativos en Windows que no admiten el carácter de 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