Windows 10

Privilege Account Management Solution Evaluation

For as long as I’ve been in IT professionally, users have been local administrators on their machines.  Time and time again, history has proven this approach undermines what might otherwise be successful IT strategies to improve an organization’s security posture.  Introducing a change requires addressing some facts:

Fact: Users do not need admin rights to accomplish day to day tasks.
Fact: Users have grown accustomed to having certain privileges on their machines
Fact: Some legitimate changes initiated by users do require elevated rights
Fact: Bears eat beets.  Bears.  Beets.  Battlestar Galactica.

Fortunately there are a sea of Privilege Account Management or Privilege Management solutions out there to control elevation rights eliminating the need to give users administrative rights.

I do want to highlight that although our research was done a few years back, the underlying concepts and organizational requirements continue to serve as the core framework for any future Privilege Management solutions we evaluate for implementation.

Executive Summary

Adhering to the principle of least privilege allows the day to day user to continue to work efficiently without interruption while introducing several desirable benefits including but not limited to:

  • Cost Savings – Successful vulnerability exploits often result in lost time, intellectual property, productivity, brand value and customers’ trust. System instability results in lost productivity. Lack of license compliance can result in unbudgeted expenses not to mention costly fines.
  • Regulatory Compliance – When users have administrator rights they can change system settings, which affect compliance to regulatory standards. Failure to meet standards can result in more audits and remediation work.
  • System Stability – When a user adds a new piece of software, installs a driver, or changes a setting, the stability of the system is affected.
  • Threat Protection – Running software with reduced privileges can mitigate a majority of software vulnerabilities that take advantage of the privileges of the running user.
  • License Compliance – When users have full control over what is installed on their computers, there is nothing to prevent them from intentionally or unintentionally using unlicensed software.

Vendor Identification

We identified the following five vendors (listed alphabetically) based on many factors including feature set, product maturity, industry reputation, community feedback and perceived position in the marketplace.

Avecto

Avecto is a leader in Windows privilege management, helping organizations to deploy secure and compliant desktops and servers. With its Privilege Guard technology, organizations can empower all Windows based desktop and server users with the privileges they require to perform their roles, without compromising the integrity and security of their systems.

BeyondTrust

BeyondTrust offers a complete Privileged Account Management (PAM) portfolio and was one of the first products on the market in this area. BeyondTrust has a worldwide presence with a large market share in the US of which banking and securities and retail organizations make up a significant share of the company’s customers.

Bit9+CarbonBlack

Bit9+Carbon Black offers a solution for advanced threat protection for endpoints and servers. Combined, it helps organizations protect themselves from advanced threats in two critical ways: by reducing their attack surface through new signature-less forms of prevention, and rapidly detecting and responding to threats.

Centrify

Centrify Privilege Management allows administrators to manage privilege globally across windows, Linux and UNIX. It is a flexible, highly granular privilege management solution that allows users get work done, reduces risks and makes implementing a least-privilege approach easy with role-based access controls.

ViewFinity

Viewfinity’s privilege management suite bolsters administrators’ ability to control user privileges on corporate desktops, helping to eliminate one of the biggest security holes on today’s enterprise networks: risky activities on corporate desktops that occur inside the firewall. Viewfinity is a suite of integrated management tools that simplify the processes involved in privilege management, enabling administrators to more effectively protect PCs from unauthorized use and providing granular control over who can do what on servers and endpoints across the enterprise.

Success Criteria

We designed designed a scoring system based on key areas of interest:

  • Solution deigned with mobility in mind (up to 15 points)
  • Application control/features (up to 15 points)
  • Experience in the legal vertical (up to 10 points)
  • Reputation and footprint by way of endpoint count (up to 10 points)
  • Client components (up to 5 points)
  • Implementation options (up to 5 points)
  • Considerations for VDI environments (up to 10 points)
  • Depth and breadth of reporting (up to 10 points)
  • Ease of use & management (up to 10 points)
  • Integrations with existing technology (up to 5 points)
  • Innovation (up to 5 points)

In addition, there were specific features and scenarios we were looking to cover in the demos:

  • Details of the elevation process (e.g.: token based)
  • Handling of products not explicitly whitelisted/blacklisted
  • Capable of elevating ActiveX controls
  • Whether or not it was offered some sort of sandboxing technology
  • Data aggregation and correlation
  • Level of customization for user facing elements

Vendor Reduction

After reviewing each product and comparing notes we decided the following vendors were not best suited for our particular requirements.

BeyondTrust:

  • The SaaS/Web solution for a mobile workforce, it wasn’t as easy to use as Avecto and Viewfinity.
  • Insignificant presence in the legal vertical.

Bit9 + Carbon Black:

  • Lack of a method for elevating the execution of processes. Users would not be able to install applications, even those approved to be installed.
  • Core focus is application whitelisting (i.e.: whether or not a process can execute) versus allowing process that require elevation to elevate automatically based on a ruleset.

Centrify:

  • Application control functionally was not nearly as robust as their competitors.
  • Product is best suited for environments where Mac’s are deployed
  • PAM is only part of a much larger product versus the primary focus of the product.
  • Lack of an appreciable presence in the legal vertical.

I want to be clear:

  • These were not bad solutions by any means.
  • They just didn’t meet enough of our core requirements for us to move forward to the next phase.
  • Also, again, this being a fairly dated review, it’s quite possible things have changed since we originally evaluated them so do your due diligence.

Reference Checks

We received a list of references from both Avecto and ViewFinity, setup calls and included those findings for consideration in our recommendation.

Avecto

  • The “best of breed” and innovative solution compared to other products on the market.
  • Integration with existing A/V and HIPS solutions allowing for centralized management and reporting
  • Able to easily workaround special handling scenarios needed for certain users and applications.
  • Support has been great, fast turn around for critical issues and the product is well documented.
  • Successful implementations not just from the IT perspective but also from the user perspective as it was completely transparent.
  • Works as designed and is easy to work with.

ViewFinity

  • Smooth transition from another competitors on-prem solution to ViewFinity’s hosted solution.
  • SaaS solution works well, delivers updated configuration to clients faster than GPO
  • No issues they couldn’t work through or around.
  • Works well for a highly mobile workforce
  • Support is responsive with no gaps in communication
  • Easy and straightforward to use with little ongoing management required

Pilot Result

We tested each solution for one month at a time on our primary systems (aka our daily driver machine).  Although they were both different, there were a lot of similarities that carried over between each product.

ViewFinity

  • Only vendor with a completely separate SaaS/Web PAM solution and we were impressed with it.  Viewfinity seems to better understand the differences of a mobile user and their Saas/Web product is solely built for a mobile population.
  • Established presence in law firms of significant size
  • Has grown substantially in install count and product maturity over the past few years.

Avecto

  • Has a mechanism to distribute updates, but it’s built on a traditional group policy based management delivery approach.
  • Appears to be the strongest and fastest innovator the PAM vertical.
  • Had features in product that Viewfinity didn’t have yet.

These findings were then added to our success criteria.

Final Score

Before I reveal the results, I want to point out a few very important items:

  1. This review took place a few years ago so I imagine that each of the products mentioned here have matured for the better since then and that there may be new players in this space.
  2. Both solutions are very solid products, each with their own set of features that clearly distinguished it from the other in a few key categories.
  3. We ultimately did not move forward with either product because of a change in strategic initiatives.

Having said that we said we gave:

  • Avecto: 79 out of 100
  • ViewFinity: 81 out of 100

From a scoring perspective, the difference was almost negligible and after some discussion we made a recommendation to move forward with one vendor.  However, it was not solely based on the numerical score but on, what I feel is, an oft overlooked point:  The level of expertise of the vendor’s technical lead assisting with the implementation.  Their technical lead driving these demos and Q&A’s demonstrated a deep level of understanding and was able to think and respond quickly when in ‘uncharted territory’; atypical use cases, examples etc.  After putting each vendor through the ringer, one gave us the confidence that they would be able to assist us in meeting the our objective to make this a successful implementation.

Closing Thoughts

This was probably one of the more fun projects we took on and some part of me was disappointed we didn’t move forward with any of the recommended products.  But on the other hand, after removing local Administrator rights and implementing Microsoft’s Local Administrator Password Solution (LAPS) we learned that we really didn’t need a solution to achieve our primary objective.

I’m eager to hear from others who are in the process of implementing – or have just implemented – a PM/PAM solution, so please let me know in the comments.

 

Good Providence!

Advertisements
The ol' 'Quick & Dirty' method - Image provided by Max Pixel

MDT Performance Boost Part 2

I need all the help I can get in terms of speeding up the build & capture process so in addition to the steps mentioned in my previous post, I use this “one weird trick” (smh) to help speed up the actual WIM capturing or generation process.

Speedup Process Overview

  • Copy the base install.wim of your B&C OS to your capture location
  • Rename the .WIM to something meaningful like 1809_install.wim
  • Use that same name for the WIM file name for the capture
  • During B&C your image will be added to the existing WIM
  • Split the captured image into it’s own .WIM
  • Delete the index

