共用方式為


Windows 的自訂指令碼延伸模組

「自訂指令碼延伸模組」會在 Azure 虛擬機器 (VM) 上下載並執行指令碼。 使用此延伸模組對部署後設定、軟體安裝或其他任何設定或管理工作。 您可以從 Azure 儲存體或 GitHub 下載指令碼,或是在擴充功能執行階段將指令碼提供給 Azure 入口網站。

自訂指令碼功能可以與 Azure Resource Manager 範本整合。 您也可以使用 Azure CLI、Azure PowerShell、Azure 入口網站或 Azure 虛擬機器 REST API 來執行。

本文說明如何使用 Azure PowerShell 模組和 Azure Resource Manager 範本,來使用自訂指令碼延伸模組。 也提供 Windows 系統的疑難排解步驟。

附註

試試 VM assist 快速診斷。 建議您執行 適用於 Windows 的 VM 協助適用於 Linux 的 VM 協助。 這些腳本型診斷工具可協助您識別影響 Azure VM 客體代理程式和整體 VM 健康情況的常見問題。

先決條件

附註

請勿使用自訂指令碼延伸模組以相同的 VM 執行 Update-AzVM 作為其參數。 延伸模組會等候其本身。

支援的 Windows 作業系統

操作系統版本 x64 ARM64
Windows 10 支援 支援
Windows 11 支援 支援
Windows 伺服器 2016 支援 支援
Windows Server 2016 核心 支援 支援
Windows 伺服器 2019 支援 支援
Windows Server 2019 核心 支援 支援
Windows 伺服器 2022 支援 支援
Windows Server 2022 核心 支援 支援
Windows 伺服器 2025 支援 支援
Windows Server 2025 核心版 支援 支援

指令碼位置

您可以將延伸模組設定為使用 Azure Blob 儲存體認證,以便能存取 Azure Blob 儲存體。 指令碼可以位於任何位置,前提是 VM 可以路由傳送至該端點 (例如,GitHub 或內部檔案伺服器)。

網際網路連線

若要從外部 (例如從 GitHub 或 Azure 儲存體) 下載指令碼,您需要開啟其他防火牆或網路安全性群組 (NSG) 連接埠。 舉例來說,如果您的指令碼位於 Azure 儲存體,則可以允許使用 Azure NSG 適用於儲存體的服務標籤進行存取。

自訂指令碼延伸模組沒有任何方法可略過憑證驗證。 如果您要從安全位置下載 (例如自我簽署憑證),您可能會收到像是根據驗證程序,遠端憑證無效的錯誤。 請確定憑證已正確安裝在 VM 上的信任的根憑證授權單位存放區中。

如果您的指令碼位於本機伺服器上,您可能仍需要開啟其他防火牆或 NSG 連接埠。

