MSBuild プロジェクト ファイルから Windows PowerShell スクリプトを実行する

作成者: Jason Lee

このトピックでは、ビルドおよびデプロイ プロセスの一部として Windows PowerShell スクリプトを実行する方法について説明します。 スクリプトは、ローカル (つまり、ビルド サーバー) で実行することも、宛先の Web サーバーやデータベース サーバーなど、リモートで実行することもできます。

デプロイ後の Windows PowerShell スクリプトを実行する理由は多数あります。 たとえば、次の操作を行います。

  • カスタム イベント ソースをレジストリに追加します。
  • アップロード用のファイル システム ディレクトリを生成します。
  • ビルド ディレクトリをクリーンアップします。
  • カスタム ログ ファイルにエントリを書き込みます。
  • 新しくプロビジョニングされた Web アプリケーションにユーザーを招待する電子メールを送信します。
  • 適切なアクセス許可を持つユーザー アカウントを作成します。
  • SQL Server インスタンス間のレプリケーションを構成します。

このトピックでは、Microsoft ビルド エンジン (MSBuild) プロジェクト ファイルのカスタム ターゲットから、ローカルとリモートの両方で Windows PowerShell スクリプトを実行する方法について説明します。

このトピックは、Fabrikam, Inc. という架空の会社のエンタープライズ配置要件を題材にしたチュートリアル シリーズの一部です。このシリーズでは、サンプル ソリューション (Contact Manager ソリューション) を使用して、現実的なレベルの複雑さを持った、ASP.NET MVC 3 アプリケーション、Windows Communication Foundation (WCF) サービス、データベース プロジェクトなどを含んだ Web アプリケーションを取り上げます。

これらのチュートリアルの核心である配置方法は、「プロジェクト ファイルについて」で説明した分割プロジェクト ファイルのアプローチを基にして、ビルド プロセスを 2 つのプロジェクト ファイル (すべての配置先環境に適用されるビルド命令を含んだファイルと、環境に特化したビルド設定や配置設定を含んだファイル) で制御するものになっています。 ビルド時には、環境に特化したプロジェクト ファイルが環境に依存しないプロジェクト ファイルにマージされ、ビルド命令の完全なセットが形成されます。

タスクの概要

自動または単一ステップのデプロイ プロセスの一環として Windows PowerShell スクリプトを実行するには、次の高レベル タスクを完了する必要があります。

  • ソリューションとソース管理に Windows PowerShell スクリプトを追加します。
  • Windows PowerShell スクリプトを呼び出すコマンドを作成します。
  • コマンド内の予約済み XML 文字をエスケープします。
  • カスタム MSBuild プロジェクト ファイルにターゲットを作成し、Exec タスクを使用してコマンドを実行します。

このトピックでは、これらの手順を実行する方法について説明します。 このトピックのタスクとチュートリアルでは、読者が MSBuild のターゲットとプロパティを既に理解していることと、カスタム MSBuild プロジェクト ファイルを使用してビルドとデプロイ プロセスを実行する方法を理解していることを前提としています。 詳細については、「プロジェクト ファイル について」および「ビルド プロセスについて」を参照してください。

Windows PowerShell スクリプトの作成と追加

このトピックのタスクでは、LogDeploy.ps1 という名前のサンプル Windows PowerShell スクリプトを使用して、MSBuild からスクリプトを実行する方法を説明します。 LogDeploy.ps1 スクリプトには、ログ ファイルに 1 行のエントリを書き込む単純な関数が含まれています。

function LogDeployment
{
  param([string]$filepath,[string]$deployDestination)
  $datetime = Get-Date
  $filetext = "Deployed package to " + $deployDestination + " on " + $datetime
  $filetext | Out-File -filepath $filepath -Append
}

LogDeployment $args[0] $args[1]

LogDeploy.ps1 スクリプトは、2 つのパラメーターを受け入れます。 最初のパラメーターは、エントリを追加するログ ファイルへの完全なパスを表し、2 番目のパラメーターは、ログ ファイルに記録するデプロイ先を表します。 スクリプトを実行すると、次の形式の行がログ ファイルに追加されます。

Deployed package to TESTWEB1 on 02/11/2012 09:28:18

LogDeploy.ps1 スクリプトを MSBuild で使用できるようにするには、次の操作を行う必要があります。

  • スクリプトをソース管理に追加します。
  • Visual Studio 2010 でソリューションにスクリプトを追加します。

ビルド サーバーとリモート コンピューターのどちらでスクリプトを実行する予定でも、ソリューション コンテンツを含むスクリプトをデプロイする必要はありません。 1 つの方法としては、ソリューション フォルダーにスクリプトを追加します。 Contact Manager の例では、デプロイ プロセスの一部として Windows PowerShell スクリプトを使用するため、スクリプトを Publish ソリューション フォルダーに追加するのが理にかなっています。

