Назад | Перейти на главную страницу

Скрипт Powershell запускается в бесконечном цикле при выполнении определенным образом

Я использую поставщик Exec Powershell для Puppet для запуска некоторых сценариев PowerShell. У меня проблема с тем, как он выполняет мой скрипт. Метод выполнения заставляет сценарий запускаться снова и снова. Я вынужден сам убить процесс, но сам скрипт вроде работает нормально.

Мне удалось собрать простой пример и сузить причину.

Действия по воспроизведению

  1. Создайте C: \ резервные копии \ сценарии \ test.ps1 со следующим:

Я почти уверен, что проблема связана с тем, как я выполняю SQLCMD.exe, или с тем, сколько времени требуется для выполнения (около одной секунды)

    $instance = '';
    $latest_output = "Hi";

    $cmd = "sqlcmd.exe -E -S .$instance -h -1 -m 1 -Q `"SET NOCOUNT ON; USE [master]; SELECT @@VERSION;`"";

    $output = [string](cmd.exe /C "$cmd");
    $output = $output.Trim(' ');

    if ($output -eq $latest_output)
    {
        Write-Host "Up to date.";
    }
    else
    {
        Write-Host "Updating...";
    }
  1. Откройте CMD.exe, выполните следующую команду, которая работает как задумано:

    C:\Users\Administrator>powershell.exe -Command C:\backups\scripts\test.ps1
    Updating...
    
    C:\Users\Administrator>
    
  2. Теперь вместо этого выполните такой сценарий, который выполняется бесконечно. Это проблемный синтаксис, который использует поставщик Exec в Puppet:

    C:\Users\Administrator>powershell.exe -Command - < C:\backups\scripts\test.ps1
    Updating...
    Updating...
    Updating...
    Updating...
    
  3. Если я добавлю exit; до конца test.ps1 он выполняется только один раз.

Мой первоначальный вопрос заключался в следующем: как мне этого избежать? Но добавив exit делает это для меня. Единственный оставшийся вопрос: Почему это происходит?

РЕДАКТИРОВАТЬ: Как только вы внесете в сценарий синтаксическую ошибку / исключение (например, пропущенную запятую), сценарий будет выполняться бесконечно, каждый раз выбрасывая исключение. Так что пока exit - обходной путь, он все еще опасен, поскольку не работает с исключениями.

Окружающая среда

Powershell, похоже, чувствителен к тому, что он получает в качестве стандартного ввода (используя <для перенаправления stdin). Он может получать символы, которых не ожидает. Я бы рекомендовал удалить все символы новой строки и сохранить ваш скрипт в блокноте. Итак, ваш сценарий будет выглядеть примерно так:

$instance = ''; $latest_output = "Hi"; $cmd = "etc...

Проведя несколько тестов, я получил разное поведение в зависимости от используемой кодировки, пробелов и символов. Может быть просто путь cmd перенаправляет ввод.

Вы также можете опубликовать свою проблему в кукольный проект PowerShell в гитхабе.

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

На немного несвязанной ноте попробуйте следующее:

$psi = New-Object System.Diagnostics.ProcessStartInfo;
$psi.FileName = "powershell.exe"
$psi.UseShellExecute = $false
$psi.RedirectStandardInput = $true
$p = [System.Diagnostics.Process]::Start($psi)

Нажмите ctrl-c, и вы должны увидеть что-то вроде этого:

PS C:\> PS C:\>

Powershell определенно демонстрирует странное поведение, когда дело доходит до перенаправления ввода.