I have numerous Windows devices that I am responsible for setting up and maintaining. I have 4 personal Windows devices including my laptop, my wife’s laptop, my children’s computer, and my home desktop which also serves as our family media server. I then have 2 work Windows devices that I am responsible for a desktop and a laptop. My goal is to be able to walk-up to any of my Windows devices re-stall the Windows operating system, kick off a setup script, and have the machine back in a fully functioning state with all of the apps and files available and ready to use. I formed this stance over the years for multiple reasons:
- Be able to wipe a device yearly to clean up the apps, extensions, and OS updates that accumulate over time.
- Make sure that all personal files are being synced to the cloud to protect against the event that a device fails or is lost.
- Limit the length of time a virus or malware can exist on a device.
- Make sure the device is running the latest versions of applications and the Windows OS.
- Make sure the device is configured properly for anti-virus, firewall, updates, and backups.
All of these items can be addressed without performing a wipe and load of the OS. But I have found that I can knock all of these out at one time by wiping the system. I get the additional benefit that if one of my devices does become infected with a virus I don’t have to struggle removing it. That process alone can take days as I wrote about here. I also don’t have to wonder afterwards whether I did completely remove the virus or if a piece of it is still lurking around in my system.
What Are the Steps
The setup and configuration of a device has many different steps and can differ from device to device. My wife’s laptop doesn’t need media server software or development tools such as Visual Studio. And it certainly doesn’t need to be joined to the domain at my company like my work devices do. So we need to create different scripts for the different roles the devices are serving. We want to be able to layer the scripts so that we can have a base script that performs the tasks that are common among all of the devices. This may include configuring Windows Update, installing Chrome and Microsoft Office, and configuring security such as Windows Controlled Folder Access.
Here is a list of tasks to consider:
- Install Windows Features
- IIS
- Windows Subsystem for Linux (WSL)
- Telnet
- Configure Windows
- Customize Windows Explorer
- Customize Desktop and Taskbar
- Setup User Accounts
- Setup Windows Update
- Install Applications
- Configure Backup
The Tools
On Windows devices PowerShell is the primary scripting language and what we will be writing our scripts in. To install applications Windows doesn’t have a built-in solution as nice as apt-get on Linux. We will use a third-party tool called Chocolatey. It combines the power of nuget and PowerShell to enable the installation of applications from the command line. The last piece of the process that will bring all of it together is Boxstarter. It provides orchestration, reboot resiliency, and a number of commands and tools to simplify the process.
Boxstarter
To get started install Boxstarter. You can download the Boxstarter module installer from the web site or you can use Chocolatey to install the Boxstarter. Alternatively, you may invoke the module installer over the web using Powershell.
If you are running Powershellv3 or higher:
. { iwr -useb http://boxstarter.org/bootstrapper.ps1 } | iex; get-boxstarter -Force
If you are running powershell v2:
iex ((New-Object System.Net.WebClient).DownloadString('http://boxstarter.org/bootstrapper.ps1')); get-boxstarter -Force
This will install Chocolatey if necessary and then install the necessary Boxstarter modules.
The next step is to compose our script. Here is the Boxstarter-Base.txt
script I use as the first step of all of my other scripts.
Set-ExplorerOptions -showHidenFilesFoldersDrives -showFileExtensions # Enable Windows Controlled Folder Access Set-MpPreference -EnableControlledFolderAccess Enabled cinst -y 7zip.install --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y vlc --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y visualstudiocode --params '"/NoDesktopIcon /NoQuicklaunchIcon"' cinst -y cmdermini --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y foxitreader --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y googlechrome --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y xyplorer --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y ditto --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" Install-WindowsUpdate -AcceptEula
The script configures Explorer options, enables Windows Controlled Folder Access, installs applications, and then runs Windows Update. The script includes –cacheLocation because Chocolately had a bug at the time of this article that would recursively created nested folders for each application install.
Here is an example of a more complex script that I use to setup my development devices.
Update-ExecutionPolicy Unrestricted Set-ExplorerOptions -showHidenFilesFoldersDrives -showProtectedOSFiles -showFileExtensions cinst Microsoft-Hyper-V-All -source windowsFeatures cinst Microsoft-Windows-Subsystem-Linux -source windowsFeatures cinst TelnetClient -source windowsFeatures # Enable Windows Controlled Folder Access Set-MpPreference -EnableControlledFolderAccess Enabled #cinst IIS-WebServerRole -source windowsfeatures #cinst IIS-HttpCompressionDynamic -source windowsfeatures cinst -y 7zip.install --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y autohotkey.portable --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y beyondcompare --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y curl --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y fiddler4 --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y git.install --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y nodejs.install --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y notepadplusplus.install --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y visualstudiocode --params '"/NoDesktopIcon /NoQuicklaunchIcon"' --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y nuget.commandline --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y sysinternals --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y vlc --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y cmdermini --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y Wget --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y baretail --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y foxitreader --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y putty.install --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y fscapture --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y linqpad --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y googlechrome --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y xyplorer --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y docker-for-windows --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y postman --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y nimbletext --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y dotpeek --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" cinst -y ditto --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" #cinst -Y listary --cacheLocation "$env:userprofile\AppData\Local\Temp\chocolatey" # Install applications not available in Chocolatey (New-Object System.Net.WebClient).DownloadFile("https://download.teamviewer.com/download/TeamViewerPortable.zip","$Env:TEMP\TeamViewerPortable.zip");(Expand-Archive "$Env:TEMP\TeamViewerPortable.zip" -DestinationPath "$Env:USERPROFILE\AppData\Local\TeamViewerPortable\" -Force); (New-Object System.Net.WebClient).DownloadFile("https://typora.io/windows/typora-setup-x64.exe","$Env:TEMP\typora-setup-x64.exe");cmd /c '%TEMP%\typora-setup-x64.exe /SILENT' # Include this if you want Xamarin installed --add Microsoft.VisualStudio.Workload.NetCrossPlat;includeOptional (New-Object System.Net.WebClient).DownloadFile("https://aka.ms/vs/15/release/vs_enterprise.exe","$Env:TEMP\vs_enterprise.exe");cmd /c 'start /wait %TEMP%\vs_enterprise.exe --wait --passive --add Microsoft.VisualStudio.Workload.Azure --add Microsoft.VisualStudio.Workload.Data;includeOptional --add Microsoft.VisualStudio.Workload.NetCoreTools --add Microsoft.VisualStudio.Workload.NetWeb;includeOptional --add Microsoft.VisualStudio.Workload.Node --includeRecommended' # Visual Studio Code Extensions code --install-extension ms-vscode.csharp code --install-extension formulahendry.code-runner code --install-extension streetsidesoftware.code-spell-checker code --install-extension msjsdiag.debugger-for-chrome code --install-extension PeterJausovec.vscode-docker code --install-extension dbaeumer.vscode-eslint code --install-extension abusaidm.html-snippets code --install-extension eg2.vscode-npm-script code --install-extension ms-vscode.powershell code --install-extension Ionide.ionide-fsharp code --install-extension Shan.code-settings-sync code --install-extension Ionide.ionide-fake code --install-extension Ionide.ionide-paket code --install-extension esbenp.prettier-vscode code --install-extension eamodio.gitlens code --install-extension robertohuertasm.vscode-icons Install-WindowsUpdate -AcceptEula
This script installs a number of Windows features including Hyper-V and Windows Subsystem for Linux, updates the PowerShell execution policy so that unsigned scripts can run, installs many applications from Chocolatey, installs several applications not available from Chocolatey, and installs Visual Studio Code extensions.
Once you have your script we need to save it. You have lots of options here. Boxstarter supports:
- Saving as a package on any Nuget feed.
- Saving a package to a Network share or any local media such as a thumb drive.
- Saving to a single text file or any text based HTTP resource (like a Github Gist)
If it is a script you don’t have secrets in such as an application license key or account credentials then a Gist is a good place to put your script. But if you do have secret information then don’t use a Gist as even a secret Gist is visible to anyone with the URL. Security through obscurity is the same as no security at all.
Once you have saved the Gist, to get the URL we need click the “Raw” link.
Now let’s run our script by invoking the the Install-BoxstarterPackage command pointing to the gist created above:
Install-BoxstarterPackage -PackgeName https://gist.githubusercontent.com/JoshuaCode/5cad04e705f31be41456e7632b3022cd/raw/7e1cb054c855c5bf725a9e85b13b59e8de59aa17/Boxstarter-Base.txt -DisableReboots
While you can use the -PackageName argument to point to any public Chocolatey package, you can also point to any URL that resolves to a plain text script like the gist we created. Note that we use the -DisableReboots argument to suppress automatic reboots.
Summary
You have now seen how easy it is to create your script, install Boxstarter, and run your script. The next step is to begin creating your own script. Remember that you have the full power of PowerShell available to you so be creative. Some additional ideas from my company device script include:
- Join the domain
-
Merges registry settings
regedit /s RegistrySettings.reg
- Add a nuget repository to Visual Studio
nuget sources Add -Name AcmeCompany -Source http://tfs.acmecompany.com:8080/tfs/CollectionName/_packaging/AcmeCompany/nuget/v3/index.json
- Add a private extension gallery to Visual Studio which I detailed in this article
One response to “Automated Setup of a Windows Environment Using Boxstarter and PowerShell”
[…] Automated Setup of a Windows Environment Using Boxstarter and PowerShell […]
LikeLike