In the Contact Manager example, because you want to use the Windows PowerShell script as part of the deployment process, it makes sense to add the script to the Publish solution folder.

ソリューション フォルダーのコンテンツは、ソース素材としてビルド サーバーにコピーされます。 ただし、これによりプロジェクト出力が形成されることはありません。

ビルド サーバーでの Windows PowerShell スクリプトの実行

一部のシナリオでは、プロジェクトのビルドに使うコンピューターで Windows PowerShell スクリプトを実行することがあります。 たとえば、Windows PowerShell スクリプトを使用してビルド フォルダーをクリーンアップしたり、カスタム ログ ファイルにエントリを書き込んだりする場合があります。

構文に関しては、MSBuild プロジェクト ファイルから Windows PowerShell スクリプトを実行することは、通常のコマンド プロンプトから Windows PowerShell スクリプトを実行する場合と同じです。 実行可能ファイル powershell.exe を呼び出し、–command スイッチを使用して、Windows PowerShell で実行するコマンドを指定する必要があります。 (Windows PowerShell v2 では、–file スイッチを 使用することもできます)。 コマンドの形式は次のとおりです。

powershell.exe –command "& { [Path to script] 'parameter1' 'parameter2' ... }"

次に例を示します。

powershell.exe –command 
  "& { C:\LogDeploy.ps1 'C:\DeployLogs\log.txt' 'TESTWEB1' }"

スクリプトへのパスにスペースが含まれている場合は、そのファイル パスを、アンパサンドを前に付けた一重引用符で囲む必要があります。 二重引用符は、コマンドを囲むのに既に使用しているため、使用できません。

powershell.exe –command 
  "& { &'C:\Path With Spaces\LogDeploy.ps1' 
        'C:\Path With Spaces\log.txt' 
        'TESTWEB1' }"

MSBuild からこのコマンドを呼び出すときには、他にもいくつかの考慮事項があります。 まず、スクリプトが黙示的に実行されるように、–NonInteractive フラグを含める必要があります。 次に、–ExecutionPolicy フラグを適切な引数値と共に含める必要があります。 これで Windows PowerShell がスクリプトに適用する実行ポリシーを指定し、スクリプトの実行を妨げる可能性がある既定の実行ポリシーをオーバーライドできます。 次の引数値から選択できます。

  • Unrestricted を指定すると、スクリプトが署名されているかどうかに関係なく、Windows PowerShell でスクリプトを実行できます。
  • RemoteSigned を指定すると、Windows PowerShell はローカル コンピューターで作成された署名されていないスクリプトを実行できます。 ただし、他の場所で作成されたスクリプトは署名する必要があります。 (実際には、ビルド サーバー上で Windows PowerShell スクリプトをローカルに作成することになる可能性は非常に低いです)。
  • AllSigned を指定すると、Windows PowerShell は署名付きスクリプトのみを実行できます。

既定の実行ポリシーは Restricted であり、Windows PowerShell でスクリプト ファイルを実行できません。

最後に、Windows PowerShell コマンドで発生する予約済み XML 文字をすべてエスケープする必要があります。

  • 単一引用符を ' に置き換えます;

  • 二重引用符を " に置き換えます;

  • アンパサンドを & に置き換えます;

  • これらの変更を行うと、コマンドは次のようになります;

powershell.exe –NonInteractive –ExecutionPolicy Unrestricted 
               –command "& { &'[Path to script]' 
                        '[parameter1]' 
                        '[parameter2]' } "

カスタム MSBuild プロジェクト ファイル内で、新しいターゲットを作成し、Exec タスクを使用して次のコマンドを実行します。

<Target Name="WriteLogEntry" Condition=" '$(WriteLogEntry)'!='false' ">
  <PropertyGroup>
    <PowerShellExe Condition=" '$(PowerShellExe)'=='' "> 
      %WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe
    </PowerShellExe>
    <ScriptLocation Condition=" '$(ScriptLocation)'=='' ">
      C:\Path With Spaces\LogDeploy.ps1
    </ScriptLocation>
    <LogFileLocation Condition=" '$(LogFileLocation)'=='' ">
      C:\Path With Spaces\ContactManagerDeployLog.txt
    </LogFileLocation>
  </PropertyGroup>
  <Exec Command="$(PowerShellExe) -NonInteractive -executionpolicy Unrestricted 
                 -command &quot;&amp; { 
                          &amp;&apos;$(ScriptLocation)&apos; 
                          &apos;$(LogFileLocation)&apos; 
                          &apos;$(MSDeployComputerName)&apos;} &quot;" />
</Target>

この例では、次の点に注意してください。

  • パラメーター値や Windows PowerShell 実行可能ファイルの場所などの変数は、MSBuild プロパティとして宣言されています。
  • ユーザーがコマンド ラインからこれらの値をオーバーライドできるようにするための条件が含まれています。
  • MSDeployComputerName プロパティは、プロジェクト ファイル内の別の場所で宣言されています。

