上一篇 用 Cloudbase-Init + sysprep 做模板,重而且容易踩坑。这篇换个思路:一个 PowerShell 脚本注册成开机计划任务,启动时自己读 PVE 的 ConfigDrive(卷标 config-2)应用配置 —— 不依赖 Cloudbase-Init,不 sysprep,不禁用 Administrator。

前置:PVE 必须把 OS Type 设为 Windows

这一步是关键。PVE 8+ 在 OS Type 为 Linux 时,会把 cipassword 用 Linux crypt 哈希存储;只有 OS Type 选 Windowswin10 / win11 等)时才会以明文写入 ConfigDrive,Windows 才能拿来设密码。

PVE Web UI:VM → Options → OS Type → Microsoft Windows,选对应版本。

或者命令行:

1qm set <vmid> --ostype win11

然后给 VM 挂上 Cloud-Init 盘并设密码:

1qm set <vmid> --ide2 local-lvm:cloudinit
2qm set <vmid> --cipassword '你的密码'
3qm cloudinit update <vmid>

Web UI 改完 Cloud-Init 任何字段后记得点 Regenerate Image

一键安装

VM 内以管理员身份打开 PowerShell:

1$ErrorActionPreference='Stop'; Set-ExecutionPolicy Bypass -Scope Process -Force; [Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12; $p="$env:TEMP\my-cloudinit.ps1"; iwr 'https://x.csz.net/scripts/my-cloudinit.ps1' -OutFile $p -UseBasicParsing; & $p -Mode Install

执行后会:

  1. 把脚本拷到 C:\Program Files\my-cloudinit\my-cloudinit.ps1
  2. 注册名为 MyCloudInit 的开机计划任务(SYSTEM 权限,开机立即跑,最多等 60s 等 ConfigDrive 出现)
  3. 询问是否立即手动跑一次

这个脚本不能用 iex (irm ...) —— Install 模式需要把脚本文件复制到安装目录,所以必须先落盘再执行。

iwr 而不是 irmInvoke-RestMethod -OutFile 在 PowerShell 5.1 上对非 JSON/XML 响应有时不写盘,Invoke-WebRequest -OutFile 更可靠。

强制 TLS 1.2:旧版 Windows Server 默认还是 TLS 1.0/1.1,握 GitHub Pages / Cloudflare 的手会失败;$ErrorActionPreference='Stop' 让下载失败时立刻终止,避免无文件就去执行。

工作流程

每次开机,计划任务会:

  • 等卷标 config-2 的盘出现
  • openstack/latest/meta_data.json / user_data / network_data.json
  • instance-id(uuid)去重,已执行过则跳过
  • 设 Administrator 明文密码、改主机名、配网络、NTFS 分区扩容、跑 runcmd

也就是说,把这台 VM 转模板克隆,每个克隆出来的新 VM 第一次开机会自动应用 PVE Cloud-Init 注入的配置;同一台机器再开机不会重复执行(除非克隆出新的 instance-id)。

调试

如果第一次没生效,VM 内跑:

1& "C:\Program Files\my-cloudinit\my-cloudinit.ps1" -Mode Debug

会生成一份完整诊断报告 C:\ProgramData\my-cloudinit\debug-report.txt,包含卷列表、网卡、ConfigDrive 文件清单、meta_data.json / user_data / 网络配置内容、演练(dry-run)执行结果等。

日志在 C:\ProgramData\my-cloudinit\my-cloudinit.log

密码不生效的几种应急办法

如果 PVE 端忘了改 OS Type,cipassword 已经是 Linux crypt 哈希,脚本会拒绝设置,并提示几种补救方式:

  • A:把 OS Type 改成 win11 后重新设 cipassword + Regenerate Image(推荐)
  • B:在 ConfigDrive 盘根目录加文件 WINPASS(明文密码)—— 通过自定义 user-data 或 snippet 写入
  • C:用 qm set <vmid> --cicustom user=local:snippets/win.yaml 自己写明文 user-data
  • D:临时测试,VM 内执行 '你的密码' | Out-File C:\ProgramData\my-cloudinit\WINPASS -Encoding ASCII -NoNewline,下次开机优先级最高

脚本源码

my-cloudinit.ps1

注意脚本含中文输出,文件保留了 UTF-8 BOM 以兼容 PowerShell 5.1。