Baseline Testing (Optional)

This isn’t required but it’s the only way to validate that the speedup procedure actually works.   In order to do that, you’re just going to start by performing a regular Build & Capture using the normal process to see how long the actual .WIM capture process takes.  This will be our baseline number.  In my test lab, after running several B&C’s I’m finding the capture process takes anywhere from 35 to 40 minutes in my lab.

MDTSpeedup2-001

Apply the Speedup Procedure

To keep things simple, let’s say we’re working on capturing an 1809 image.

Copy the stock 1809 install.wim to your Captures directory and rename it to something meaningful like 1809_install.wim.

Check the details of the WIM you just copied:

dism /get-wininfo /image:"\\MDTServer\DeploymentShare$\Captures\1809_install.wim"

Deployment Image Servicing and Management tool
Version: 10.0.14393.0

Details for image : \\MDTServer\DeploymentShare$\Captures\1809_install.wim

Index : 1
Name : Windows 10 Education
Description : Windows 10 Education
Size : 14,356,142,049 bytes

Index : 2
Name : Windows 10 Education N
Description : Windows 10 Education N
Size : 13,548,111,095 bytes

Index : 3
Name : Windows 10 Enterprise
Description : Windows 10 Enterprise
Size : 14,356,212,795 bytes

Index : 4
Name : Windows 10 Enterprise N
Description : Windows 10 Enterprise N
Size : 13,548,004,622 bytes

Index : 5
Name : Windows 10 Pro
Description : Windows 10 Pro
Size : 14,356,028,734 bytes

Index : 6
Name : Windows 10 Pro N
Description : Windows 10 Pro N
Size : 13,547,960,587 bytes

Index : 7
Name : Windows 10 Pro Education
Description : Windows 10 Pro Education
Size : 14,356,071,811 bytes

Index : 8
Name : Windows 10 Pro Education N
Description : Windows 10 Pro Education N
Size : 13,548,039,957 bytes

Index : 9
Name : Windows 10 Pro for Workstations
Description : Windows 10 Pro for Workstations
Size : 14,356,106,696 bytes

Index : 10
Name : Windows 10 Pro N for Workstations
Description : Windows 10 Pro N for Workstations
Size : 13,548,075,292 bytes

Index : 11
Name : Windows 10 Enterprise for Virtual Desktops
Description : Windows 10 Enterprise for Virtual Desktops
Size : 14,356,177,402 bytes

The operation completed successfully.

Now perform a B&C to get the updated timing details. In my lab, I’m seeing it take about 9 minutes*.

MDTSpeedup2-002

Once the .WIM is created, verify the new index was created:


dism /get-wininfo /image:"\\MDTServer\DeploymentShare$\Captures\1809_install.wim"

Deployment Image Servicing and Management tool
Version: 10.0.14393.0

Details for image : \\MDTServer\DeploymentShare$\Captures\1809_install.wim

Index : 1
Name : Windows 10 Education
Description : Windows 10 Education
Size : 14,356,142,049 bytes

Index : 2
Name : Windows 10 Education N
Description : Windows 10 Education N
Size : 13,548,111,095 bytes

Index : 3
Name : Windows 10 Enterprise
Description : Windows 10 Enterprise
Size : 14,356,212,795 bytes

Index : 4
Name : Windows 10 Enterprise N
Description : Windows 10 Enterprise N
Size : 13,548,004,622 bytes

Index : 5
Name : Windows 10 Pro
Description : Windows 10 Pro
Size : 14,356,028,734 bytes

Index : 6
Name : Windows 10 Pro N
Description : Windows 10 Pro N
Size : 13,547,960,587 bytes

Index : 7
Name : Windows 10 Pro Education
Description : Windows 10 Pro Education
Size : 14,356,071,811 bytes

Index : 8
Name : Windows 10 Pro Education N
Description : Windows 10 Pro Education N
Size : 13,548,039,957 bytes

Index : 9
Name : Windows 10 Pro for Workstations
Description : Windows 10 Pro for Workstations
Size : 14,356,106,696 bytes

Index : 10
Name : Windows 10 Pro N for Workstations
Description : Windows 10 Pro N for Workstations
Size : 13,548,075,292 bytes

Index : 11
Name : Windows 10 Enterprise for Virtual Desktops
Description : Windows 10 Enterprise for Virtual Desktops
Size : 14,356,177,402 bytes

Index : 12
Name : W10_1809_Entx64
Description : 
Size : 24,935,992,683 bytes

The operation completed successfully.

Success!

 

*So, What’s the Catch?

Alright – so maybe I cut a corner or two.

I’ll admit, it might not be helpful to have one giant .WIM with 12+ indexes, so you’d probably want to export that newly created index to it’s own .WIM:

dism /export-image /sourceimagefile:\\MDTServer\DeploymentShare$\Captures\1803_install.wim /sourceindex:12 /destinationimagefile:\\MDTServer\DeploymentShare$\Captures\1803_bnc.wim

I find this process takes about 90 seconds putting us at about 10m30s.

And if you’re doing that you might also want to delete the new index you created in the original install.wim:

dism /delete-image /imagefile:\\MDTServer\DeploymentShare$\Captures\1803_install.wim /index:12

This process takes about 2 seconds putting us at about 10m32s.

On the surface, capturing or generating a WIM in 8-10 minutes sounds like some appreciable gains but this is where the corner cutting begins.

Like a fine wine, I find this process gets [somewhat] better with age:

  • Without any funny business my first capture typically takes anywhere from 35 to 40 minutes.
  • When I use this technique I might shave 5-10 minutes off my first capture depending on what’s in there.  It’s something but not significant.
  • However, when I do my second (third, fourth etc.) capture with this technique – like when I’m doing another B&C to include this/last month’s patches and/or updated software etc. – that’s when I begin to appreciate the speed difference and now the actual WIM capture/generation process takes ~8 to ~11 minutes.

After the first big capture – thick image with everything in it – that usually becomes it’s own .WIM and the differential .WIMs are appended to it.  From here we can either export those differential indexes into their own .WIMs or we leave them in the ‘master’ .WIM which allows for easy regression to a previous ‘version’ by just using a lower number index in the Task Sequence.

In Conclusion

I don’t think this is ground breaking and there are some caveats – specifically being that you have go through one capture before you can truly realize the benefits – but like I said, I need all the help I can get so every little bit counts!

So hopefully this “one weird trick” helps you 🙂

Good Providence!

An authentication error has occurred. The function requested is not supported. This could be due to CredSSP encryption oracle remediation. CVE-2018-0886

Problem:

I’ve been working furiously on some Citrix XenApp stuff recently on shiny new Server 2016 boxes.  Yesterday was a productive day and all was well.  With it also being Patch Tuesday and my machines part of the Patient Zero Device Collection targeted for updates I received May’s patches last night/this morning.

Today, when I attempted to RDP into Server 2016 boxes I received the following error:

CredSSPOracle

[Window Title]
Remote Desktop Connection

[Content]
An authentication error has occurred.
The function requested is not supported

Remote computer: <remote computer>
This could be due to CredSSP encryption oracle remediation.
For more information, see https://go.microsoft.com/fwlink/?linkid=866660

[OK]

Cause:

This is intentional and I urge you to direct your attention to the URL in the message: https://go.microsoft.com/fwlink/?linkid=866660

Cliff’s Notes version of the cause from the article:

  • The initial March 13, 2018, release updated the CredSSP authentication protocol but did NOT enforce the new version of the CredSSP protocol.
  • The April 17, 2018, Remote Desktop Client (RDP) update in KB 4093120 enhances the error message that is presented when an updated client fails to connect to a server that has not been updated.
  • The May 8, 2018, update makes the new updates CredSSP protocol mandatory.
    This intentional change adjusts the default setting from ‘Vulnerable’ to ‘Mitigated’.

Solution:

In reviewing the interoperability matrix there are only a few blocked scenarios:

  1. Server Patched ‘Force updated clients’ + Clients Unpatched = Blocked
  2. Server Unpatched + Clients Patched ‘Force updated clients’ = Blocked
  3. Server Unpatched + Clients Patched ‘Mitigated’ = Blocked

Well I know my client is patched so that rules out Scenario 1, making it clear our Server 2016 servers are missing KB 4103723.

Solution: Patch your servers!

Fauxlution

This is not a solution.  It’s a fake solution or as I like to call them faux-lutions.

So is there a workaround?  Sure.  So in my particular scenario, I would set the patched client(s) to ‘Vulnerable’  which means that I would then be exposing remote servers to attacks by supporting fallback to insecure versions.

Arguments can be made either way to justify this but I don’t think its wise:

  • It negatively affects our security posture
  • I’m human thus prone to forgetting things and then I’ll never undo it.

I’d rather submit an emergency change request to patch the servers.

