Use PowerShell to Install Windows Features and Reboot

Recently, I installed the Windows Subsystem for Linux (WSL) feature on my Windows 10 computer. Microsoft has an installation guide that walks you through the entire process, but I thought I'd share a few PowerShell tricks when it comes to installing Windows features.

The system used throughout this blog article runs Windows 10 version 1803 which ships with Windows PowerShell version 5.1. Your mileage may vary if you're using a different version of Windows and/or PowerShell.

Run Windows PowerShell elevated as an administrator. Add the Windows Subsystem for Linux feature.

1Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online

install-wsl1a.jpg

A reboot is required and I thought this was kind of a bummer until I discovered that the Enable-WindowsOptionalFeature cmdlet doesn't have a parameter to make it go ahead and automatically reboot if one is needed. That's the real bummer :-(. Well, not really, because PowerShell can be used to solve that problem.

Specify the NoRestart parameter to make it give your prompt back. Luckily, the RestartNeeded property is returned as an object-oriented result and not just output to the screen. Yes, there's a difference. This allows you to store the results in a variable and perform logic on them to automatically reboot if needed. By the way, this will work with any feature added with Enable-WindowsOptionalFeature, not just the one shown in this blog article.

1Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online -NoRestart -OutVariable results
2if ($results.RestartNeeded -eq $true) {
3  Restart-Computer -Force
4}

install-wsl2a.jpg

Well, that's nice and all, but some of the command output as shown in the previous example is still displayed on the screen along with this progress information shown in the following example.

install-wsl3a.jpg

How can you silence all of that and just make it so without displaying any results? Most people don't know about the $ProgressPreference global variable and while it's generally not considered to be a best practice to change the value of these types of global preference variables, it's what must be done in this scenario if you want to silence the progress information. I always like to say best practices are a starting point, not an ending one. Anytime you're going to change the values of these types of global preference variables, store the current value in a variable, change it, run the command, and then change it back to it's previous value immediate after the command finishes. It's also worth noting that changes to these types of preference variables only affects the current PowerShell session.

The second part of the puzzle is that when the OutVariable parameter is used to store the results in a variable, it returns the results and stores them in the specified variable. To perform this functionality silently, simply store the results of the command in a variable instead of using the OutVariable parameter.

Set the global $ProgressPreference variable to silently continue (the default is continue), store the results of the command in a variable, and perform logic on the contents of the variable to determine if a reboot is needed.

1$ProgPref = $ProgressPreference
2$ProgressPreference = 'SilentlyContinue'
3$results = Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online -NoRestart
4$ProgressPreference = $ProgPref
5if ($results.RestartNeeded -eq $true) {
6  Restart-Computer -Force
7}

install-wsl4b.jpg

Last, but not least, the warning about the restart being suppressed needs to be silenced in the previous example. This is a scenario where there's no need to change the value of the global $WarningPreference variable because the command has a WarningPreference parameter that only affects this single command this one time.

1$ProgPref = $ProgressPreference
2$ProgressPreference = 'SilentlyContinue'
3$results = Enable-WindowsOptionalFeature -FeatureName Microsoft-Windows-Subsystem-Linux -Online -NoRestart -WarningAction SilentlyContinue
4$ProgressPreference = $ProgPref
5if ($results.RestartNeeded -eq $true) {
6  Restart-Computer -Force
7}

install-wsl5b.jpg

As you've seen in this blog article, it seems as if something is missing from the Enable-WindowsOptionalFeature cmdlet when trying to automate the installation of Windows features with it, but when you know how to harness the power of PowerShell, there's almost always a solution to every problem.

µ