共用方式為


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

演講者:Jason Lee

本主題介紹如何在建置和部署程序中執行 Windows PowerShell 指令碼。 您可以在本機 (即在建置伺服器上) 或遠端 (例如在目標 Web 伺服器或資料庫伺服器上) 執行指令碼。

您可能想要執行部署後 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 將應用於您的指令碼的執行策略,並允許您覆寫預設執行策略,這可能會阻止指令碼的執行。 您可以從以下參數值中進行選擇:

  • 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 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 專案檔案控制部署程序的詳細資訊,請參閱了「解專案檔案」和「了解建置程序」。