In fact, Microsoft’s recommendation is to set AllowEncryptionOracle on clients and server computers as soon as possible to one of the following:

  • Force updated clients = 0
  • Mitigated = 1

But if you want to go down this slippery slope at your own risk, set on your patched client(s), set AllowEncryptionOracle to 2 and you’ll be able to connect to your unpatched server(s):


reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters" /v AllowEncryptionOracle /d 2 /t reg_dword

The documentation states a reboot is required but in testing, a reboot is not required.

References:

  1. CVE-2018-0886 | CredSSP Remote Code Execution Vulnerability
  2. Windows 10 1803 May 8, 2018—KB4103721 (OS Build 17134.48)
  3. Windows 10 1709 May 8, 2018—KB4103727 (OS Build 16299.431)
  4. Windows 10 1703 May 8, 2018—KB4103731 (OS Build 15063.1088)
  5. Windows 10 1607 & Server 2016 May 8, 2018—KB4103723 (OS Build 14393.2248)

 

Whatever route you take, I bid you Good Providence!

Deployment Error Invalid DeploymentType value "" specified.  The deployment will not proceed.

MDT Tutorial Part 11: Troubleshooting Part 5: Invalid DeploymentType value “” specified. The deployment will not proceed.

Living Table of Contents

 

What These Guides Are:
A guide to help give you some insight into the troubleshooting process in general.

What These Guides Are Not:
A guide to fix all issues you’re going to encounter.

We’re going to role-play a bunch of scenarios and try to work through them.  Remember in math where you had to show your work?  Well, what follows is like that which is why this post is [more than] a [little] lengthy.

Invalid DeploymentType value “” specified. The deployment will not proceed.

You enabled the Windows Updates steps in the Build & Capture Task Sequence so you can have a fully patched Windows 10 v1511 WIM.

Troubleshoot-014.PNG

And you also updated your CustomSettings.ini so that your Build & Capture VM would set all the properties/variables but not start immediately.


[Settings]
Priority=MACAddress,GetAbbrModel,Build,Default
Properties=OfficeCode,AbbrModel

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; BEGIN MACADDRESS SECTION
; This is my Windows 10 v1511 build & capture VM
[00:15:5D:13:79:01]
SkipTaskSequence=NO
TaskSequenceID=BC151164ENT
SkipComputerName=NO
OSDComputerName=BnC-#UCase(Right(Replace(Replace("0000000%SERIALNUMBER%"," ","",1,-1,1),"-","",1,-1,1),8))#
SkipDomainMembership=NO
JoinWorkgroup=BnC-WrkGrp
SkipUserData=NO
SkipComputerBackup=NO
ComputerBackupLocation=NETWORK
BackupDir=Captures\%OSDComputerName%
BackupFile=%OSDComputerName%_%TaskSequenceID%_#year(date) & "-" & month(date) & "-" & day(date) & "_" & Hour(Now()) & Minute(Now())#.wim
SkipProductKey=NO
SkipLocaleSelection=NO
SkipTimeZone=NO
SkipAdminPassword=NO
SkipCapture=NO
DoCapture=YES
SkipBitLocker=NO
SkipSummary=NO

; END MACADDRESS SECTION
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; BEGIN GETABBRMODEL SECTION
; Lets get the abbreviated model
[GetAbbrModel]
UserExit=jgp_GetAbbrModel.vbs
AbbrModel=#GetAbbrModel#
; END GETABBRMODEL SECTION
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; BEGIN BUILD SECTION
; Set things here for use below
[Build]
OSDComputerName=%OfficeCode%-%AbbrModel%-#UCase(Right(Replace(Replace("0000000%SERIALNUMBER%"," ","",1,-1,1),"-","",1,-1,1),8))#
; END GETABBRMODEL SECTION
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; BEGIN DEFAULT SECTION
[Default]
OSInstall=Y
; Skip Screen: Task Sequence
SkipTaskSequence=NO
; Skip Screen: Computer Details
SkipComputerName=NO
; Skip Screen: Computer Details
SkipDomainMembership=NO
; Skip Screen: Move Data and Settings & User Data (Restore)
SkipUserData=NO
; Skip Screen: Computer Backup
SkipComputerBackup=NO
; Skip Screen: Product Key
SkipProductKey=NO
; Skip Screen: Locale & Time
SkipLocaleSelection=NO
KeyboardLocale=en-US
UserLocale=en-US
UILanguage=en-US
; Skip Screen: Locale & Time
SkipTimeZone=NO
; https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx
TimeZoneName=Eastern Standard Time
; Skip Screen: Administrator Password
SkipAdminPassword=NO
; Skip Screen: Capture Image
SkipCapture=NO
; Skip Screen: BitLocker
SkipBitLocker=NO
; Skip Screen: Ready to begin
SkipSummary=NO
; Skip Screen: R
SkipFinalSummary=NO
SLShare=%DeployRoot%\TSLogs
SLShareDynamicLogging=%DeployRoot%\TSLogs\%OSDComputerName%
EventService=http://ITF1MDT01:9800
; END DEFAULTSECTION
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Having learned your lesson from last time, you test the updated CustomSettings.ini & spent a few minutes verifying the output in the console.  Feeling confident, you boot into WinPE and when the Wizard I displays, verify all the defaults are set correctly.

This slideshow requires JavaScript.

You click begin and almost immediately the process halts with an obscure error:

Deployment Error Invalid DeploymentType value

Deployment Error Invalid DeploymentType value “” specified.  The deployment will not proceed.

You’d be forgiven for thinking you’ve made a mistake and I’d be willing to bet you’d figure this out but that road wouldn’t be fun.

Fortunately Michael Niehaus himself confirmed this is a bug (SRC1, SRC2) and there are two options to fixing/working around the bug:

  1. Easiest: Update your CS.INI with SkipProductKey=YES.
  2. Hardest (and arguably unsupported?):
    1. Open DeployWiz_ProductKeyVista.vbs in the Scripts directory
    2. Find: ​if oProperties("DeploymentType") = "UPGRADE" then
    3. Replace: If Property("DeploymentType") = "UPGRADE" then
    4. Save the file and try again
Note: There appears to be a plausible explanation of what’s happening here if you’re interested.

Since you rarely need to prompt for a Product Key – especially considering you can stick it in the unattend.xml or you go down the easy path and now the image kicks off.

Troubleshoot-028.PNG

Copypasta Closing

Hopefully these examples will help give you an idea of the overall troubleshooting process.  Most of the time the problems you’ll encounter will be caused by a typso, order of operations or a ‘known issue’ that requires a specific process to be followed.

As you make changes to your environment, here’s what I recommend:

  • Be diligent about keeping a change log so you can easily backtrack
  • Backup your CS.INI or Bootstrap.ini before you make any changes
  • Backup your ts.xml or unattend.xml (in DeploymentShare\Control\TaskSequenceID) before you make any changes
  • Introduce small changes at time with set checkpoints in between and set milestones markers where you backup core files (e.g cs.ini bootstrap.ini ts.xml unattend.xml etc) to help minimize frustration troubleshooting.

And if when you do run into some turbulence, upload relevant logs (at least smsts.log but be prepared to submit others depending on the issue) to a file sharing service like OneDrive, post on TechNet then give a shout to your resources on Twitter.

Good Providence to you!

MDT Tutorial Part 11: Troubleshooting Part 4: Task Sequence Variable is Being Overwritten

Living Table of Contents

 

What These Guides Are:
A guide to help give you some insight into the troubleshooting process in general.

What These Guides Are Not:
A guide to fix all issues you’re going to encounter.

We’re going to role-play a bunch of scenarios and try to work through them.  Remember in math where you had to show your work?  Well, what follows is like that which is why this post is [more than] a [little] lengthy.

Task Sequence Variable is Being Overwritten – The Case of the Incorrectly Named Log Folder

After [finally] fixing your computer naming issue, you decide to take a look at the live BDD.log just to keep an eye on things.  You hop into the TSLogs directory & find 2 directories that have the same time stamp:

Troubleshoot-008

According to your CS.INI the “real” log directory should be named after the machine so how did that other one get created?  You open the BDD.log in BLD-HPV-22404895 and it’s practically empty, but you do see that the property is being set to the other directory.

Troubleshoot-009.PNG

There are some clues in the BDD that lead you to above that point to a smoking gun.

You open the BDD.log in the other directory & scroll to the top & see a familiar set of lines: The same ones you see when testing the CustomSettings.ini manually:

Troubleshoot-011

While the machine is imaging you press F8 to launch a console, fire up CMTrace, open the smsts.log (in %temp%\smstslog), scroll to the top & search downwards for ‘dyn’:

Troubleshoot-012.PNG

