Send Text and Email to User from Task Sequence

Bonus: Learn to use Gmails SMTP service.

Updated 3/6 - added auto close feature, so if user ignores the window, it will auto close allowing the TS to continue. (Updated the 3rd Form image below to reflect the change)

Or if some of you awesome PowerShell guys want to make my code pretty and add that feature...  🙂

As I try to improve the user experience for in-place upgrades, notifications came to mind, and how to incorporate that into the process.  Using the TS variable _SMSTSUserStarted = true, I launch a powershell driven “front end” to collect the user’s email, cell number & provider, then use that to notify user when process is complete.


Using @FoxDeploy’s guide and a little help over twitter, I was able to create a form to collection the information.

The form launches, to ask for the email, then check a box, if you check the box, it un-hides the rest of the form required for the text, and also “greys-out” the “OK” button, until the required information is collected.


Once the user inserts their Cell Number & selects a
radio button, the Ok button lights back up, and they can choose OK.  The Skip button just closes the form allowing the TS to continue with no data collected.

Once you click OK, the Data goes into the registry & into TS Variables.  I add it to the registry because I want it there for the next upgrade.  When the form loads, it will look for those keys, if they are there, it will auto populate, allowing the user to then click OK, or modify first, and then continue.

Code for Form:


TS Step for Form:

Code from Command Line: *NOTE, requires ServiceUI.exe in the same package as the scripts:


At the end of the TS, there is a last step that runs another script that will grab the variables and send the email and text.  Currently I’m using Gmail’s SMTP service to do it, I created a new gmail account and set the required changes needed to use it to relay SMTP email. Instructions HERE - Follow the instructions for use Gmail SMTP Server, which requires you to first set "Less Secure Apps" is enabled for the account. The username & password are in clear text in my script, feel free to modify it to use a more secure method, like a password file, or use an internal SMTP server that doesn’t require authentication.

Why the radio buttons for the carrier?  Most carriers have a way to send text using an email address.  I use this feature to append the email address suffix onto the cell number and send the email to that cell phone’s SMS email address, so it comes in as a text.  If your carrier isn’t listed, you can probably look it up on their website.  Example, I use Boost Mobile, which is on the Sprint Network, in my testing, using my cell number and the Sprint’s email, it would send me the text.  You can probably just google it too..

Code for Script:


Step in TS:

Feel free to skip the user interaction part, and just hardcode the script to send a text or email to a specific person for every upgrade / OSD deployment, like your boss, so you can prove how often you upgrade a machine successfully, I’m sure the sentiment will be of Awe, and not annoyance.


As always, please leave a comment or hit me up on twitter.  I only tested sending text messages to Boost Mobile & Verizon, but I ASSUME rest of them will work.  If you find any problem, please leave a comment to help others.


PS.. please forgive my powershell code, I’m still learning, and most of it is thanks to googling and trial and error.

ConfigMgr Client Provisioning Mode

Update 3/15 - Ran several more tests to learn what actions are available to run during Provisioning mode.  Scroll to bottom for updates.

I’ve been doing a lot of testing with Provisioning Mode.  I needed to know what was going on when a system was in provisioning mode.

