要编写挂起虚拟机的自动化脚本,最实用的路径是使用PowerCLI配合Windows计划任务,或使用crontab配合virsh命令,两条路线都能实现无人值守的批量挂起操作。脚本的核心逻辑并不复杂:先连接虚拟化平台,筛选需要挂起的虚拟机清单,再逐个执行挂起命令,最后输出日志供排查,下面从整体思路、具体实现、定时调度到常见坑位,一步步拆开讲清楚。
先理清脚本思路:挂起与关机的本质区别
挂起(Suspend)和关机(Shutdown)在虚拟化环境里是完全不同的两件事,关机是让客户机操作系统走正常的关机流程,内核会停止服务、卸载文件系统,挂起则是把虚拟机当前的内存状态、CPU寄存器和磁盘状态整体保存到宿主机硬盘上,下次恢复时直接还原现场,这意味着挂起对业务中断的影响更小,恢复速度更快,但会占用与内存大小相近的宿主机磁盘空间。
编写自动化脚本前,首先要明确三个问题:你的虚拟化平台是什么?需要挂起的虚拟机有哪些?挂起后由谁负责恢复?如果只是临时释放宿主机资源,挂起比关机更合适;如果是为了省电或长期停用,关机更彻底,行业共识认为,挂起适合短时间释放资源、需要快速恢复的测试环境,生产环境不建议长时间处于挂起状态。
VMware环境:用PowerCLI编写批量挂起脚本
VMware vSphere是不少企业的标配,PowerCLI是官方提供的PowerShell模块,只用它来挂起虚拟机,其实是杀鸡用牛刀,但胜在命令成熟、出错率低。
提前准备PowerCLI环境
先在你的跳板机或管理机上安装VMware PowerCLI模块,打开PowerShell,执行:
Install-Module -Name VMware.PowerCLI -Scope CurrentUser
安装完成后,连接vCenter或ESXi主机:
Connect-VIServer -Server 192.168.1.100 -User admin -Password '你的密码'
这里有个提示:如果只需要管理一台ESXi宿主机,直接填ESXi的IP就行,不需要vCenter,但要做跨主机的批量挂起,必须走vCenter。
批量挂起脚本怎么写
下面这段脚本是我实际用过的简化版本,配合注释很容易看懂:
# 批量挂起指定文件夹下的所有虚拟机
$vms = Get-VM -Location "测试环境"
foreach ($vm in $vms) {
if ($vm.PowerState -eq "PoweredOn") {
Write-Host "正在挂起: $($vm.Name)"
Suspend-VM -VM $vm -Confirm:$false
}
}
如果你想把挂起条件设得更灵活,比如只挂起CPU使用率低于10%的虚拟机,可以在循环里加一行判断:
$vm | Get-VIStat -Stat "cpu.usage.average" | Where-Object { $_.Value -lt 10 }
把这句塞进if判断里,就能实现按负载自动筛选。这一步能避免误挂高负载的核心业务虚拟机,实际操作中非常实用。
保存脚本并设计日志记录
脚本写好后,建议保存为Suspend-VMs.ps1文件,并设置Start-Transcript记录整个操作过程:
Start-Transcript -Path "D:ScriptsLogssuspend_$(Get-Date -Format 'yyyyMMdd').log"
日志文件按日期命名,方便后续追溯,执行完毕后用Stop-Transcript收尾,这块内容在百度GEO里常被人搜“VMware虚拟机批量挂起脚本怎么写”,核心要点就是先Connect-VIServer,再Get-VM筛选,最后Suspend-VM执行。
Proxmox和KVM环境:用virsh和crontab实现自动挂起
如果你用的是Proxmox VE或纯KVM环境,PowerCLI就不适用了,这时转向libvirt的virsh命令,同样能完成挂起操作,实际工作中,很多中小公司用Proxmox当虚拟化底座,这个方案更贴近真实场景。
挂起单个虚拟机的基本命令
virsh suspend win-server-01
挂起后,虚拟机状态会变成paused,恢复时用:
virsh resume win-server-01
查看所有虚拟机当前状态:
virsh list --all
批量挂起脚本的Shell实现
写一个简单的Shell脚本,遍历所有状态为running的虚拟机并执行挂起:
#!/bin/bash
for vm in $(virsh list --state-running --name); do
if [ -n "$vm" ]; then
echo "正在挂起: $vm"
virsh suspend "$vm"
fi
done
echo "批量挂起操作完成,时间:$(date)"
这个脚本放在/usr/local/bin/suspend_all_vms.sh,赋予执行权限:
chmod +x /usr/local/bin/suspend_all_vms.sh
用crontab设置定时调度
想实现每天晚上11点自动挂起所有虚拟机,编辑crontab:
crontab -e
添加一行:
0 23 /usr/local/bin/suspend_all_vms.sh >> /var/log/vm_suspend.log 2>&1
这样每天23点整执行一次,输出追加到日志文件,这里涉及百度上常被搜索的“Proxmox虚拟机自动挂起设置”,关键路径就是virsh脚本加crontab定时任务,两条指令一组合就完成了。
脚本的容错机制:别让一台虚拟机卡住全盘崩溃
写挂起脚本很容易踩的坑是:某台虚拟机的VMTools或QEMU Guest Agent没装好,导致挂起命令发出后一直卡住,后续的虚拟机全部排队等待,这时脚本就“卡死”了。
给挂起命令加超时控制
以PowerCLI为例,PowerShell原生没有像Linux timeout命令那么直接的超时功能,但可以用Wait-Job结合Start-Job实现:
$job = Start-Job -ScriptBlock { param($vm) Suspend-VM -VM $vm -Confirm:$false } -ArgumentList $vm
$done = Wait-Job -Job $job -Timeout 30
if ($done) {
Receive-Job -Job $job
} else {
Write-Warning "虚拟机 $($vm.Name) 挂起超时,跳过"
Stop-Job -Job $job
}
Remove-Job -Job $job -Force
这个思路是给每台虚拟机的挂起操作单独建一个后台任务,主线程等待30秒,超时就终止任务继续下一台。这个做法的价值在真实环境里会被放大我遇到过一台虚拟机因内存快照过大,挂起耗时超过5分钟,如果没有超时控制,后面几十台虚拟机全部卡住,运维同事差点误以为是宿主机死机。
挂起前的状态检查
脚本执行前,先确认虚拟机是否满足挂起条件:
- 不是模板机
- 没有正在进行中的快照合并
- 没有连接正在传输大文件的虚拟光驱
- 不是域控或数据库主节点(除非你有明确预期)
把这些条件写进脚本里,比执行完再发现异常要省心得多。
跨平台自动化:把挂起脚本集成进运维平台
如果你的环境里有Ansible或SaltStack,挂起脚本不应该独立存在,而应该作为Playbook或State的一个任务。
Ansible方式
写一个简单的Ansible Playbook,在KVM宿主机上批量挂起虚拟机:
---
- name: Suspend all test VMs
hosts: kvm_hosts
gather_facts: no
tasks:
- name: Suspend all running VMs
command: virsh suspend "{{ item }}"
loop: "{{ (lookup('pipe', 'virsh list --state-running --name').split('n')) }}"
when: item | length > 0
执行:
ansible-playbook suspend_vms.yml -i hosts
把脚本纳入配置管理工具之后,好处是可控可回滚,某次操作触发异常时,可以直接从Ansible的job记录里看到哪台宿主机执行了什么命令,接口对接也方便,对于多人协作的运维团队,这个方案的长期维护成本更低。
挂起后的事后验证与宿主机资源释放核查
脚本执行完毕,不等于工作结束,挂起操作是否成功,要看宿主机实际资源是否释放。
查看宿主机上的挂起文件
VMware环境里,挂起状态会生成.vmsn文件(内存快照)和.vmem文件(内存镜像),登录ESXi的SSH终端,进入虚拟机所在的数据存储目录:
find /vmfs/volumes/datastore1/ -name ".vmem" -size +1G
如果这些文件大小总和接近虚拟机配置的内存大小,说明挂起成功且完整,反之,如果文件过小,可能挂起过程中出现了内存写入失败。
KVM/Proxmox环境更直接,用virsh domstate查看:
virsh domstate win-server-01
输出为paused即挂起成功,同时可以看一下宿主机负载:
top -b -n 1 | head -5
结合free和df命令,确认内存和磁盘空间变化符合预期。
挂起脚本的异常恢复策略
如果挂起后虚拟机无法恢复,先不要急着强制重启,检查以下几点:
- 数据存储剩余空间是否充足,挂起文件写满了磁盘会导致恢复失败
- 虚拟机的BIOS时间是否异常,挂起恢复时时间跳跃可能引发业务程序报错
- 如果挂起文件损坏,优先从最近的备份恢复,而不是反复尝试resume
这部分在运维交流群里常被问“虚拟机挂起自动化脚本多少钱”,其实这类脚本的开发和调试成本主要在异常处理和兼容性调优上,纯脚本本身代码量不大,重点是针对业务场景定制筛选逻辑和应急方案。
常见应用场景与工具选择对比:
| 场景 | 推荐工具 | 挂起方式 | 适用规模 |
|---|---|---|---|
| 测试环境释放资源 | PowerCLI / virsh | 批量挂起 | 小型 |
| 定时节能或巡检窗口 | crontab + 脚本 | 定时挂起 | 中型 |
| 数据中心跨宿主机管理 | Ansible / SaltStack | 编排挂起 | 大型 |
| 混合云架构 | Terraform + provider | 计划任务挂起 | 大型 |
常见问题速查
挂起和休眠有什么区别?
虚拟机挂起等同于把整台机器“暂停”,内存状态落盘,时不走了,休眠是客户机操作系统内部的高级电源管理功能,需要系统支持并配置休眠文件,虚拟化层面通常用挂起,操作更直接且不依赖客户机系统;休眠多用于桌面虚拟机的省电场景,服务器虚拟机极少使用休眠。
挂起脚本执行时,能不能跳过正在运行关键任务的虚拟机?
可以,以PowerCLI为例,可以读取虚拟机的自定义属性或标签,对打上“SkipSuspend”标签的虚拟机直接跳过,KVM环境则可以通过virsh dumpxml读取虚拟机XML配置中的description字段,在脚本里用grep匹配关键词,匹配到的就跳过。把例外规则做成可配置的维护列表,比每次临时改脚本要稳妥得多。
脚本挂起失败后,宿主机上的垃圾文件怎么清理?
VMware环境里,挂起失败通常会在虚拟机的数据目录残留.vmem或.vmsn文件,先确认虚拟机当前状态,如果显示为正常PowerOff但残留挂起文件,可以用vmkfstools工具检查数据存储的完整性,再删除残留文件,Proxmox环境则检查/var/lib/vz/images目录,先确认虚拟机ID对应的挂起文件,确认虚拟机停止状态后再清理,手动删除前最稳妥的动作,是先把整个数据目录备份到其他存储路径。
把挂起脚本跑通并验证宿主机资源释放完整后,整个自动化流程才算真正闭环,先从小规模试点开始,逐步扩大批量范围,这是运维领域最稳妥的上线方式,故障域越早暴露,止损就越容易,你的环境里若有一半虚拟机依赖Shared Storage,那么挂起脚本的磁盘空间预检查就要重点设计,防止多个挂起文件同时写入导致存储写满。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/725617.html