Ok, you’re piecing it together:

  1. Initially it’s good, points to the proper location
  2. Then at some point it changes
  3. In the first, short, BDD.log you see ‘Task Sequence’ mentioned
  4. In the second, long, BDD.log you see lines that look like it’s processing the CustomSettings.ini, something that also happens during the Task Sequence,
  5. The smsts.log shows a step that sets a variable
  6. SLShareDynamicLogging isn’t a property (or variable) that is ‘last write wins’, so it can’t be a case of a rogue CustomSettings.ini

So maybe it’s the Task Sequence?

Troubleshoot-013

Bingo was his name.

 

Copypasta Closing

Hopefully these examples will help give you an idea of the overall troubleshooting process.  Most of the time the problems you’ll encounter will be caused by a typso, order of operations or a ‘known issue’ that requires a specific process to be followed.

As you make changes to your environment, here’s what I recommend:

  • Be diligent about keeping a change log so you can easily backtrack
  • Backup your CS.INI or Bootstrap.ini before you make any changes
  • Backup your ts.xml or unattend.xml (in DeploymentShare\Control\TaskSequenceID) before you make any changes
  • Introduce small changes at time with set checkpoints in between and set milestones markers where you backup core files (e.g cs.ini bootstrap.ini ts.xml unattend.xml etc) to help minimize frustration troubleshooting.

And if when you do run into some turbulence, upload relevant logs (at least smsts.log but be prepared to submit others depending on the issue) to a file sharing service like OneDrive, post on TechNet then give a shout to your resources on Twitter.

Good Providence to you!

Troubleshooting the Lenovo ThinInstaller Installation

During OSD, install the Lenovo ThinInstaller, and have been doing this for quite some time.  Whenever a new build is released, we duplicate the source files and swapping out the older installer for the new.  This process worked well for several versions:

  • v1.2.0014
  • v1.2.0015
  • v1.2.0017
  • v1.2.0018

In early 2017 we updated our Lenovo ThinInstaller to v1.2.0020 and noticed that the ThinInstaller installation executable would run seemingly forever, but during OSD and in real Windows when installing manually.  We reverted back to 1.2.0018 until we could do more testing to narrow the scope of the problem.  Shortly afterwards, 1.2.0022 was released so we tried again thinking maybe it was a build-specific bug, but it too failed.

We spent a decent amount of time trying to hunt this down and confirmed it wasn’t:

  • unique to the Task Sequence
  • a model specific issue
  • an upgrade scenario (e.g.: only 1.2.0014 to 1.2.0022)
  • software that was already installed and causing a conflict
  • security software on the machine.

Again, we could reproduce at will by removing the new installer and restoring the old.

A while later we learned that Lenovo had made some changes to the ThinInstaller package, and you can read about that here:
https://thinkdeploy.blogspot.com/2017/03/changes-required-to-use-thin-installer.html

To ensure the highest rate of installation success, we took the shotgun approach:


# Unregister the DLL if it's found - update the path accordingly
if(Test-Path -Path "$envProgramFilesX86\ThinInstaller\Lenovo.PnPSignedDriverEx.dll" -PathType Leaf)
    {
        If(Test-Path -Path "$env:windir\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe" -PathType Leaf)
            {
                Start-Process -FilePath "$env:windir\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe" -ArgumentList "/u `"$envProgramFilesX86\ThinInstaller\Lenovo.PnPSignedDriverEx.dll`"" -PassThru -Wait
            }
        elseif(Test-Path -Path "$env:windir\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe" -PathType Leaf)
            {
                Start-Process -FilePath "$env:windir\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe" -ArgumentList "/u `"$envProgramFilesX86\ThinInstaller\Lenovo.PnPSignedDriverEx.dll`"" -PassThru -Wait
            }
    }

# Remove the existing 'installation'
Rename-Item -Path "${env:ProgramFiles(x86)}\ThinInstaller" -NewName "ThinInstaller_$(Get-Date -Format 'yyyy-MM-dd_hhmmss')"; Start-Sleep -Seconds 3

# Perform the 'install'
Start-Process -FilePath 'thin_installer_VERSION.exe' -ArgumentList "/SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /LOG=Path\To\Install.log" -Wait

# Drop in the ThinInstaller.exe.configuration
Copy-Item -Path $(Join-Path $PSScriptRoot 'ThinInstaller.exe.configuration') -Destination "${env:ProgramFiles(x86)}\ThinInstaller\ThinInstaller.exe.configuration" -Force&lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&gt;&amp;#65279;&lt;/span&gt;

 

Some time around ThinInstaller v1.2.0029, the Lenovo.PnPSignedDriverEx.dll as well as the .cmd files used to register/unregister said DLL, quietly disappeared suggesting they either found a better way to do what they were doing or baked that process into their installer or … ?  That said, the above code is probably no longer needed.  However, since ThinInstaller is an application that’s generally available to all Lenovo machines in Software Center, we left the code in there on the off chance someone upgrades or uninstalls/reinstalls ThinInstaller on a machine with an older build.

If you find the ThinInstaller is hanging during upgrade scenarios, try the above to see if that helps.

If you find the ThinInstaller is hanging during a fresh installation, try generating a log and review the log file to see where it’s getting hung up then troubleshoot from there.

Good Providence To You!

Title: Windows Setup Body: Windows could not parse or process unattend answer file [C:windowsPantherunattend.xml] for pass [specialize]. The answer file is invalid.

MDT Tutorial Part 11: Troubleshooting Part 3: Windows could not parse or process unattend answer file [C:\windows\Panther\unattend.xml] for pass [specialize].  The answer file is invalid.

Living Table of Contents

 

What These Guides Are:
A guide to help give you some insight into the troubleshooting process in general.

What These Guides Are Not:
A guide to fix all issues you’re going to encounter.

We’re going to role-play a bunch of scenarios and try to work through them.  Remember in math where you had to show your work?  Well, what follows is like that which is why this post is [more than] a [little] lengthy.

Windows could not parse or process unattend answer file [C:\windows\Panther\unattend.xml] for pass [specialize].  The answer file is invalid.

Your last victory is short lived as the same error message appears and this time unattend.xml looks fine:

Troubleshoot-010.PNG

Stumped, you might search for ‘Microsoft-Windows-Shell-Setup’ which might lead you here:
https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup

As you review each section carefully the issue becomes clear: The computer name is more than 15 characters.

Copypasta Closing

Hopefully these examples will help give you an idea of the overall troubleshooting process.  Most of the time the problems you’ll encounter will be caused by a typso, order of operations or a ‘known issue’ that requires a specific process to be followed.

As you make changes to your environment, here’s what I recommend:

  • Be diligent about keeping a change log so you can easily backtrack
  • Backup your CS.INI or Bootstrap.ini before you make any changes
  • Backup your ts.xml or unattend.xml (in DeploymentShare\Control\TaskSequenceID) before you make any changes
  • Introduce small changes at time with set checkpoints in between and set milestones markers where you backup core files (e.g cs.ini bootstrap.ini ts.xml unattend.xml etc) to help minimize frustration troubleshooting.

And if when you do run into some turbulence, upload relevant logs (at least smsts.log but be prepared to submit others depending on the issue) to a file sharing service like OneDrive, post on TechNet then give a shout to your resources on Twitter.

Good Providence to you!

Title: Windows Setup Body: Windows could not parse or process unattend answer file [C:windowsPantherunattend.xml] for pass [specialize]. The answer file is invalid.

MDT Tutorial Part 11: Troubleshooting Part 2: Windows could not parse or process unattend answer file [C:\windows\Panther\unattend.xml] for pass [specialize].  The answer file is invalid.

Living Table of Contents

 

What These Guides Are:
A guide to help give you some insight into the troubleshooting process in general.

What These Guides Are Not:
A guide to fix all issues you’re going to encounter.

We’re going to role-play a bunch of scenarios and try to work through them.  Remember in math where you had to show your work?  Well, what follows is like that which is why this post is [more than] a [little] lengthy.

Windows could not parse or process unattend answer file [C:\windows\Panther\unattend.xml] for pass [specialize].  The answer file is invalid.

You boot your special VM, click the ‘Run the Deployment Wizard to install a new Operating System‘ button and it immediately starts.  Excellent!  It applies the OS, reboots and you’re faced with this error:

Title: Windows Setup Body: Windows could not parse or process unattend answer file [C:\windows\Panther\unattend.xml] for pass [specialize].  The answer file is invalid.

Windows could not parse or process unattend answer file [C:\windows\Panther\unattend.xml] for pass [specialize]. The answer file is invalid.

Well this is strange, because you didn’t touch the unattend.xml so what gives?
Fortunately, this dialog provides some meaningful insight:

    • The unattend file is C:\Windows\Panther\unattend.xml
    • The specific area is the specialize pass

Press SHIFT+F10 here to open a command prompt and then open C:\Windows\Panther\unattend.xml with notepad

Troubleshoot-005

You search for ‘specialize’ and after taking a very close look see that your computer name is incorrect.  It should be some two or three character prefix not %OfficeCode%.

Troubleshoot-006

Since that is set via the CS.INI, you run the CustomSettings.ini test again and now you see what was missed before:

