﻿# 如何在 Azure Pipelines 使用 MSDeploy 部署任意檔案到 App Service 站台

我之前有在 [使用 MSDeploy 部署一個在 Private Link 封閉網路環境下的 Function App](/post/2021/06/29/MSDeploy-to-Azure-Function-App-with-Private-Link-VNet) 文章中分享透過 MSDeploy 部署到任意網站的方法。今天這篇文章我則是要來分享如何在只有 **發行設定檔** (Publish Profile) 的情況且沒有任何 Azure 訂用帳戶權限的情況下，如何順利透過 Azure Pipelines 的 Hosted Agent 將檔案發佈到 Azure App Service 任意站台下。

這裡我將會用到 [Download secure file](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/download-secure-file?view=azure-devops&WT.mc_id=DT-MVP-4015686) 將較為機密的 **發行設定檔** (Publish Profile) 加入到一個安全的地方保存，即便複製到你自己管理的 Agent 上，這個 Task 也會在 Pipelines 結束的時候自動刪除該檔案，確保敏感資料不會殘留在主機上！👍

以下是設定步驟：

1.  設定一個 [Download secure file](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/download-secure-file?view=azure-devops&WT.mc_id=DT-MVP-4015686) 工作，並上傳 `yoursite.PublishSettings` 發行設定檔
    
    請務必設定 `Output Variables` 底下的 `Reference name` 欄位，可輸入 `PublishSettings` 當作參考名稱
    
2.  設定一個 [Download secure file](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/download-secure-file?view=azure-devops&WT.mc_id=DT-MVP-4015686) 工作，並上傳 [ConvertFrom-XML.ps1](https://github.com/Phil-Factor/PowerShell-Utility-Cmdlets/blob/main/ConvertFrom-XML/ConvertFrom-XML.ps1) 函式 (function)
    
    請務必設定 `Output Variables` 底下的 `Reference name` 欄位，可輸入 `ConvertFromXML` 當作參考名稱
    
    > 我主要是不太想在原始碼版控中特別加上一個 `ConvertFrom-XML.ps1` 檔案，所以透過 **Download secure file** 工作來管理此檔案。
    
3.  設定一個 [PowerShell](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/powershell?view=azure-devops&WT.mc_id=DT-MVP-4015686) 工作
    
    你可以利用 `$(ConvertFromXML.secureFilePath)` 來取得 [ConvertFrom-XML.ps1](https://github.com/Phil-Factor/PowerShell-Utility-Cmdlets/blob/main/ConvertFrom-XML/ConvertFrom-XML.ps1) 的實際路徑。
    
    你可以利用 `$(PublishSettings.secureFilePath)` 來取得 **發行設定檔** 的實際路徑。
    
    ```powershell
    . $(ConvertFromXML.secureFilePath)
    
    # 先從 Azure App Service 取得發行設定檔 (Publish Profile)
    $PublishProfile = '$(PublishSettings.secureFilePath)'
    
    # 利用 ConvertFrom-XML.ps1 將 XML 轉為 DictionaryEntry 物件
    $WebDeployProfiles = ([xml[]] (Get-Content -Raw $PublishProfile) | ConvertFrom-Xml).publishProfile
    
    # 篩選出 publishMethod 為 MSDeploy 的資訊
    For ($i=0; $i -lt $WebDeployProfiles.Count; $i++) {
      If ($WebDeployProfiles[$i].publishMethod -eq 'MSDeploy') {
        $publishUrl   = $WebDeployProfiles[$i].publishUrl
        $msdeploySite = $WebDeployProfiles[$i].msdeploySite
        $userName     = $WebDeployProfiles[$i].userName
        $userPWD      = $WebDeployProfiles[$i].userPWD
      }
    }
    
    # 這裡要設定你實際想要部署到遠端站台的來源路徑
    $sourcePath = '$(System.DefaultWorkingDirectory)/yoursite-CI/drop'
    
    # 我這裡假設你的 app_offline.template.htm 是 CI 的時候自動產生的
    # 你當然也可以透過 Download secure file 上傳一個 app_offline.htm 檔案
    $appOffline = $sourcePath + '\app_offline.template.htm'
    
    # 部署 app_offline.htm 站台離線檔，避免 DLL 檔案被鎖定導致無法更版
    . "C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:contentPath=$appOffline -dest:contentPath=`"$msdeploySite/app_offline.htm`",computerName=`"https://$publishUrl/msdeploy.axd?site=$msdeploySite`",userName=`"$userName`",password=`"$userPWD`",authtype=`"Basic`",includeAcls=`"False`"
    
    # 實際進行部署動作，最多重試 10 次！
    . "C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:contentPath=$sourcePath -dest:contentPath=`"$msdeploySite`",computerName=`"https://$publishUrl/msdeploy.axd?site=$msdeploySite`",userName=`"$userName`",password=`"$userPWD`",authtype=`"Basic`",includeAcls=`"False`" -retryAttempts:10 -retryInterval:3000 -enableRule:DoNotDeleteRule
    
    # 移除 app_offline.htm 站台離線檔，讓網站恢復連線
    . "C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:delete -dest:contentPath=$msdeploySite/app_offline.htm,computerName=`"https://$publishUrl/msdeploy.axd?site=$msdeploySite`",userName=`"$userName`",password=`"$userPWD`",authtype=`"Basic`",includeAcls=`"False`"
    ```
    

### 相關連結

-   [ConvertFrom-XML: a PowerShell utility Cmdlet](https://www.red-gate.com/simple-talk/blogs/convert-from-xml/)
-   [azure devops: copy file to artifact folder to access in release pipeline - Stack Overflow](https://stackoverflow.com/a/63025968/910074)
-   [Download Secure File task - Azure Pipelines | Microsoft Docs](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/download-secure-file?view=azure-devops&WT.mc_id=DT-MVP-4015686)
