PowerShell, выполняющий функцию в блоке скрипта с помощью Start-Process, делает странные вещи с двойными кавычками


У меня есть скрипт PowerShell, который редактирует реестр, поэтому он должен работать от имени администратора. Для этого я запускаю новый процесс PowerShell из запущенного сценария PowerShell и передаю часть пути раздела реестра, используя блок сценария с функцией в нем. Когда я использую двойные кавычки в этой функции, PowerShell пытается интерпретировать их как команды, а не строку. Если я использую одинарные кавычки, то все работает нормально.

Я создал немного урезанный образец сценарий powershell, который воспроизводит проблему. Вот фрагмент:

$ScriptBlock = {
    function Test
    {
        $status = "This is a string"
        Write-Output $status
    }
}
Start-Process -FilePath PowerShell -ArgumentList "-NoExit -NoProfile -ExecutionPolicy Bypass -Command & {$ScriptBlock Test}"

Таким образом, в новом процессе PowerShell сначала определяется код в блоке скрипта, а затем вызывается тестовый метод, и он выдает следующую ошибку:

This: термин "This" не распознается как имя командлета, функция, файл сценария или действующая программа. Проверьте правильность написания имя, или если путь был включен, убедитесь, что путь правильный и попробовать еще раз.

Итак он пытается рассматривать строку как запятую, как если бы я только что набрал This is a string сам по себе на новой строке в моем сценарии.

Если я изменю строку

$status = "This is a string"

To

$status = 'This is a string'

Скрипт работает как ожидалось и просто выводит строку This is a string.

Еще одна странная проблема, которую я заметил, заключается в том, что если я не использую переменную, а просто использую:

Write-Output "This is a string"

Затем он выводит каждое слово на отдельной строке следующим образом:

Это

Is

A

Строка

Но если я использую одинарные кавычки, как это:

Write-Output 'This is a string'

Затем он выводит все предложение на одной строке, как и ожидалось.

Кто-нибудь знает, почему PowerShell ведет себя странно в таких ситуациях?

Ответ

Так что, как упоминает Тесселлатингхеклер, решение заключается в том, чтобы обернуть все, что находится в двойных кавычках, в двойные двойные кавычки, одинарные кавычки или вы можете использовать скобки.

Таким образом, в моем примере вы бы изменение:

$status = "This is a string"

К этому:

$status = """This is a string"""

Или вот это:

$status = '"This is a string"'

Или вот это:

$status = {"This is a string"}

Если вы хотите оценить переменную в вашей строке (т. е. увидеть значение переменной), то вам нужно использовать метод двойных кавычек:

$status = """This is a string that evaluates $someVariable"""

Все еще не уверен, является ли это ошибкой или по замыслу, но, по крайней мере, у нас есть обходной путь, так как это устраняет обе проблемы, которые я описал выше.

1 6

1 ответ:

Если я изменю ваш сценарий на

-Command $ScriptBlock

Запустите его, и пусть он откроет новое окно оболочки, а затем запустите

gci function:test | fl 

Чтобы увидеть определение функции в новом окне, показан код

$status = This is a string

С тем же тестом на версии с одной кавычкой он показывает

$status = 'This is a string'

Таким образом, он теряет двойные кавычки. Избавьтесь от них с помощью двойных кавычек

$status = """This is a string"""

И они проходят нормально. Кроме того, хотя scriptblocks-это скомпилированный код, мне кажется, что они встроены в текст, если вы разворачиваете их в строку:

> $s = { "hello" }
> "---$s---"
---"hello"---

Поэтому я думаю, что вы сталкиваетесь с такой проблемой цитирования: PowerShell удаляет двойные кавычки из аргументов командной строки и ответDroj в частности, говоря: "странная вещь в отправке параметров внешним программам заключается в том, что существует дополнительный уровень оценки цитат. Я не знаю, является ли это ошибкой, но я предполагаю, что это не будет изменено, потому что поведение такое же, когда вы используете Start-Process и проходите в аргументы.".

PowerShell разворачивает блок скрипта в виде строки в вашу команду, затем эти одиночные кавычки вокруг строки интерпретируются как параметры в кавычках и удаляются где-то в вызове. Что является либо известной проблемой, либо ошибкой, либо по замыслу, в зависимости от того, как Вы читаете эту связанную статью connect.