Troubleshoot-007.PNG

You review the CS.INI and find your problems

  1. You didn’t define the OfficeCode property: Wasn’t added to the Properties line
  2. You didn’t set a value for OfficeCode.

With that fixed, you run the test again, the variable is populated and as you reimage the machine, you see it is named correctly in the logs.

Copypasta Closing

Hopefully these examples will help give you an idea of the overall troubleshooting process.  Most of the time the problems you’ll encounter will be caused by a typso, order of operations or a ‘known issue’ that requires a specific process to be followed.

As you make changes to your environment, here’s what I recommend:

  • Be diligent about keeping a change log so you can easily backtrack
  • Backup your CS.INI or Bootstrap.ini before you make any changes
  • Backup your ts.xml or unattend.xml (in DeploymentShare\Control\TaskSequenceID) before you make any changes
  • Introduce small changes at time with set checkpoints in between and set milestones markers where you backup core files (e.g cs.ini bootstrap.ini ts.xml unattend.xml etc) to help minimize frustration troubleshooting.

And if when you do run into some turbulence, upload relevant logs (at least smsts.log but be prepared to submit others depending on the issue) to a file sharing service like OneDrive, post on TechNet then give a shout to your resources on Twitter.

Good Providence to you!

MDT Tutorial Part 10: CustomSettings.ini Validation Testing & Troubleshooting Part 1

Living Table of Contents

 

Today’s Agenda: Troubleshooting

  • CustomSettings.ini Validation Testing
  • Troubleshooting OSD Issues

Recommended Reading

CustomSettings.ini Validation Testing

If you haven’t already done so, go ahead and make some useful edits to your CustomSettings.ini.  Since my aim is to have a dedicated ‘build’ machine that boots and automatically images the proper Task Sequence, this is what my CS.INI looks like now:


[Settings]
Priority=MACAddress,GetAbbrModel,Build,Default
Properties=AbbrModel

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; BEGIN MACADDRESS SECTION
; This is my Windows 10 v1511 build VM
[00:15:5D:13:79:01]
SkipTaskSequence=YES
TaskSequenceID=B151164ENT
SkipComputerName=YES
SkipDomainMembership=YES
JoinWorkgroup=BLD-WrkGrp
SkipUserData=YES
SkipComputerBackup=YES
SkipProductKey=YES
SkipLocaleSelection=YES
SkipTimeZone=YES
SkipAdminPassword=YES
SkipCapture=YES
SkipBitLocker=YES
SkipSummary=YES
; END MACADDRESS SECTION
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; BEGIN GETABBRMODEL SECTION
; Lets get the abbreviated model
[GetAbbrModel]
UserExit=jgp_GetAbbrModel.vbs
AbbrModel=#GetAbbrModel#
; END GETABBRMODEL SECTION
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; BEGIN BUILD SECTION
; Set things here for use below
[Build]
OSDComputerName=%OfficeCode%-%AbbrModel%-#UCase(Right(Replace(Replace("0000000%SERIALNUMBER%"," ","",1,-1,1),"-","",1,-1,1),8))#
; END GETABBRMODEL SECTION
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
; BEGIN DEFAULT SECTION
[Default]
OSInstall=Y
SkipTaskSequence=NO
SkipComputerName=NO
SkipDomainMembership=NO
SkipUserData=NO
SkipComputerBackup=NO
SkipProductKey=NO
SkipLocaleSelection=NO
SkipTimeZone=NO
SkipAdminPassword=NO
SkipCapture=NO
SkipBitLocker=NO
KeyboardLocale=en-US
UserLocale=en-US
UILanguage=en-US
; https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx
TimeZoneName=Eastern Standard Time
SLShare=%DeployRoot%\TSLogs
SLShareDynamicLogging=%DeployRoot%\TSLogs\%OSDComputerName%
; END DEFAULTSECTION
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Following the methods outlined in the recommended reading section, set up an area for testing your CustomSettings.ini.  When I execute my test, it runs, I see a bunch of data:

There are no obvious errors, I see see some custom properties and various built-in properties getting set so it looks good.  Time to execute for real!

Troubleshooting – Part 1

Troubleshooting MDT (and SCCM) is something of an art and this is not a once-size-fits-all silver bullet post.

I ran across this post SCCM 2012 – How to catch errors in Task Sequence around the same time I started using MDT and found it greatly helped me to hone in on OSD issues.  Because it has worked well for me, I’m recommending it – and others like it – to you.

Task Sequence Setup

Take a look at the links at the top to see how others are setting up their Task Sequences and adjust to suit your needs but here’s a basic example:

Troubleshoot-041.PNG

Right now when your Task Sequence fails you see this dialog:

Troubleshoot-042.PNG

This dialog is incredibly helpful without making any adjustments and you should ge able to get an idea as to what went wrong without having to go super deep into the logs.  But once you get into a production scenario, you’ll likely suppress this dialog and I find that having the Try/Catch steps in the Task Sequence makes it easier from a log reviewing perspective, especially after the Task Sequence gets busy.

Crack open the smsts.log and immediately you see red:

Troubleshoot-043.PNG

With the Try/Catch model you can easily hone in on the offending step:

  1. Scroll to the bottom of the log
  2. Search for key text in the log
    • Option 1: Search for: Try) ignored
    • Option 2: Search for: Catch) has been

Either one will get you just a few short lines away from the failure, so scroll up a bit and it should become apparent.

Troubleshoot-044.PNG

  • The blue line above is the ‘Catch) has been‘ match.
  • The first red line above that is the ‘Try) ignored‘ line
  • Just above that we see the second red line which is the actual failure:
    Failed to run the action: This will break it.
  • Above that are the details for that specific step.

This is obviously a very simple example, but the process is the same for all errors:

  • Review the smsts.log
  • Find the actual error
  • Evaluate if it’s a problem specific to that step OR if it was caused by an environmental issue such as dependencies.
  • Review other logs as necessary based on what you’re seeing in the smsts (e.g.: domain join failure)

In Closing

I don’t expect you to be an expert at this point, but I hope it and the links in the recommended reading section have helped to get you a little more comfortable with searching the smsts.log for errors.

When doing BnC’s I like to keep my changes small and modular:

  • Test that the basic BnC works fine: OS is installed, sysprep & capture is succesful
  • Add Windows Updates into the mix & repeat the test
  • Prepare your application payload:
    • for some complex applications you’ll rely on scripts so test them outside of the Task Sequence to confirm they are syntactically correct
    • for simple installations make sure you have the correct command line arguments
    • once installed validate the installation & configuration
  • Introduce applications a few at a time doing BnC’s to ensure nothing is broken.
  • Set milestones for yourself so you don’t have to go back to square one
  • Backup files (ts.xml, unattend.xml, scripts etc) before you make any changes.

Good Providence to you!

MDT Tutorial Part 8: Unattend.xml

Living Table of Contents

 

Today’s Agenda:

  • View Unattend.xml
  • Generate Catalog
  • Edit Unattend.xml

Recommended Reading

View Unattend.xml

The unattend.xml lives in subdirectory named after your Task Sequence ID that sits in the Control directory of your Deployment Share.  For example, if your Task Sequence ID is BC151164ENT then you can find the unattend.xml in either:

  • C:\DeploymentShare\Control\BC151164ENT
  • \\MDTServer\DeploymentShare$\Control\BC151164ENT

You can edit it using your favorite text editor, but I recommend using the Windows System Image Manager (SIM).

  1. Edit your Task Sequence
  2. Go to the OS Info tab
  3. Click the Edit Unattend.xml button
  4. Go make a pizza

Generate Catalog

Doing the above will require you to generate a catalog file for the WIM you imported.  Fortunately this process happens automatically.

Unattend-003

Unfortunately this process can take a while depending on your configuration.

Once the generation is complete, you’re free to make changes to your Unattend.xml.

Also, you may want to pre-generate catalogs in a separate SIM session since it takes a while:

Unattend-010

Edit Unattend.xml

Typically my first step is to run the Validation check to see what the SIM isn’t happy about.

Unattend-011

Double click on any results to be taken right to that setting to remediate any issues.

  1. For the first four in the screenshot above, I simply revert the change by secondary mouse-clicking on the setting and selecting that option.
    .
  2. For the NetworkLocation warning, I typically leave it as-is & ignore warning.  Even though it’s officially deprecated, it still seems to work but for how long is anyone’s guess.

Since we’re already in amd64_Microsoft-Windows-Shell-Setup__neutral/OOBE, why don’t we set ProtectYourPC to 3.

Make any other necessary changes, verify the answer file, save and exit.

In Closing

You can do a lot in the unattend.xml but since I’m prone to forgetting  🙂  I try to add just the bare minimum and put the rest in a Task Sequence; It’s much easier to manage/maintain that way but there are legitimate reasons to put something in the unattend.  Do what works for you.

Good Providence to you!

MDT Tutorial Part 4: CustomSettings.ini

