As a substitute for becoming a real programmer, I have for years been writing VBScripts and wrapping them up with the Z-Zip Self-Extracting executable. After the release of Windows 8, this model became more difficult. Out-of-box, the 7-Zip self extractor started generating application compatibility troubleshooter pop-ups on clients. Even prior to that, clients would get warnings asking them “do you really want to execute this scary unsigned possibly-from-a-murdering-hacker” when they launched our executables.

The solution for this is, of course, to add an application manifest to the self-extractor, and then to digitally sign the resulting executable. Easy, right?

I actually did this a few years ago for our venerable Wi-Fi profile installation tool. It was not quite easy, and unfortunately I never did get the process fully automated. The roadblock was in automating the addition of a manifest to the application. Microsoft’s tool for this, “mt.exe”, from the Windows SDK, consistently corrupts my executables. Others in the blogosphere have identified the tool “Resource Hacker” to fill this need:http://angusj.com/resourcehacker/https://www.autoitscript.com/forum/topic/113657-autoit-and-manifest/

I added this tool to my ugly-old script packaging batch files, and had good success with eliminating the program compatibility dialogs:

I recently had to replace the public-facing service communication certificates on our primary ADFS deployment on Server 2012 R2. I followed a procedure that I thought had a reasonable chance of actually doing what I wanted it to:

Obtained a new private key with signed certificate.

Saved the file to a pfx, and imported it onto each node in the ADFS cluster

Set permissions on the certificate according to documentation

Used the ADFS MMC -> Certificates -> Set Service Communications Certificate.

Everything seemed to go okay, but after a bit we started to get some complaints that some of our users could not access the Office 365 Pro Plus software download page. This was a curiosity to me, because I could not reproduce the problem. A colleague later noticed a raft of SSL errors in the System event log on one of the ADFS nodes, and disabled it in the load balancer configuration.

When I finally got around to investigating, I noticed that the system log reported problems from source ‘HTTPEvent’, with details DeviceObject: \Device\Http\ReqQueue, Endpoint: adfs.uvm.edu:443 (and also Endpoint: 0.0.0.0:443). What gives?

I found a related TechNet Blog that shed some light on the subject:
http://blogs.technet.com/b/tune_in_to_windows_intune/archive/2013/11/13/replace-certificates-on-adfs-3-0.aspx

According to this document, after setting the Service Communications Certificate in the MMC, you must run:Get-ADFSCertificate
to fetch the certificate thumbprint of the Service Communications Cert. Take note of the certificate thumbprint, then run:Set-ADFSSslCertificate -Thumbprint [yourThumbprint]

“Set-AdfsSslCertificate” will fix the HTTP.SYS bindings used by ADFS. Apparently the MMC does not set the bindings, which is pretty annoying because this leaves the service in a pretty darn broken state. The HTTP bindings are mentioned in this TechNet documentation:
https://technet.microsoft.com/en-us/library/dn781428.aspx
BUT, the docs do not explicitly state that the Set-AdfsSslCertificate cmdlet needs to be run on all of the ADFS server nodes in your farm. This also is a key missing detail.

Good Documentation… you always take it for granted, until you don’t have it anymore.

Note above that I mentioned a binding problem with the address 0.0.0.0:443. This was a carry-over from our initial deployment of ADFS 3. Back then, Microsoft did not provide a health check URL for ADFS, and the supplemental binding was needed to allow health monitor connections from our F5 load balancer without using SNI, which is required by ADFS 3.0, but not supported on the F5. These days (and if you have KB2975719 installed), you can instead monitor the following URL from your F5:
http://[yourServerFQDN:80/adfs/probe
More details on this solution can be found here:
http://blogs.technet.com/b/applicationproxyblog/archive/2014/10/17/hardware-load-balancer-health-checks-and-web-application-proxy-ad-fs-2012-r2.aspx

While it is nice having a proper health check, problems can arise when your ADFS server HTTP bindings go sour. It would seem that nothing is perfect.

Waaaay back we used to use a spiffy little tool called “ping plotter” to discover vacant IP addresses on our subnets. I had not had to do an exhaustive study of this for awhile. When it came up again today, I thought “I’ll bet we can do that with two lines of PowerShell.” But I was wrong… it took three lines, since I needed to initiate an array variable:

Now some variations… write out only addresses with no DNS entry and that do not respond to ping. (This will help to weed out addresses that are in use that for whatever reason to not have a DNS name.):

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!

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.

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:
http://regexhero.net/tester/
AND, of course, to the Regular-Expressions.info site:
http://www.regular-expressions.info/

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.

I think that the script has been posted without wordpress-induced errors. The main problem there is the use of .NET style named capture groups, which use ‘greater than’/’less than’ characters. WordPress hates gt/lt, which resemble XML/HTML/XHTML tags. I had to enter these bits of code as HTML escape sequences instead of raw code. It looks like it worked this time.

The following is a procedure for updating Application information in the UVM UDI environment. Use it as a template for your own operations:

When adding a new application (or app version): Categorize the application:

In the SCCM console under Software Library->Application Management->Applications, select the new application and get “properties”.

