Category Archives: Programming and Scripting

Error Code 1 – Using Invoke-MbamClientDeployment.ps1 in SCCM OSD

I know I’m not alone in the misery of getting this less-than-perfect script to work during OSD and after a good couple of weeks of on-off testing I can finally say I got my desired result and it most certainly deserved a post. Please note, you may need to click on the pictures to see them fully.


Encrypt used space only with XTSAES256 encryption and escrow keys in MBAM database during SCCM OSD task sequence. I also need a PIN to be requested automatically at first logon.

I’m not going to detail the ins and outs of what I tried because this post will be far longer than necessary so I’ll concentrate on the steps that finally got it working for me. Don’t get me wrong, this is a buggy script that should really have been updated by Microsoft by now.  Error code 1 is an extremely common problem and can result for any number of reasons.

I would suggest you create an MBAM section in the task sequence, filtering on laptops or whatever criteria you require and add the steps below to this section.

High Level:



Contrary to what I have read elsewhere, the pre-provision step in the task sequence isn’t necessary. In fact, it’ inclusion will cause the error code 1. These steps should be disabled.


This is a strange one but I have had trouble getting the Invoke-MbamClientDeployment.ps1 to run properly without first disabling the certificate update mechanism in Windows. Trust me, just do it, reboot, run the rest of the steps and make sure you remember to re-enable afterwards.

REG ADD HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\AuthRoot /v DisableRootAutoUpdate /t REG_DWORD /d 1 /f

The assumption is that you have installed the MBAM 2.5 SP1 client with the August 2017 hotfix by this stage so there will be an MBAM Agent service running on the machine.

Net stop mbamagent


Now I am recreating what worked for me here and despite my requirement for XTSAES256 the below setting seems to work fine for this in my task sequence. However evidence elsewhere suggests the DWORD value should be 7. Feel free to test in your own environment though and let me know how you get on.

REG ADD HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\FVE /v EncryptionMethod /t REG_DWORD /d 2 /f

We want used space only as this is quickest. See here for other values. Be careful though – if you want the PIN prompt to appear at first logon the disk has to be ‘fully encrypted’, ie with used space only OR full disk. If the disk is still encrypting when the user logs on, they won’t be prompted for the PIN.

REG ADD HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\FVE /v OSEncryptionType /t REG_DWORD /d 2 /f


This is where * I believe * stage 3 gets overwritten (tbc). Essentially this will set the OS encryption to XTSAES256.

REG ADD HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\FVE /v EncryptionMethodWithXtsOs /t REG_DWORD /d 7 /f


Call the MBAMClientUI on first login. Technically this shouldn't be needed as I have a step further down which will call this anyway but no harm in adding.
REG ADD HKLM\Software\Microsoft\MBAM /v EnactOnFirstLoginRequired /t REG_DWORD /d 1 /f

Force MBAM client to wake up within a minute.

REG ADD HKLM\Software\Microsoft\MBAM /v NoStartupDelay /t REG_DWORD /d 1 /f


Net start mbamagent

This adds a setting to the default user so that every NEW user that logs onto the machine gets prompted for a new MBAM PIN for startup. Note, this will only fire if the disk is fully encrypted to type, ie used space only or full disk. Since we’re aiming for used space only here, disk encryption is pretty quick but it still needs to complete before the prompt will appear. If you log on before encryption is complete then the automatic prompt won’t appear and you will instead need to rely on GPO.

powershell.exe -ExecutionPolicy Bypass -command "reg load HKLM\DefaultUser C:\Users\Default\NTUSER.DAT; New-ItemProperty -Path 'HKLM:\Defaultuser\Software\Microsoft\Windows\CurrentVersion\RunOnce' -Name PromptForPIN -Value '""C:\Program Files\Microsoft\MDOP MBAM\MBAMClientUI.exe"""' -Type String; reg unload HKLM\DefaultUser"