Living Table of Contents

 

Today’s Agenda:

  • CustomSettings.ini Overview

Recommended Reading

CustomSettings.ini

The CustomSettings.ini is a rules file processed by ZTIGather.wsf after the Bootstrap.ini is processed (more on that in my next post) as well as periodically during the Task Sequence.  The CustomSettings.ini contains instructions to perform specific actions and set various parameters in MDT.  You can great very creative when it comes to customizing the CustomSettings.ini, but that’s beyond the scope of this post.  Today I just want to focus on explaining what’s currently in your CustomSettings.ini to whet your appetite for getting this setup in your environment.

The CustomSettings.ini can be accessed two ways:

  1. In the ‘Rules’ tab of the Deployment Share properties
  2. The CustomSettings.ini file in the Control subdirectory of your Deployment Share, for example:
    1. C:\DeploymentShare\Control
    2. \\MDTServer\DeploymentShare$\Control

At the moment your current CustomSettings.ini it pretty bare bones


[Settings]
Priority=Default
Properties=MyCustomProperty

[Default]
OSInstall=Y
SkipCapture=NO
SkipAdminPassword=YES
SkipProductKey=YES
SkipComputerBackup=NO
SkipBitLocker=NO

I want to start by pointing out that everything in the [Default] section is set to ‘NO’ except for ‘SkipAdminPassword’ and ‘SkipProductKey’.  If you recall when we created the first Deployment Share, we saw the screen below:

NDS-004

Everything was checked except for ‘Ask for a product key’ and ‘Ask to set the local Administrator password’ which if you can guess corresponds to what we’re seeing in the CustomSettings.ini.

The OSInstall property is provided out of the box and I suppose it’s meant to tip the MDT Admin that you can set it to N if need be.  It’s important to note that this property is not required, and if it’s missing an OS installation will proceed by default.  So don’t go thinking that by deleting that you’re going to prevent OS’ from installing.

Another baked in property is MyCustomProperty which has no references anywhere.  This is really just to let the MDT Admin know that this is where they can declare properties (like declaring variables) for use in the CustomSetitngs.ini and thus the MDT environment.  We’ll get into that more a little later but just know that you can delete ‘MyCustomProperty’ – and in fact that whole line – and things would work fine.

At the moment there are two Sections – the square bracket surrounded text – in your CustomSettings.ini:

  1. Settings
  2. Default

And the rest are properties, or variables, that we’ll explore further.

The [Settings] Section

The settings section holds just two properties

  • Prioroty
  • Properties

Priority

The Priority property is a reserved property used for determining the order in which sections within the CustomSettings.ini will process items.  I like to think of Priority as a listing of declared Functions I want to call in a specific order when the CustomSettings.ini is processed, and each of these functions do something.  Let’s go over some basic real-world examples to help explain.

Say your CustomSettings.ini looked like this:


[Settings]
Priority=MACAddress,Default

[00:11:22:33:44:55]
SkipAdminPassword=NO

[00:11:22:33:44:56]
OSInstall=Y

[TestGroup]
SkipCapture=YES

[Default]
OSInstall=Y
SkipCapture=NO
SkipAdminPassword=YES
SkipProductKey=YES
SkipComputerBackup=NO
SkipBitLocker=NO

When the CustomSettings.ini is processed it will read the Priority line to determine the order in which the sections need to be processed.

  1. MACAddress
  2. Default

The MACAddress directive is a special one that is built-into MDT that doesn’t look for a section called [MACAddress] but instead determines your machine’s MACAddress and looks for a section that matches your machine’s MAC Address, like [00:11:22:33:44:55].  If a matching section is found, it processes the properties in that section, which in this case is just SkipAdminPassword=NO.  When that’s done it’ll move into the [Default] section and process everything there and then it’s done.

But wait a minute, what about that third section called [TestGroup] with it’s own set of properties?  Well the [TestGroup] section would not be processed because it was not specified on the Priority line, so it’s ignored completely.

Let’s try another example: Suppose you wanted to add a section to do something special for machines using a particular default gateway IP address:


[Settings]
Priority=DefaultGateway,MACAddress,Default

[192.168.1.1]
SkipProductKey=NO
SkipAdminPassword=NO

[00:11:22:33:44:55]
OSInstall=N

[00:11:22:33:44:56]
OSInstall=Y

[TestGroup]
SkipCapture=YES

[Default]
OSInstall=Y
SkipCapture=NO
SkipAdminPassword=YES
SkipProductKey=YES
SkipComputerBackup=NO
SkipBitLocker=NO

From a processing perspective this is the order:

  1. DefaultGateway
  2. MACAddress
  3. Default

Like MACAddress, DefaultGateway is a special directive that looks up the default gateway IP address of the machine in question.  In this scenario, any machines with a Default Gateway of 192.168.1.1 will always display the MDT screens that prompt for the product key and administrator password, which may seem a little odd considering in the [Default] section we’re suppressing them, which brings me to my next important point.

For most MDT properties, once it has been set, it becomes ‘read-only’ and won’t be changed again via processing of the CustomSettings.ini.  The ‘documentation’ calls these variables ‘first value wins’ but I usually refer to them as ‘write-once’.  This is very important because once an internal MDT property is set, say in Section A, it will not be altered in Section C even if it’s present with a different value.

However, there are some variables that are ‘last value wins’, meaning they can be overwritten multiple times, and I’m only aware of 9 that fit into this category:

  1. DeployRoot
  2. ResourceRoot
  3. DeployDrive
  4. ResourceDrive
  5. DeploymentMethod
  6. DeploymentType
  7. Phase
  8. DestinationDisk
  9. DestinationPartition

Can you override this behavior?  Yes, by editing the ZTIGather.xml, but I’d advise against it unless you know what you’re doing.  Plus by doing so you may not be in a supported configuration and Microsoft Support would probably ask you to undo your changes.

Properties

The Properties property is more like a variable declaration directive.  In the CustomSettings.ini you can’t just create lines for various properties all willy nilly:


[Settings]
Priority=DefaultGateway,MACAddress,Default
Properties=SkipWindowsUpdates

[192.168.1.1]
SkipProductKey=NO
SkipAdminPassword=NO

[00:11:22:33:44:55]
OSInstall=N

[00:11:22:33:44:56]
OSInstall=Y

[TestGroup]
SkipCapture=YES

[Default]
OSInstall=Y
SkipCapture=NO
SkipAdminPassword=YES
SkipProductKey=YES
SkipComputerBackup=NO
SkipBitLocker=NO
SkipWindowsUpdates=YES
InstallOffice2016=YES

In the above example, I declared a new property (or variable) called SkipWindowsUpdates via the ‘Properties’ line.

In the [Default] section I added the new declared property, SkipWindowsUpdates, and set it to YES.

In the [Default] section I also added a property called InstallOffice2016 and set that to YES.

Unfortunately only the SkipWindowsUpdates property (or variable) is going to get picked up by MDT.  The InstallOffice2016 property is ignored because it’s not ‘declared’ in the Properties line in the [Settings] section.

Please note that SkipWindowsUpdates is NOT a built-in MDT property; I just made it up and that is why I had to ‘declare’ it.  Any custom properties you create must be declared – added to the Properties line under Settings – before you can use them.

The [Default] Section

There’s no special meaning behind the name ‘Default’ – it’s just the name of a section.  It could be called Chazwazza and it would work just as well.  But generally speaking the ‘Default’ section is the last section to be processed and that’s where you set all of the ‘Default’ settings not set in the sections above.

  • OSInstall=Y – Indicates an OS will be installed.
  • SkipCapture=NO – Indicates the Capture screen will NOT be suppressed and thus visible.
  • SkipAdminPassword=YES – Indicates the Password screen WILL be suppressed and thus NOT visible.
  • SkipProductKey=YES – Indicates the Product Key screen WILL be suppressed and thus NOT visible.
  • SkipComputerBackup=NO – Indicates the Computer Backup screen will NOT be suppressed and thus visible.  Please note that this is not a screen we’ve seen yet.
  • SkipBitLocker=NO – Indicates the BitLocker screen NOT be suppressed and thus visible.

You can completely change the ordering of the Default section or even have other sections execute after the Default section, provided you added (aka declared) it in the Priority line in the Settings section after Default.

Putting It All Together

Going back to our current stock CustomSettings.ini we’re going to alter some defaults just to show how it works and how it can streamline imaging.


[Settings]
Priority=Default
Properties=MyCustomProperty

[Default]
OSInstall=Y
SkipCapture=NO
SkipAdminPassword=YES
SkipProductKey=YES
SkipComputerBackup=NO
SkipBitLocker=YES
SkipUserData=YES

Since we’re not looking to backup and/or restore anything, and we’re not enabling BitLocker, we can skip those screens altogether by setting SkipBitLocker to ‘YES’ and adding a new property called SkipUserData and setting that to ‘YES’.