提示

  • 輸出僅限於最後 4,096 個位元組。
  • 正確逸出字元有助於確保正確剖析字串。 例如,處理檔案路徑時,您一律需要兩個反斜線來逸出單一常值反斜線。 範例: {"commandToExecute": "C:\\Windows\\System32\\systeminfo.exe >> D:\\test.txt"}
  • 此擴充功能的最高失敗率導因於指令碼中的語法錯誤。 確認指令碼執行無誤。 將更多的記錄放入指令碼,以便於更容易找到失敗問題。
  • 撰寫具有等冪性的指令碼,這樣即使意外執行多次也不會導致系統變更。
  • 確保在指令碼執行時,不需要使用者輸入。
  • 指令碼可執行 90 分鐘。 任何過長的內容都會導致延伸模組佈建失敗。
  • 請勿將重新啟動置於指令碼內。 此動作會導致正在安裝的其他延伸模組發生問題,而且在重新啟動後延伸模組不會繼續運作。
  • 如果您的指令碼在安裝應用程式和執行指令碼之前會導致重新啟動,請使用 Windows 排程工作或 DSC、Chef 或 Puppet 等延伸模組來排程重新啟動。
  • 請勿執行會導致 VM 代理程式停止或更新的指令碼。 它可能會讓延伸模組處於過渡的狀態,並導致逾時。
  • 延伸模組只會執行一次指令碼。 如果您想要在每次啟動時執行指令碼,請使用擴充功能建立 Windows 排程工作。
  • 如果您想要排程指令碼的執行時間,請使用延伸模組來建立 Windows 排程工作。
  • 當指令碼正在執行時,您只能從 Azure 入口網站或 Azure CLI 看到正在過渡的延伸模組狀態。 如果您想要更頻繁地查看正在執行的指令碼的狀態更新,請建立自己的解決方案。
  • 自訂指令碼延伸模組原生不支援 Proxy 伺服器。 不過,您可以在指令碼中使用支援 Proxy 伺服器的檔案傳輸工具 (例如 Invoke-WebRequest)。
  • 請注意指令碼或命令可能依賴的非預設目錄位置。 有邏輯可以處理此情況。
  • 請確定您在登錄機碼 HKLM\SOFTWARE\Microsoft\Command Processor\AutoRun 中沒有任何自訂設定 (詳情在此處)。 這會在自訂指令碼延伸模組安裝或啟用階段期間觸發,並導致像 'XYZ is not recognized as an internal or external command, operable program or batch file' 一樣的錯誤。
  • 自訂指令碼延伸模組會在 LocalSystem 帳戶下執行。
  • 如果您打算使用 storageAccountNamestorageAccountKey 屬性,這些屬性必須共置在 protectedSettings 中。
  • 您只能將一個延伸模組版本套用至 VM。 若要執行第二個自訂指令碼,您可以使用新設定,更新現有延伸模組。 或者,您也可以移除自訂指令碼延伸模組,並使用更新的指令碼來重新套用它

擴充功能結構描述

「自訂指令碼擴充功能」組態會指定指令碼位置和要執行命令等項目。 您可將此組態儲存在組態檔中、在命令列中指定組態,或在 Azure Resource Manager 範本中指定組態。

您可將敏感性資料儲存在受保護的組態中,此組態會經過加密,並且只會在 VM 內解密。 當執行命令包含密碼或共用存取簽章 (SAS) 檔案參考等祕密時,受保護的組態很有用。 以下是範例:

{
    "apiVersion": "2018-06-01",
    "type": "Microsoft.Compute/virtualMachines/extensions",
    "name": "virtualMachineName/config-app",
    "location": "[resourceGroup().location]",
    "dependsOn": [
        "[concat('Microsoft.Compute/virtualMachines/', variables('vmName'),copyindex())]",
        "[variables('musicstoresqlName')]"
    ],
    "tags": {
        "displayName": "config-app"
    },
    "properties": {
        "publisher": "Microsoft.Compute",
        "type": "CustomScriptExtension",
        "typeHandlerVersion": "1.10",
        "autoUpgradeMinorVersion": true,
        "settings": {
            "timestamp":123456789
        },
        "protectedSettings": {
            "commandToExecute": "myExecutionCommand",
            "storageAccountName": "myStorageAccountName",
            "storageAccountKey": "myStorageAccountKey",
            "managedIdentity" : {},
            "fileUris": [
                "script location"
            ]
        }
    }
}

附註

managedIdentity 屬性「不得」storageAccountNamestorageAccountKey 屬性搭配使用。

VM 上一次只能安裝一個擴充功能版本。 在相同 Azure Resource Manager 範本中針對相同 VM 指定自訂指令碼兩次將會失敗。

您可以在 VM 資源內使用此結構描述,也可以將此結構描述作為獨立資源。 如果將此擴充功能作為 Azure Resource Manager 範本中的標準資源,則資源名稱的格式必須是 virtualMachineName/extensionName

屬性值