ビルド プロセスの一環としてこのターゲットを実行すると、Windows PowerShell がコマンドを実行し、指定したファイルにログ エントリが書き込まれます。

リモート コンピューターでの Windows PowerShell スクリプトの実行

Windows PowerShell は、Windows リモート管理 (WinRM) を使用してリモート コンピューターでスクリプトを実行できます。 これを行うには、Invoke-Command コマンドレットを使用する 必要があります。 これにより、スクリプトをリモート コンピューターにコピーしなくても、1 つ以上のリモート コンピューターに対してスクリプトを実行できます。 スクリプトを実行したローカル コンピューターに結果が返されます。

Note

Invoke-Command コマンドレットを 使用してリモート コンピューターで Windows PowerShell スクリプトを実行する前に、WinRM リスナーをリモート メッセージを受け入れるように構成する必要があります。 これを行うには、リモート コンピューターでコマンド winrm quickconfig を実行します。 詳細については、「Windows リモート管理のためのインストールと構成」をご覧ください

Windows PowerShell ウィンドウでは、次の構文を使用して、リモート コンピューターで LogDeploy.ps1 スクリプトを実行 します。

Invoke-Command –ComputerName 'REMOTESERVER1' 
               –ScriptBlock { &"C:\Path With Spaces\LogDeploy.ps1"
                               'C:\Path With Spaces\Log.txt'
                               'TESTWEB1' }

Note

Invoke-Command を 使用して スクリプト ファイルを実行する方法は他に何種類かありますが、パラメーター値を指定し、スペースを使用してパスを管理する必要がある場合は、この方法が最も簡単です。

コマンド プロンプトからこれを実行する場合は、Windows PowerShell 実行可能ファイルを呼び出し、–command パラメーターを 使用して手順を指定する必要があります。

powershell.exe –command 
  "& {Invoke-Command –ComputerName 'REMOTESERVER1' 
                     –ScriptBlock { &'C:\Path With Spaces\LogDeploy.ps1'
                                     'C:\Path With Spaces\Log.txt'
                                     'TESTWEB1' } "

前と同様に、MSBuild からコマンドを実行するには、いくつかの追加のスイッチを指定し、予約済みの XML 文字をエスケープする必要があります。

powershell.exe -NonInteractive -executionpolicy Unrestricted 
               -command &quot;&amp; Invoke-Command 
                 –ComputerName &apos;REMOTESERVER1&apos;
                 -ScriptBlock { &amp;&apos;C:\Path With Spaces\LogDeploy.ps1&apos; 
                                &apos; C:\Path With Spaces\Log.txt &apos;  
                                &apos;TESTWEB1&apos; } &quot;

最後に、前と同様に、カスタム MSBuild ターゲット内で Exec タスクを使用してコマンドを実行します。

<Target Name="WriteLogEntry" Condition=" '$(WriteLogEntry)'!='false' ">
  <PropertyGroup>
    <PowerShellExe Condition=" '$(PowerShellExe)'=='' "> 
      %WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe
    </PowerShellExe>
    <ScriptLocation Condition=" '$(ScriptLocation)'=='' ">
      C:\Path With Spaces\LogDeploy.ps1
    </ScriptLocation>
    <LogFileLocation Condition=" '$(LogFileLocation)'=='' ">
      C:\Path With Spaces\ContactManagerDeployLog.txt
    </LogFileLocation>
  </PropertyGroup>
  <Exec Command="$(PowerShellExe) -NonInteractive -executionpolicy Unrestricted 
                 -command &quot;&amp; invoke-command -scriptblock { 
                          &amp;&apos;$(ScriptLocation)&apos; 
                          &apos;$(LogFileLocation)&apos;  
                          &apos;$(MSDeployComputerName)&apos;}
                          &quot;"/>  
</Target>

ビルド プロセスの一環としてこのターゲットを実行すると、Windows PowerShell が –computername 引数で指定したコンピューターでスクリプトを実行します。

まとめ

このトピックでは、MSBuild プロジェクト ファイルから Windows PowerShell スクリプトを実行する方法について説明します。 この方法を使用すると、自動または単一ステップのビルドとデプロイ プロセスの一環として、ローカルまたはリモート コンピューターで Windows PowerShell スクリプトを実行できます。

もっと読む

Windows PowerShell スクリプトへの署名と実行ポリシーの管理に関するガイダンスについては、「Windows PowerShell スクリプトの実行」を参照してください。 リモート コンピューターからの Windows PowerShell コマンドの実行に関するガイダンスについては、「リモート コマンドの実行」を参照してください。

カスタム MSBuild プロジェクト ファイルを使用して配置プロセスを制御する方法の詳細については、「プロジェクト ファイルについて」および「ビルド処理について理解する」を参照してください。