Category Archives: Scripting the Windows Experience

Some Windows scripting work that I have done to help get my job done.

Modify Thunderbird Settings using Logon Scripts

Last time with VBScript, I swear it…

While working at UVM on their Exchange 2016 deployment, we came across an interesting environmental anomaly (UVM has lots of those). The popular Thunderbird IMAP mail client installer had been customized by someone (*cough*) to handle various local environment quirks in the UW IMAP server deployment. Once of these was the use of a “mailbox path prefix” variable. When UVM migrated to Dovecot IMAP many years back now, this setting became obsolete, but I, er, I mean *someone* never removed this setting from the custom T-bird installer. Surprisingly, it appears that thousands of users in the environment have the IMAP path prefix setting defined. I guess people really loved that custom Thunderbird installer?

Smug satisfaction with the success of *someone’s* mail client installer evaporated quickly when migrating Thunderbird users to Exchange. Why? As it turns out, this setting unexpectedly causes Thunderbird to point to a non-existent mailbox folder, and thus gives the impression that the Exchange migration had resulted in the deletion of all IMAP server folders. Gah!

It took me only an hour or two to figure out how to fix this problem using PowerShell, but I then discovered that it was not really practical to package PowerShell scripts for execution on non-domain-joined computers. Why?

  1. By default, PowerShell does not allow execution of scripts on new non-domain-joined Windows computers. But even if you could work around that problem…
  2. PowerShell will not trust code signatures unless they explicitly were imported into the “Trusted Publishers” branch of the user’s certificate store.

So, PowerShell is not going to be of overly much use to me today, since we want this script to run on-demand in addition to as a logon script. It really would be nice if I could have taken the time to learn C#, C++, Visual Basic, or some other “real” programming language, wouldn’t it? Because now I have to fall back on VBScript again.

Last time… Last time…

The script below will detect the “mail/” IMAP path prefix and delete it if present. It also will set the server polling interval to 10 minutes if set longer than 10 (29 was the default previously, which does not work well with Exchange IMAP). If Thunderbird is running, the user will be prompted to restart their mail client:


Server 2012 boot hang in vSphere/ESXi

Over the past year or so we have been having some problems with Server 2012 and 2012 R2 virtual machines hanging during reboot operations. The systems hang at the “spash screen”, showing the Windows logo and the ring of spinning dots… forever!

Finally I was able to find an fix for this problem here:

From a tip-off here:

The problem? Well, probably it is best that you just read the TechNet social thread, if you really want to know. It is none too exciting, and all very aggravating. The fix? Run a PowerShell script, then vMotion your machines to force ESXi to re-read the VMX file for your guests.

I am posting my variation on the script in the KB here, because VMware’s script is incomplete, and difficult to read.

#Script intended to correct the bug where Windows Server 2012+ systems on VM Hardware v10 will hang at the 
#boot-up splash screen.  Problem is caused by the failure of ESX to clear the "TS" counter on system reboot.

Set-PSDebug -Strict

