• 使用Powershell及Choco实现自动安装 Windows 10 开发环境
  • 发布于 2个月前
  • 1032 热度
    0 评论

程序员最讨厌的事情之一可能就是装电脑了。因为程序员的电脑环境配置和正常人的很不一样。通常,人工安装一台新开发机得花上几个小时。得让这个过程自动化,毕竟编程的精髓就在于让复杂事情简单化,想办法偷懒!

其实自动安装和配置Windows并不是什么新鲜事,早在十几年前那个组装机盛行的年代,电脑城里的“高手”就在用各种民间封装的镜像实现一键安装系统和软件了。方法有很多,比如通过微软或三方工具编辑Windows安装镜像,加入自动应答文件,最后用静默参数安装常用软件,以及更偷懒的Ghost封装等等。十几年前的我,也曾热衷过自己封装Windows,写脚本安装软件,然后修完妹子的电脑还要帮妹子的男朋友们修……
今天我介绍的方法与十几年前的有所不同,与十几年前比,现在我们要面对一些新的问题:
01 软件更新越来越频繁,每次装电脑希望用最新的,传统方式封装软件没几天就会过时。
02 软件不想和操作系统镜像一起分发,Windows 10半年更新一次,维护传统方式封装的镜像十分费力。
03 正常人的电脑很容易安装,无需专门设计自动装机工具。但是程序员的环境越来越复杂,工具越来越多。

针对这些现状,我选择使用Powershell及Choco来设计新的自动装机脚本。Powershell负责配置Windows,Choco则可以自动从网上下载最新的软件安装包并静默安装。这样就不用将软件安装包整合到Windows镜像里去,以免没几个月就全部过时导致你辛辛苦苦制作的好人装机盘又得更新。

目标
以我自己为例,我是一名ASP.NET程序员,同时也做一些UWP应用开发。所以对我来说,环境要求是:
.Windows 10 Pro 系统
.开启IIS + ASP.NET
.开启开发者模式
.安装Chrome,7z,NotePad++,VSCode,LINQPad等常用软件
我们来看看Powershell + Choco 如何自动化完成这些任务。我的整个装机脚本的代码是开源的,文章最后有GitHub地址,所以本文只介绍重点步骤和代码。完整脚本大家可以看GitHub自由修改和使用。更欢迎高手们参与贡献,一起完成一个造福各种程序员的脚本。


重命名计算机
装机第一步我喜欢重命名计算机,以便管理。在Powershell中,可以使用Rename-Computer命令完成。
获取用户输入的命令是Read-Host,输出文字的命令是Write-Host,给变量赋值直接用=,不需要声明类型。
要求用户输入计算机名,并重命名的Powershell代码如下:

$computerName = Read-Host 'Enter New Computer Name'
Write-Host "Renaming this computer to: " $computerName  -ForegroundColor Yellow
Rename-Computer -NewName $computerName

当然,这一部是要求重启计算机生效的,我们会放稍后执行。
禁用自动待机
我们不希望跑自动化脚本装逼的时候,电脑超时待机就尴尬了。所以在漫长的自动化装机开始的时候,要禁用接通电源(AC)时候的自动待机。
使用Powercfg命令,设置接通电源的情况下,闲时20分钟关闭屏幕,但永不待机。
Powercfg /Change monitor-timeout-ac 20
Powercfg /Change standby-timeout-ac 0

桌面图标处理
全新的Windows 10安装完成,桌面默认是没有“此电脑”图标的,并且故意留了个Edge浏览器的快捷方式,大家也知道它的唯一作用是下载Chrome,并且以后也会变成Chromium核心,活得还没WP长,IE都笑了……(不好意思扯远了)因此我希望能自动添加“此电脑”图标并去掉没用的Edge。


添加“此电脑”图标的操作是通过修改注册表实现的

$thisPCIconRegPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"
$thisPCRegValname = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
$item = Get-ItemProperty -Path $thisPCIconRegPath -Name $thisPCRegValname -ErrorAction SilentlyContinue
if ($item) {
Set-ItemProperty  -Path $thisPCIconRegPath -name $thisPCRegValname -Value 0  
}
else {
New-ItemProperty -Path $thisPCIconRegPath -Name $thisPCRegValname -Value 0 -PropertyType DWORD  | Out-Null  
}


去除Edge的快捷方式非常简单,直接删除文件就行。在Powershell里要用环境变量的方法是使用 $env 关键词。当前用户的环境变量是USERPROFILE,Edge在桌面上,所以拼接路径是Desktop目录。

$edgeLink = $env:USERPROFILE + "\Desktop\Microsoft Edge.lnk"
Remove-Item $edgeLink


自动安装IIS
在这个Windows服务器非政治正确的时代,IIS依然有一席之地,维护老的ASP.NET项目还是得用,并且ASP.NET Core 2.2上有明显的性能优势,谁喊的Linux我保证不派软狗去暗杀……所以又扯远了,Powershell启用Windows组件的命令是 Enable-WindowsOptionalFeature,带上-All参数的话可以自动安装依赖项。所以脚本如下:

Enable-WindowsOptionalFeature -Online -FeatureName IIS-DefaultDocument -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-HttpCompressionDynamic -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-HttpCompressionStatic -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebSockets -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-ApplicationInit -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-ASPNET45 -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-ServerSideIncludes
Enable-WindowsOptionalFeature -Online -FeatureName IIS-BasicAuthentication
Enable-WindowsOptionalFeature -Online -FeatureName IIS-WindowsAuthentication