The script itself. Note the encryption method, Unspecified. Because we have specified the encryption method earlier, the XTSAES256 encryption is automatically derived from that. Strangely, I couldn’t get this script to work unless I used this parameter and manually set the reg entry. Also note, I am running the script from the local installation of the MBAM client. This ensures that I am running the script that is aligned to that version of the client, ie it should contain any updates provided by any client upgrades you’ve applied, eg August 2017 update.

powershell.exe -ExecutionPolicy Bypass -File "C:\Program Files\Microsoft\MDOP MBAM\Invoke-MbamClientDeployment.ps1" https://MBAMSERVER.local/MBAMRecoveryAndHardwareService/CoreService.svc -EncryptionMethod UNSPECIFIED

Don’t forget to re-enable this otherwise you’ll end up with all sorts of certificate errors when trying to reach HTTPS sites.


That’s it. One would assume much of this legwork should automatically be taken care of by the script itself but unfortunately that doesn’t appear to be the case. Don’t forget, you will also need to make sure that no MBAM policies are in place when the script runs. This isn’t a problem with SCCM as GPOs will be suppressed but if you’re using native MDT this can be an issue.

Hopefully this will save some of you a few hours (more likely days) of frustration!



OSD Scripting Hacks Part 4 – Renaming NICs

In a new series of short posts I’m going to show how to get around some frustrations I have had with the lack of GPO support for some common requirements plus a few other issues I have come across which have crept up recently.

More for a bit of fun really but this was another serious request I have had where a machine contained several adaptors, they should all be sequentially named to specification, in this case NIC1, NIC2, NIC3 ,etc.

Here’s the script. It renames the adaptor numerically and outputs to a logfile:

# Rename NICs
ForEach($nic in (Get-NetAdapter -Name *)) {
$number += 1
Get-NetAdapter -Name $nic.Name | Rename-NetAdapter -NewName NIC$number - PassThru | Out-File %WinDir%\Temp\NicName.log -Append

For MDT users I recommend using a commandline action as follows:

powershell.exe -ExecutionPolicy Bypass -command "$number=0; ForEach($nic in (Get-NetAdapter -Name *)) { $number+=1; Get-NetAdapter -Name $nic.Name | Rename-NetAdapter -NewName NIC$number -PassThru | Out-File %WinDir%\Temp\NicName.log -Append }"

That concludes this series for now until such time as another request comes my way…


OSD Scripting Hacks Part 3 – Disable NETBIOS in Powershell

In a new series of short posts I’m going to show how to get around some frustrations I have had with the lack of GPO support for some common requirements plus a few other issues I have come across which have crept up recently.

Another requirement that came up in my recent project was to disable the NETBIOS over TCP/IP setting function under the network adaptor settings | IPv4 properties | Advanced. The issue here is that there are multiple GUIDs present in the registry that must be changed and these can’t be easily predicted. Fortunately Powershell is kind to us and allows the use of a wildcard (*) to just hit them all. This is achieved with the following script:

 # Disables NETBIOS over TCP/IP
set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\services\NetBT\Parameters\Interfaces\tcpip* -Name NetbiosOptions -Value 2

For MDT users, I recommend using a commandline action as follows:

powershell.exe -ExecutionPolicy Bypass -command "set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\services\NetBT\Parameters\Interfaces\tcpip*' -Name NetbiosOptions -Value 2"

Next, renaming NICs!

OSD Scripting Hacks Part 2 – Performance Settings

In a new series of short posts I’m going to show how to get around some frustrations I have had with the lack of GPO support for some common requirements plus a few other issues I have come across which have crept up recently.

In part 2, I will show you how to change the performance settings via a script which can be run from a task sequence step. Like the file extensions in Part 1, this was another area that (at the time of writing) seems frustratingly missing from group policy. I was creating an MDT task sequence recently to build some servers and one of the requirements was that the Visual Effects setting was specifically set for ‘Best Performance’ as opposed to Let Windows choose…

Anyway, the script:

# VisualFX - Best Performance
$RegKey ="HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VisualEffects"
Set-ItemProperty -Path $RegKey -Name VisualFXSetting -Type DWORD -Value 2

For MDT, you may wish to run this as a commandline as follows:

powershell.exe -ExecutionPolicy Bypass -command "set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VisualEffects' -Name VisualFXSetting -Type DWORD -Value 2"

In the above I set the value to 2 for best performance. Other values can be:
0 – Let Windows choose what’s best for my computer settings.
1 – for Adjust for best appearance settings.
2 – for Adjust for best Performance settings.
3 – for Custom settings.

OSD Scripting Hack Part 1 – Enable file extensions for all users

In a new series of short posts I’m going to show how to get around some frustrations I have had with the lack of GPO support for some common requirements plus a few other issues I have come across which have crept up recently.

First in the series is a build fix for file extensions. By default, these aren’t enabled and at the time of writing there isn’t a GPO that can be applied that applies them for users when they log on so they have to be enabled manually. Personally I find it frustrating that I can’t see what kind of file something is and it is usually the first thing I change when  I log into a new computer. Anyway, among others, this became a requirement for a recent project I was on and after a bit of playing around and further research I came up with the following Powershell script:

reg load HKLM\DefaultUser C:\Users\Default\NTUSER.DAT
 $path = "HKLM:\Defaultuser\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
 New-ItemProperty -Path $path -Name HideFileExt -Value "0" -Type DWord
 reg unload HKLM\DefaultUser

This should be run as a task sequence step but depending on your deployment tool of choice, Powershell commands can occasionally be a little fussy. If you are using MDT, you might find the following works better if set up as a commandline:

Powershell.exe -ExecutionPolicy Bypass -command "reg load HKLM\DefaultUser C:\Users\Default\NTUSER.DAT; New-ItemProperty -Path 'HKLM:\Defaultuser\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' -Name HideFileExt -Value 0 -Type DWord; reg unload HKLM\DefaultUser"

The above should also work fine for SCCM although SCCM isn’t as picky as stand-alone MDT so either might work there.

Next time, Performance settings.

Securing Web Services

One of the main criticisms of using web services is that they’re inherently insecure. By default anyone can access them and if they have functions to actually change anything then one must proceed with caution.

My current client was somewhat skeptical about their introduction and the only way I could bring them round to the wonderful gifts that they offer was to promise that we’d investigate a secure way to present them. There was some trial and error but I think we came up with a pretty good solution which I shall share here.

Why use web services at all?

There are an awful lot of reasons so I’ll keep it to why I like to use them. They’re a cheap and cheerful way to provide functionality by proxy.  They can be used to off-load many tasks which, if you don’t have the budget for something like the wonderful System Center Orchestrator product, can make a great shoe-in. OK a little more explanation…

From a deployment perspective they can provide a mechanism to access Active Directory, MDT and SCCM without a client OS necessarily being part of AD. For example, they could be called from a WinPE session to update a database or query/update an OU. They’re relatively easy to write if you possess basic programming skills but if not, then I fully recommend you check out Maik Koster’s toolset here.  Installation instructions are provided but do fall a little short on security, so let me crack on.

Securing the Web Services

First of all, if you run a PKI infrastructure, let me recommend you you change the URL to run under HTTPS. I am not going into detail in this respect here as there are plenty of how-to’s on this topic elsewhere on the web. Suffice to say it’s a no-brainer if you’re truly concerned about security, particularly if there are any services which need to pass confidential information such as passwords.

Next, ensure you have read Maik’s security blog for his web services. They’re basic but a good start. Now to secure it properly:

Securing the website via pass-through authentication

Follow these steps to lock down page to an AD group. I won’t go into detail on  clicky-clicky, I assume if you have come this far you’ll know this stuff from within IIS and from the screen shots provided. If enough people tell me otherwise, I’ll review this though.

  1. Before changing anything, this is the expected configuration:

2. Install url authorisation feature and windows authentication features from server manager or Powershell.

3. After installation, change authentication model as follows (apologies, image is a little blurry, I’ll try to update in due course).

4. Update Authorisation rules. Note that All Users verbs have been changed to POST. This prevents the web page appearing at all without a login prompt (ie the initial GET action is prevented from running) for all users other than those in that are members of the specified AD group.


5. Providers should remain at their defaults:

6. Update local Intranet sites. If the site isn’t trusted you may need to add this to local intranet sites to prevent a login box appearing.


You should now have full pass-through authentication for your web service, dependent on membership of the AD group of your choice.

Can’t run PowershellInstance.invoke() from C# (but code is fine)

I recently wrote a GUI to duplicate MDT database roles based on the excellent Powershell commandlets written by Michael Niehaus:
Although the Powershell code worked fine when executed directly in a Powershell window, I was seeing mixed results when executing the same code in C# through PowershellInstance.invoke(). Specifically, when I compiled the executable I was able to run the powershell code through the utility without issue, whereas it failed for my colleagues for some reason.


It seems that what I needed to do was ensure that the code was compiled specifically for the platform I was running it on as opposed to ‘any CPU’. In my case this was for x64. You can set this under the project properties in Visual Studio:


However, after making this change, I found I was getting compilation errors along the lines of:
An attempt was made to load an assembly with an incorrect format: [path to exe]

To fix this, I needed to change Generate serialization assemply to Off and everything compiled as expected. More on this here.

New-CMBoundary IPSubnet Doesn’t work

CM2012 introduces to us the ability to easily script many labour-intensive tasks. I was recently adding numerous boundaries to a ConfigMgr implementation for a client so decided the best approach was to automate this procedure.  I fired up the Powershell session from within ConfigMgr and checked the syntax for New-CMBoundary. Now, I had a spreadsheet with a bunch of IP subnets in CIDR notation so it made sense to use this for my script. Running Get-Help New-CMBoundary I got the following:

Example 1: Create a new IP Subnet site boundary
PS C:\>New-CMBoundary -DisplayName "IPSubNetBoundary01" -BoundaryType IPSubNet -Value ""
BoundaryFlags: 0
BoundaryID: 6338009
BoundaryType: 0
CreatedBy: Contoso\PFuller
CreatedOn 6/10/2012 1:17:42 PM
DisplayName: IPSubNetBoundary01
GroupCount: 0

Looks straightforward enough but no. This simply doesn’t work as stated. The problem seems to be that it doesn’t understand the ‘/24’ part (in this example). Instead, what you first need to do is to find the subnet ID which is associated with your address. If you’re unsure what this is then I’d recommend you use something like




In the example above we have a CIDR range of You can see from the calculator that this produces a network ID of Therefore the correct syntax for New-CMBoundary is as follows:
New-CMBoundary -DisplayName “IPSubNetBoundary01” -BoundaryType IPSubNet -Value “”
All that said, I’d personally avoid IPSubnet boundaries completely. Instead, just go for a range, far simpler to understand. The CIDR calculator is again helpful for this and displays the range at the bottom.
Thankfully, the IPRange syntax is correct so you shouldn’t have any issues.



How to deploy x86 and x64 universal printer drivers en-masse

I was recently asked to come up with a solution to update our entire print server esate (around 600 boxes) with univeral PCL6 and PS drivers over x86 and x64 architectures. Specifically in this case I was asked to update with Lexmark and HP drivers although I see no reason this solution shouldn’t extend to any other manufacturers.

Since we have SCCM, my immediate idea was to create a package and push all packages out to the servers concerned but I found some shortcomings when creating the driver packages. Lexmark provide a tool to create the packages but I found I was unable to install both x86 and x64 drivers on the same machine. In fact, the executable created for the x86 drivers just threw errors. For the HP drivers, I had to throw in a few command line switches but again it simply wouldn’t install both architectures of driver. I should point out that the print server I was using for the test was Windows 2008 x64.

So another method was required. After much testing, I found the most reliable method was to use the Microsoft utility, prndrvr.vbs. This utility (along with several others) can be found under C:\Windows\System32\Printing_Admin_Scripts\en-US on the print server. I then deployed these using a task sequence in SCCM, running this utility with the drivers in question. Everything installs just fine and I don’t get any of the other rubbish which the manufacturer utilities include, such as extra printer objects, pre-configured ports etc. I have outlined what I did below for the HP drivers but remember, this should work for any print drivers.

  1. Download HP Universal Drivers package from the net. Create a folder called HPUniversalDrivers in C:\Temp on your test workstation. Create another folder inside called HPUPD. Copy xcopy.exe into this folder. Copy the 32bit and the 64bit folders out of the HP Universal Drivers package into C:\Temp\HPUniversalDrivers\HPUPD. Finally copy prndrvr.vbs into C:\Temp\HPUniversalDrivers\HPUPD. Your HPUPD folder should now contain two folders (32bit and 64bit) and the vbs script.
  2. Create a package in SCCM pointing the source to the location we have just described on your test box, eg \\testbox\C$\temp\HPUniversalDrivers, create a distribution point and update it. You don’t need a program.
  3. Create a new custom task sequenceSelect General > Run Command Line: NAME=Copy HP Drivers Locally, Command Line=xcopy “HPUPD” “C:\Temp\HPUPD\” /E /Y, select the ‘package’ checkbox and browse to your HP driver package you created earlier. OK
  4. Decide which driver version you require. You may have to dig about in the .inf files to find the one for your particular requirements but for the purposes of this blog I required v5.4 which could be found in hpcu118d.inf: 
    • Create a new custom task sequenceSelect General > Run Command Line: NAME=HP UPD PS v5.4 x86, Command Line=cscript prndrvr.vbs -a -m “HP Universal Printing PS (v5.4)” -e “Windows NT x86” -i “C:\Temp\HPUPD\32bit\PS\hpcu118d.inf” -h “C:\Temp\HPUPD\32bit\PS”, Start in:= C:\Temp\HPUPD
    • Create a new custom task sequenceSelect General > Run Command Line: NAME=HP UPD PCL6 v5.4 x86, Command Line=cscript prndrvr.vbs -a -m “HP Universal Printing PCL 6 (v5.4)” -e “Windows NT x86” -i “C:\Temp\HPUPD\32bit\PCL6\hpcu118c.inf” -h “C:\Temp\HPUPD\32bit\PCL6”, Start in:= C:\Temp\HPUPD
    • Create a new custom task sequenceSelect General > Run Command Line: NAME=HP UPD PS v5.4 x64, Command Line=cscript prndrvr.vbs -a -m “HP Universal Printing PS (v5.4)” -e “Windows x64” -i “C:\Temp\HPUPD\64bit\PS\hpcu118v.inf” -h “C:\Temp\HPUPD\64bit\PS”, Start in:= C:\Temp\HPUPD
    • Create a new custom task sequenceSelect General > Run Command Line: NAME=HP UPD PS v5.4 x64, Command Line=cscript prndrvr.vbs -a -m “HP Universal Printing PCL 6 (v5.4)” -e “Windows x64” -i “C:\Temp\HPUPD\64bit\PCL6\hpcu118u.inf” -h “C:\Temp\HPUPD\64bit\PCL6”, Start in:= C:\Temp\HPUPD
    • Create a new custom task sequenceSelect General > Run Command Line: NAME=Remove HP Directory, Command Line=cmd.exe /c RD C:\Temp\HPUPD /S /Q
  5. Your task sequence is now complete. Next, create a collection and add the print server of your choice to the collection. Advertise the task sequence to the collection and you should be good to go. This example will install both x86 and x64 drivers, PS and PCL6.

Print Drivers

Disclaimer: I am in no way responsible if you accidentally deploy something nasty to your whole estate. Please test responsibly before deployment!