求助:创建Azure自动化Runbook实现VM启动后执行本地/Blob脚本
解决Azure Automation Runbook启动VM后执行脚本的问题
Hey Tom, 我完全懂你现在的困扰——VM能正常启动,但后续的登录和脚本执行环节总掉链子,这种情况我帮不少人排查过。下面给你整理两种最实用的实现方案,一步步来,应该能搞定你的问题:
方案一:用Invoke-AzVMRunCommand(推荐!依赖更少更稳定)
这个方法是Azure原生的VM命令执行方式,不需要直接建立WinRM连接,靠Azure VM扩展就能完成脚本执行,适合大多数场景。
前提准备
- 你的VM已经默认安装了Azure VM扩展(新建VM一般自带,老VM可以手动安装)
- 自动化账户的Run As账户需要有VM的Contributor权限,以及
Microsoft.Compute/virtualMachines/runCommand/action权限 - 如果脚本存在Blob存储,要生成带读取权限的SAS URL,或者给VM配置Managed Identity让它能访问Blob
Runbook代码示例
# 用Run As账户登录Azure $connectionName = "AzureRunAsConnection" try { $servicePrincipalConnection = Get-AutomationConnection -Name $connectionName Connect-AzAccount ` -ServicePrincipal ` -TenantId $servicePrincipalConnection.TenantId ` -ApplicationId $servicePrincipalConnection.ApplicationId ` -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint } catch { if (!$servicePrincipalConnection) { $ErrorMessage = "找不到连接 '$connectionName'." throw $ErrorMessage } else{ Write-Error -Message $_.Exception throw $_.Exception } } # 自定义参数:替换成你的资源信息 $vmName = "你的VM名称" $resourceGroupName = "你的资源组名称" # 可选:VM本地脚本路径 或 Blob SAS URL $localScriptPath = "C:\Scripts\你的脚本.ps1" $blobScriptUri = "https://你的存储账户.blob.core.windows.net/容器名/脚本.ps1?SAS参数" # 启动VM Start-AzVM -Name $vmName -ResourceGroupName $resourceGroupName # 等待VM完全就绪(避免刚启动就执行脚本) do { $vmStatus = Get-AzVM -Name $vmName -ResourceGroupName $resourceGroupName -Status Write-Output "当前VM状态:$($vmStatus.Statuses[1].DisplayStatus)" Start-Sleep -Seconds 30 } while ($vmStatus.Statuses[1].DisplayStatus -ne "VM running") # 执行VM本地脚本 Invoke-AzVMRunCommand ` -ResourceGroupName $resourceGroupName ` -Name $vmName ` -CommandId 'RunPowerShellScript' ` -ScriptPath $localScriptPath # 如果要执行Blob里的脚本,替换成下面的命令 # Invoke-AzVMRunCommand ` # -ResourceGroupName $resourceGroupName ` # -Name $vmName ` # -CommandId 'RunPowerShellScript' ` # -ScriptUri $blobScriptUri
注意事项
- RunCommand默认用系统账户执行,自带管理员权限,不需要额外配置
- Blob的SAS URL要设置足够长的过期时间,并且只开放读取权限
- 如果执行失败,先看Runbook的详细日志,里面会明确指出是权限问题还是脚本本身的错误
方案二:用Invoke-Command(适合需要直接交互的场景)
这个方法需要建立WinRM连接到VM,适合需要在VM上执行复杂交互操作的情况,但配置步骤更多。
前提准备
- VM已开启WinRM服务(Azure VM默认开启,自定义镜像可能需要手动配置)
- NSG规则要允许WinRM端口(5985 HTTP / 5986 HTTPS)
- 自动化账户已存储VM的本地管理员凭据(就是你提到的个人凭据)
- 如果用私有IP连接,自动化账户的Hybrid Worker需要和VM在同一个VNet,或者通过VPN/ExpressRoute访问
Runbook代码示例
# 用Run As账户登录Azure $connectionName = "AzureRunAsConnection" try { $servicePrincipalConnection = Get-AutomationConnection -Name $connectionName Connect-AzAccount ` -ServicePrincipal ` -TenantId $servicePrincipalConnection.TenantId ` -ApplicationId $servicePrincipalConnection.ApplicationId ` -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint } catch { if (!$servicePrincipalConnection) { $ErrorMessage = "找不到连接 '$connectionName'." throw $ErrorMessage } else{ Write-Error -Message $_.Exception throw $_.Exception } } # 自定义参数 $vmName = "你的VM名称" $resourceGroupName = "你的资源组名称" $credentialName = "自动化账户里存储的凭据名称" $localScriptPath = "C:\Scripts\你的脚本.ps1" $blobScriptUrl = "https://你的存储账户.blob.core.windows.net/容器名/脚本.ps1" # 启动VM并等待就绪 Start-AzVM -Name $vmName -ResourceGroupName $resourceGroupName do { $vmStatus = Get-AzVM -Name $vmName -ResourceGroupName $resourceGroupName -Status Write-Output "当前VM状态:$($vmStatus.Statuses[1].DisplayStatus)" Start-Sleep -Seconds 30 } while ($vmStatus.Statuses[1].DisplayStatus -ne "VM running") # 获取VM的私有IP(用公网IP的话替换成PublicIpAddress) $vmNicId = (Get-AzVM -Name $vmName -ResourceGroupName $resourceGroupName).NetworkProfile.NetworkInterfaces[0].Id $privateIp = (Get-AzNetworkInterface -ResourceId $vmNicId).IpConfigurations.PrivateIpAddress # 获取存储的VM凭据 $vmCred = Get-AutomationPSCredential -Name $credentialName # 创建WinRM会话(自签证书需要跳过校验) $sessionOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck $vmSession = New-PSSession -ComputerName $privateIp -Credential $vmCred -SessionOption $sessionOptions # 执行VM本地脚本 Invoke-Command -Session $vmSession -FilePath $localScriptPath # 如果执行Blob脚本:先下载到VM再执行 # Invoke-Command -Session $vmSession -ScriptBlock { # Invoke-WebRequest -Uri $using:blobScriptUrl -OutFile "C:\temp\临时脚本.ps1" # & "C:\temp\临时脚本.ps1" # } # 关闭会话 Remove-PSSession $vmSession
注意事项
- 生产环境建议给WinRM配置正式SSL证书,不要一直用跳过校验的参数
- 如果连接失败,先检查NSG端口是否开放、VM的防火墙是否允许WinRM流量
- 凭据必须是VM本地的管理员账户,否则没有执行权限
额外排查小技巧
- 先在本地PowerShell里模拟执行脚本,排除脚本本身的语法错误
- 查看Runbook的详细日志,里面会有具体的错误代码和描述,比如权限不足、连接超时等
- 优先尝试方案一,因为它依赖更少,不需要配置WinRM,稳定性更高
内容的提问来源于stack exchange,提问作者Tom Djernæs
相关产品推荐
相关产品推荐