其实用DISM命令也可以实现这些功能的,有兴趣的可以自己研究。DISM还能自定义Windows镜像……
启用 Windows 10 开发者模式
启用开发者模式的唯一作用就是维护那些年少不懂事时候开发的UWP应用。同样,只要修改注册表就可以了:

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"


// 可能不久得将来,等UWP凉凉了,这一步也就不需要了……


启用远程桌面
一个敬业的程序员,就应该连上厕所时候也掏出手机远程回去写代码。方法还是修改注册表,并开启对应的防火墙规则。

Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\" -Name "fDenyTSConnections" -Value 0
Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" -Name "UserAuthentication" -Value 1
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"


安装 Choco for Windows
Chocolatey 是我们接下来要用的自动安装软件的工具,即 choco 命令,和Linux上的apt/yum很像。它是用Powershell + NuGet 实现的,有兴趣可以去官网了解一下:
https://chocolatey.org/
我们用官方提供的Powershell命令安装Chocolate:

Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))


重启 Windows
还记得第一步改了计算机名吗,最后我们需要重启电脑,让配置生效,然后再装软件,以避免有的软件把机器名设死在配置里然后爆。
为了假装用户友好,我们可以给用户一个确认,让人工来触发重启操作,只要用Read-Host就行。Powershell重启机器的命令是 Restart-Computer,当然你用 shutdown -r -t 0 也可以。

Read-Host -Prompt "Configuration is done, restart is needed, press [ENTER] to restart computer."
Restart-Computer


自我提权
各位可能已经发现了,上面的步骤几乎都是要求管理员权限才能执行的。我们装机时候可以手工用管理员权限跑Powershell,但是更方便的是在普通权限下运行,并让它自己提升为管理员权限。在文件头部加入:

if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit }


这样,脚本会检测当前自己是否有管理要权限,如果没有,会弹出UAC申请一个管理员权限的Powershell并继续运行当前脚本。
以上所有步骤的最终Powershell脚本在我的GitHub上:
https://github.com/EdiWang/EnvSetup/blob/master/01-Prepare-Windows.ps1

使用 Choco 自动安装软件
重启完电脑以后,我们可以在管理员权限的CMD或者Powershell下,用choco命令自动安装软件。我选择的是cmd,因为它是个有情怀的exe。
chocolatey的库中有大量常用软件,并且很多都是面向程序员的。需要的可以去官方库里看看:
https://chocolatey.org/

安装命令是 choco install 包名 -y,其中 -y 参数表示自动应答 Yes,以便在无人值守时候静默安装,无需用户确认。
安装常用软件的批处理就可以这样写:

@echo ------------------------------------
@echo Installing 7-Zip...
@echo ------------------------------------
choco install 7zip.install -y

@echo.
@echo ------------------------------------
@echo Installing Google Chrome...
@echo ------------------------------------
choco install googlechrome -y

完整的脚本在 https://github.com/EdiWang/EnvSetup/blob/master/02-Install-Software.cmd
截止发稿,我已经加入了下列软件的自动安装脚本,其中VSCode的插件也是有包的,可以自动安装:
7-Zip
Google Chrome
Pot Player
Microsoft Teams
SysInternals
Lightshot
FileZilla
TeamViewer
Notepad++
Visual Studio Code
C-Sharp
Icons
MSSQL
DotPeek
LINQPad
Fiddler
Git
GitHub for Windows
FFMpeg
CURL
WGet
OpenSSL
Beyond Compare


删除不需要的预装 UWP 应用
全新安装的Windows 10会自带一些微软自家以及合作伙伴的UWP应用,有些我用不上。这些应用也可以用自动化的方式删除。
首先要获取UWP应用的包名,可以用 Get-AppxPackage 命令。它会返回一串这样的东西:

要删除UWP应用,微软官网的命令是删它的PackageFullName,比如必应新闻的:
Remove-AppxPackage -Package Microsoft.BingNews_4.28.3242.0_x64__8wekyb3d8bbwe
但是这样是会爆的,一旦Windows在后台偷偷更新了这些应用,版本号变了,你的脚本就失效。所以我们要用另一种方法,不匹配具体版本,只匹配名称去删除UWP应用。技巧如下:
Get-AppxPackage -Name Microsoft.BingNews | Remove-AppxPackage
我们有很多UWP要删,程序员思维当然是写一个循环,而不是一条条复制命令。Powershell里做循环的方式和C#非常类似,用foreach语法。在这个例子里,我把要删除的UWP名称放在了一个字符串数组中,然后用循环去删除他们。

$uwpRubbishApps = @(
"Microsoft.Messaging",
"king.com.CandyCrushSaga",
"Microsoft.BingNews",
"Microsoft.MicrosoftSolitaireCollection",
"Microsoft.People",
"Microsoft.WindowsFeedbackHub",
"Microsoft.YourPhone",
"Microsoft.MicrosoftOfficeHub",
"Fitbit.FitbitCoach",
"4DF9E0F8.Netflix")

foreach ($uwp in $uwpRubbishApps) {
    Get-AppxPackage -Name $uwp | Remove-AppxPackage
}

至此,就大功告成了!感谢看到这里的各位~

用户评论