PowerShell脚本遍历Azure资源后无限循环问题求助
问题修复:Azure多订阅VM状态采集脚本无限循环问题
问题根源
你的脚本出现重复执行(看似无限循环)的核心原因有两点:
- 订阅ID列表存在重复项:示例中两个订阅ID完全一致,会导致同一订阅被重复遍历
- VM范围错误:在资源组循环内使用
Get-AzVM获取当前订阅下所有VM,而非当前资源组的VM,导致每个资源组都会遍历所有VM,重复处理同一台机器
此外,手动拼接CSV字符串容易出错,也会增加调试难度。
修复后的脚本
# 去重后的Azure订阅ID列表 $subscriptionIds = @( "c0978b9d-b809-xxxxxx-xxxx-391ceb2cfdba" ) | Select-Object -Unique $scriptPath = "C:\Users\xxxxx\Desktop\Windows\CHECK_WINDOWS.ps1" $outputFile = "C:\Users\xxxxx\Desktop\Windows\Outputfiles\StateWindows.csv" # 初始化结果数组,用于存储采集到的状态对象 $results = @() foreach ($subscriptionId in $subscriptionIds) { # 设置订阅上下文 Set-AzContext -SubscriptionId $subscriptionId | Out-Null Write-Host "开始处理订阅:$subscriptionId" # 获取带有指定标签的资源组 $resourceGroups = Get-AzResourceGroup | Where-Object { $_.Tags -ne $null -and $_.Tags['ApplicationName'] -like "*US*" } foreach ($group in $resourceGroups) { Write-Host "开始处理资源组:$($group.ResourceGroupName)" # 移除资源组锁(如果存在) $rgLock = Get-AzResourceLock -ResourceGroupName $group.ResourceGroupName -ErrorAction SilentlyContinue if ($rgLock) { Remove-AzResourceLock -LockId $rgLock.LockId -Force Write-Host "已移除资源组 $($group.ResourceGroupName) 的锁定" } # 获取当前资源组下的Windows VM,减少不必要的遍历 $vms = Get-AzVM -ResourceGroupName $group.ResourceGroupName | Where-Object { $_.StorageProfile.OSDisk.OSType -eq "Windows" -and $_.Tags['ApplicationName'] -like "*OSS.NORAM.US*" } foreach ($vm in $vms) { Write-Host "开始处理VM:$($vm.Name)" # 移除VM锁(如果存在) $lock = Get-AzResourceLock -ResourceName $vm.Name -ResourceType "Microsoft.Compute/virtualMachines" -ResourceGroupName $group.ResourceGroupName -ErrorAction SilentlyContinue if ($lock) { Remove-AzResourceLock -LockId $lock.LockId -Force Write-Host "已移除VM $($vm.Name) 的锁定" } # 获取VM状态 $statuscheck = Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status $vmState = $statuscheck.Statuses.DisplayStatus[1] # 初始化状态对象 $vmStatus = [PSCustomObject]@{ "Server Name" = $vm.Name "GPO_HARMOR" = "-" "BIOMEDIC_AGENT" = "-" "EDWARD_STATUS" = "-" "SENSOR_STATUS" = "-" "SENTINEL_STATUS" = "-" "VM_STATE" = $vmState } # 如果VM处于运行状态,执行脚本采集详细状态 if ($vmState -eq "VM running") { Write-Host "正在采集 $($vm.Name) 的代理状态..." $scriptResult = Invoke-AzVMRunCommand -ResourceGroupName $vm.ResourceGroupName -VMName $vm.Name -CommandId 'RunPowerShellScript' -ScriptPath $scriptPath # 解析脚本输出(假设CHECK_WINDOWS.ps1返回的是CSV格式的一行) $stateLine = @($scriptResult | Out-String -Stream) -match '^".*AZ-.*"$' if ($stateLine) { $stateValues = $stateLine -split ',' | ForEach-Object { $_.Trim('"') } # 将解析后的值赋值给对象 $vmStatus."GPO_HARMOR" = $stateValues[1] $vmStatus."BIOMEDIC_AGENT" = $stateValues[2] $vmStatus."EDWARD_STATUS" = $stateValues[3] $vmStatus."SENSOR_STATUS" = $stateValues[4] $vmStatus."SENTINEL_STATUS" = $stateValues[5] } Write-Host "$($vm.Name) 状态采集完成" } else { Write-Host "$($vm.Name) 未运行,跳过代理状态采集" } # 将状态对象加入结果数组 $results += $vmStatus # 恢复VM锁(可选,根据你的需求启用) # New-AzResourceLock -LockLevel CanNotDelete -LockName "PreventDel" -LockNotes "PreventDel" -ResourceName $vm.Name -ResourceType "Microsoft.Compute/virtualMachines" -ResourceGroupName $group.ResourceGroupName -Force # Write-Host "已恢复VM $($vm.Name) 的锁定" } # 恢复资源组锁 New-AzResourceLock -LockLevel CanNotDelete -LockName "PreventDel" -LockNotes "PreventDel" -ResourceGroupName $group.ResourceGroupName -Force Write-Host "已恢复资源组 $($group.ResourceGroupName) 的锁定" } Write-Host "订阅 $subscriptionId 处理完成" } # 将结果导出为CSV文件,覆盖原有内容 $results | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8 Write-Host "所有资源处理完成,结果已导出至 $outputFile"
关键优化点
- 订阅ID去重:使用
Select-Object -Unique确保每个订阅只处理一次 - 缩小VM范围:仅获取当前资源组下符合条件的Windows VM,避免重复遍历
- 对象化处理CSV:使用
PSCustomObject存储状态,通过Export-Csv导出,避免手动拼接字符串的错误 - 明确的终止逻辑:脚本完成所有循环后自动导出结果并退出,不会重复执行
内容的提问来源于stack exchange,提问作者woodyboow
相关产品推荐
相关产品推荐

