web-dev-qa-db-ja.com

Powershellスクリプトは、特定の方法で実行されると無限ループで実行されます

Puppet用のExecPowershellプロバイダーを使用して、いくつかのPowerShellスクリプトを実行しています。スクリプトの実行方法に問題があります。実行方法により、スクリプトが何度も実行されます。プロセスを自分で強制終了する必要がありますが、スクリプト自体は正常に実行されているようです。

簡単な例をまとめて、原因を絞り込むことができました。

再現手順

  1. 次のようにC:\ backups\scripts\test.ps1を作成します。

この問題は、SQLCMD.exeの実行方法、または実行にかかる時間(約1秒)に関連していると確信しています

    $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. 代わりに、このようなスクリプトを実行します。このスクリプトは無限に実行されます。これは、PuppetのExecプロバイダーが使用する問題のある構文です。

    C:\Users\Administrator>powershell.exe -Command - < C:\backups\scripts\test.ps1
    Updating...
    Updating...
    Updating...
    Updating...
    
  3. Test.ps1の最後にexit;を追加すると、1回だけ実行されます。

私の最初の質問は、どうすればこれを回避できるかということでした。しかし、exitを追加することでそれが可能になります。残っている唯一の質問は:なぜこれが起こるのですか?

[〜#〜] edit [〜#〜]:構文エラー/例外(コンマの欠落など)をスクリプトに取り込むとすぐに、スクリプトは無限に実行され、毎回例外がスローされます。したがって、exitは回避策ですが、例外に対しては機能しないため、依然として危険です。

環境

  • Windows 2008 R2 Server Standard
  • 高度なサービスを備えたMicrosoftSQL Server Express 10.50.2500
  • Powershell 2.0
2
Geekman

Powershellは、標準入力として受け取るものに敏感であるようです(<を使用してstdinをリダイレクトします)。予期しない文字を受信して​​いる可能性があります。すべての改行を削除し、スクリプトをメモ帳に保存することをお勧めします。したがって、スクリプトは次のようになります。

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

いくつかのテストで、使用するエンコーディング、空白、文字に応じて異なる動作を受け取りました。ちょうどその方法かもしれません cmdリダイレクト 入力。

Githubの powershell puppet project に問題を投稿することもできます。

また、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は、入力リダイレクトに関しては間違いなく奇妙な動作を示します。

2
James Santiago