重装系统一条龙:用winget与PowerShell脚本实现全自动软件部署

📅 发布时间:2026/9/14 21:18:05
重装系统一条龙:用winget与PowerShell脚本实现全自动软件部署
重装系统这件事干过的人都懂真正耗时间的不是装系统本身而是装完系统之后那一大堆软件的重新安装和配置。浏览器、输入法、压缩软件、办公套件、开发环境、常用工具……一个个去官网下载再一个个点安装、选路径、跳过全家桶、关掉开机自启一套下来大半天就没了。要是期间再遇到某个软件下载慢、某个安装包捆绑垃圾软件心态直接崩。我用的办法是给自己做了一套“重装系统一条龙部署服务”装完系统、进入桌面后只需要双击运行一个脚本就能自动把必要软件全部装好、把常用系统配置调好中间不需要我盯着点下一步跑完就能直接进工作状态。这套东西我用了两年多前后迭代了好几版已经稳定得很。这篇文章就把整个思路、方案、脚本和踩过的坑完整写出来想省事的可以直接照着抄。这套方案适合三类人一是经常折腾系统、隔段时间就想重装一遍的玩家二是给同事、客户、朋友装机的“免费IT运维”三是需要在新电脑上快速搭建开发环境的程序员。哪怕你只会双击运行bat文件跟着步骤做也能复制出一套自己的部署服务。1. 整体设计思路一条龙服务到底要解决什么问题1.1 “必要软件”的范围怎么定做一键部署之前第一件事是把需求想清楚到底哪些软件需要自动化安装我总结了一个原则叫“必须装、愿意等、不怕爆”。必须装是指没有它电脑就没法正常用比如浏览器、输入法、压缩工具愿意等是指安装过程比较久或者步骤多的比如Office、PhotoShop这种大型套件不怕爆是指这些软件不会因为默认安装路径、默认配置而搞出兼容性问题。按照这个原则我一般把软件分成四类基础工具类浏览器Chrome、Firefox、输入法搜狗/微软拼音替代品、压缩软件7-Zip、Bandizip、截图工具Snipaste、PixPin办公类Office/WPS、PDF阅读器、腾讯会议、钉钉/微信开发类Git、VS Code、Node.js、Python、JDK、Docker Desktop、数据库客户端系统增强类PowerToys、Everything本地文件搜索、耳塞降噪工具、显示器色温工具每个人的“必要软件”不一样但思路是一样的把安装频率最高、配置成本最大的那批软件收进脚本里。以后换了新电脑只需要改一小部分清单剩下的流程照旧跑。1.2 用脚本批量装还是用工具一键装市面上有各种“一键装机工具”很多会捆绑全家桶、改浏览器主页我一开始就直接放弃了。让我下定决心自己写脚本的原因是工具类方案的三个致命问题一是不透明。你永远不知道工具到底帮你勾选了哪些附加软件出了安全问题也没法审计。二是不可定制。每个人需要的软件清单不同工具给的套餐不符合我的使用习惯。三是不可维护。工具版本更新后以前装好的环境无法复现重装一次就变化一次。最终我选择了“脚本 软件包管理器”的组合方案。脚本负责调度流程包管理器负责从官方源下载和静默安装软件。这样做的核心逻辑是脚本本身很短只是一个按顺序执行的清单真正干活的软件包管理器本身就是专业工具它们的静默安装能力比手动点下一步要稳定得多。2. 核心工具选型主流包管理器怎么选、各自的痛点2.1 Windows下三大包管理器的取舍Windows平台目前主流的包管理器主要是三个winget、Chocolatey、Scoop。我实际都用过简单说一下各自特点。winget是微软官方出的新一代Windows 10/11系统里自带直接可以用。它的优点是后台是微软维护的源软件收录比较全而且静默安装参数是统一的。缺点是国内网络环境下访问微软服务器速度不稳定源更新偶尔会慢。Chocolatey是老牌工具流行很多年了软件包非常丰富很多企业用它做批量部署。它的安装原理是先安装Chocolatey本体然后通过choco install命令装软件。优点是生态成熟缺点是它的默认源在国外国内下载速度经常让人抓狂很多软件包还依赖管理员权限。Scoop是轻量级方案最大的特点是“绿色安装”软件默认安装到用户目录不需要管理员权限不会污染注册表。但它主要偏开发工具办公类软件收录不全。我的选择是以winget为主力Scoop作为开发工具的补充Chocolatey基本不用。原因很简单winget自带、命令统一、源可配置对普通用户最友好。如果你经常需要装一些开发命令行工具Scoop的“免管理员”特性真的很香。下面是这三个工具的对比。工具安装方式是否需要管理员软件覆盖国内访问速度适用场景winget系统自带部分软件需要较全一般批量办公、常用软件Chocolatey手动安装需要全较慢企业批量部署Scoop手动安装不需要开发工具为主较快程序员个人环境2.2 静默安装为什么能“一键”很多新手在考虑一键部署时最担心的就是“装到一半弹个安装向导要怎么办”。这里就要理解静默安装的原理。大多数Windows安装包都支持命令行参数常见的包括/S或/silent静默模式不显示安装界面/D路径指定安装目录/NORESTART装完不要求重启/VERYSILENT更彻底的静默连进度条都基本不显示/SP-跳过“是否开始安装”的确认页面winget的好处是把这些参数统一了你只需要写winget install --id xxx --silent --accept-package-agreements --accept-source-agreements它就会自动执行静默安装。也就是说你的脚本只需要负责按顺序触发安装命令真正让安装过程“无声”进行的是这些约定好的参数。2.3 部署脚本的两种常见架构做一条龙部署很多人上来就写一个巨大的脚本把所有软件装一遍结果维护起来特别累。我建议用“配置驱动”的思想把脚本拆成两个部分执行部分固定不变的一段逻辑负责读取配置、调起安装、记录日志配置部分一个清单文件列出所有要装的软件ID和建议参数这样以后想加一个软件只需要在清单里加一行完全不用动执行代码。我用的是JSON格式的清单也可以直接用PowerShell里的数组。这个设计后续扩展起来非常舒服。3. 实操从零编写一键部署脚本3.1 准备工作管理员权限与执行策略先解决两个最基础的问题以管理员身份运行以及允许执行脚本。右键单击PowerShell选择“以管理员身份运行”这个是基础操作。如果系统提示脚本执行被禁止需要先修改执行策略在管理员PowerShell里执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser这个命令的意思是本机自己写的脚本允许运行从网上下载的脚本要有数字签名才能运行。RemoteSigned是比较平衡的策略既不影响使用又有一定的安全性。接着创建一个工作目录比如C:\Deploy把脚本和配置文件都放进去。我们的整个部署服务就放在这个目录下重装系统后只需要把它从U盘拷回来就能用。3.2 用winget安装基础软件清单核心的安装逻辑其实很短。新建一个install.ps1文件内容分两块。第一块是软件列表$apps ( Google.Chrome, Mozilla.Firefox, 7zip.7zip, WPS.Office, Microsoft.PowerToys, Microsoft.VisualStudioCode, Git.Git, OpenJS.NodeJS.LTS, Python.Python.3.12 )第二块是循环安装foreach ($app in $apps) { Write-Host 正在安装: $app -ForegroundColor Green winget install --id $app --silent --accept-package-agreements --accept-source-agreements }这段逻辑就是一条龙服务的地基。每次运行脚本winget会检查当前系统里有没有装过这个软件如果已经安装了会提示已经存在如果没装就自动下载并静默安装。有人会问为什么不用winget upgrade --all直接升级所有软件因为那条命令只会升级已安装的软件不会装新的。我们这里的winget install才是真正的“缺失即安装”。3.3 开发环境自动配置软件装完之后开发环境的环境变量也往往需要设置。比如Node.js装好后默认会配置好npm路径但一些全局包可能需要额外路径Python的Scripts目录也要加到环境变量里。我写了一段自动添加环境变量的函数function Add-Paths { param([string[]]$Paths) $current [Environment]::GetEnvironmentVariable(Path, Machine) $toAdd $Paths | Where-Object { $current -notlike *$_* } if ($toAdd) { $newPath $current.TrimEnd(;) ; ($toAdd -join ;) ; [Environment]::SetEnvironmentVariable(Path, $newPath, Machine) } } Add-Paths -Paths ( C:\Users\$env:USERNAME\AppData\Roaming\npm, C:\Python312\Scripts, C:\Program Files\Git\cmd )这里面有个容易踩的坑[Environment]::SetEnvironmentVariable(Path, $newPath, Machine)里一定要加第三个参数Machine否则它只修改当前进程的环境变量关掉脚本就失效了。另外修改了系统环境变量后当前已打开的程序不会生效新开的命令行窗口才会读到新路径。3.4 系统设置、驱动与网络问题处理软件装完一些系统层面的设置也需要自动调。我通常会做这几件事关闭Windows传递优化这是带宽杀手将系统还原点关闭换来性能和磁盘空间适合不需要还原功能的场景设置文件资源管理器默认打开“此电脑”关闭UAC弹窗不推荐但有些人喜欢电源计划调整为高性能这段代码可以用PowerShell的注册表和系统命令实现# 关闭传递优化 Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config -Name DODownloadMode -Value 0 # 资源管理器默认打开此电脑 Set-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name LaunchTo -Value 1 # 显示文件扩展名 Set-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name HideFileExt -Value 0驱动这块我的经验是尽量让Windows Update自己去搞定脚本里一般不折腾显卡驱动。因为显卡厂商的驱动静默安装参数五花八门而且装错了容易蓝屏。除非是重装完系统后网卡驱动都没有的特殊情况这种情况在下面的常见问题章节单独讲。3.5 打包成“一条龙”启动脚本为了让整个流程更傻瓜化我再写一个start.bat放在桌面或U盘根目录echo off chcp 65001 nul echo echo 一条龙部署服务 v3.0 echo echo. echo 正在启动部署脚本请勿关闭窗口... echo. powershell -ExecutionPolicy Bypass -File %~dp0install.ps1 echo. echo 部署完成按任意键退出。 pause nul%~dp0的意思是用批处理所在目录作为脚本路径这样不管U盘放在哪台电脑上双击这个bat都能正确找到install.ps1。-ExecutionPolicy Bypass是在启动时临时绕过执行策略避免每次都要手动改。到这里“双击bat文件脚本自动干活”的体验就成了。整个流程跑完大部分基础软件都装好了编码环境可用了常用系统配置也调好了。4. 常见问题与排查技巧实录在实际使用这套方案的过程中我遇到过不少问题挑几个发生频率最高、对初学者最头疼的来说。4.1 重装系统后网卡驱动丢失无法联网这是重装系统后最致命的问题系统装好了但网卡驱动没有上不了网更别说下载软件了。win11重装系统后没有wifi、电脑重装系统后网卡没了这类问题几乎每个装机的人都遇到过。解决思路有两个。第一个是提前预防重装之前先用驱动备份工具把你机器里的网卡驱动导出放到U盘里装完系统先装网卡驱动再跑部署脚本。第二个是应急处理用手机USB共享网络或者插入免驱的USB无线网卡临时连上网络后让Windows更新自动补驱动。我个人更推荐第一种。驱动的备份工具很多比如驱动精灵、360驱动大师都带备份功能导出后是一个文件夹重装完系统右键选择更新驱动程序指定到这个文件夹就能装好。不过我的部署脚本里现在也加了一步保险检测到系统没有可用网络时会先尝试用pnputil导入U盘里备好的驱动包。代码大概长这样$driverPath D:\DriverBackup if (Test-Path $driverPath\*.inf) { pnputil /add-driver $driverPath\*.inf /subdirs /install }4.2 winget 源访问慢或者下载失败winget在国内的访问速度确实不太稳定尤其是刚装完系统、网络什么都没优化的时候经常出现下载到一半就报错的情况。我的处理方式是配置镜像源。winget支持通过环境变量或配置文件切换源具体做法是修改ms-windows-store://相关配置。但这里有个更实用的小技巧把安装重试逻辑写进脚本比如每个安装最多尝试3次失败后等待几秒钟再重试。下面是改进后的安装函数function Install-App { param([string]$Id) $retry 0 do { $retry winget install --id $Id --silent --accept-package-agreements --accept-source-agreements 2$null if ($LASTEXITCODE -eq 0) { break } Write-Host 安装失败重新尝试 ($retry/3)$Id -ForegroundColor Yellow Start-Sleep -Seconds 5 } while ($retry -lt 3) }实测下来加了重试机制后成功率提升非常明显。能想到的原因是第一次失败往往是因为winget源还没初始化好第二次再试时缓存和索引已经建立起来了。4.3 安装过程中弹窗卡住进程不动了虽然加了很多静默参数但总有软件不听话安装到一半还是弹个向导出来导致脚本卡住。这种情况最常见的两个原因软件包本身不支持静默安装或者包的安装器是多层的外层是一个引导程序内层才是真正的安装包。我的排查思路是先试手动静默安装这个软件看能不能成功。如果不行就用进程监视工具看一下安装时实际调用了哪个子进程然后单独配置那个子进程的参数。实在搞不定的软件就把它从自动化清单里剔除改成脚本运行到末尾时提醒手动安装Write-Host 以下软件需要手动安装 -ForegroundColor Cyan Write-Host - 某某软件请到官网下载安装包后手动安装不硬刚是一种智慧脚本不是用来解决所有软件的把能自动化的自动化不能自动化的明确提示整个体验反而更流畅。4.4 脚本报错“无法加载文件因为在此系统上禁止运行脚本”这个错误是因为PowerShell默认执行策略是Restricted禁止运行任何脚本。处理方法前面提过执行Set-ExecutionPolicy RemoteSigned -Scope CurrentUser即可。另外我推荐在bat里通过-ExecutionPolicy Bypass启动powershell这样连首次设置都省了。4.5 部分软件安装完还需要重启才能完全生效这种情况常见于.NET环境、Visual C运行库这类系统组件。我的做法是在脚本最后检测是否有待生效的系统变更然后设置一个提示让用户决定是否立即重启Write-Host 部署完成。部分系统组件需要重启才能生效。 -ForegroundColor Yellow $restart Read-Host 是否立即重启(y/n) if ($restart -eq y) { Restart-Computer }如果你是在给“小白”装机建议把“是否需要重启”的询问做成默认yes也就是几秒不输入就自动重启省得对方看着提示不知道怎么操作。4.6 各个击破软件残留与卸载冲突重装系统后有些软件装第一次时可能带着旧版本的痕迹比如安装目录没删干净、注册表里有残留导致静默安装失败。这种情况我一般在脚本开头强制删除几个已知的冲突目录比如$cleanupPaths ( C:\Program Files\SomeApp, $env:LOCALAPPDATA\SomeApp ) foreach ($p in $cleanupPaths) { if (Test-Path $p) { Remove-Item -Recurse -Force $p } }写这段时要特别小心千万别把整个Program Files删了。我的经验是只针对自己清单里安装失败过的那几个软件路径做定向清理不要做全局扫描。4.7 在企业批量装机场景下的扩展思路如果是给公司批量部署几十台机器纯靠个人脚本一个个跑效率太低可以用Sysprep封装镜像把软件装好之后做系统镜像新机器直接恢复镜像。但镜像封装维护起来比较麻烦而且软件更新后要重新封装。我的建议是个人和小团队用“脚本 winget”方案公司层面才考虑用企业部署工具。只要把脚本和配置清单放到共享盘或企业内部站点重装完系统后拉下来执行一样能保证软件版本一致比重新封装镜像要灵活得多。后话两个我一直在用的加分项最后分享两个我日常使用中觉得特别好用的细节。第一个是把部署脚本的运行日志保存下来方便回看。在install.ps1开头加一行$logFile C:\Deploy\deploy_$(Get-Date -Format yyyyMMdd_HHmmss).log然后在每个关键步骤的输出后面追加| Tee-Object -FilePath $logFile -Append。有了日志脚本如果装到一半崩了能很快定位是哪一步出了问题。第二个是维护一个“装机后手动步骤”的备忘清单放在部署目录里的Markdown文件里。比方说登录微信、修改浏览器主页、导入书签、登录网盘客户端这些没法自动化的操作列成checklist每次照着过一遍就行。这样整套流程就从“自动化脚本”变成“半自动人工清单”覆盖得更全面也不怕遗漏。这套一条龙部署服务我已经用了两年多从最初的几十行批处理迭代到现在历经了三次大改版。最大的感触是部署服务本身就是个“项目”要持续维护软件变化、网络环境变化都会影响它的稳定性。但只要框架搭对了后续的维护成本其实很低一次投入长期受益。