Under the “General Information” tab, Click “Select” next to the “Administrative Categories”. Add the new application to an existing App Category or create a new category, as appropriate. Applications that are categorized will be added to UDI. Non-categorized applications will not be available.

Update the UDI config files:

Run C:\local\scripts\CM-TaskSequences\build-UDIAppList.ps1.

Locate the “MDT 2013 Files” package in the SCCM console under Software Library->Application Management->Packages, and run an “Update Distribution Points” action. Verify that distribution was successful before proceeding.

And that is the whole story of the SCCM/UDI migration here at UVM to date. Clearly there is room for improvement. I will try to keep this series updated with revisions as we make them. As always, I hope that these posts will be of help to others in similar situations. If any of the code in this series makes its way into your environment, please let me know. I also am happy to answer any [short] questions about the topics covered here.

The following is a procedure for updating Operating System image data in UDI that is specific to the UVM environment. Use it as a template for your own operations:

Add the new WIM image to SCCM. The WIM must contain only one OS image (e.g. at index 1).

Run c:\local\scripts\CM-TaskSequences\build-udiInfoFiles.ps1.(This make a CSV files available to the UDI client that matches the OS Image Name to the version of the OS within the image.) (Required for driver injection.)

Run c:\local\scripts\CM-TaskSequences\build-udiImageList.ps1.(This updates the UDI XML-based control file that generates the OS selection options to the end-user in the UDI Wizard.)

Run c:\local\scripts\Update-OSApplyTaskSequence.ps1. When prompted, provide the name of the UDI task sequence to be updated.(This script updates the task sequence so that the OS selected in the UDI Wizard can be applied to the UDI target machine.)

Locate the “MDT 2013 Files” package in the SCCM console under Software Library->Application Management->Packages, and run an “Update Distribution Points” action. Verify that distribution was successful before proceeding.(This makes the new CSV info files and Wizard configs available to end-users.)

Create a new folder under the matching OS version folder (i.e. Win7 or Win8) within the driver import source directory: “\\confman3\sources\drivers\import“. The name of this new folder must match the model information discovered in step 2. Extract the new drivers into this folder.

If updating a model: Update the driver source:

Locate the source folder for the driver package to update. Remove all contents of the directory including the “.hash” file in the root.

Extract the new drivers into this folder.

If updating a model: Cleanup existing drivers in SCCM:

Find the package to be updated in the SCCM management console. Delete it.

Right-click and get the properties on any driver in the SCCM console. Call up the list of driver categories, and delete the category for the driver to be updated.

Import the drivers from source:

Run C:\local\scripts\CM-Drivers\ImportDrivers.ps1 to import the new drivers into the SCCM environment. The script will create new packages and driver categories for each new folder that you created.

Wait.

Distribute the drivers:

Refresh the SCCM console to reveal the new driver packages and categories.

Right-click the driver package and select “Distribute Content”. Distribute the drivers to “Confman2”.

Monitor the distribution process in the bottom pane of the SCCM console. Make sure distribution succeeds before proceeding.

If adding a model/package: Update the MDT files with the new driver information:

Run C:\local\scripts\CM-TaskSequences\build-UdiInfoFiles.ps1 on Confman3

Locate the “MDT 2013 Files” package in the SCCM console under Software Library->Application Management->Packages, and run an “Update Distribution Points” action. Verify that distribution was successful before proceeding. This will publish a new list of drivers packages to the UDI clients.

If adding a model/package: Update the OS Installation Task Sequence:

Run C:\local\scripts\CM-TaskSequences\Update-DriverInjectionTaskSequence.ps1. Specify the name of the Task Sequence to update when prompted, or provide the name using the “-name” parameter. This script will update the Task Sequence to allow for injection of the new driver package, if one is available for the current model.

If adding or updating WinPE, Peripheral, or “Other” drivers: Update the boot media:

In the SCCM console under Software Library->Operating Systems->Drivers, select “Saved Searches”, then select WinPE 64-bit or WinPE 32-bit. Once the drivers have been filtered, Select All, and then right-click and select Edit->Boot Images. Select the MDT boot image for your architecture (32-bit or 64-bit).

As noted above, you need a custom Workstation Authentication certificate to generate the boot media. If your certificate has expired or you want to generate a new certificate for any other reason, use the following procedure, adopted from:

From a workstation that has access to your Certificate Authority web interface, open Internet Explorer using your admin account, and access:
https://caServer.domain.edu/certsrv/
Logon as a user with rights to generate workgroup certificates. Currently this is scoped to high-level admins in our organization.

Add the site to the “Trusted sites” zone in your Internet Settings Control Panel.

Activate “compatibility view” if your CA is still running on Server 2008 R2, otherwise the required ActiveX controls will not load.

Note: This is a lightly-modified copy of the stock “Workstation Authentication” certificate template. As per MS requirements, the certificate has been forced to use the legacy “Server 2003” certificate format, not the Vista+ “CNG” format.

An Enterprise Admin can add permissions to the template to allow enrollment rights for additional users/groups, if necessary.

