Adding support for OS deployment through Wi-Fi to SCCM
So you can reimage your devices on any Wi-Fi network
[edited] 9.7.2021 - added section 4. Automatically use Wi-Fi profile from the running OS
[edited] 25.6.2021 - added section Adding Wi-Fi support to Boot Image imported into SCCM
[edited] 19.6.2021 - IMPORTANT - solved timeouts problem! Check section 3. Making Wi-Fi connection persistent during OS installation reboots
[edited] 17.6.2021 - added workaround for startup timeouts
In this post, I will show you, how to add Wi-Fi support for OSD to SCCM. This can be really helpful if, for example, you want to let your remote employees reimage their computers using a home Wi-Fi network. So for this particular example, I will use SCCM's Cloud Management Gateway (CMG) component as an installation source i.e. installation data will be downloaded from the Internet instead of an on-premise SCCM server.
- For MDT different approach has to be taken
- Setting CMG for deploying Task Sequence is not part of this post. But you can check this good one
Table of Contents
- Prerequisites
- Three problems to solve
- 1. Adding Wi-Fi support into the boot image
- 2. Initialize Wi-Fi before Task Sequence network checks kick in
- 3. Making Wi-Fi connection persistent during OS installation reboots
- 4. Automatically use Wi-Fi profile from the running OS
- Summary
- Useful information
- OS installation screenshots
- TODO
Prerequisites
SCCM
(MEMCM)CMG
(only if you want to make the installation through the Internet)
- OSDCloud PowerShell module
- USB flash drive
- Wi-Fi network (WPA-personal)
- PowerShell console
- Admin rights
Three problems to solve
- We need a boot image, that supports Wi-Fi
- Wi-Fi connection has to be established before the Task Sequence checks kick in
- Wi-FI connection has to survive restarts during the installation process
1. Adding Wi-Fi support into the boot image
This problem is quite easy to solve, thanks to the great work of David Segura and his OSDCloud tool.
So the steps are as follows:
- Create WinPE boot image with Wi-Fi support using OSDCloud
- Upload this boot image to SCCM
- Create Bootable Task Sequence Media
- Deploy Task Sequence Media to USB drive
Create WinPE boot image with Wi-Fi support using OSDCloud
Download and install Windows ADK + WinPE support as stated in OSDCLoud requirements
In Administrator PowerShell console run:
Install-Module OSD -Force
Import-Module OSD -Force
# WinRE instead of WinPE to support Wi-Fi
New-OSDCloud.template -WinRE -Verbose
# create OSDCloud workspace folder
$WorkspacePath = "C:\temp\OSDCloud"
New-OSDCloud.workspace -WorkspacePath $WorkspacePath
# add general Wi-Fi NIC drivers to boot image
Edit-OSDCloud.winpe -CloudDriver Dell, HP, Nutanix, VMware, WiFi
# if you need to add some custom drivers, use
# Edit-OSDCloud.winpe -DriverPath "C:\myCustomDrivers"
After running the command above, there should be boot.wim
in the C:\temp\OSDCloud\Media\Sources
folder.
Upload OSDCloud boot image to SCCM
Import created boot image (boot.wim
) into the Boot Images
Create Bootable Task Sequence Media
Just don't forget to select imported Boot Image!
Deploy Task Sequence Media to USB drive
Use Rufus or similar application to create bootable USB drive from created Bootable Task Sequence Media
ISO.
To avoid redownloading of boot image during OSD, make sure that your USB drive contains exactly the same boot image version as your SCCM
2. Initialize Wi-Fi before Task Sequence network checks kick in
Wi-Fi enabled boot image created by OSDCloud lets you connect to the Wi-Fi network by default. The problem is, that it happens after Task Sequence inner checks. To fix this, we have to customize the default behavior, to initialize Wi-Fi as soon as possible after the WinPE starts. Otherwise, the installation will fail with error
Customize OSDCloud boot image to support Wi-Fi in SCCM OS installation
Several customizations have to be done in boot.wim saved on USB drive created from Bootable Task Sequence Media
ISO, we have created in the previous section. Therefore I've created PowerShell script customize_sccm_usb_boot_image_to_support_wifi.ps1 for you.
Just download and run the script in administrator PowerShell console to make the necessary modification of the connected USB boot drive.
TIP: we are modifying
Bootable Task Sequence Media
boot image instead of the earlier generated OSDCloud image because SCCM customizes boot.wim content automatically (winpeshl.ini especially) when you: import boot image, redistribute it orBootable Task Sequence Media
image is created. Therefore our customization would be removed.
It will automatically:
- Find USB drive that contains boot.wim
- Mount that boot.wim
- Customize winpeshl.ini, to initialize Wi-Fi ASAP after the WinPE start
- If you are interested why not use the
Prestart
command, it is because it is being run too late in the startup process. On contrary winpeshl.ini si processed by winpeshl.exe, which is run right after winlogon.exe kicks in
- If you are interested why not use the
- Customize OSDCloud Set-WinREWiFi function, to omit removal of exported Wi-Fi xml profile (persistence preparation)
- Customize startnet.cmd, to omit OSDCloud builtin attempt, to initialize Wi-Fi (we already done that)
- (optional) Create/copy XML Wi-Fi profile to \Windows\Temp\wprofile.xml (for unattended Wi-Fi connection)
- Save and dismount boot.wim
TIP: There is also an option to integrate Wi-Fi credentials for making unattended connection! Just use parameter
wifiCredential
orxmlWiFiProfile
when you call this script. For more details check help in the script itself.
This is how the unattended Wi-Fi connection will look like, when you boot from created USB.
Adding Wi-Fi support to Boot Image imported into SCCM
To use boot image that supports Wi-Fi not just to start Task Sequence from USB, but also from running OS (i.e. boot.wim will be downloaded from MP), you will have to do one modification in sccm before importing it.
Because SCCM replaces the existing winpeshl.ini
on boot image when you import it or do any action with it, you have to hack it a little bit.
To be more specific, we will force SCCM to use our custom winpeshl.ini
instead of the default one. To manage that, you have to create winpeshl.ini
in [SCCM Install directory]\OSD\bin\x64\
(or i386
for 32-bit boot images) with the following content and do it before you import previously created and customized Wi-Fi capable boot.wim into SCCM!
[LaunchApps]
PowerShell.exe, -NoProfile -NoLogo -ExecutionPolicy Bypass -File connectWifi.ps1
%SYSTEMDRIVE%\sms\bin\x64\TsBootShell.exe
This will force SCCM to use this winpeshl.ini
instead of the default one, every time, any action with any boot image will take place! So it's a good idea to remove this file when the boot image will be safely stored on Management Point.
Thanks Jan-Kristian Arntzen for pointing this out!
3. Making Wi-Fi connection persistent during OS installation reboots
To automatically connect to Wi-Fi you only need two things:
- Wi-Fi profile exported to an XML file
- Logic, that will connect to Wi-Fi specified in such XML file after each restart
The first part is halfway solved thanks to CloudOSD function Start-WinREWiFi
, which automatically creates such XML (during interactive connection to Wi-Fi at start of WinPE). And the customization we've made in the previous section (to not delete this profile after making a connection). So we just have to copy this file to a freshly installed OS drive (I've chosen C:\Windows\WCFG\wprofile.xml
as a destination).
- For details check Task Sequence step COPY Wi-Fi PROFILE TO OS DISK in the next section.
The second part will be solved by customizing the startup command defined in cmdline registry value. The file defined in this registry will be automatically started at the system startup. SCCM itself is using this registry value to manage Task Sequence installation (by running osdsetuphook.exe /execute
). There is also a second important registry value and that is setupType for defining how to treat with cmdline
.
- For details check Task Sequence step CUSTOMIZE STARTUP COMMAND in the next section.
As an easy solution, I have created several helper Task Sequences, that I use as sub-TS
in my main deployment TS
. It makes the process much easier to maintain and reuse, but of course, you can extract the logic and use it as common TS steps.
Helper Task Sequences
All these helper Task Sequences are stored in my GitHub repository, so you can easily import them into your SCCM and use them as described in your own deployment Task Sequence.
COPY Wi-Fi PROFILE TO OS DISK
- What it does
- Search for XML Wi-Fi profile in %TEMP% folder and copies it to newly installed OS disk (
C:\Windows\WCFG\wprofile.xml
), so it is possible to import it later, to maintain Wi-Fi connection persistence after each restart.- Such XML profile could have been created by OSDCloud
Start-WinREWiFi
function or by running mycustomize_sccm_usb_boot_image_to_support_wifi.ps1
script
- Such XML profile could have been created by OSDCloud
- Creates
TS
variableWifiProfile
so it is possible to detect later, that the installation is running through a Wi-Fi connection
- Search for XML Wi-Fi profile in %TEMP% folder and copies it to newly installed OS disk (
- When to use it
- Has to be run in WinPE right after OS installation step
- Called script content
Start-Transcript "$env:TEMP\wProfileCopy.log"
# Get-Volume seems to not work in winpe
$OSDrive = Get-WmiObject win32_logicaldisk | ? { $_.VolumeName -eq "Windows" } | select -exp DeviceId
if (!$OSDrive) { throw "Unable to find OS drive. Did you run this step RIGHT AFTER OS was installed?" }
# location where Wi-FI profile will be stored
$WCFG = "$OSDrive\Windows\WCFG"
# create if doesn't exists
[Void][System.IO.Directory]::CreateDirectory($WCFG)
# search for saved Wi-Fi xml profile in TEMP
# OSDCloud function Start-WinREWiFi saves it there as <SSID>.xml
Get-ChildItem $env:TEMP -File -Filter *.xml | % {
$fileBaseName = $_.BaseName
$filePath = $_.FullName
# if Wi-Fi profile is found, copy it to newly installed OS DISK
if (([xml](Get-Content $filePath)).WLANProfile.Name) {
# RECONNECT TASK SEQUENCE STEP EXPECTS such name and location
$wifiProfile = Join-Path $WCFG "wprofile.xml"
"copying Wi-Fi profile $filePath to $wifiProfile"
Copy-Item $filePath $wifiProfile -Force -ea Stop
# this string will be saved to WifiProfile TS Variable and will be used to detect, that installation is running using Wi-Fi
return $wifiProfile
}
}
Write-Warning "No Wi-Fi profile was found in $env:TEMP"
CUSTOMIZE STARTUP COMMAND
- What it does
- Customizes
cmdline
andsetuptype
registry values plus creates helper batch script, so the first action after OS restart will be establishing connection to Wi-Fi
- Customizes
- When to use it
- Has to be run right after step
Setup Windows and Configuration Manager
i.e. first start of the installed OS
- Has to be run right after step
- Called script content
# customize startup command to prefix whatever there is, with connecting to Wi-Fi
if ($env:TEMP -match "^X:") {
Write-Error "Don't run this in WinPE! Unless you've figured out, how to start Wi-Fi after first OS start"
Start-Sleep 10
exit
}
# Get-Volume seems to not work in winpe
$OSDrive = Get-WmiObject win32_logicaldisk | ? { $_.VolumeName -eq "Windows" } | select -exp DeviceId
# location where Wi-FI profile should be stored
$WCFG = "$OSDrive\Windows\WCFG"
# location of the script, that will be called in cmdline registry value
$helperScript = "$WCFG\custom_cmdline.cmd"
# location of the Wi-Fi profile
$wifiProfile = "$WCFG\wprofile.xml"
# SSID of the Wi-Fi to connect
$SSID = ([xml](Get-Content $wifiProfile)).WLANProfile.Name
# startup command
$cmdLine = Get-ItemPropertyValue "HKLM:\SYSTEM\Setup" -Name cmdline
# from some reason the cmdline in SCCM TS looks like: system32\osdsetuphook.exe /execute
# i.e. it is not absolute path, which causes trouble (boot loop, because of non existent path), when you call it from script
if ($cmdLine -and $cmdLine -notmatch "^$OSDrive\\Windows\\") {
$cmdLine = "$OSDrive\Windows\$cmdLine"
}
if (!$OSDrive) { throw "Unable to find OS drive. Did you run this step AFTER OS was installed?" }
if (!(Test-Path $wifiProfile)) { throw "This shouldn't happen, because this step should be run ONLY if WifiProfile TS variable is filled" }
if (!$SSID) { throw "Unable to extract SSID from $wifiProfile" }
# ensure, that cmdline registry value contains call to my helper script
if ($cmdLine -eq $helperScript) {
# it does >> no change is needed
"No change needed"
return
} else {
# it doesn't >> I have to create new helper script with registry key command + add my own command to it + call this script in cmdline
"CmdLine has to be customized"
$myCommand = @"
@echo off
echo MAKING Wi-FI CONNECTION
REM start Wi-Fi service if needed
SC query wlansvc | FIND /i "RUNNING" > nul
IF ERRORLEVEL 1 (
echo Starting wlansvc
SC start wlansvc
ping 127.0.0.1 -n 10 > nul
) else (
echo wlansvc was already running
ping 127.0.0.1 -n 3 > nul
)
REM add Wi-Fi profile
netsh wlan add profile filename="$wifiProfile"
IF ERRORLEVEL 1 (
REM Wi-Fi adapter is not initialized yet
echo Giving this a second chance
ping 127.0.0.1 -n 15 > nul
netsh wlan add profile filename="$wifiProfile"
IF ERRORLEVEL 1 (
echo Unable to add Wi-Fi profile. Wi-Fi adapter is probably missing
echo ######## Existing NIC^(s^)
wmic nic get name, index, NetEnabled
echo ######## Existing Interface^(s^)
netsh interface show interface
ping 127.0.0.1 -n 15 > nul
exit 1
)
)
REM connect to Wi-Fi
echo Connecting to $SSID
netsh wlan connect name="$SSID" ssid="$SSID"
REM wait for connection
echo Waiting for internet connection
:loop
(ping -n 1 www.google.com | find "TTL=") > nul || goto :loop
echo Success!
REM run command, that was originally mentioned in cmdline value
echo Running original cmdline
$cmdLine
"@
"NEW CONTENT OF cmdline WILL BE"
$myCommand
$myCommand | Out-File $helperScript -Force -Encoding ascii
# replace original value with my script
Set-ItemProperty "HKLM:\SYSTEM\Setup" -Name cmdline -Value $helperScript
# SetupType https://social.technet.microsoft.com/Forums/windows/en-US/b942a34d-c4a7-489c-bb01-45dd65fa9b20/setuptype-and-cmdline-at-hkeylocalmachinesystemsetup?forum=itproxpsp
Set-ItemProperty "HKLM:\SYSTEM\Setup" -Name setuptype -Value 2 -Type Dword
}
DISABLE RE-TRIES FOR SENDING STATUS MSG BACK TO MP
- What it does
- As the name suggests, this step disables re-tries for sending Status Messages back to SCCM MP
- Via setting Task Sequence Variable SMSTSDisableStatusRetry
- As the name suggests, this step disables re-tries for sending Status Messages back to SCCM MP
- When to use it
- To avoid timeouts in case, there is no network connection
- That is the reason I use it before
Setup Windows and Configuration Manager
step, because this is the only place when Wi-Fi adapter is not yet ready (check TODO section)
RESTART
There are two Task Sequences for restart
- RESTART (to OS)
- RESTART (to WinPE)
What it does
- Restart
- Ensures, that connecting to Wi-Fi will be made as the first step after the restart
- When to use it
- Use it if you need to make a restart (+ connect to Wi-Fi after)
REMOVE Wi-Fi CONNECTION DATA
- What it does
- Removes whole folder
C:\Windows\WCFG
i.e. deletes Wi-Fi XML profile file - Removes added Wi-Fi profile from installed OS
- Removes whole folder
- When to use it
- Has to be run as a final step of your
TS
- Has to be run as a final step of your
- Called script content
# location where Wi-Fi connection data should be stored
$WCFG = "$env:SystemRoot\WCFG"
$wifiProfile = "$WCFG\wprofile.xml"
# disconnecting from the Wi-Fi
if (Test-Path $wifiProfile) {
# get SSID
$SSID = ([xml](Get-Content $wifiProfile)).WLANProfile.Name
"Removing Wi-Fi profile $SSID"
$null = netsh wlan delete profile "$SSID"
}
# remove configuration data (Wi-Fi password is there in plaintext!)
if (Test-Path $WCFG) {
"Removing '$WCFG'"
Remove-Item $WCFG -Recurse -Force
} else {
"'$WCFG' not Found"
}
How resultant Task Sequence should look like
You can download it from my GitHub Repository and import it into your SCCM console.
- The Wi-FI profile is copied from WinPE environment to installed OS
- Disable retries for sending Status Messages back to MP. To eliminate timeouts in
Setup Windows and Configuration Manager
step, where Wi-Fi is not working yet - Customize OS startup to initiate Wi-Fi connection as the first thing after the restart, restart the computer (because right now you are offline :( ) and enable sending of Status Messages, so you can monitor progress on your MP
- Again disable retries for sending Status Messages back to MP. To eliminate timeouts after removal of the Wi-Fi profile connection (it will immediately disconnect the Wi-Fi)
4. Automatically use Wi-Fi profile from the running OS
To further make the installation through Wi-Fi connection easier, we can set Task Sequence to reuse the existing Wi-Fi connection from the OS that is being reinstalled. As a result, user won't be prompted to make a Wi-Fi connection and the same Wi-Fi network he was connected to will be used for OSD too automatically.
This can be of course used only in cases when the installation is invoked from running OS (via Software Center).
To make this work, we need two new Task Sequence steps:
- EXPORT WIFI PROFILE FROM RUNNING OS
- Has to be run before restarting to WinPE from the running OS
- If an active Wi-Fi connection is found, its profile will be exported to xml file
- COPY Wi-Fi PROFILE FROM OS DISK TO WINPE
- If finds exported Wi-Fi profile, copies it to WinPE to the location that is later checked by step
COPY Wi-Fi PROFILE TO OS DISK
- If finds exported Wi-Fi profile, copies it to WinPE to the location that is later checked by step
So to make this work, download these two Task Sequences, import them to your SCCM Task Sequence list and use them in your own Task Sequence like Also make sure to use Wi-Fi supporting boot image in your SCCM i.e. follow Adding Wi-Fi support to Boot Image imported into SCCM. Because this boot image will be downloaded from SCCM in case of invoking OS installation from the running OS.
!!! There was a bug in customize_sccm_usb_boot_image_to_support_wifi.ps1 script, that I fixed 9.7.2021. So to make this work, use this new fixed version to customize your Wi-Fi supporting boot image AND redistribute it to your SCCM DP's!!!
Summary
If you got to this point, you are ready to reimage any of your devices on any personal Wi-Fi network. To accomplish this task, we've created Wi-Fi supporting boot image using OSDCloud tool, customized it a little bit to match SCCM needs, and customized our deployment Task Sequence to make Wi-Fi connection persistent.
Moreover, we can import Wi-Fi profile directly to boot image or set the Task Sequence to reuse the existing Wi-Fi connection from OS that is being reinstalled.
Have fun ๐
Useful information
- oofhours.com/2020/12/03/windows-pe-startup-.. (extremely helpful!)
- prajwaldesai.com/deploy-task-sequence-over-..
- docs.microsoft.com/en-us/windows-hardware/m..
- anoopcnair.com/sccm-osd-task-sequence-ultim..Stage-_SCCM_OSD_Task_Sequence
OS installation screenshots
Connecting to Wi-Fi
Manually
Unattended
Choosing TS
Installing OS
Reconnecting to Wi-Fi after the restart
TODO
Solve connecting the Wi-Fi in step Setup Windows and Configuration Manager
. Right now this is the only step, where Wi-Fi is not working, so I have to do workarounds like disabling re-tries for sending Status Messages to MP. Therefore in your Task Sequence restart ASAP after this step to make Wi-Fi working i.e. do it as I did in my example of Task Sequence :)
PS: I already tried to initialize network adapters by netcfg -v -winpe
plus start the wlansvc
service, but it ended in start-pending state...