Как избежать специальных символов в PowerShell?

Когда мой сценарий PowerShell запускается, он запрашивает у пользователя параметр пароля. Этот пароль может содержать любое количество специальных символов, например *\~;(%?.:@/ Этот пароль затем используется в качестве параметра для команды.exe, но часто он неверен из-за того, что некоторые специальные символы не экранируются должным образом.

Примером прошлого пароля был $(?-.?-(. Единственными символами, которые мне нужно было экранировать, были '(', который я заменил на '' (', чтобы он работал. Однако срок действия этого пароля истек. Новый пароль это что-то вроде *\~;~(%?.:@/ * ПРИМЕЧАНИЕ: в этих паролях также смешаны случайные числа и буквы, но они были отредактированы.

Единственные символы в новом пароле, НЕ в первом, - это *\~;%:@/ Есть ли простой способ избежать всех символов и просто принять любой ввод пользователя? Если нет, не мог бы кто-нибудь помочь мне избежать этих специальных символов?


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

Приведенный выше код предшествует сценарию, заставляя консоль запрашивать ввод данных пользователем.

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

^ это команда, которая использует этот параметр пароля


Я пробовал много других предложений на stackru, Reddit и других форумах / блогах по кодированию, но ни один из них не сработал. Любая помощь высоко ценится!

2 ответа

Решение

Вы используете Invoke-Expressionдля вызова внешней программы:

  • Там нет нет причин, чтобы сделать это, и Invoke-Expressionобычно следует избегать: это вызывает головную боль при цитировании (как в вашем случае), но, что более важно, это может быть угрозой безопасности, и, как правило, есть лучшие решения.

    • В качестве отступления: к сожалению, даже при прямом вызове могут возникнуть проблемы с цитированием аргументов с пустой строкой и аргументов со встроенными "символы. - см. сноску [1] и этот ответ.
  • Если вместо этого вы вызываете внешнюю программу напрямую - как и предназначена любая оболочка, включая PowerShell, - ваша проблема, скорее всего, исчезнет:[1]

& <path_to_exe> -install $user $password

Примечание: &, Оператор вызова PowerShell, необходим только в том случае, если путь к вашему исполняемому файлу указан (например,"C:\Program Files\foo.exe") и / или указывается через ссылку на переменную (например,$HOME\foo.exe); в противном случае вы можете вызвать исполняемый файл как есть (например, чтобы вызватьcmd.exe, используйте что-нибудь вроде
cmd /c 'echo hi').


Отдельно, если вам когда-нибудь понадобится экранировать любой из символов в наборе символов, используйте-replaceс классом персонажа,[...]:

Примечание. В этом нет необходимости для передачи аргументов ни во внешние программы, как показано выше, ни в команды PowerShell; однако из-за нарушенной обработки PowerShell"символы, встроенные в значения аргументов, передаваемых во внешние программы, возможно, вам придется экранировать" символы (только), как \"[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

Примечание. Поскольку \ имеет особое значение даже внутри класса символов, его нужно было экранировать как \\- все остальные символы. используются как есть.

Для получения дополнительной информации о -replaceоператор, см. этот ответ.


[1] Есть один символ, который все еще вызывает проблемы: встроенный". По историческим причинам, PowerShell это не правильно проходит встроенный"правильно для внешних программ, и досадно требует ручного\-escaping - подробности см. в этой проблеме на GitHub. Применяется к вашему решению:& <path_to_exe> -install $user ($password -replace '"', '\"')

Использование приведенного ниже приведет к экранированию символов с помощью указанного вами escape-префикса. Обычный префикс перехода - \, как показано ниже. Я установил его таким образом, чтобы вам было проще добавить дополнительные символы для экранирования или изменить префикс 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

В качестве альтернативы, если вы хотите избежать стандартных метасимволов PowerShell, вы можете просто сделать

$Password = [Regex]::Escape($Password)
Другие вопросы по тегам