名稱 值或範例 資料類型
apiVersion 2018-06-01 date
發行者 Microsoft.Compute 字串
型別 CustomScriptExtension 字串
typeHandlerVersion 1.10 整數 (int)
fileUris https://raw.githubusercontent.com/Microsoft/dotnet-core-sample-templates/master/dotnet-core-music-windows/scripts/configure-music-app.ps1 陣列
時間戳記 123456789 32 位元整數
commandToExecute powershell -ExecutionPolicy Unrestricted -File configure-music-app.ps1 字串
儲存帳戶名稱 examplestorageacct 字串
存儲帳戶密鑰 TmJK/1N3AbAZ3q/+hOXoi/l73zOqsaxXDhqa9Y83/v5UpXQp2DQIBuv2Tifp60cE/OaHsJZmQZ7teQfczQj8hg== 字串
managedIdentity { }{ "clientId": "00001111-aaaa-2222-bbbb-3333cccc4444" }{ "objectId": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" } JSON 物件

附註

這些屬性名稱會區分大小寫。 為了避免發生部署問題,請使用如下所示的名稱。

屬性值詳細資料

屬性 選擇性或必要 詳細資料
fileUris 選用 要下載的 URL 或檔案。 如果 URL 是敏感性的,例如包含金鑰,則這個欄位應該在 protectedSettings 中指定。
commandToExecute 必要 要執行的進入點指令碼。 如果您的命令包含祕密 (例如密碼),或您的檔案 URI 是敏感資料,請改用此屬性。
時間戳記 選用 只在觸發重新執行指令碼的情況下,變更此值。 只要與先前的值不同,任何整數值都可接受。
儲存帳戶名稱 選用 儲存體帳戶的名稱。 如果您指定儲存體認證,則所有 fileUris 值都必須是 Azure Blob 的 URL。
存儲帳戶密鑰 選用 儲存體帳戶的存取金鑰。
managedIdentity 選用 用於下載檔案的受控識別。 有效值為 clientId (選用、字串),這是受控識別的用戶端識別碼,而 objectId (選用、字串),這是受控識別的物件識別碼。

公開設定會以純文字格式,傳送到執行指令碼所在的 VM。 受保護的設定會透過只有 Azure 和 VM 知道的金鑰加密。 設定會以傳送時的形式,儲存至 VM。 也就是說,如果設定經加密,會以加密形式儲存在 VM 上。 用來解密加密值的憑證會儲存在 VM 上。 此憑證也會用來在執行階段解密設定,如有需要。

使用公開設定可能有助於偵錯,但是建議您使用受保護的設定。

您可以在公用或受保護的設定中設定下列值。 延伸模組會拒絕任何在公用和受保護的設定中設定下列值的設定。

  • commandToExecute
  • fileUris

屬性:managedIdentity

附註

必須在受保護的設定中,才能指定此屬性。

自訂指令碼延伸模組,1.10 版和更新版本支援受控識別,從 fileUris 設定中提供的 URL 下載檔案。 屬性可讓自訂指令碼延伸模組存取 Azure 儲存體私人 Blob 或容器,而不需要使用者傳遞 SAS 權杖或儲存體帳戶金鑰之類的祕密。

附註

自訂指令碼延伸模組目前不支援在已啟用 Azure Arc 的伺服器上使用受控識別驗證。

若要使用這項功能,將系統指派使用者指派的身分識別,新增至預期執行自訂指令碼延伸模組的 VM 或虛擬機器擴展集。 然後將受控識別存取權授與 Azure 儲存體容器或 Blob

若要在目標 VM 或虛擬機器擴展集上,使用系統指派的身分識別,請將 managedidentity 設定為空白 JSON 物件。

{
  "fileUris": ["https://mystorage.blob.core.windows.net/privatecontainer/script1.ps1"],
  "commandToExecute": "powershell.exe script1.ps1",
  "managedIdentity" : {}
}

若要在目標 VM 或虛擬機器擴展集上,使用使用者指派的身分識別,請使用受控識別的用戶端識別碼或物件識別碼設定 managedidentity

{
  "fileUris": ["https://mystorage.blob.core.windows.net/privatecontainer/script1.ps1"],
  "commandToExecute": "powershell.exe script1.ps1",
  "managedIdentity" : { "clientId": "00001111-aaaa-2222-bbbb-3333cccc4444" }
}
{
  "fileUris": ["https://mystorage.blob.core.windows.net/privatecontainer/script1.ps1"],
  "commandToExecute": "powershell.exe script1.ps1",
  "managedIdentity" : { "objectId": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" }
}

附註

managedIdentity 屬性「不得」storageAccountNamestorageAccountKey 屬性搭配使用。

範本部署

您可以使用 Azure Resource Manager 範本部署 Azure VM 延伸模組。 上一節詳述的 JSON 結構描述可以用於 Azure Resource Manager 範本,在部署範本期間執行自訂指令碼延伸模組。 下列範例會說明如何使用「自訂指令碼延伸模組」:

PowerShell 部署

您可以使用 Set-AzVMCustomScriptExtension 命令,將「自訂指令碼延伸模組」新增至現有的虛擬機器。 如需詳細資訊,請參閱 Set-AzVMCustomScriptExtension

Set-AzVMCustomScriptExtension -ResourceGroupName <resourceGroupName> `
    -VMName <vmName> `
    -Location myLocation `
    -FileUri <fileUrl> `
    -Run 'myScript.ps1' `
    -Name DemoScriptExtension

範例

使用多個指令碼

在此範例中,使用三個指令碼來建置伺服器。 commandToExecute 屬性會呼叫第一個指令碼。 接著您可以選擇其他指令碼的呼叫方式。 例如,您可以擁有負責控制執行的前置指令碼,其中包含正確的錯誤處理、記錄和狀態管理。 指令碼會下載到本機電腦執行。

例如,在 1_Add_Tools.ps1 中,您會藉由將 新增至指令碼來呼叫 .\2_Add_Features.ps1。 針對在 $settings 中定義的其他指令碼重複這個程序。

$fileUri = @("https://xxxxxxx.blob.core.windows.net/buildServer1/1_Add_Tools.ps1",
"https://xxxxxxx.blob.core.windows.net/buildServer1/2_Add_Features.ps1",
"https://xxxxxxx.blob.core.windows.net/buildServer1/3_CompleteInstall.ps1")

$settings = @{"fileUris" = $fileUri};

$storageAcctName = "xxxxxxx"
$storageKey = "1234ABCD"
$protectedSettings = @{"storageAccountName" = $storageAcctName; "storageAccountKey" = $storageKey; "commandToExecute" = "powershell -ExecutionPolicy Unrestricted -File 1_Add_Tools.ps1"};

#run command
Set-AzVMExtension -ResourceGroupName <resourceGroupName> `
    -Location <locationName> `
    -VMName <vmName> `
    -Name "buildserver1" `
    -Publisher "Microsoft.Compute" `
    -ExtensionType "CustomScriptExtension" `
    -TypeHandlerVersion "1.10" `
    -Settings $settings `
    -ProtectedSettings $protectedSettings;

從本機共用執行指令碼

在此範例中,您可以使用本機伺服器訊息區 (SMB) 伺服器作為指令碼的位置。 您就不需要提供任何其他設定,但 commandToExecute 除外。

$protectedSettings = @{"commandToExecute" = "powershell -ExecutionPolicy Unrestricted -File \\filesvr\build\serverUpdate1.ps1"};

Set-AzVMExtension -ResourceGroupName <resourceGroupName> `
    -Location <locationName> `
    -VMName <vmName> `
    -Name "serverUpdate"
    -Publisher "Microsoft.Compute" `
    -ExtensionType "CustomScriptExtension" `
    -TypeHandlerVersion "1.10" `
    -ProtectedSettings $protectedSettings

使用 CLI 多次執行自訂指令碼

如果已傳遞完全相同的設定,自訂指令碼延伸模組處理常式將會防止重新執行指令碼。 此行為可防止意外重新執行,如果指令碼不具等冪性,可能會導致非預期的行為。 若要確認處理程式是否封鎖重新執行,請檢視 C:\WindowsAzure\Logs\Plugins\Microsoft.Compute.CustomScriptExtension\<HandlerVersion>\CustomScriptHandler.log*。 搜尋如下的警告:

Current sequence number, <SequenceNumber>, is not greater than the sequence number
of the most recently executed configuration. Exiting...

如果您想要執行「自訂指令碼延伸模組」多次,您只有在下列情況下才能這麼做:

  • 延伸模組的 Name 參數等同於先前的延伸模組部署。
  • 您已更新組態。 您可以將動態屬性新增至命令,例如時間戳記。 如果處理常式偵測到組態設定中的變更,會將該變更視為重新執行指令碼的明確需求。

或者,您也可以將 ForceUpdateTag 屬性設定為 true

使用 Invoke-WebRequest

如果您在指令碼中使用 Invoke-WebRequest,您必須指定參數 -UseBasicParsing。 如果您未指定參數,則會在檢查詳細狀態時收到下列錯誤:

The response content cannot be parsed because the Internet Explorer engine
is not available, or Internet Explorer's first-launch configuration
is not complete. Specify the UseBasicParsing parameter and try again.

虛擬機器擴展集

如果您從 Azure 入口網站部署自訂指令碼延伸模組,就無法控制存取儲存體帳戶中指令碼之 SAS 權杖的到期日。 初始部署可運作,但儲存體帳戶的 SAS 權杖到期時,任何後續擴充作業都失敗,因為自訂指令碼延伸模組無法再存取儲存體帳戶。

在虛擬機器擴展集上部署自訂指令碼延伸模組時,建議您使用 PowerShellAzure CLI 或 Azure Resource Manager 範本。 如此一來,您可以選擇使用受控識別,或直接控制 SAS 權杖的到期日,以便只要您需要,即可存取儲存體帳戶中的指令碼。

疑難排解與支援

您可以從 Azure 入口網站擷取關於延伸模組部署狀態的資料,以及使用 Azure PowerShell 模組來擷取。 若要查看 VM 的延伸模組部署狀態,請執行下列命令:

Get-AzVMExtension -ResourceGroupName <resourceGroupName> `
    -VMName <vmName> -Name myExtensionName

延伸模組輸出會記錄至目標虛擬機器上下列資料夾中的檔案:

C:\WindowsAzure\Logs\Plugins\Microsoft.Compute.CustomScriptExtension

指定檔案會下載至目標虛擬機器上的下列資料夾之中:

C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.*\Downloads\<n>

在上述路徑中,<n> 是可能會在延伸模組執行之間變更的十進位整數。 1.* 值符合擴充功能目前實際的 typeHandlerVersion 值。 例如,實際的目錄可能是 C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.8\Downloads\2

執行 commandToExecute 命令時,延伸模組會將此目錄,例如 ...\Downloads\2,設定為目前的工作目錄。 此程序可讓您使用相對路徑找出使用 fileURIs 屬性下載的檔案位置。 以下是下載檔案的範例:

fileUris 中的 URI 相對下載位置 絕對下載位置
https://someAcct.blob.core.windows.net/aContainer/scripts/myscript.ps1 ./scripts/myscript.ps1 C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.8\Downloads\2\scripts\myscript.ps1
https://someAcct.blob.core.windows.net/aContainer/topLevel.ps1 ./topLevel.ps1 C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.8\Downloads\2\topLevel.ps1

如同上述,絕對目錄路徑會隨 VM 生命週期而變更,但不會在自訂指令碼延伸模組的單次執行期間。

由於絕對下載路徑會隨時間而改變,最好盡可能在 commandToExecute 字串中選擇相對的指令碼/檔案路徑。 例如:

"commandToExecute": "powershell.exe . . . -File \"./scripts/myscript.ps1\""

會為使用 fileUris 屬性清單下載的檔案保留第一個 URI 區段後的路徑資訊。 如稍早的資料表中所示,下載的檔案會對應到下載的子目錄,以反映 fileUris 值結構。

支援