次の方法で共有


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

ジェイソン・リー

このトピックでは、ビルドおよびデプロイ プロセスの一部として 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 つのプロジェクト ファイルによって制御されます。1 つは、すべての移行先環境に適用されるビルド命令を含み、1 つは環境固有のビルドと配置の設定を含みます。 ビルド時に、環境固有のプロジェクト ファイルが環境に依存しないプロジェクト ファイルにマージされ、ビルド命令の完全なセットが形成されます。

タスクの概要

自動またはシングルステップのデプロイ プロセスの一環として 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 スクリプトを使用するため、スクリプトを [ソリューションの発行] フォルダーに追加するのが理にかなっています。

Contact Manager の例では、展開プロセスの一部として Windows PowerShell スクリプトを使用するため、スクリプトを [ソリューションの発行] フォルダーに追加するのが理にかなっています。

ソリューション フォルダーの内容は、ソース マテリアルとしてビルド サーバーにコピーされます。 ただし、それらはプロジェクト出力には含まれません。

ビルド サーバーでの 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 がスクリプトに適用する実行ポリシーを指定し、スクリプトの実行を妨げる可能性がある既定の実行ポリシーをオーバーライドできます。 次の引数値から選択できます。

  • [無制限] の値を指定すると、スクリプトが署名されているかどうかに関係なく、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 つ以上のリモート コンピューターに対してスクリプトを実行できます。 スクリプトを実行したローカル コンピューターに結果が返されます。

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' }

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 プロジェクト ファイルを使用して配置プロセスを制御する方法の詳細については、「 プロジェクト ファイル について」および「 ビルド プロセスについて」を参照してください。