從 MSBuild 專案檔執行 Windows PowerShell 指令碼

作者 :Jason Lee

本主題描述如何在建置和部署程式中執行 Windows PowerShell 腳本。 您可以在本機 (執行腳本,換句話說,在組建伺服器上) 或遠端執行,例如目的地網頁伺服器或資料庫伺服器。

您可能想要執行部署後 Windows PowerShell 腳本的原因有很多。 例如,您可能要:

  • 將自訂事件來源新增至登錄。
  • 產生上傳的文件系統目錄。
  • 清除組建目錄。
  • 將專案寫入自訂記錄檔。
  • 將邀請使用者的電子郵件傳送至新布建的 Web 應用程式。
  • 建立具有適當許可權的用戶帳戶。
  • 設定 SQL Server 實例之間的複寫。

本主題將示範如何在 Microsoft Build Engine (MSBuild) 項目檔中,從本機和遠端執行 Windows PowerShell 腳本。

本主題以名為 Fabrikam, Inc 的虛構公司企業部署需求為基礎,形成一系列教學課程的一部分。本教學課程系列使用範例解決方案聯繫人 管理員解決方案來代表具有實際複雜程度的 Web 應用程式,包括 ASP.NET MVC 3 應用程式、Windows Communication Foundation (WCF) 服務和資料庫專案。

這些教學課程的核心部署方法是以 了解項目檔中所述的分割項目檔方法為基礎,其中建置程式是由兩個專案檔控制,一個包含適用於每個目的地環境的建置指示,另一個包含環境特定的組建和部署設定。 在建置階段,環境特定的專案檔會合併到與環境無關的項目檔中,以形成一組完整的建置指示。

工作概觀

若要在自動化或單一步驟部署程式中執行 Windows PowerShell 腳本,您必須完成這些高階工作:

  • 將 Windows PowerShell 文稿新增至您的解決方案和原始檔控制。
  • 建立會叫用 Windows PowerShell 腳本的命令。
  • 逸出命令中的任何保留 XML 字元。
  • 在自定義 MSBuild 項目檔中建立目標,並使用 Exec 工作來執行命令。

本主題將示範如何執行這些程式。 本主題中的工作和逐步解說假設您已熟悉 MSBuild 目標和屬性,並瞭解如何使用自定義 MSBuild 專案檔來驅動建置和部署程式。 如需詳細資訊,請參閱 瞭解專案檔瞭解建置程式

建立和新增 Windows PowerShell 腳本

本主題中的工作會使用名為LogDeploy.ps1的範例 Windows PowerShell 腳本,說明如何從 MSBuild 執行腳本。 LogDeploy.ps1 文稿包含簡單的函式,會將單行專案寫入記錄檔:

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 腳本接受兩個參數。 第一個參數代表您要新增專案之記錄檔的完整路徑,而第二個參數則代表您要記錄在記錄檔中的部署目的地。 當您執行文稿時,它會以下列格式將一行新增至記錄檔:

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

若要讓 LogDeploy.ps1 腳本可供 MSBuild 使用,您需要:

  • 將腳本新增至原始檔控制。
  • 在 Visual Studio 2010 中將腳本新增至您的方案。

不論您打算在組建伺服器或遠端電腦上執行腳本,您都不需要使用解決方案內容來部署腳本。 其中一個選項是將腳本新增至方案資料夾。 在聯繫人管理員範例中,因為您想要使用 Windows PowerShell 腳本作為部署程式的一部分,所以將腳本新增至 [發佈方案] 資料夾是合理的做法。

在聯繫人管理員範例中,因為您想要使用 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 字元:

  • 將單引號取代為 apos&;

  • &引號取代雙引號;

  • 將連字元取代為 &

  • 當您進行這些變更時,您的命令會像這樣:

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 Cmdlet。 這可讓您對一或多部遠端電腦執行腳本,而不需將腳本複製到遠端計算機。 任何結果會傳回您執行腳本的本機計算機。

注意

在使用 Invoke-Command Cmdlet 在遠端電腦上執行 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 專案檔來控制部署程式的詳細資訊,請參閱 瞭解專案檔瞭解建置程式