Fill in the identifying information and friendly name for the certificate. Make sure to select the option to “Mark keys as exportable”, then click “Submit”.

When prompted, install the certificate. The certificate will be installed into the “Personal” or “My” store for the user running Internet Explorer.

Run MMC.EXE as the user who requested the certificate:

Add the “Certificates” snap-in for the current user.

Navigate to the “personal” store. Locate the new certificate.

Right-click the certificate and select All Tasks -> Export.

In the certificate export wizard, select the option “Yes, export the private key.”

Select Personal Information Exchange – PCKS #12 (.PFX), and ensure that “Include all certificates in the certification path if possible” AND “Export all extended properties” are checked, then click Next.

Type in a password and confirm it in the boxes provided on the Password screen, then click Next. (Save this password for later use)

Browse for a location to which to export the certificate. Make sure that it is somewhere accessible from SCCM, give it a name (i.e. ‘WinPE-Cert.pfx’) and click Save.

In the previous parts of this blog series I have shown how PowerShell and VBScript can be used to automate Driver, Application, and Operating System selection and installation in MDT/UDI. In this final post I will discuss a few final UDI quirks that we worked though without using scripts.

UDI Boot Media:

We experienced an odd problem during our OS Deployments when booting from SCCM/UDI media. The deployment process starts, as documented, with a dialog allowing the user to configure the networking environment for OS deployment, followed by a Task Sequence selection dialog. After selecting the task sequence, we expected some scripts to run, followed by the initiation of the UDI Wizard dialogs. Instead what we found was that UDI would first format an partition the local drive, copy a new WinPE environment to the drive, and then restart into WinPE running from local disk before brining up the UDI Wizard. This created a substantial delay between Task Sequence selection and the start of the Wizard. My impression was that users would find this delay unacceptable.

Our MS consultant suggested that this was happening because the revision of the UDI/WinPE environment on our boot media did not match boot image referenced by our active task sequence. To test this, we rebuilt all of the boot images in our environment from the Windows 8.1 ADK sources, then created a new MDT boot image from the ADK image, created a new task sequence referencing the ADK image, and finally generated new UDI Boot Media with the MDT boot image as a source. After completing these actions and updating our distribution points, we were able to get the UDI Wizard to start after Task Sequence selection without first requiring a reboot.

Improper OS Drive Letter Assignment

In our first deployments, we found that at the end of the Task Sequence, our operating system was left running on a D: or E: drive, instead of the usual “C:” drive. Knowing full well that this could cause massive end user confusion, I set out to correct this problem.

After weighing the options, I chose to try the “Delete Mounted Devices from registry” option. This required me to import a custom task sequence into our SCCM instance, and then copy/paste the required Task Sequence steps into our production Task Sequence. This approach instantly was successful, so I am sticking with it. Thanks again, Michael.

Failure of UserExit Script Processing

Under MDT/LTI, we made use of the “User Exit Script” capabilities of MDT to generate unique default computer names for UDI clients. Cursory inspection of the docs suggested that User Exit script functionality also is supported under SCCM/UDI, so I decided to transplant our script. However, after doing so I found that the default presented in the UDI Wizard was #GenUniComp()#, rather than a generated computer name.

#GenUniComp()# is the value assigned in our CustomSettings.ini file for the OSDComputerName variable. However, MDI/UDI is supposed to “exit” any code placed between the hash tags (#) out to the Windows Scripting Host. “GenUniComp” is the name of a VBScript function that I defined in our “ZUVMUserExit.vbs” User Exit script. The function works well enough under MDT/LTI, so what is going wrong in UDI?

To diagnose this problem, it helps to know a bit about how User Exit scripts are processed. “UserExit” is set as a variable in the CustomSettings.ini for your environment. This variable is detected and processed by the ZTIGather.wsf script that is run several times during each MDT/LTI and SCCM/UDI deployment. To troubleshoot problems with the script, you should look to the SCCM/UDI log files generated by ZTIGather.wsf. When I examined the ZTIGather logs, I could find no reference at all to the UserExit variable getting processed by the ZTIGather script. The next logical question is, why not?

Logically, the problem is not likely to be caused by an error in the script. First, the same script works just fine under MDT/LTI. Additionally, the script uses the MDT logging functions, so if it had executed, we would have expected to see at least some log output. I thus assumed that the script was not getting executed at all. I started looking at the ZTIGather logs from the top, and found reported “processing [Settings]…” followed immediately by “processing [Default]…”. Interestingly, I had defined the UserExit variable under the [Settings] section of CustomSettings.ini, which worked find under MDT/LTI. However, the SCCM version of ZTIGather appears to process only “Priority” and “Properties” settings under the [Settings] section. My UserExit definition was getting ignored because it was in the wrong place. After moving the “UserExit” definition to the [Default] section, UDI started to process the GenUniComp() function of my User Exit script just as it had under MDT/UDI.

In the final section of this series, I will present operational instructions for the use of these scripts in our environment. These documents are tailored for the UVM environment, but might serve as a template for instructions at other sites.

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 ‘UDIWizard_Config.xml.app’). 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.