#Initialize the VIToolkit:
if ( (Get-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) -eq $null ) {
    Add-PsSnapin VMware.VimAutomation.Core

#Connect to your virtual center:
$viServ = ""
Connect-VIServer -Server $viServ

#Get all VMs in the vCenter:
$vms = Get-VM 
#Loop though the VMs:
ForEach ($vm in $vms){
	#Get a "View" object for each VM.  Views expose useful data that is not contined in the VM object:
	$vmv = Get-VM $vm | Get-View
	$name = $vmv.Name
	$guestid = $vmv.Summary.Config.GuestId
	if ($guestid -like "windows8*Guest") {
		#windows8*Guest will match Windows 8 client 32-bit and 64-bit, as well as 
		# "windows8Server64Guest" (which is Windows Server 2012 and 2012 R2).
		#We need to update the VMX file for the VM, which is dong using a VirtualMachineConfigSpec.
		$vmx = New-Object VMware.Vim.VirtualMachineConfigSpec
		$vmx.extraConfig += New-Object VMware.Vim.OptionValue
		$vmx.extraConfig[0].key = "monitor_control.enable_softResetClearTSC"
		$vmx.extraConfig[0].value = "TRUE"
		write-host "Edited" $  
		$ | out-file -FilePath c:localtempsoftTscOut.txt -NoClobber -Append

Discover user rights in SharePoint

Among the top items capable of derailing your whole day or week are requests from auditors.  Who has access to a resource?  When did they exercise those rights?  In the pas few months, I have had several requests of this sort related to SharePoint rights.  Since I have once again started working on our SharePoint 2010-to-2013 migration project, and most of the SharePoint Powershell cmdlets were fresh in my mind, I though I would take a crack at this somewhat intimidating task.

As usual, writing a useful script took more time that I would have liked, but I am fairly pleased with the results.  The final product makes heavy use of Regular Expressions.  Special thanks go out to RegEx Hero, an online .NET regular expressions tester:
AND, of course, to the site:

Using .NET-style RegEx named capture groups, I was able to eliminate redundant loops though the SharePoint web site list, thus making it possible to crawl all SharePoint web and site-level ACLs in only a few minutes. Hurray!

This code will work only on SharePoint 2010 farms that use Windows authentication. There may be limitations related to sites with multiple Windows domains as well. I will need to update this script in the near future to handle claims authentication, but we will cross that bridge when we come to it.

The script has some pretty convoluted loops that may not make any intuitive sense… I have tried to insert comments to explain what is going on. If you do choose to use this script in your environment and find it difficult to understand, feel free to contact me with questions.

Owing to the agonizing pain of attempting to embed complex PowerShell code in WordPress, this script now is provided as a GitHub “Gist”. Enjoy!

Migrating to the SCCM UDI for OSD, part 4: Applications

Continued from part 3b:

Previously in this series I demonstrated how you can manage Operating System selection and application in UDI, and one (rather complicated) method for managing drivers in SCCM/UDI. To complete our UDI experience, I now present a handy script for automation of populating select SCCM applications into UDI.

There is some conventional wisdom floating around out there in the ‘tubes that you should not deploy the new SCCM 2012-style “Applications” in SCCM OSD Task Sequences. Instead, it is asserted that you should use only traditional application “Packages”. Since we have developed all or our application installer using the new “Application” objects, I have chosen to ignore this guidance. Fortunately, it appears that the earlier bugs that led to dispensing of this advice have been corrected in the 2012 R2 CU2-CU3 timeframe.

The script below will make use of Configuration Manager application tags to determine which Applications should be populated into UDI. Additionally, the tags are used to generate application groups in the UDI wizard. If you don’t want an application to appear in UDI, don’t tag it. Applications can have multiple tags, and thus can end up getting defined more than once un UDI. This does not appear to cause any problems during deployment.

This script will re-write the entire UDI designer “.app” file, which is an XML-formatted document that defines all of the applications and groups that will be displayed during the UDI Wizard (the default name for this file is ‘’). Because I am writing out the entire file, I chose to use the System.Xml.XmlTextWriter .Net Framework class to do the heavy lifting for me. I probably could have used System.Xml.XmlDocument (which I used in part 3 of this series for updating the main UDI XML control file), but the XmlTextWriter seemed to be a more direct route to getting the job done in this case.

Note that in this code I am again using the SCCM PowerShell cmdlets. In this case, I am using Get-CMCategory and Get-CMApplication. These commands easily could be replaced with simple WMI queries (as seen in part 3 of this series). I also am using some SCCM managed code. I call the “Microsoft.ConfigurationManagement.ApplicationManagement.Serialization.SccmSerializer” class in order to use the “Deserialize” method. This method converts the large volume of data in the SDMPackageXML attribute of the application object into somewhat more accessible PowerShell objects.

To use this script in your environment, you will need to update the $outPath, $CMSiteCode, and $CMBinPath variables to match your environment. After running the script, you will need to redistribute the content of your MDT Files package to your distribution points. You UDI clients will read the new data as soon as it is made available on your DP.

And that is all of the new code that I needed to write for SCCM/UDI. In the final part of this series, I will discuss a few SCCM/UDI quirks that were easily corrected without custom coding:

Series Index:

Migrating to the SCCM UDI for OSD, part 3b: Operating System Selection (Continued)

Continued from part 3a:

In part 3a of this series, I provided a script that automates updating of the OS selection dialog boxes in UDI. I also noted that while UDI presents that OS selection, the UDI client ignores the selection and instead installs whichever OS image was specified at image creation time. This was very frustrating because I was able to verify that the syntax of the generated UDI XML file was correct. In examining the task sequence logs, I even could see that the “OSDImageName” and “OSDImageIndex” variables had been set as expected. Yet still UDI would not apply the select image. Why?

I found multiple explanations for this phenomenon, none in the MDT/UDI documentation:

The upshot is, while UDI wizard will set the “OSDImageName” variable, the SCCM Task Sequence ignores it by design. This issue is exposed in the Task Sequence reference:

The observant reader will notice that the “Apply Operating System Image” task sequence step does not contain a variable for supplying an image name or path. You only can provide an image index. It looks like MS only supports selection of different images indexed in one monolithic WIM image. I am not enamored with this limitation, so I have authored the following script which will create one “Apply Operating System Image” for each OS in the SCCM inventory. Each step will have a condition that will allow the step to run only if the OSDImageName environment variable matches the name of the image specified in the task sequence step. Note that we are assuming only one image per WIM file in this case, so the image index of the selected WIM has to be ‘1’.

Note that this script requires the “UVM-ConfigurationManager.psm1” module file, which can be found in this post:

The script will create a single group of Apply Operating System tasks (one task for each OS Image Package in the infrastructure) in the Task Sequence, using the group name supplied in the $TSPackageName variable. If the group already exists, it will be updated. Additionally, if the stock "Apply Operating System Image" step is still present, it will be removed. Each time you add or remove an OS Image, you will need to re-run the script and re-copy/paste the actions.

We have now dealt with handling Drivers and Operating Systems in SCCM/UDI OS deployment. That leaves managing UDI application selection, which I will discuss in part four of this series, coming up next.

Series Index:

Migrating to the SCCM UDI for OSD, part 3a: Operating System Selection

Continued from part 2f:

In this part of the series, I will make it possible for the end-user to select from a list of available operating system images. I will provide required scripting logic to update this selection automatically, and I will provide an additional script to make these selections work as expected. (The out-of-box UDI image selection process makes no intuitive sense at all, as we shall soon see.)

Under MDT/LTI, we used Task Sequences as the unit to control the selection of operating systems by the end user. This was necessary because the LTI wizard did not provide an operating system selection dialog. We could have authored our own OS selection dialog, but back when UVM was new to MDT (then BDD) I was a wet-behind-the-ears programmer, and programming of BDD was more difficult. However, under UDI we have the option to allow the user to select different operating systems within the UDI Wizard, so we no longer need one Task Sequence per operating system. I think that this is a positive development, although maintenance of this option proved to be more difficult than expected.

First challenge: Programmatic updating of OS Selections in the UDI Wizard

Anyone who has done experimentation with UDI surely is familiar with the UDI Designer tool. This tool provides a GUI which generates a somewhat large XML file that controls the options that are presented to UDI clients. The UDI designer allows the administrator to select the objects within SCCM that will be presented to the end-user. While this presentation granularity may be desirable for some, it presents a maintenance challenge for us. Any time an object is updated in the SCCM inventory, we need to update the UDI dialogs as well, and Microsoft provides no out-of-box means of updating these links. While this is only a minor problem for OS Image updates, it is a major hassle for Application updates. Since we really needed to solve this problem for Application updates, adding logic for operating systems was an easy extension.

To solve this problem, we need to script the reconfiguration of our UDI wizard XML file. Microsoft likes to claim that PowerShell provides “powerful” XML handling capabilities. In my experience, this claim is debatable as the built-in cmdlets have limited XML formatting capabilities. However, the .NET framework upon which PowerShell is built does provide many classes for XML handling. In this script we will be using the ‘[xml][/xml]’ type accelerator. This accelerator represents the System.Xml.XmlDocument .NET Class, for which full documentation is available in MSDN:

I also use the “Get-CMOperatingSystemImage” SCCM PowerShell cmdlet. As mentioned previously, I recommend avoiding the use of the cmdlets as they behave unpredictably. However, this particular cmdlets appears to work as well as we need it to. If you hate it, the commands could replaced with a WMI calls, although you would need to first discover the OS images:

$images = Get-WmiObject -namespace root/sms/site_[SiteCode] -Class SMS_ImagePackage | %{$_.__Path}

And then retrieve the “full object”, since the above query will not retrieve the required “ImageProperty” attribute (which Microsoft calls a “loosely bound” attribute):

$fullImages = @()
$fullImages += $images | % {[wmi] $_}

To use this script in your environment, you would need to update the $udiXmlIn and $udiXmlOut paths to match the desired locations of the UDIWizard_Config.xml in your environment. These paths can be the same, if desired. You also will need to update the $CMSiteCode and $CMBinPath variables.

After running this script, our UDI Wizard correctly displays all available OS Images in our environment. However, we found that the selections were not being honored by the UDI process. The fault is not in this script, but rather in the logic used by UDI. We will explore the fix for this in the next part of the series (3b).

Next: Operating Systems – Update the Task Sequence with new OS Image data

Series Index:

Migrating to the SCCM UDI for OSD, Part 2f: Driver Handling (concluded)

Continued from part 2e:

So, my driver handling routine is probably looking pretty scary right now. There are a lot of scripts that need to be run, and I have not discussed where to put them, or in which order they should be executed.  In part 6 of this series, I will provide playbook procedures for using the scripts.  Here I will provide a sys admin’s overview of where the scripts should be stored, and how they work with each other.

Script location and customization:

  1. Copy ImportDrivers.ps1, Update-DriverInjectionTaskSequence.ps1, UVM-ConfigurationManager.psm1, Create-UDIInfoFiles.ps1, and Build-UDIImageList.ps1 (see part 3) to a local directory on your Management Point or Site Server.  We use “c:localscripts”, with “CM-[Category]” subdirectories for each category of script.  I keep dependencies such as the “UVM-ConfigurationManager.psm1 in the “Script Root” directory.
  2. Review the starting sections for each file for local references that you might need to customize for your site.
  3. Update the path to the “UVM-ConfigurationManager.psm1” PowerShell module in the Create-UDIInfoFiles script.
  4. Update the path to the “UVM-ConfigurationManager.psm1” file in the Update-DriverInjectionTaskSequence script.
  5. Update the path to your MDT Files package source in the Create-UDIInfoFiles script.
  6. Copy the ZUVMDetectDriverPackage.wsf file into the “Scripts” directory of your MDT Files package.

Script sequence and dependency chains:

  1. Run “ImportDrivers.ps1” – creates the Driver Packages and groups referenced by all future scripts and operations.  Note that the script does not distribute the packages that get created.  You must do this manually.  Anyone want to share a tip on programmatic package distribution?
  2. The remaining server side scripts can be run in any order.  After running the scripts, you must re-distribute your MDT Files to your distribution points or the UDI Task Sequence will fail with missing file or missing dependency errors.

I think that covers the procedure. I will work on streamlining the process to make it simpler to implement.

On to the handling of operating system images in UDI…

Next: Operating Systems – Update the OS Image List in the UDI Wizard:

Series Index: