Silence is Golden during Setup

Thanks to @gwblok for pointing me to this twitter thread about Windows OOBE Setup.

When Unattended is not Silent

During Windows 10 OOBE, the Windows Welcome process uses the Cortana voice engine to speak during Windows Setup.

Now we can go look for any updates

Shut up!

Yes, I’m one of those guys who sets my Sound Profile to “silent”, Silence is Golden!

And if I’m going to be running several Windows Deployments in my lab (read my home office), then I would prefer the machine to be silent. Reminds me of the XP/Vista days when we had boot up sounds. How rude.

So how to disable… Well the answer doesn’t appear to be that straight forwards.

SkipMachineOOBE

At first I suggested SkipMachineOOBE, and works on my test machine! Yea!

Then I got a reminder that SkipMachineOOBE is deprecated according to documentation.

DisableVoice

Thanks to @Jarwidmark for pointing me in the thread above to:

reg.exe add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE /v DisableVoice /t REG_DWORD /d 1

However, Microsoft Documentation also states that you should only use this for testing, and that Cortana Voice should be-enabled for users. OK… Fine, we’ll delete the key after setup is complete.

So where to place all this stuff?

Specialize

Several people suggested modifying the local registry within the imaging process, but I would prefer to avoid that, instead trying to see if we can perform the action during Setup using our unattend.xml file.

The command to disable would need to be *before* “OOBE”, sounds like the perfect job for the “Specialize” process.

Some quick testing, verified, and we are ready to go.

Automating OOBE

So, given the guidance from Microsoft on how to automate Windows 10:

https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/settings-for-automating-oobe

Here are my changes:

  • We disable Cortana during the Specialize Pass before OOBE.
  • Then during OOBE, we clear the Cortana setting, and continue.

 

Advertisements

Bypass OEM Setup and install your own image.

AutoPilot

Really Windows Autopilot is the future. As soon as the OEM’s get their act together, and offer machines without the bloatware and adware. Yea, I’m talking about you Anti-Virus Trial! Go away, shoo! Shoo! Give me Signature Images, or I’ll do it myself.

Unfortunately, I’m currently working for a client that is “Cloud Adverse”, and very… particular about Security. “have our machines go through the internet, and download our apps from a cloud, oh heavens no!!”.

So all machines come from the OEM’s and into a centralized distribution center, where they run a hodge-podge of OS Imaging tools to get the machines ready to ship out to each user.

And, No they don’t use any MDT… at least not yet…

Really it’s the Anti AutoPilot…

Where to start.

Well, when the machines arrive from the OEM, they are unboxed and placed on a configuration rack. If they are Desktop Machines, they are also connected to a KVM switch (Imagine several 8-port switches daisy chained together). Then they are plugged into power, network, and turned on.

Here’s our first challenge: How do we stop the PC from booting into the OEM’s OOBE process into OUR process? Well right now the technicians need to press the magic function key press at just the right time during boot up.

You know the drill, Press F12 for Dell, or perhaps press F9 for HP, or Press enter for Lenovo. Perhaps you have a Surface Device, and need to hold down the Volume button while starting the machine. Yuck, but better than nothing…

Well, the feedback we got from the technicians is that sometimes they miss pressing the button… at “just” the right time. This is really a problem for a Desktop PC’s connected to that KVM switch. If the Monitor doesn’t sync to the new PC quickly enough, you might easily miss pressing the boot override switch.

This sounded like a good challenge to start with.

Audit Mode

Really, IT departments don’t use Audit Mode. Audit Mode is a way to make customizations *during* Windows Setup and then re-seal the OS, so the end-user gets the nice shiny Windows Setup process (Specialize and OOBE) that they expect in a new PC.

Deployments in IT are all about bypassing the shiny Windows OOBE experience. No we don’t care about all the fancy new features in Cortana, We have already signed the SA agreement with Microsoft, we already know the domain to connect to, and our company has only one locale and keyboard type. IT departments would much rather skip all that, and get the user to their machine. So the thought of re-sealing a machine and going *back* to OOBE when we just finished joining to the domain and installing apps is silly.

But there are some Possibilities here. Turns out, that when Windows Setup is running, it will look for an Unattend.xml file and try to use it.

Methods for running Windows Setup

MDT uses an Unattend.xml file on the local machine it we can skip over the settings we know about, and re-launch MDT LiteTouch when finished. What about this process? If we place the Unattend.xml file on the root of a removable USB drive, the Windows version on the hard disk will look there and use these settings. The Lab Techs appeared to have a lot of USB sticks laying around, so using them shouldn’t be a problem.

We can’t use a MDT unattend.xml file as-is, but we can use AuditMode to get to a command prompt and install our own MDT LitetouchPE_x64.wim file.

  1. Boot into Audit Mode.
  2. While in Audit Mode, auto login using the Administrator Account.
  3. Find our PowerShell script and run it!

PowerShell script

Once we are in PowerShell, we now have full access to the system, and can modify it in any we choose. In this case, I have copied a LiteTouchPE_x64.wim file to the USB Stick, and we can force the Hard Drive to boot from that instead, continuing our process in MDT LiteTouch. Yea!

Now we have a bridge between the OEM system and our LiteTouch, or any other automated WinPE disk.

Yea! Now for the *REAL* automation to begin… 🙂

-k

 

Windows 10 In-Place Security Considerations

TL;DR – When performing a Windows 10 In-Place upgrade, you must temporarily suspend any Disk Encryption protections, for BitLocker *AND* 3rd party disk encryption too!

In Place Upgrade

So, how do we upgrade an Operating System? You know, the one we are currently using? Can we still upgrade it while still in use? Unfortunately, no. The Windows 10 In-Place process is very complex, and it requires full access to all the files on the machine. So how do we do that? Well, the upgrade process needs to shift to another OS, just temporarily, to modify the OS on our C:\ drive, we can use WinPE (Windows Pre-Installation Environment), or in this case WinRE (Windows Recovery Environment).

WinPE and WinRE are lightweight OS’es that are contained in a compressed boot.wim file, about 300MB to 500MB in size, and placed somewhere on the disk. We can boot into WinPE/RE and have it completely reside in memory. Now we have full access to the C:\ drive on the machine, and we can move files around and including a new OS.

winre.png

3rd Party Drivers

One of the challenges of shifting to a separate OS like WinPE/WinRE is that we’ll need to re-load any drivers required to access the system, including Disk and File System Drivers. For the most part, the latest versions of WinPE/WinRE will have very excellent support for the latest disk controller drivers. And it’s very rare that I’ve had needed to supply 3rd party drivers for mainstream hardware. Starting with Windows 10 1607, Microsoft gives us the ability to add 3rd party Drivers to the WinPE/WinRE using the /ReflectDrivers switch. This includes the ability to supply drivers for a Storage Controller or even a 3rd party Disk Encryption tool. Anything that is required to access the machine.

Suspending Encryption

First some background…

lock.jpg

At my house I have a Lock Box like this. I can place my house key in the box, and if someone needs to get into the house, I can just give them the code to the lock box. This is much better than giving everyone their own key, or just leaving the main door unlocked while I’m out. If I want to revoke access, I just change the code on the lock box, rather than re-keying my whole house.

If you have an OS disk that is encrypted, and you want to upgrade the OS, you probably don’t want to decrypt the ENTIRE disk before the OS upgrade, and re-encrypt the disk when the new OS is ready, that would take time to read and write data to the entire disk. Instead it would be better if we could leave the disk encrypted, and just temporarily give the setup system full access. It’s similar to the Lock box analogy above, we don’t want to give everyone access to the main encryption key, but the system will allow access at the right time to the right users.

For Microsoft BitLocker, the process is called “suspending”. We leave the disk encrypted, but the encryption keys for the disk are no longer protected. When the new OS is installed, we can re-establish protection via our usual protectors like TPM, SmartCard, Password, etc…

3rd party encryption products need to function in the same way.  We would like to leave the disk encrypted, but any protections like “Pre-Boot authentication”, should be disabled, so the WinPE/WinRE Operating System, with the correct Encryption filter drivers have full access to the main OS. When finished, we can re-establish any Pre-Boot authentication protections supported by the encryption software like Passwords, TPM chips, Smart Cards, etc…  If the 3rd party disk encryption product does not offer this then the WinPE/WinRE OS won’t be able to access the local C:\ Drive.

Misconceptions

I’ve been working with a client lately whose security team has correctly identified the In-Place Upgrade-Suspending Encryption behavior I described above. However, they incorrectly prescribe this as a vulnerability of BitLocker, and have not acknowledged that it is also a vulnerability of other 3rd party disk encryption tools.

First off, yes, this is a known security Vulnerability in the way Windows 10 handles In-Place Upgrades, we simply must temporarily suspend protections as we move off to offline OS, this is by design. More below…

Secondly, It’s disingenuous to claim that this is only a BitLocker problem, by the design of the current Windows 10 In-Place upgrade system with the /ReflectDrivers hook, 3rd party disk encryption tools must also suspend protections so the WinPE/WinRE offline OS’es.

This is really important for fully automated In-Place upgrade scenarios like MDT Litetouch or System Center Configuration Manger (SCCM) OSD (Operating System Deployment) tools.

Mitigations

Well, it’s not all gloom and doom, It’s not perfect, but like most things related to security, there are compromises, and tradeoffs.

Note that your data at-rest, protected by encryption, is only one potential threat vector where bad guys can get your data. There is also Malware, OS bugs, and other vectors that are made more secure with the latest Windows Releases. It *IS* important to keep your machine up to date and healthy with the latest OS and security tools, and simply avoiding upgrades because you don’t want to expose your machine, isn’t the best solution.

But there are also techniques/mitigations we can do to limit the exposure of your data during In-Place Upgrades. You will, of course, need to perform your own threat analysis. Some ideas might be:

  • Don’t allow Upgrades to be performed in an automated fashion, always run attended. (not possible in some large environments).
  • Only allow Upgrades to be performed on site, in semi-secured environments. Never over VPN or Wi-FI
  • If you are running in a SCCM environment, we could develop some scripts/tools to monitor Upgrades. If a machine hasn’t returned from In-Place upgrade after XX minutes, then auto-open a Support Ticket, and immediately dispatch a tech.

-k

Install Windows 10 on Surface 1TB with MDT

TL;DR – Here is a script to get past the Disk0 to Disk2 mapping issue with the new Surface Pro with a 1TB drive.

Surface Hardware

OK, first a bit of history, I used to work for the Surface Imaging team back in 2015 to 2016. Overall a cool job, I learned a lot, and got to sharpen my PowerShell coding skills.

During that time I got to see my first Surface Studio device, even before it was released. Once of the unique features of the device was it’s unique disk architecture, it contains TWO disk drives, one a SSD in a M.2 format, and a Spinning Hard disk in a 2.5″ format. The OS contains a driver that uses the SSD as a cache. The idea is that you get the size of the 2TB hard disk, with (generally) the speed of the SSD.

Of course this creates a problem for OS deployment because we need to load the Special Caching driver into WinPE before deployment, so both drives are properly identified.

The Surface Pro with the 1TB drive is also unique in this manner, on the inside it isn’t a single 1TB drive, instead it’s two 512GB drives running in a Raid 0 configuration.

So you’re probably wondering how this works within WinPE on MDT, well the good news is that the built in 1709 drivers can correctly identify the two SSD disk as a single 1TB drive…

… The only problem is that it’s identified as Disk(2), and that breaks stuff.

ZTIDiskPart

Yes, yes, I know… mea culpa…

MDT (and SCCM/OSD) make an assumption on the “Format and Partition Disk” step: The target disk number is fixed for each Task Sequence. Now, we can change the target disk dynamically within the Task Sequence by chaning the OSDDiskIndex variable. But it will require some coding.

Fix 1

One fix, if you are OK with some WMI queries, is to test for a “Surface Pro” model and a 1TB disk at index 2. I would prefer to test for the ABSENCE of a disk at index 0, but not sure how to do that.

Fix 2

The following is a modification of my ZTISelectBootDisk.wsf script. Designed specifically for this configuration. Just drop it into the scripts folder and add a step in the Task Sequence before the “Format and Partition disk step.

Testing

Now this script has NOT been tested on a 1TB Surface device. However I *AM* available for testing the 1TB surface device. I can forward my home mailing address, if you want to send me one :^).

 

Windows 1709 In Place Upgrade Bug

Thanks to Johan Arwidmark and Dan Vega for pointing me out to this bug. It took me a while to set up a scenario where it could reproduce, but it’s a good bug. Windows 10 In-Place Upgrade is an important new feature of Windows 10, and it’s good to have MDT support it.

The Bug

When upgrading to Windows 10 Version 1709 using the built-in MDT “Standard Client Upgrade Task Sequence”, you will get an error during OS upgrade within a MDT Wizard page that shows something like:

A VBScript Runtime Error has occurred:
Error: 500 = Variable is undefined

VBScript Code:
-------------------
IsThereAtLeastOneApplicationPresent

At this point, the OS *has* been upgraded, but the Task Sequence can no longer continue.

The Background

During OS upgrades, MDT needs a way to hook into the OS Installation process when done and continue installation tasks in the New OS.

Before In-Place upgrades, MDT would perform this by adding in a custom step into the unattend.xml file. Perhaps you have seen this segment of code before:

<FirstLogonCommands>
 <SynchronousCommand wcm:action="add">
  <CommandLine>wscript.exe %SystemDrive%\LTIBootstrap.vbs</CommandLine>
  <Description>Lite Touch new OS</Description>
  <Order>1</Order>
 </SynchronousCommand>
</FirstLogonCommands>

Windows would run the LTIBootStrap.vbs script, which would call the LiteTouch.wsf script, which would find the existing Task Sequence environment and kick of the remaining steps within the “State Restore” of the Task Sequence.

For the Windows 10 In-Place upgrade process, instead of processing the unattend.xml file, they have their own method of calling back into our LiteTouch environment using a SetupComplete.cmd file. This SetupComplete.cmd is responsible for finding our LiteTouch script and calling it.

The Analysis

It took me a while to setup a repro scenario (my test lab is configured for new-computer scenarios with the Windows 10 Eval bits, which can’t be used in an In-Place upgrade scenario). But I was able to reproduce the issue, and I got the bug, and was able to get the bdd.log file for analysis.

The challenge here is that during In-Place upgrade, I can’t open a Cmd.exe window for debugging using F8 or Shift-F10. Instead I hard coded a “start cmd.exe” line into the SetupComplete.cmd file.

What I observed is that the Window being displayed was the ZTIGather.wsf progress screen. LiteTouch.wsf will kick off the ZTIGather.wsf script early in the process, and will show a customized version of the LiteTouch wizard as a progress dialog. Well clearly the wizard isn’t working properly. But after closer analysis, ZTIGather.wsf shouldn’t be running AT ALL. For some reason, LiteTouch.wsf didn’t recall that it was in the MIDDLE of a task sequence, and that it should just directly go back to the TS in progress.

MDT has two methods for storing variables. When within the SMS Stand Alone Task Sequencing Engine, MDT LiteTouch scripts will read the SMS variables through the Microsoft.SMS.TSEnvironment COM object. But if ZTIUtility.vbs can’t open the variable store, it will store variables locally in the Variables.dat file.

Finally, after getting a powershell.exe window, creating the Microsoft.SMS.TSEnvironment, and making a couple of test calls to verify the contents of the variable store, a surprise. All variables returned empty *Successfully* (which is bad) but writes caused an Exception (which is correct). Since we were not running the SMS Stand Alone Task Sequencing Engine, all calls should have caused an exception.

Why is the Microsoft.SMS.TSEnvironment COM object registered, but not working? Well, that’s still under investigation, but now we can work on a fix/work around for MDT!!!

The Fix

The fix (Not written by me), is to force the Microsoft.SMS.TSEnvironment COM object to unregister before calling LiteTouch.wsf. This can be done by a simple call at the start of the SetupComplete.cmd script:

:: Workaround for incorrectly-registered TS environment
reg delete HKCR\Microsoft.SMS.TSEnvironment /f

The issue has been acknoleged by Microsoft, and this fix is currently targeted for the next release of MDT.

<Code Removed>

Thanks!

k

Create a Remote Desktop Conn. Mgr. file for Azure

Every now and then, I will spin up a test environment in azure with a couple of Virtual Machines. And as much as enjoy the User interface of the Portal, there have been times that I longed for the ease of use of the Remote Desktop Connection Manager.

One of the frustrations is that the *.rdp files downloaded from Azure run at full screen, which I find awkward, so the first thing I do is bring down the resolution, which is a pain, when I have several machines.

So I decided to create a tool to auto-generate a Remote Desktop Configuration Manager configuration file.

This also gave me the opportunity to play around with the way *.rdg stores passwords.

RDG security

First a word about security.

The Remote Desktop Connection Manager uses the “Data Protection API” to “Encrypt” passwords stored within the *.rdg file.

cred.PNG

The great thing about this API, is that if another user were to open this file on another machine, it can’t be read. Only the user running on the same machine can extract this password.

Note that any program or script running under your user’s context can read this password as plaintext, works great for this script, but my one design change to the “Remote Desktop Connection Manager” would be to add a “PIN” or other layer of security abstraction to prevent other “rouge” processes or users from gaining access to the passwords stored locally on my machine.

Azure

This script will log into your Azure Account, enumerate all the service groups, and get a list of all Virtual Machines within these groups, Creating entries within the “Remote Desktop Connection Manager” for each Azure Virtual Machine.

Script

-k

Make DisMount-DiskImage work

TL;DR – DisMount-DiskImage doesn’t work the same it did in Windows Server 2012 R2, here is how to make it work in Windows 10 and Server 2016.

Dirty Boy

OK, with the release of Windows 1709, I’ve been downloading all sorts of *.ISO images from MSDN to try out the latest features, kits, and support utilities. As I develop scripts to auto mount and extract the contents, sometimes I leave the ISO images mounted, so I’ll need to clear everything off before I begin a new test run.

I developed a new powershell script function to do all of this for me: Dismount-Everything. I had the VHDX part working, but somehow the DVD part wasn’t working well.

I specifically wanted to dismount ISO images, even though I might now recall the path where they came from, even though the drive letter should be easily visible.

Blogs

I went to a couple of blog sites to find out how to dismount ISO images, and got some hits.

https://rcmtech.wordpress.com/2012/12/07/powershell-mounting-and-dismounting-iso-images-on-windows-server-2012-and-windows-8/

https://superuser.com/questions/499264/how-can-i-mount-an-iso-via-powershell-programmatically

But on the superuser site, the author suggests that you should be able to take the output from get-volume and pipe it into Get-DiskImage, but that was not working for me.

Get-Volume [Drive Letter] | Get-DiskImage | Dismount-DiskImage

No matter what, Get-DiskImage didn’t like the volume Path.

Get-Volume would output:

\\?\Volume{1f8dfd40-b7ae-11e7-bf06-9c2a70836dd4}\

but Get-DiskImage would expect:

\\.\CDROM1

Well, Windows NT will create virtual shortcuts between long path names like \\?\volume and something more readable like \\.\CDROM1, so I assumed there was an association there.

Well after testing I found out that this command didn’t work:

get-diskimage -devicepath \\?\Volume{1f8dfd40-b7ae-11e7-bf06-9c2a70836dd4}\

But this command did:

get-diskimage -devicepath \\?\Volume{1f8dfd40-b7ae-11e7-bf06-9c2a70836dd4}

Turns out that I just needed to strip out the trailing \.

Easy!

Code

Get-Volume | 
  Where-Object DriveType -eq 'CD-ROM' |
  ForEach-Object {
    Get-DiskImage -DevicePath  $_.Path.trimend('\') -EA SilentlyContinue
  } |
  Dismount-DiskImage