文章目录
- [[编程达人挑战赛] 用 PowerShell 写了一个"电脑一键初始化脚本":从混乱到可复制的开发环境](#[编程达人挑战赛] 用 PowerShell 写了一个“电脑一键初始化脚本”:从混乱到可复制的开发环境)
-
- 一、为什么我要做一个"一键初始化脚本"?
- 二、整体设计思路:别急着写脚本,先把套路想清楚
- [三、关键实现一:用配置驱动的软件安装(不再写一堆 if)](#三、关键实现一:用配置驱动的软件安装(不再写一堆 if))
-
- [3.1 用 JSON/YAML 列表维护软件清单](#3.1 用 JSON/YAML 列表维护软件清单)
- [3.2 通用安装函数(以 winget 为例)](#3.2 通用安装函数(以 winget 为例))
- 四、关键实现二:系统设置自动化(用脚本替代"狂点控制面板")
-
- [4.1 显示桌面"此电脑"图标(经典需求)](#4.1 显示桌面“此电脑”图标(经典需求))
- [4.2 显示文件扩展名](#4.2 显示文件扩展名)
- 五、踩坑与调试:权限、编码、路径,这三件事最容易"阴沟翻船"
-
- [5.1 权限:不是所有 PowerShell 都等于"管理员"](#5.1 权限:不是所有 PowerShell 都等于“管理员”)
- [5.2 编码与中文路径](#5.2 编码与中文路径)
- [5.3 路径相对/绝对混用导致"找不到文件"](#5.3 路径相对/绝对混用导致“找不到文件”)
- 六、进一步的代码优化:从"能用"到"敢分享"
- 七、总结:把"搭环境"变成一段可以复用的代码
[编程达人挑战赛] 用 PowerShell 写了一个"电脑一键初始化脚本":从混乱到可复制的开发环境
每次装新系统,都要重复安装软件、改配置、调环境变量,浪费时间还容易漏。
这篇文章聊聊我是怎么用 PowerShell 写了一个"PC 一键初始化脚本",把这些琐事自动化,并且在实战中踩坑、调优,最后变成一个可以放心分享给同事使用的小工具。
一、为什么我要做一个"一键初始化脚本"?
先说场景:
我日常需要在多台机器上工作(办公室台式机、笔记本、测试机),而且经常重装系统 / 换设备。每次环境搭建都要重复:
- 安装常用软件(浏览器、Git、IDE、压缩工具、终端工具等);
- 配置环境变量(Python、Java、Node、Go......看项目吃什么);
- 调整系统设置(显示"此电脑"图标、显示文件扩展名、关一些开机自启);
- 配置 Git、SSH key、常用 alias 等。
之前完全靠"记忆 + 手点",问题是:
- 步骤容易漏(比如忘记装某个 CLI 工具,写代码写到一半才发现);
- 很难复现"上一台机器上那个刚刚好的状态";
- 帮同事配环境时全靠嘴讲,对方边听边做,效率极低。
于是我决定做一件事:
用 PowerShell 写一个「一键初始化脚本」,把"我脑子里的那套环境模板"变成可执行代码。
二、整体设计思路:别急着写脚本,先把套路想清楚
一开始我就给自己定了几个约束:
-
脚本必须支持重复运行
- 再跑一次不会把系统搞坏,而是幂等:有的就跳过,没有的就补上。
-
配置和逻辑尽量分离
- 软件列表、下载地址、安装参数不要写死在代码逻辑里,方便以后统一改动。
-
需要有"可见反馈"
- 不只是黑屏滚 log,要让使用者知道"现在在做什么、哪一步失败了"。
-
能适应几种常见场景
- 新系统全新初始化;
- 已有系统补充安装;
- 给同事远程指导使用。
因此我最后把脚本拆成了几个模块(逻辑上):
- 01_EnvCheck.ps1(环境检测与权限检查)
- 02_SoftInstall.ps1(常用软件安装与配置)
- 03_SystemTweaks.ps1(系统设置调整)
- 04_DevConfig.ps1(开发环境与 Git / SSH 等)
主入口 Init-MyPC.ps1 只做调度:加载配置 → 按顺序调用模块 → 输出结果。
在这里插入图片描述(建议放一张"脚本目录结构 + PowerShell 运行界面"的截图)
三、关键实现一:用配置驱动的软件安装(不再写一堆 if)
很多人写"初始化脚本"的第一个版本,都长这样:
powershell
# 典型"长成一坨 if"的版本
if (-not (Get-Command git.exe -ErrorAction SilentlyContinue)) {
# 安装 Git
}
if (-not (Test-Path "C:\Program Files\7-Zip\7z.exe")) {
# 安装 7zip
}
if (-not (Get-Command code.cmd -ErrorAction SilentlyContinue)) {
# 安装 VS Code
}
这样写的问题是:
扩展性极差,软件一多,脚本又臭又长,而且换一个下载地址,就要改多处。
我后面改成了 配置 + 通用安装函数 的方式:
3.1 用 JSON/YAML 列表维护软件清单
例如 softwares.json:
json
[
{
"Name": "Git",
"Check": "git.exe",
"Type": "winget",
"Id": "Git.Git"
},
{
"Name": "7zip",
"CheckPath": "C:\\Program Files\\7-Zip\\7z.exe",
"Type": "winget",
"Id": "7zip.7zip"
},
{
"Name": "VSCode",
"Check": "code.cmd",
"Type": "winget",
"Id": "Microsoft.VisualStudioCode"
}
]
3.2 通用安装函数(以 winget 为例)
powershell
function Test-SoftInstalled {
param(
[string]$CheckCommand,
[string]$CheckPath
)
if ($CheckCommand) {
return [bool](Get-Command $CheckCommand -ErrorAction SilentlyContinue)
}
if ($CheckPath) {
return Test-Path $CheckPath
}
return $false
}
function Install-SoftFromConfig {
param(
[Parameter(Mandatory)]
[string]$ConfigPath
)
$list = Get-Content $ConfigPath | ConvertFrom-Json
foreach ($soft in $list) {
Write-Host "==> 检查 $($soft.Name) ..." -ForegroundColor Cyan
$installed = Test-SoftInstalled -CheckCommand $soft.Check -CheckPath $soft.CheckPath
if ($installed) {
Write-Host " 已安装,跳过。" -ForegroundColor Green
continue
}
if ($soft.Type -eq 'winget') {
Write-Host " 使用 winget 安装:$($soft.Id)" -ForegroundColor Yellow
winget install --id $soft.Id --silent --accept-package-agreements --accept-source-agreements
} else {
Write-Host " 不支持的安装类型:$($soft.Type)" -ForegroundColor Red
}
}
}
主脚本调用:
powershell
Install-SoftFromConfig -ConfigPath ".\config\softwares.json"
这样有几个好处:
- 新增软件只需要改 JSON,不用再往脚本里堆 if;
- 支持重复执行:已安装就跳过;
- 以后要换安装方式(比如某些机器不用 winget 而用本地安装包),只需在配置中增加类型和对应逻辑。
四、关键实现二:系统设置自动化(用脚本替代"狂点控制面板")
我经常会调整这些设置:
- 桌面显示"此电脑"、"控制面板"等图标;
- 资源管理器显示文件扩展名、显示隐藏文件;
- 关闭一些烦人的开机提示。
这些本质上就是注册表 + 一些系统 API 调用,所以我把常用的设置封成函数:
4.1 显示桌面"此电脑"图标(经典需求)
powershell
function Enable-DesktopThisPC {
Write-Host "==> 开启桌面'此电脑'图标" -ForegroundColor Cyan
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"
New-Item -Path $regPath -Force | Out-Null
# {20D04FE0-3AEA-1069-A2D8-08002B30309D} 是"此电脑"的 CLSID
Set-ItemProperty -Path $regPath -Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0
# 刷新桌面
rundll32.exe user32.dll,UpdatePerUserSystemParameters
}
4.2 显示文件扩展名
powershell
function Show-FileExtensions {
Write-Host "==> 设置显示文件扩展名" -ForegroundColor Cyan
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
Set-ItemProperty -Path $regPath -Name "HideFileExt" -Value 0
}
然后在 03_SystemTweaks.ps1 里统一调用:
powershell
Enable-DesktopThisPC
Show-FileExtensions
# 其他 tweaks ...
这一块的"成就感"非常高:点一次脚本,桌面和资源管理器瞬间变成自己熟悉的样子。
五、踩坑与调试:权限、编码、路径,这三件事最容易"阴沟翻船"
5.1 权限:不是所有 PowerShell 都等于"管理员"
一开始我常遇到这样的问题:
- 在普通 PowerShell 窗口里跑脚本,各种 Set-ItemProperty/winget 调用失败;
- 提示 Access Denied 或某些安装步骤静默失败。
后来脚本开头我统一加了一个检查:
powershell
function Ensure-Admin {
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentIdentity)
$isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "[ERROR] 请用管理员权限运行此脚本。" -ForegroundColor Red
Read-Host "按回车键退出..."
exit 1
}
}
Ensure-Admin
少了这几行,后面所有报错都是"诈尸";加上之后,问题定位成本直线下降。
5.2 编码与中文路径
我有一台机器的用户名中带有中文,结果脚本里使用硬编码路径时各种炸:
C:\Users\某某某\AppData\...- 某些工具对非 ASCII 路径支持不好。
解决方案:
- 一律使用
$env:USERPROFILE/$HOME等环境变量组成路径; - 读取/写入文件时,养成显式声明编码的习惯,例如:
powershell
Set-Content -Path $profilePath -Value $profileContent -Encoding UTF8
5.3 路径相对/绝对混用导致"找不到文件"
脚本有时会被放到 U 盘、网络盘或其他路径运行,
如果用相对路径 .\config\xxx 而不切换工作目录,就容易找不到文件。
我最后把入口脚本统一写成这样:
powershell
# 取得当前脚本所在路径,并切换到该目录
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
Set-Location $ScriptDir
# 后续路径都基于 $ScriptDir
Install-SoftFromConfig -ConfigPath (Join-Path $ScriptDir "config\softwares.json")
这小小几行能救你无数次"同一脚本在不同机器表现不一样"的折磨。
六、进一步的代码优化:从"能用"到"敢分享"
在基本功能跑通后,我做了几件优化工作,让它更像一个"可以公开分享的作品":
-
增加日志输出与日志文件
- 关键步骤打印到控制台,同时写入
logs\init-YYYYMMDD.log; - 方便事后排查,比如某步 winget 安装失败、网络中断等。
- 关键步骤打印到控制台,同时写入
-
参数化执行
-
支持
-SkipSoft、-SkipTweaks之类参数:- 有时我只想跑系统设置,而不想重新检查所有软件;
-
在入口脚本中解析
$args或用param()定义参数,提升灵活性。
-
-
增加"预检查模式"(Dry Run)
- 加一个
-WhatIf模式,只打印"将要安装/修改什么",不做实际变更; - 同事在第一次跑时可以先预览,信任感会高很多。
- 加一个
做到这个阶段,我才觉得它从"我的个人脚本"升级成了"可以发到团队、写成教程"的项目。
七、总结:把"搭环境"变成一段可以复用的代码
最后用三句话总结这次项目给我的收获:
-
所有重复性的操作,迟早都应该被脚本接管。
哪怕一开始只自动化 30% 的步骤,对长期效率提升也非常可观。
-
写脚本之前先想清楚:幂等性、配置分离、可见反馈。
这三点想明白了,后面的重构和扩展都会轻松很多。
-
把自己的"小工具"做成可以分享的作品,本身就是一次"系统性编码思维训练"。
你会被迫去考虑别人怎么用、怎么出错、怎么阅读你的代码和说明。
如果你也在为"每次换电脑就从零搭环境"头疼,可以从非常小的一步开始:
先写一个只安装 1~2 个软件 的 PowerShell 脚本,把这个流程跑通,再慢慢加模块、加配置。
等你回头看时,你会发现:
你不仅节省了大量机械劳动,还多了一篇可以参加【编程达人挑战赛】的"项目复盘 & 开发经验总结"博客。