When you make changes to the CustomSettings.ini, they’re live right then and there so just boot your media and go again.

  • If you’re already in WinPE at the Welcome screen, the one with the ‘Run the Deployment Wizard…‘ button, click it and it’ll process your updated CustomSettings.ini.
  • However if you’re already at the Task Sequence screen you’ll need to reboot since the CustomSettings.ini was processed before you made you changes.

Now when I boot into WinPE and image, I no longer see those respective screens.
Before, I had both ‘Move Data and Settings’ and ‘USer Data (Restore)’ steps:

SBTS-011

After making the change, those screens are gone altogether:

NoBLNoUD

If I wanted to bring back BitLocker screen, I could Set SkipBitLocker to ‘NO’ or commend the line by adding a semicolon in front like ;SkipBitLocker=YES

In case you’re wondering, I didn’t declare SkipUserData because it’s a built-in MDT property that I’m just toggling.  Please see the links under recommended reading above for more information on [many] built-in variables.

In Closing

We’re really only scratching the surface here at what we can do with the CustomSettings.ini.  You can do so much from here including calling a UserExit script which is a way for the CustomSettings.ini to call an external vbscript that will return a value which will get set as the property (or variable) value.

In the next post we’ll talk about the other .INI file, Bootstrap.ini and we’ll make some other adjustments to both files to make some things a little easier for us.

For now, I bid you Good Providence.

MDT Tutorial Part 3: Imaging

Living Table of Contents

 

Today’s agenda: Image All The Things!

  • Image a machine with the Build Task Sequence
  • Image a machine with the Build, Sysprep & Capture Task Sequence

Prerequisites

  • Copy the bootable ISOs from the Boot directory in the Deployment Share Share (e.g.: \\MDTServer01\DeploymentShare$\Boot) to your Hyper-V server
  • Add the ISO to your VM
  • Set the DVD Drive as the first boot device
  • Boot your VM
  • Press any key to boot the media.

Build Task Sequence

Once the WinPE environment loads, you’ll be greeted by this window.

SBTS-001

Click ‘Run the Deployment Wizard to install a new Operating System‘ and it will prompt you for credentials.  If you created a dedicated MDT account, good on you – use those.  In my lab (torn down & rebuilt regularly) I just use the local Administrator account.SBTS-003

Assuming you entered the proper credentials, you’ll see the available Task Sequences.
Choose the Task Sequence you created and click next.

SBTS-004

On the ‘Computer Details’ step feel free to enter in a computer name and workgroup name; Or don’t – that’s fine too.

SBTS-005

On the ‘Move Data and Settings’ step you can leave the default, ‘Do not move user data and settings.‘, since there’s nothing to backup/move.

SBTS-006

On the ‘User Data (Restore)’ step leave the default, ‘Do not restore user data and settings.‘ because there’s nothing to restore from.

SBTS-007

On the ‘Locale and Time’ step, adjust the settings accordingly.

SBTS-008

On the ‘Capture Image’ step you can leave the default, ‘Do not capture an image of this computer.‘  Right now we’re just looking to lay down the OS and the B&C will come later.

SBTS-009

On the ‘BitLocker’ step you can leave ‘Do not enable BitLocker for this computer.

SBTS-010

The ‘Ready’ step is really just a summary of the configuration you set above.
Give it a once over to make sure it’s correct and click begin.

SBTS-011

Will run, doing the steps listed in the Task Sequence.  I like to follow along with the VM on one side of the screen and the Task Sequence on the other to ensure things are executing as I expect.  A number of steps take place in WinPE, like laying down the WIM on the disk.

Afterwards the machine will reboot and boot into Windows

Eventually you’ll see the desktop and you might think ‘it’s done’ or that ‘it stalled’ and be tempted to start playing around with it but please don’t!

SBTS-022

Give it a minute and you’ll see the process continue.

After a sigh of relief it’ll move on and finish up very quickly after that.

SBTS-025

Mid Boss Battle Complete!

This is the halfway mark and if this goes smoothly the next step should be just as easy.

Build, Sysprep & Capture Task Sequence

If you didn’t already guess, the Build, Sysprep & Capture – or B&C for Build & Capture because it’s assumed you’re going to sysprep the machine since you don’t want to be in an unsupported situation – process is the same as the above.

  • Add the ISO to your B&C VM
  • Boot from the media
  • Click ‘Run the Deployment Wizard to install a new Operating System
  • Enter your authentication credentials

This time you want to select your B&C Task Sequence

Cap-001

The screens that follow are identical to what you had before, and for the most part everything is the same…

EXCEPT when you get to the ‘Capture Image’ step!
This time we are going to select ‘Capture an image of this reference computer.‘ so that we can capture an image of this machine.  You’re welcome to adjust the Location and File name but the defaults are fine for our purposes.

Cap-007

Again, review your configuration to ensure it’s correct before clicking ‘Begin’

Cap-008

For the most part, it’s exactly the same as before: A number of steps take place in WinPE before rebooting into the OS.

Once in the OS, MDT will start up again, finish up the normal tasks

This slideshow requires JavaScript.

Run sysprep

Cap-010

Stage the boot media

Cap-009

Reboot into WinPE

Cap-012

Initialize the WinPE environment

Cap-013

Capture the WIM

This slideshow requires JavaScript.

Display a summary when complete

Cap-017

A High Five is in Order: Your First B&C via MDT!

Seriously, this is a big deal so request the highest of fives from someone.

The Importance of MDT in a WaaS World

I do not like doing the same thing over and over again, and the idea of building a physical machine that I need to patch, load software onto and configure is not how I want to spend my day.  You can expect a feature update release for Windows 10 twice a year which means you could be asked to perform a B&C twice a year.

So instead of spending days:

  • installing Windows 10
  • thumbing through a 40 page build document
  • locating build change notes scattered across sticky notes scattered throughout desk and emails

I would much rather spend a few hours or a couple of days:

  • cataloguing the OS level configurations required for the organization
  • packaging applications & testing them to ensure they’re complete and work
  • putting it all together in scripts
  • loading all these into MDT

This way I can have reliable, repeatable process for building machines & capturing images.

I promise, once you get this going you’ll never look back.

Good Providence to you!

Facilitating KMS Activations

Occasionally we run into situations where Windows or the Office Suite fails to activate.

The solution: Use the built-in product-specific scripts to activate.

The problem: Many people in IT are not aware of these scripts, and thus how to use them, which results in a guaranteed call or email to the appropriate team.

Since I’m all about empowering people, I figured I’d put together a little script to help facilitate all this.

Enter: KMSActivate-MicrosoftProducts

I probably could have just left it as ‘Activate-MicrosoftProducts’ but I wanted to make sure potential users knew this was specifically for KMS scenarios, not MAK which has it’s own procedure.


[cmdletbinding()]
Param
    (
        [Parameter(Mandatory=$false)]
            [Switch]$ActivateOS = $true,

        [Parameter(Mandatory=$false)]
            [Switch]$ActivateOffice = $true
    )

Function Check-IfRunningWithAdministratorRights { If (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]“Administrator”)) { Write-Warning “ERROR: You DO NOT have Administrator rights to run this script!`nPlease re-run this script as an Administrator!”; Break } }

Function Get-KMSHost { try { return (nslookup -type=srv _vlmcs._tcp | ? { $_ -like '*svr hostname*' }).Replace('svr hostname','').Replace('=','').Trim() } catch { throw $_ } }

Function Get-KMSClientSetupKey
    {
        # https://technet.microsoft.com/en-us/library/jj612867(v=ws.11).aspx
        [cmdletbinding()]
        Param
            (
                [Parameter(Mandatory=$false)]
                    [string]$OperatingSystemCaption = (Get-CimInstance -ClassName win32_operatingsystem).caption
            )

        Switch -Wildcard ($OperatingSystemCaption)
            {
                '*Windows Server 2016 Datacenter*' { return 'CB7KF-BWN84-R7R2Y-793K2-8XDDG' }

                '*Windows Server 2016 Standard*' { return 'WC2BQ-8NRM3-FDDYY-2BFGV-KHKQY' }

                '*Windows Server 2016 Essentials*' { return 'JCKRF-N37P4-C2D82-9YXRT-4M63B' }

                '*Windows 10 Enterprise*' { return 'NPPR9-FWDCX-D2C8J-H872K-2YT43' }

                '*Windows 7 Enterprise*' { return '33PXH-7Y6KF-2VJC9-XBBR8-HVTHH' }

                default { write-host "ERROR INVALID OPERATING SYSTEM CAPTION: $_"; throw }
            }
    }

Function KMSActivate-OperatingSystem
    {
        [cmdletbinding()]
        Param
            (
                [Parameter(Mandatory=$false)]
                    [string]$KMSHost = $(Get-KMSHost),

                [Parameter(Mandatory=$false)]
                    [string]$KMSClientSetupKey = $(Get-KMSClientSetupKey)
            )

        Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$env:windir\System32\slmgr.vbs`" -dlv" -Wait

        Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$env:windir\System32\slmgr.vbs`" -skms $KMSHost" -Wait

        Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$env:windir\System32\slmgr.vbs`" -ipk $KMSClientSetupKey" -Wait

        Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$env:windir\System32\slmgr.vbs`" -ato" -Wait

        Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$env:windir\System32\slmgr.vbs`" -dlv" -Wait
    }