Quick Overview of what works and what is difference. (As I continue testing, I'll continue to update this list)

  1. Works Normally
    1. Software Center
      1. Lists all Deployments available & required it knew about before entering provisioning mode
      2. Can Install any of those by clicking "Install"
    2. ConfigMgr Control Panel
      1. You can still trigger actions, or change cache size
        1. By Triggering Actions, you can get deployments to install if they are past deadline
  2. Differences
    1. Policy doesn't update Automatically
    2. Does NOT report to CM (Inventory)
    3. Does NOT run Required Deployments automatically once deadline hits.


Basics: (Enter Provisioning Mode & Exit Commands) - More info HERE @

To Check Status: HKLM\SOFTWARE\Microsoft\CCM\CcmExec
Provisioning Mode: False (Not in Provisioning Mode)

Provisioning Mode: True (In Provisioning Mode)

In the CcmExec.log, once you tell the machine go into provisioning mode, you'll see it shutting down CCMEXEC and move into Provisioning Mode State, but it never actually says it's entering into provisioning mode.

Learned from Testing (while in Provisioning Mode)

  1. Client will not pull down any new CM Policies
    1. Provisioning mode has NO connection to Group Policy.  Group Policies still process while in Provisioning mode
  2. When a deployment reaches it’s deadline, it will change status to “Past Due” but does not start the installs.
    1. Tested with both Application Deployments & Software Updates.  Neither started installing when reached their deadlines, only Status changed from “Scheduled for XX Time” to “Past Due”
  3. When client is removed from Provisioning mode, machine policy is updated nearly immediately, and past due installations start ASAP.

When is the client set to Provisioning mode (When is it supposed to be)?   If it is in provisioning mode outside of these scenarios, it's probably an issue and you'll want to look into it

  1. During OSD, once the Client is installed, it is set to provisioning mode and stay in provisioning mode until the end of the TS. For context of how close to the end it is, it’s set after all of the steps in the TS, but right before the SMSTSPostAction
  2. In Place Upgrade
    1. Once the TS reaches “Upgrade Operating System” Step, it enters provisioning mode, and stops ccmexec service (Software Center closes if you still had that open) – It enters Provisioning Mode before the TS even downloads the Upgrade Media. unless you tell the TS to download all content before starting, this is a good reason to precache!
    2. After the upgrade process is complete, even if it fails like in my test, it will take the client back out of provisioning mode and restart the services.
  3. In Place Upgrade (Compat-Scan Only Mode)
    1. Identical process to Upgrade, even though it doesn’t actually upgrade.  This has been raised as a bug / uservoice item, and in a future release, the upgrade process, if running compat / scan only mode, it will not put the system into provisioning mode.


Issues I've run into with Provisioning Mode.  During CompatScan Only mode TS running, I've had users reboot the machine, leaving the machine in provisioning mode when it came back up.  While the window for this happening is small, 5 - 20 minutes, it has happened.  We have the CompatScan Only TS running in the background unknown to the users, so it's not really their fault if they reboot it during the process.  To work around this, I create a run once command to take a machine out of provisioning mode, if the process completes successfully, I delete the run once key as all is well, however, if the user does happen to reboot during the process, the next logon on, it will remove itself from provisioning mode thanks the turn run once key. (as shown in the twitter image of the TS Steps above)


Collection with Required Deployments: 2 apps & software updates.  Deadline for 6:30PM Client Time.

Machine is already in Provisioning Mode when Deployments are Created.  Results:  The Required Deployments never show up in the Software Center.

Deployments Created on Machine NOT in provisioning Mode, they show up in software Center with Deadline time. Then after the machine has the updated Policy, I placed it into Provisioning Mode.  Sorry, this machine is already patched, so it doesn't show any of the MS Updates, but I have confirmed on other tests that Software Updates also respect Provisioning Mode and do NOT install.

After the Deadline, "Nothing" happens.  Status changes from Scheduled... to Past Due, but the installs do NOT start.
So 2.5 hours past deadline, still no change.

Then I run command to take machine out of provisioning mode (which closes the software center).  I then reopen Software Center and see those two Apps are already installing.


So, provisioning mode, hopefully this helps demystify what it is, and the effects it has on the ConfigMgr client.

Update 3.15.2018

When Client is in provisioning Mode, you can trigger actions and the client will kick in and perform those actions.

Example Scenario. Client is set into provisioning mode, client has several deployments that reach their deadline, provisioning mode prevents those from running. UNLESS... a policy update is triggered.  From the ConfigMgr Console, if you right click a machine and tell it to run a Machine Policy Update, it will run and get that information, HOWEVER, it will NOT act on it, it only gets the policy.  If you have added deployments to that machine, it will NOT show up in software center, even if you run a machine policy update.
To trigger Applications or Software Updates to actually install while in provisioning Mode

  1. Right Click Machine -> Client Notification -> Trigger "Evaluate Application Deployments" (Application Model ONLY)
  2. Right Click Machine -> Client Notification -> Trigger "Evaluate Software Update Deployments" (Software Updates ONLY)

I was not able to trigger a package program using any of the built in Client Notifications.

Two ways to remove a client from Provisioning Mode Remotely using Configuration Manager

  1. Application
    1. Create Application
      1. No Content - Command Line =
        powershell.exe Invoke-WmiMethod -Namespace "root\ccm" -Class "SMS_Client" -Name "SetClientProvisioningMode" $false
      2. Detection Mode = Registry = HKLM\Software\Microsoft\CCM\CCMExec  provisioningmode = false
    2. Deploy to Collection with Machine
    3. Right Click Machine -> Client Notification -> Trigger "Download Machine Policy"
    4. Right Click Machine -> Client Notification -> Trigger "Evaluate Application Deployments
  2. Run Script
    1. Create new "Run Script" with same Command line as Application
    2. Right Click on Machine -> Run Script -> Choose the One you just created to remove machine from Provisioning Mode.

BGIn-Place Upgrades


If (You Enjoy Reading)

I thought that was a clever title, but it seems more confusing the longer I look at it… anyway, this is the follow up post to take BGinfo from MDT, and add it’s capabilities to the ConfigMgr In-Place Upgrade Task Sequence Process.  If you’ve been working with in-place upgrade task sequences, you’ll know they are a different beast than regular OSD.  You can’t just call an application and expect it to show up on the screen.. like in OSD, you can say Command Line Step: notepad.exe… and guess what, a notepad.exe window opens during the TS.. freaking amazing!

In Place Upgrades also have new challenges we didn’t really have before with OSD.  OSD (bare metal) typically meant it was a clean image, we didn’t have end users sitting in front of it while installing the OS, didn’t have user profiles already full of “super precious data”, we really didn’t need to worry about the end user experience.  Now here comes Windows 10, Love it or love it, it’s here to stay, Windows as a Service, it means once OSD is done, that was the easy part, now we have to “touch” that computer every 6 months with a large upgrade.  Now we do have users to worry about, we have their precious little datas, and we have to deal with users who don’t read emails, and don’t read popups, and don’t read “ARE YOU SURE” dialog boxes, who just click “Sure” when something pops up, then freak out when it reboots 15 minutes later after they “consented” to an update.  And because they were working on large sales strategy document they only save on their desktop (Where else would you save business critical documents), and because the moon was full and the person sneezed in the cube adjacent, their document is now gone, or corrupted, or missing 4 days of edits!   Anyway, my point, we have the privilege of attempting to provide a decent user experience and making the process the most user friendly while still applying a huge upgrade that is ripping out the guts of the OS and dropping in the newer OS, with features they didn’t really request, and unknown stability with their current business apps.  But I digress…

Where was I going with that… oh yeah, ways to let the user know that hey “A BIG UPGRADE IS HAPPENING… SAVE YOUR STUFF”.  I’ve done this in the past with changing the Lock Screen, creating a method to prevent a user from logging on, but what if the user is logged in, they started the TS, but still just don’t get it… how about we temporarily change the background and put up a message that displays for that logged on user until the moment that beautiful first reboot happens?  I say, why not… lets do it.  My idea, steal MDT’s Bginfo “Set Status” Step, and add it to the In Place upgrade TS.  I copied  over the “Use MDT Tool Kit” Step, and “Set Status 2” Step, but when it ran that step in the TS… ERROR city.  Figured it was too easy. So this is what I had to do.



Assuming you followed the last blog, you’re most of the way there. (I’ve provided all of the files in the zip download, so you can steal those or create your own)

Your folder structure will look like this basically:

  • BGInfo64.exe – Download Here
  • vbs scripts – to be used for the custom fields
  • ServiceUI.exe – Take from MDTPackage\Tools\x64
  • BGI file(s) – Create new, or steal from MDT – Included in my download
  • Image file (.bmp) – Create new, or steal from MDT – Included in my download

Open your BGI File with BGInfo64 and add your fields and text (or modify the one I’ve provided)
imageNote, this will be different than the one we used for OSD, as this time, it is running in the OS, and not WinPE.
Set your Background, note, do not use the full path, just the name of the file, as all of the required files are located in the same directory.

Ok, the BGInfo part is done, feel free to press Preview and confirm it looks how you want, when you’re satisfied, save everything, and create your ConfigMgr package and distribute
Now that you have your package ready, its time to add it to the TS
Run Command Line Step

Basically, we’re stealing the logic from the ztiSetBackground.wsf file in MDT Scripts, and manually creating the command line:
"bginfo64.exe WinUpgradeGaryTown.BGI /nolicprompt /silent /timer:0"
But you’d quick learn, that doesn’t work… you need to use ServiceUI.exe to make it visible, which once you figure out that syntax, you get this:

Now add a condition that it only runs if it was user imitated.  no point in changing the background is no one is there to see it. 🙂
Also have seen this step failed if a user is NOT logged on.  So recommend you set to "Continue on Error" if you plan to have it run without checking to see if  a user is logged on, and run it without a user logged on.

TS Variable = _SMSTSUserStarted = True


Now, sit back and watch your TS give the user something they can’t avoid… unless their desktop is completely covered with files / icons…


BGinfo Updating MDT Default Templates

If you use MDT, then you’re familiar with their use of changing the background and adding system information during the OSD process.  This is pretty handy to get some basic info, but with a little tweaking, you can add additional data that can be very useful to make visible during OSD.

Basics, the required files used during this process are stored here: MDT Package\Tools\x64 & x86


It currently comes with old version of bginfo 4.20, the current version when writing this is 4.25.  I replace the ones that come bundled with the updated version. Download BGInfo

In the x86 folder is where the templates and images files are located.  This will also be the folder you add your custom .vbs files, but we’ll get to that later.

the .BGI files are the bginfo “database” files that contain the template information (layout, options, background choice).  The .BMP files are the images referenced in the .BGI files. The image files are 800x600, so they can look fuzzy on high-res screens. This image below is STEP_02.BMP (referenced by STEP_02.BGI) - Called during "Set Status 2" Step in a MDT enabled Task Sequence.

Bginfo then overlays additional information:
This image below is pretty close to the default, after adding 2 of the items Mike Terrill blogged about, and one additional Item based on a TS Variable.

Here is my current template after a few additional modifications, which I go into more detail below.

Following Mike’s blog, I added the BIOS Mode & Secure Boot Fields, as well as the Make & Model information (WQL Query), pulled directly from his post.  I then proceeded to add Processor Model & BIOS version, then several TS Variables.

Make sure you’ve downloaded the updated bginfo.exe files and place them into their corresponding MDT folders (x86 & x64).  Then on the x86 folder (even if on x64 machine), open bginfo.exe

At this point in the reading, you have hopefully stopped and read Mike’s blog, as I don’t want to completely plagiarize,  and this will be pretty similar.
(Sorry, the default fonts are hard to see against the default black background)

Once you launch the tool, go ahead and open STEP_02.BGI file in the x86 folder.

If you click on “Background” you’ll see the name of the background file that is associated with the template: Step_02.bmp, which is located in the same x86 folder, as shown in the earlier pictures.

At this point you can start to modify to get it how you like.  Mine now looks like this: (Keep reading, I’ll get to the Custom Fields)



I broke it into a few categories, WinPE info, which is the current OS when STEP_02 runs, so the commands are being run against the WinPE image.  This is why you get a MININT-XXXXXX computer name and no workgroup, as WinPE isn’t in your domain, and auto generates the computer name.

I then broke out hardware info about the physical machine into it’s own area, which includes additional built in options, and a few additional vbs scripts.

Finally, pulling in OSD information from the TS that is running.  To achieve this, in the TS, I write those items to the WinPE registry, so I can easily harvest it from bginfo.  Since it's written to the WinPE registry, it's only temporary, and you don't need to worry about cleaning it up later, it goes away after the reboot.

To add fields, click "Custom" right under the fields list.


Click New…


Choose the method to pull your info, in the example I’m using WMI Query to get the BIOS version.

Here are a few example WMI Queries: Note, WMIExplorer was really handy to dig around and find information that I wanted to display.


.VBS Files (must all be placed in the x86 folder, even if using x64, place them in the x86 folder)

NOTE, the .vbs files do not work if you try to run it from the command prompt, but they do work in bginfo.  If you want to test the scripts, replace echo with wscript.echo, then remove the wscript before using in bginfo.  Don't ask me, it's just the way it is.

Here are the .vbs scripts used.  I heard Mike will be updating the ones he posted, the ones below are the original.  They work fine in PE, and that was good enough for me, I don't need them to be fancy.  If you want to clean them up, be my guest, I basically found a template thanks to google and slightly modified to fit my needs.  Please don't judge me based on the beauty of the scripts I post.

BIOSMode (From Mike Terrill – UEFI or Legacy)

Drive (C: Drive Space)

SecureBoot (From Mike Terrill – Enabled or Not)

VolumeFree (C: Drive – Free Space)


Registry, these were keys I created during the TS by stamping TS Variables to Key Values.

These are stamped to the WinPE registry, as that is the OS running when this is displaying.  In my TS, I don’t have any additional BGinfo / Images display once it’s out of PE, after that’s it’s finishing the OSD with the windows setup black screen, so I only needed this info to display during the WinPE stage, which made writing it to the registry the perfect solution for my purposes.

The Variables are set using a FrontEnd or Collection Variables.  I use the Now Micro front end in my lab. Link HERE, scroll down to the FrontEnd Link.  The AD OU is a direct relation to the "Branch" Chosen and auto populated. In this front end, everything in the top area is auto generated based on Queries, or other imput, the only field that can be modifed is teh Computer Name, either leave the auto generated one, or modify for the deployment.  If doing a "Refresh" all of the variables are set on my collections, %OSDComputerName% is the name the computer already has,  so the settings (variables) would be reapplied automatically during a Reimage with no need for the front end.  This is just an example, basically you can put anything you want into BGInfo, just need to be a little creative.

Note, if you're creating variables and registry keys to use in BGInfo, I know this seems obvious, but make sure you run the steps to create the variables and keys before you run the step for BGInfo! (Set Status 2 - Which is a native MDT Step auto generated) The Step is calling the ztibackground.wsf file, which gathers information (architecture, etc) uses that to call the correct version of bginfo (x86 or x64) then pull the additional files (templates, Images, scripts) from the x86 folder, even on x64 machines.

Once you’ve added all of your Custom Fields, you can then add them into your bginfo template, and play around with that, it’s basically like working with wordpad from windows 95.

Once you have your desired layout, save the template and overwrite the default.  Then update the MDT Package in ConfigMgr.

Here is my Template File & VBS files, over write the ones in the x86 folder.

Coming up next, taking this and applying it to in-place upgrade.

Please comment with additional .vbs scripts or things you've found handy to add.  Feedback is always welcome.

ConfigMgr Lab - Adding Ninite Apps

So you have a Personal ConfigMgr lab, but you want to add some app deployments to better simulate your actual environment.  So you add Chrome, Reader, and a couple others (NOT JAVA).  Next Month, they are out of date.  You probably don’t have time to keep your personal lab app deployments updated, so you keep deploying old versions.  How about, you leverage’s ability to dynamically install the latest version of the app every time?  Now you're asking, "Isn't the command line version that supports silent install cost money?"  Yes, yes, it does, to use ninite’s silent install, you need the Pro version.  What, you don't want to pay for pro when it’s your personal lab?  I hear you.  Powershell to the rescue!  It doesn’t make it completely silent, but it will allow you to automate it to work with the ConfigMgr App Model during OSD and Post OSD.

If you're not familiar with, it's pretty awesome.  I've been using it for years, when I get a new computer, or just want to make sure my apps are updated.  Also use it to help setup how many friend's and family's computers. Basically, you go to the website, you check the box next to the app(s) you want, and click "Get your Ninite".  Then run the small stub installer file.  Awesome right?  They figured out all of the command lines. They keep the apps updated. They make it so easy.

Please remember, this is for your personal lab, if it is for anything other than personal use, you’d have to get the Pro version.  With the Pro version, you don't need my work around.

Basically my solution is a powershell wrapper that downloads the ninite stub installer,  runs the installer, waits for it to finish, then kills the installer dialog box.  Why would you want to do this?  Automation, being able to leverage Ninite's Free Personal installers in the context of a Task Sequence or App Model deployment in your Personal ConfigMgr Home Lab.

The Script does this:

  1. You choose the App you want to install from the predefined list built into the script
  2. The script then Downloads the Ninite.exe stub file from
  3. Then launches the Ninite Installer.exe stub file which downloads the actual app installer and launches
  4. Waits for either MSIEXEC.EXE or TARGET.EXE Subprocess of Ninite.exe to start.
  5. Monitors the SubProcess (MSIEXEC.EXE or TARGET.EXE)
  6. Once SubProcess (software install) completes and goes away, Sends “Stop-Process” signal to stop all Ninite.EXE processes
  7. Deletes the file it downloaded
  8. DONE.

In Software Center (Application Model Deployment).  It will Launch the installer, the ninite dialog box will be visible until it is complete. (See video below for demo


In the TS, you can add the Applications like any other.  During at TS, the installers are not visible. (See video below for demo)


Content: One PowerShell Script

Same Command Line Install for each, just change it to match the software.

Detection Method (File Only) - I don't use version number, as it's constantly changing.  If you want to rerun the app, uninstall it first, then rerun to get the updated version.  However, assuming this was a lab, I made the assumption the machines you're installing apps on, probably won't "live" for long before blown away or reloaded.

PS Code



See it in Action

Video (Task Sequence)

Video (Software Center)

Watch the Script in Action:

If you'd like to add other Ninite App options into the script, feel free.  I've found not all of them use the target.exe or msiexec.exe sub processes, so you'd have to account for that (Examples are .Net 4.7.1 and Paint.Net, for my lab, I pulled those out and made separate app scripts).

More info: Terms: "The free version of Ninite is only licensed for home use and as a trial for Ninite Pro. If you get paid for running Ninite (like in an IT department, PC shop, managed service provider, school, non-volunteer helpdesk, etc.) you must upgrade to Ninite Pro. "