¿Cómo escapar de caracteres especiales en PowerShell?

Resuelto Enoch Chan asked hace 4 años • 2 respuestas

Cuando se ejecuta mi script de PowerShell, le solicita al usuario un parámetro de contraseña. Esa contraseña puede contener cualquier cantidad de caracteres especiales como *\~;(%?.:@/ Esa contraseña luego se usa como parámetro para un comando .exe, pero a menudo es incorrecta debido a que algunos caracteres especiales no se escapan correctamente.

Un ejemplo de contraseña anterior era $(?-.?-(. Los únicos caracteres que necesitaba para escapar eran '(', que reemplacé con '`(' para que funcionara. Sin embargo, esa contraseña ya expiró. La nueva contraseña es algo así como *\~;~(%?.:@/ *NOTA: estas contraseñas también tienen números y letras aleatorios mezclados, pero han sido redactadas.

Los únicos caracteres de la nueva contraseña que NO están en el primero son *\~;%:@/ ¿Existe una manera fácil de escapar de todos los caracteres y simplemente tomar cualquier entrada del usuario tal como está? Si no, ¿a alguien le importaría ayudarme a escapar de estos personajes especiales?


param (
    [Parameter(Mandatory=$true)][string]$password
)

El código anterior precede al script, lo que hace que la consola solicite la entrada del usuario.

Invoke-Expression -Command "<path_to_exe> -install $user $password"

^este es el comando que usa ese parámetro de contraseña


Probé muchas otras sugerencias en Stack Overflow, Reddit y otros foros/blogs de codificación y ninguna funcionó. ¡Cualquier ayuda es muy apreciada!

Enoch Chan avatar Sep 17 '19 06:09 Enoch Chan
Aceptado

Estás usando Invoke-Expressionpara llamar a un programa externo :

  • No hay razón para hacerlo y, Invoke-Expressionen general, debe evitarse : causa dolores de cabeza (como en su caso), pero, lo que es más importante, puede ser un riesgo para la seguridad y, por lo general, existen mejores soluciones.

    • Como comentario aparte: desafortunadamente, incluso con la invocación directa puede haber desafíos al citar argumentos de cadena vacía y argumentos con caracteres incrustados " . - consulte la nota al pie [1] y esta respuesta .
  • Si, en cambio, invoca el programa externo directamente , como está diseñado para hacer cualquier shell, incluido PowerShell, es probable que su problema desaparezca : [1]

& <path_to_exe> -install $user $password

Nota: , el operador de llamada& de PowerShell , solo es necesario si la ruta de su ejecutable está citada (por ejemplo, ) y/o se especifica mediante una referencia variable (por ejemplo, ); de lo contrario, puede invocar el ejecutable tal cual (por ejemplo, para invocar , use algo como )."C:\Program Files\foo.exe"$HOME\foo.execmd.exe
cmd /c 'echo hi'


Por separado, si alguna vez necesita escapar de cualquiera de los caracteres de un conjunto de caracteres, utilícelo -replacecon una clase de carácter ,[...] :

Nota : Esto no es necesario para pasar argumentos, ni a programas externos, como se muestra arriba, ni a comandos de PowerShell; sin embargo, debido al manejo incorrecto de PowerShell de "los caracteres incrustados en los valores de los argumentos pasados ​​a programas externos , es posible que tenga que utilizar "caracteres de escape (únicamente), como \"[1] .

PS> 'a*b\c~d;e(f%g?h.i:j@k/l' -replace '[*\\~;(%?.:@/]', '`$&'
a`*b`\c`~d`;e`(f`%g`?h`.i`:j`@k`/l  # all chars. inside [...] were `-escaped

Nota: Dado que \tiene un significado especial incluso dentro de una clase de carácter, debía escaparse como \\todos los demás caracteres. se utilizan tal cual.

Para obtener más información sobre el -replaceoperador, consulte esta respuesta .


[1] Hay un carácter que todavía causa problemas: incrustado ". Por razones históricas, PowerShell no pasa correctamente la integración "a programas externos y, molestamente, requiere escape manual en las versiones de Windows PowerShell y PowerShell (Core) hasta v7.2.x; consulte esta respuesta para obtener más detalles. Aplicado a su solución :)\& <path_to_exe> -install $user ($password -replace '"', '\"'

mklement0 avatar Sep 17 '2019 01:09 mklement0

El uso de lo siguiente escapará de los caracteres usando el prefijo de escape que mencionaste. El prefijo de escape normal es \ como se muestra a continuación. Lo configuré de esta manera para que le resulte más fácil agregar caracteres adicionales para escapar o cambiar el prefijo de escape.

function Set-EscapeCharacters {
    Param(
        [parameter(Mandatory = $true, Position = 0)]
        [String]
        $string
    )
    $string = $string -replace '\*', '`*'
    $string = $string -replace '\\', '`\'
    $string = $string -replace '\~', '`~'
    $string = $string -replace '\;', '`;'
    $string = $string -replace '\(', '`('
    $string = $string -replace '\%', '`%'
    $string = $string -replace '\?', '`?'
    $string = $string -replace '\.', '`.'
    $string = $string -replace '\:', '`:'
    $string = $string -replace '\@', '`@'
    $string = $string -replace '\/', '`/'
    $string
}

$Password = Set-EscapeCharacters $Password
Drew avatar Sep 16 '2019 23:09 Drew