Nathan Ziehnert

7 minute read

I’ve spent the better part of the last two evenings working on this - and I’m honestly not 100% satisfied but I’ve made some excellent progress thus far that I’ve decided to share. Monitoring a task sequence to me has been a rather manual process - either I get notified by a support tech that a task sequence failed or I happen to see a failure in the monitoring tab of SCCM. This ultimately leads me to request the tech send me the SMSTS.log file, the error code presented, and at which step the task sequence failed. This can sometimes be cumbersome because the techs just aren’t as familiar with SCCM and or the logs associated with it - or sometimes it’s challenging when the machine isn’t joined to the domain yet and the tech doesn’t have a flash drive handy.

So my initial goal was just to launch a monitoring tool in the background of the task sequence that would alert me via email the second a task sequence failed, the step it failed on, the return code of the failed step, and attaching the SMSTS.log file for review. I was able to do this pretty simply with a “Run Command Line” step and a custom monitoring script. The downside to this was that I had to re-run this script at every. flippin. reboot. And there wasn’t even a guarantee that I could do that at every reboot - for example if I have a “Install Applications” step with 20 applications and the application 10 steps in has a reboot, SCCM reboots and then picks up where it left off (this time without the monitoring script running).

Enter the Windows Setup keys…

Down the Rabbit Hole

I’m going to go over an explanation to how I got to this point. If you want to skip to the important stuff CLICK HERE. Look - I know that this is probably not a “supported” method, and honestly maybe I’m a bit of a fringe case. I like fringe stuff. Forgive me @DJammmer… I know not what I do. Ultimately my goal was to make this work AS A STEP in a task sequence rather than modifying the boot image manually (using DISM / etc) or any associated SCCM binaries.

First I went digging around the boot image. I tried to locate some sort of INI file or something else that I could hijack using the custom files option when building an MDT boot image. This led me to \sms\bin\x64\TsBootShell.ini. So I tried my hand at creating my own TsBootShell.ini and then building a base image to drop this file inside. This didn’t work. Surprise, surprise. What was more surprising is that it seemed to ignore the rest of my custom files (background, cmtrace, etc) when it noticed that I was trying to drop files in the \sms\bin\x64 folder. I have admittedly not spent much time trying to make this autolaunch in the boot image but after messing with it for awhile I landed on just running the monitoring task manually during the WindowPE phase, since for the most part this phase lasts no more than 2-3 reboot cycles and the reboots are at generally known points.

The next phase that I needed to solve was the FullOS phase of the Task Sequence. So I figured the best first place to look was where any guy might look in the full OS: the run key. This was a big disappointment - or maybe it’s totally a good thing. SCCM seems to entirely block or ignore these keys and I suspect it has something to do with how SCCM is “launching” itself during the task sequence (the Windows Setup keys) - I assume that Windows Setup just assumes that the run key should be ignored during the “setup” phase of Windows.

So I moved on to the logging and poked around the smsts.log file for any indicators of what “flags” it was setting for boot that might be of benefit. I found a couple of interesting keys that SCCM sets (volatile keys for reboot pending, etc) but ultimately nothing fruitful. That is with the exception of an interesting executable that was being run (TsBoot.exe or something along those lines). Sooooo, I put away the trowel (CMTrace.exe) and pulled the CAT Excavator out of the garage (procmon.exe). Using ProcMon is always like drinking out of a firehose when you just needed a sippy cup, but at this point it was late and I was interested in finding a solution before I succumbed to exhaustion.

Unfortunately this also proved to be a somewhat fruitless venture as well. It did ConfigMgr get me thinking… what processes are running during the Task Sequence? After taking a long look over the running processes one particular one caught my eye “OSDSETUPHOOK.exe”. After a cursory search for this EXE through the registry I finally found the key to success.

Hijacking the SCCM Task Sequence Startup Process

I’m actually relatively surprised at how easy it was to take over the startup sequence for the Task Sequence in FullOS mode (not WinPE), but then again I assume that this method was used because it was already built into Windows, is reliable, and frankly does more than just launch an application (blocks certain processes from running, ignores some registry keys… basically everything you don’t want running during Windows Setup). Essentially the whole startup sequence comes down to a single registry key value:

HKLM\SYSTEM\Setup: CmdLine

That’s it. Whatever the value of this particular key is, is the command that gets executed at startup. This could be just an executable or maybe, just maybe, even a script. So I started off with just a simple CMD file I called startSetup.cmd. This worked nearly flawlessly. By “nearly” I mean that it left a really nasty command prompt window open while the TS executed. Gross. So I made use of the “START” command so that it would start the process but not wait for it to exit - but much to my chagrin when the command window disappeared so did my running task sequence.

Turns out that Windows Setup just assumed that when the setup task (HKLM\SYSTEM\Setup\CmdLine) is complete, a reboot is in order. I had two problems to solve now - how do I keep the TS running, and how do I hide that godawful CMD window. I decided to make use of PowerShell - a bit bulky for what I wanted to do, but what is 40MB of memory between friends, right? The script looked something like this:

Start-Process -FilePath PowerShell.exe -ArgumentList "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -file $ENV:SYSTEMDRIVE\TSAlerter\TSAlerter.ps1"
Start-Process -FilePath "$ENV:SYSTEMDRIVE\windows\system32\osdsetuphook.exe" -ArgumentList "/execute" -Wait

And voila! It worked! The task sequence continued to run and my monitoring script was running!

All the way up until the next reboot - at which point the registry key got reset to it’s default value.

This particular issue proved to be a bit simpler to resolve than I thought it would be. I just have to wait for the OSDSETUPHOOK process to exit (already handled by the Start-Process -Wait command in the PoSH script) and then reset the key back to what I want the script to run. Easy. So now the script looked like this:

Start-Process -FilePath PowerShell.exe -ArgumentList "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -file $ENV:SYSTEMDRIVE\TSAlerter\TSAlerter.ps1"
Start-Process -FilePath "$ENV:SYSTEMDRIVE\windows\system32\osdsetuphook.exe" -ArgumentList "/execute" -Wait
Set-ItemProperty HKLM:\SYSTEM\Setup -Name CmdLine -Value "Powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -file $ENV:SYSTEMDRIVE\Windows\startTSAandSetup.ps1" -Type String

This has proved most fruitful and as far as I can tell the task sequence completes without issue. In a future post I promise I’ll share out my monitoring script, but for now it’s still a bit buggy (sending multiple alerts, not stating the correct step that the TS reported a failure on, etc) - probably tomorrow because that’s what MMS is all about for me - unfettered time to complete some of these crazy projects.

Happy Admining!!

comments powered by Disqus