Function KMSActivate-OfficeSuite
    {
        [cmdletbinding()]
        Param
            (
                [Parameter(Mandatory=$false)]
                    [string]$KMSHost = $(Get-KMSHost)
            )

        #write-host "KMSHost [$KMSHost]"

        [System.Collections.ArrayList]$OfficeInstallationDirs = @()
        foreach($ProgFilePath in $env:ProgramFiles,${env:ProgramFiles(x86)})
            {
                if(!(Test-Path -Path $ProgFilePath -PathType Container)) { continue }
                foreach($OfficeVersion in (gci "$ProgFilePath\Microsoft Office" -Filter Office* -ErrorAction SilentlyContinue)) { $OfficeInstallationDirs += $OfficeVersion.Fullname }
            }

        foreach($OfficeInstallationDir in $OfficeInstallationDirs)
            {
                if(!(Test-Path -Path "$OfficeInstallationDir\ospp.vbs" -PathType Leaf)) { continue }

                Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$OfficeInstallationDir\ospp.vbs`" /dstatusall" -Wait

                Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$OfficeInstallationDir\ospp.vbs`" /sethst:$KMSHost" -Wait

                Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$OfficeInstallationDir\ospp.vbs`" /act" -Wait

                Start-Process -FilePath 'cscript' -ArgumentList "/nologo `"$OfficeInstallationDir\ospp.vbs`" /dstatusall" -Wait
            }
    }

Check-IfRunningWithAdministratorRights

if($ActivateOS -eq $true) { KMSActivate-OperatingSystem }

if($ActivateOffice -eq $true) { KMSActivate-OfficeSuite }

 

The script will attempt to:

  • Confirm it’s running elevated otherwise it’ll quit
  • Determine the KMS server (or use the one supplied)
  • Determine the OS to set the correct client setup key
  • Determine the version(s) of Office installed (if any)
  • Activate Windows 7, 10 and a few flavors of Server 2016
  • Activate any various versions of Office if present

Not saying this is the best way – just a way.  I merely wanted a turn-key solution for our IT staff and this was what made sense as it solves some of the more infrequent issues that occasionally arose.

Good Providence to you!

Preparing for Windows 10: Move Computers into to Win 10 OUs

One thing that has annoyed me about MDT and SCCM was that there wasn’t a built-in method to move machines into the proper OU.  As such it required creating something from scratch and I opted for something that didn’t require dependencies, like the ActiveDirectory module.

This isn’t the best way and this isn’t the only way – it’s just a way; one of many in fact.

Please note that this is NOT the ideal way to handle any operations that require credentials!  Keeping credentials in a script is bad practice as anyone snooping around could happen upon them and create some problems.  Instead, you should rely on web services to do this and Maik Koster has put together an excellent little care package to help get you started.

Move-ComputerToOU Prerequisites

My script has a few prerequisites:

  • The current AD site
  • A [local] Domain Controller to use (recommended)
  • The current OU of the machine to be moved
  • The new OU to move the machine into

It’s important to know that this script does not rely on the ActiveDirectory module.
One of my [many] quirks is to try to keep everything self-contained where it makes sense to do so, and I liked the idea of not having to rely on some installed component, an EXE and so on.  But to be honest, web services is the way to go for this.

Getting the Current AD Site

Better see this post for that.

Getting a Local Domain Controller

Better see this post for that.

Getting the Current OU

Better see this post for that.

Getting / Setting the New OU

If this is being executed as part of an OSD, yank those details from the MachineObjectOU Task Sequence variable via something like:

Function Get-TaskSequenceEnvironmentVariable
    {
        Param([Parameter(Mandatory=$true,Position=0)]$VarName)
        Try { return (New-Object -COMObject Microsoft.SMS.TSEnvironment).Value($VarName) }
        Catch { throw $_ }
    }
$MachineObjectOU = Get-TaskSequenceEnvironmentVariable MachineObjectOU

Otherwise just feed it the new OU via the parameter

Process Explanation

We first have to find existing object in AD


# This is the machine we want to move
$ADComputer = $env:COMPUTERNAME

# Create Directory Entry with authentication
$de = New-Object System.DirectoryServices.DirectoryEntry($LDAPPath,"$domain\$user",$pass)

# Create Directory Searcher
$ds = New-Object System.DirectoryServices.DirectorySearcher($de)

# Fiter for the machine in question
$ds.Filter = "(&(ObjectCategory=computer)(samaccountname=$ADComputerName$))"

# Optionally, set other search parameters
#$ds.SearchRoot = $de
#$ds.PageSize = 1000
#$ds.Filter = $strFilter
#$ds.SearchScope = "Subtree"
#$colPropList = "distinguishedName", "Name", "samaccountname"
#foreach ($Property in $colPropList) { $ds.PropertiesToLoad.Add($Property) | Out-Null }

# Execute the find operation
$res = $ds.FindAll()

 

Then we bind to the existing computer object


# If there's an existing asset in AD with that sam account name, it should be the first - and only - item in the array.
# So we bind to the existing computer object in AD
$CurrentComputerObject = New-Object System.DirectoryServices.DirectoryEntry($res[0].path,"$domain\$user",$pass)

# Extract the current OU
$CurrentOU = $CurrentComputerObject.Path.Substring(8+$SiteDC.Length+3+$ADComputerName.Length+1)

 

From there setup the destination OU


# This Here we set the new OU location
$DestinationOU = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$SiteDC/$NewOU","$domain\$user",$pass)

 

And finally move the machine from the old/current OU to the new/destination OU


# And now we move the asset to that new OU
$Result = $CurrentComputerObject.PSBase.MoveTo($DestinationOU)

Move-ComputerToProperOU.ps1

So this is a shortened version of the script I’m using in production.  All you need to do is fill in the blanks and test it in your environment.


# There's a separate function to get the local domain controller
$SiteDC = Get-SiteDomainController
# Or you can hard code the local domain controller
$SiteDC = 'localdc.domain.fqdn'

# Build LDAP String
# I //think// there were maybe two cases whre this din't work
$LocalRootDomainNamingContext = ([ADSI]"LDAP://$SiteDC/RootDSE").rootDomainNamingContext
# So I added logic to trap that and pull what I needed from SiteDC
#$LocalRootDomainNamingContext = $SiteDC.Substring($SiteDC.IndexOf('.'))
#$LocalRootDomainNamingContext = ($LocalRootDomainNamingContext.Replace('.',',DC=')).Substring(1)

# Building the LDAP string
$LDAPPath = 'LDAP://' + $SiteDC + "/" + $LocalRootDomainNamingContext

# Set my domian for authentication
$domain = 'mydomain'

# Set the user for authentication
$user = 'myjoindomainaccount'

# Set the password for authentication
$pass = 'my sekret leet-o-1337 creds'

# This is the machine I want to find & move into the proper OU.
$ADComputerName = $env:COMPUTERNAME

# This is the new OU to move the above machine into.
$NewOU = 'OU=Laptops,OU=Win10,OU=Office,OU=CorpWorkstations,DC=domain,DC=fqdn'

# Create Directory Entry with authentication
$de = New-Object System.DirectoryServices.DirectoryEntry($LDAPPath,"$domain\$user",$pass)

# Create Directory Searcher
$ds = New-Object System.DirectoryServices.DirectorySearcher($de)

# Fiter for the machine in question
$ds.Filter = "(&(ObjectCategory=computer)(samaccountname=$ADComputerName$))"

# Optionally, set other search parameters
#$ds.SearchRoot = $de
#$ds.PageSize = 1000
#$ds.Filter = $strFilter
#$ds.SearchScope = "Subtree"
#$colPropList = "distinguishedName", "Name", "samaccountname"
#foreach ($Property in $colPropList) { $ds.PropertiesToLoad.Add($Property) | Out-Null }

# Execute the find operation
$res = $ds.FindAll()

# If there's an existing asset in AD with that sam account name, it should be the first - and only - item in the array.
# So we bind to the existing computer object in AD
$CurrentComputerObject = New-Object System.DirectoryServices.DirectoryEntry($res[0].path,"$domain\$user",$pass)

# Extract the current OU
$CurrentOU = $CurrentComputerObject.Path.Substring(8+$SiteDC.Length+3+$ADComputerName.Length+1)

# This Here we set the new OU location
$DestinationOU = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$SiteDC/$NewOU","$domain\$user",$pass)

# And now we move the asset to that new OU
$Result = $CurrentComputerObject.PSBase.MoveTo($DestinationOU)

 

Happy Upgrading & Good Providence!