通过ARM模板自定义脚本扩展调用PowerShell执行多个cmd文件
实现PowerShell DSC脚本调用多个CMD文件(适配ARM自定义脚本扩展)
我来帮你调整这个PowerShell DSC脚本,实现调用多个CMD文件的功能,同时适配ARM自定义脚本扩展的触发场景。首先你原来脚本里的Invoke-Item File 'sr...'写法是不对的,我们可以用DSC的Script资源来实现(这是推荐方式,支持依赖管理和重复执行检查),或者直接用Start-Process执行CMD脚本。
方法一:用DSC Script资源(推荐,支持依赖与幂等性)
这种方式能确保CMD脚本在IIS、ASP.NET等组件安装完成后再执行,还能避免重复执行(通过检查标记文件):
Configuration IIS { Node ("localhost") { # 安装IIS角色 WindowsFeature IIS { Ensure = "Present" Name = "Web-Server" } # 安装ASP.NET 4.5,依赖IIS安装完成 WindowsFeature ASP { Ensure = "Present" Name = "Web-Asp-Net45" DependsOn = "[WindowsFeature]IIS" } # 安装IIS管理控制台 WindowsFeature WebServerManagementConsole { Name = "Web-Mgmt-Console" Ensure = "Present" DependsOn = "[WindowsFeature]IIS" } # 执行第一个CMD脚本 Script RunFirstCmd { GetScript = { @{ Result = "FirstCmdCompleted" } } TestScript = { # 检查标记文件,判断是否已经执行过 $markerFile = "C:\DSCLogs\FirstCmd_Done.txt" return Test-Path $markerFile } SetScript = { # 替换成你的CMD文件实际路径 $cmdPath = "C:\CustomScripts\FirstSetup.cmd" # 执行CMD,等待完成并捕获退出码 $process = Start-Process -FilePath "cmd.exe" -ArgumentList "/c `"$cmdPath`"" -Wait -PassThru -NoNewWindow # 非0退出码则抛出错误,终止DSC配置 if ($process.ExitCode -ne 0) { throw "First CMD script failed with exit code $($process.ExitCode)" } # 创建标记文件,避免重复执行 New-Item -Path "C:\DSCLogs\FirstCmd_Done.txt" -ItemType File -Force | Out-Null } # 依赖所有Windows功能安装完成 DependsOn = "[WindowsFeature]ASP", "[WindowsFeature]WebServerManagementConsole" } # 执行第二个CMD脚本,依赖第一个完成 Script RunSecondCmd { GetScript = { @{ Result = "SecondCmdCompleted" } } TestScript = { $markerFile = "C:\DSCLogs\SecondCmd_Done.txt" return Test-Path $markerFile } SetScript = { $cmdPath = "C:\CustomScripts\SecondSetup.cmd" $process = Start-Process -FilePath "cmd.exe" -ArgumentList "/c `"$cmdPath`"" -Wait -PassThru -NoNewWindow if ($process.ExitCode -ne 0) { throw "Second CMD script failed with exit code $($process.ExitCode)" } New-Item -Path "C:\DSCLogs\SecondCmd_Done.txt" -ItemType File -Force | Out-Null } DependsOn = "[Script]RunFirstCmd" } } }
方法二:批量执行CMD脚本(适合简单场景)
如果不需要严格的顺序检查,也可以批量遍历CMD文件列表执行,同样放在Script资源里确保依赖:
Configuration IIS { Node ("localhost") { # 保留原有的WindowsFeature配置 WindowsFeature IIS { Ensure = "Present" Name = "Web-Server" } WindowsFeature ASP { Ensure = "Present" Name = "Web-Asp-Net45" DependsOn = "[WindowsFeature]IIS" } WindowsFeature WebServerManagementConsole { Name = "Web-Mgmt-Console" Ensure = "Present" DependsOn = "[WindowsFeature]IIS" } # 批量执行所有CMD脚本 Script RunAllCmds { GetScript = { @{ Result = "AllCmdsExecuted" } } TestScript = { # 这里可以检查所有标记文件是否存在,或者直接返回$false每次都执行 $allMarkersExist = @( "C:\DSCLogs\FirstCmd_Done.txt", "C:\DSCLogs\SecondCmd_Done.txt" ) | ForEach-Object { Test-Path $_ } | Where-Object { $_ -eq $false } return $allMarkersExist.Count -eq 0 } SetScript = { # 定义要执行的CMD文件列表 $cmdFiles = @( "C:\CustomScripts\FirstSetup.cmd", "C:\CustomScripts\SecondSetup.cmd", "C:\CustomScripts\ThirdSetup.cmd" ) foreach ($cmd in $cmdFiles) { Write-Host "Starting execution of: $cmd" $logFile = "C:\DSCLogs\$(Split-Path $cmd -Leaf)_Log.txt" # 执行并将输出写入日志文件 $process = Start-Process -FilePath "cmd.exe" -ArgumentList "/c `"$cmd`"" -Wait -PassThru -NoNewWindow ` -RedirectStandardOutput $logFile -RedirectStandardError $logFile if ($process.ExitCode -ne 0) { throw "Script $cmd failed! Check log at $logFile" } # 创建对应标记文件 $markerFile = "C:\DSCLogs\$(Split-Path $cmd -Leaf)_Done.txt" New-Item -Path $markerFile -ItemType File -Force | Out-Null Write-Host "Successfully executed: $cmd" } } DependsOn = "[WindowsFeature]ASP", "[WindowsFeature]WebServerManagementConsole" } } }
适配ARM自定义脚本扩展的关键注意点
- CMD文件路径:如果你的CMD文件是通过ARM模板的
fileUris参数上传的,默认会被下载到C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\<版本号>\Downloads\<编号>目录下,你可以在ARM模板中指定commandToExecute先把文件复制到固定路径(比如C:\CustomScripts),或者直接使用这个默认路径。 - 权限:自定义脚本扩展以系统权限运行,确保CMD文件和操作的目标资源有足够的权限,避免“访问被拒绝”的问题。
- 日志排查:建议给每个CMD脚本添加日志输出,或者在PowerShell中重定向输出到日志文件,方便后续排查执行问题。
内容的提问来源于stack exchange,提问作者Helay
相关产品推荐
相关产品推荐

