读取VM列表转换为Azure托管磁盘时遇PowerShell脚本问题
解决Azure VM转换托管磁盘的PowerShell脚本问题
我来帮你一步步排查和修复这两个核心问题:
问题1:导出CSV时拿到全订阅VM而非指定列表
你的脚本逻辑里犯了一个关键错误:每次读取vm.txt里的一行,就执行一次Get-Azurermvm(拉取全订阅所有VM),然后把所有结果追加到CSV里,自然最终CSV里是全订阅VM的重复数据。
修复方案
先读取txt里的VM信息,再从订阅中精准筛选对应的VM,再导出CSV。假设你的vm.txt每行格式为资源组名 VM名称(比如RG-01 vm-01),代码调整如下:
# 读取txt并整理成结构化的VM列表 $vmList = Get-Content C:\temp\vm.txt | ForEach-Object { $parts = $_.Trim().Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries) # 确保每行是有效的资源组+VM名格式 if ($parts.Count -eq 2) { [PSCustomObject]@{ ResourceGroupName = $parts[0] Name = $parts[1] } } } # 筛选指定VM并导出CSV(替换你原来的导出逻辑) $vmList | ForEach-Object { Get-Azurermvm -ResourceGroupName $_.ResourceGroupName -Name $_.Name | Select-Object ResourceGroupName,Name } | Export-Csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Force
如果你的vm.txt只有VM名称,可改用Where-Object筛选:
$vmNames = Get-Content C:\temp\vm.txt Get-Azurermvm | Where-Object { $vmNames -contains $_.Name } | Select-Object ResourceGroupName,Name | Export-Csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Force
问题2:循环中参数无法传递给Stop/Convert命令
你的循环语法混合了管道ForEach-Object和常规foreach循环,导致$_变量无法正确指向当前VM对象。
修复方案
选以下两种正确的循环写法之一即可:
方式1:常规foreach循环(用循环变量引用)
$comps = Import-Csv c:\temp\Vm.csv foreach ($Comp in $comps) { Stop-AzureRmVM -ResourceGroupName $Comp.ResourceGroupName -Name $Comp.Name -Force ConvertTo-AzureRmVMManagedDisk -ResourceGroupName $Comp.ResourceGroupName -VMName $Comp.Name }
方式2:管道式ForEach-Object(用$_引用)
Import-Csv c:\temp\Vm.csv | ForEach-Object { Stop-AzureRmVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name -Force ConvertTo-AzureRmVMManagedDisk -ResourceGroupName $_.ResourceGroupName -VMName $_.Name }
完整修正后的脚本
整合所有修复点,加上日志提示和订阅切换的规范写法:
# 登录并切换目标订阅 Login-AzureRmAccount $sub = Get-AzureRmSubscription | Out-GridView -PassThru Set-AzureRmContext -Subscription $sub.Id # 从txt读取VM列表并导出正确CSV $vmList = Get-Content C:\temp\vm.txt | ForEach-Object { $parts = $_.Trim().Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries) if ($parts.Count -eq 2) { [PSCustomObject]@{ ResourceGroupName = $parts[0] Name = $parts[1] } } } $vmList | ForEach-Object { Get-Azurermvm -ResourceGroupName $_.ResourceGroupName -Name $_.Name | Select-Object ResourceGroupName,Name } | Export-Csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Force # 执行停止VM并转换为托管磁盘 Import-Csv c:\temp\vm.csv | ForEach-Object { Write-Host "正在停止VM: $($_.Name)..." Stop-AzureRmVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name -Force -ErrorAction Stop Write-Host "正在转换VM $($_.Name)为托管磁盘..." ConvertTo-AzureRmVMManagedDisk -ResourceGroupName $_.ResourceGroupName -VMName $_.Name -ErrorAction Stop Write-Host "VM $($_.Name)转换完成!`n" }
内容的提问来源于stack exchange,提问作者Norrin Rad
相关产品推荐
相关产品推荐

