• Michael Niehaus' Windows and Office deployment ramblings

    MDT 2010 Wizard Example: Role Selection

    • 8 Comments

    We have seen lots of requests over the past couple of years for a wizard pane that allows you to select from a list of roles that should be applied to a machine, where those roles are defined in the MDT database.  There are a few examples of this available on the web, implemented in different ways.  I’ll throw another one into the mix, this one using an ADO.NET Data Services web service to get the needed data.  (If you didn’t read my previous posting about this setup, click here.)

    <?xml version="1.0" encoding="utf-8"?>
    
    <Wizard>
    
      <Global>
    
        <CustomStatement><![CDATA[
    
    ' ***************************************************************************
    
    ' File:	Roles.xml
    
    ' Author:	Michael Niehaus
    
    ' Version:	1.0
    
    ' Purpose:	Display a list of roles from the MDT database, retrieved
    
    '	using an ADO.NET Data Services.web service.  One
    
    '	or more roles can be selected.  After they have been
    
    '	chosen, CustomSettings.ini needs to be re-processed
    
    '	to pick up the new settings.  Ideally this would be done
    
    '	after the wizard is complete (just in case someone 
    
    '	navigated back to the screen after initially making
    
    '	changes), but that requires changing LiteTouch.wsf.
    
    '
    
    ' NOTE:	Be sure to modify the web service URL below
    
    '
    
    ' ***************************************************************************
    
    Function InitializeRoleList
    
    	Dim sScript
    
    	Dim oDataService
    
    	Dim oRole
    
    	Dim sRoles
    
    	' Make sure that ZTIDataAccess.vbs is available since it isn't loaded by Wizard.hta
    
    	sScript = oFSO.OpenTextFile(oUtility.ScriptDir & "\ZTIDataAccess.vbs", 1, false).ReadAll
    
    	On Error Resume Next
    
    	ExecuteGlobal sScript
    
    	On Error Goto 0
    
    	' Call the web service
    
    	Set oDataService = New WebService
    
    	oDataService.WebService = "http://localhost:62932/MDTDatabase.svc/RoleIdentity"
    
    	oDataService.Method = "REST"
    
    	Set oResult = oDataService.Query
    
    	' Process the roles to populate the list of checkboxes
    
    	sRoles = ""
    
    	For each oRole in oResult.SelectNodes("//d:Role")
    
    		sRoles = sRoles & "<input type=checkbox name=Roles id=Roles enabled value='" & oRole.Text & "'>" & oRole.Text & "</input><br>"
    
    	Next
    
    	' If no roles were found, set the div to indicate that
    
    	If sRoles = "" then
    
    		sRoles = "<label class=errmsg style='display: inline;' >No roles could be found."
    
    	End if
    
    	' Update the pane
    
    	RoleList.InnerHTML = sRoles
    
    End Function
    
    Function ValidateRoleList
    
    	' Flush the value to variables.dat, before we continue.
    
    	SaveAllDataElements
    
    	SaveProperties
    
    	' Process full rules (needed to pick up the role settings, apps, etc.)
    
    	sCmd = "wscript.exe """ & oUtility.ScriptDir & "\ZTIGather.wsf"""
    
    	oItem = oShell.Run(sCmd, , true)
    
    	ValidateRoleList = True
    
    End Function
    
    ]]></CustomStatement>
    
      </Global>
    
      <Pane id="Roles">
    
        <Body><![CDATA[<H1>Select the roles to be assigned to this computer.</H1>
    
    <br>
    
    <div class=TreeList id=RoleList style="height: expression( GetDynamicListBoxSize(this) );">
    
    <label class=errmsg style="display: inline;" >Loading roles...
    
    <!-- List goes here -->
    
    </div>
    
    ]]></Body>
    
        <Validation><![CDATA[ValidateRoleList]]></Validation>
    
        <Initialization><![CDATA[setTimeout GetRef("InitializeRoleList"), 0]]></Initialization>
    
      </Pane>
    
    </Wizard>

    While this is set up as a stand-alone wizard, you can insert this into an existing deployment wizard using the MDT Wizard Editor by following these steps:

    1. Launch the MDT Wizard Editor.
    2. Open the DeployWiz_Definition_ENU.xml file.
    3. Click on the “Global” pane.  Click “Add” on the “Settings” pane and choose to add a new “CustomStatement”.
    4. Select the new “CustomStatement” at the end of the “Settings” list.
    5. Select the VBScript code above (from the first comment line to the last End Function line) and copy it to the clipboard.
    6. Paste the copied VBScript code into the text box in the MDT Wizard Editor.  Edit the web service URL to specify your ADO.NET Data Services web service URL.
    7. Select a wizard pane (the new pane will be inserted after this one, so select appropriately).
    8. Select all the text above from “<Pane” through “</Pane>” and copy it to the clipboard.
    9. Right-click on the selected pane name in the MDT Wizard Editor and choose “Paste”.

    What, your MDT Wizard Editor doesn’t have a “Paste” option?  Well, you need to download a new version from http://mdtwizardeditor.codeplex.com/, as I just added the paste capability tonight (along with other general usability improvements – I forced myself to actually use the program to create the rules wizard pane above and fixed all the behaviors I didn’t like while I was at it).

    A few notes to mention:

    • Because the wizard runs after CustomSettings.ini has been processed, the role settings, applications, etc. wouldn’t be processed as the “Gather” process isn’t run again.  To work around this, I added logic above to run ZTIGather.wsf again.  This could add a delay when clicking “Next”, so you might choose to do this later (possibly by modifying LiteTouch.wsf).  The other problem with running ZTIGather.wsf from this wizard pane:  If you navigate back to this wizard pane and uncheck an item, it’s too late – the settings for that role have already been added into the task sequence environment.
    • The MDT 2010 wizard hypertext application (Wizard.hta) doesn’t load the ZTIDataAccess.vbs script needed to make web service calls from a wizard pane.  To work around this, I added logic above to dynamically load the file.  The other alternative would be to edit Wizard.hta to tell it to include the file.
    • The role list is populated asynchronously so that the wizard doesn’t appear to be hung.  This is done by the “setTimeout” initialization statement above.  Note that the “Next” (or “Finish”) button will be enabled even while this is happening, so if you don’t want to wait you can probably go ahead and click the button to move on to the next pane.
    • If you don’t have the ADO.NET Data Services web service set up and working, don’t expect this wizard pane to somehow magically fix it :-)
  • Michael Niehaus' Windows and Office deployment ramblings

    Fun with ConfigMgr 2007 and PowerShell

    • 5 Comments

    I needed some PowerShell practice this evening, so I did some experimentation to figure out how to interact with the ConfigMgr provider via PowerShell and WMI.  As a result of that experimentation, I’ve put together a module that you might find useful, if nothing else as a good example of how to do similar activities yourself.

    A few notes:

    • I am using PowerShell v2 CTP 3 (download from http://www.microsoft.com/downloads/details.aspx?FamilyID=c913aeab-d7b4-4bb1-a958-ee6d7fe307bc&DisplayLang=en) for this, and it will not work with PowerShell v1 because I am using modules and advanced functions.
    • Because this is a PowerShell script, you’ll need to save the text below locally on your computer and make sure you’ve set the execution policy to something like “RemoteExecute”.  (The script isn’t signed.)
    • The script doesn’t currently support credentials for connecting to the ConfigMgr site – you can add that if you want, but I prefer to use the credentials of the currently-logged-on account.
    • Presently the script only does queries.  Creating and updating items are a little more dangerous (and as you can see below, deletes are trivial).

    Here’s a brief description of each of the functions included in the module:

    • Connect-SCCMServer [-serverName <name>] [-siteCode <siteCode>]

      The Connect-SCCMServer method handles the details of connecting to the ConfigMgr provider (properly, by following the link from the site server to the provider server).  If you don’t specify a server name, the script will assume the local machine.  If you don’t specify a site code, it will use the default site code on the machine.  The resulting connection details (provider server name, site code, namespace path) are saved in global variables so that the other functions don’t require specifying all the same details.  (Yes, it gets a bit tiring to type those over and over again.
    • Get-SCCMObject -class <className> [-filter <filterText>]

      The Get-SCCMObject method is the base routine used for retrieving items from ConfigMgr.  Specify the class name (e.g. SMS_Package) and an optional filter (the where clause to insert in the WQL, e.g. “Name=’ABCD’”).  This function is used by all the other functions, so you don’t need to use this one directly if you don’t want to.
    • Get-SCCMPackage
    • Get-SCCMCollection
    • Get-SCCMAdvertisement
    • Get-SCCMDriver
    • Get-SCCMDriverPackage
    • Get-SCCMTaskSequence
    • Get-SCCMSite
    • Get-SCCMImagePackage
    • Get-SCCMOperatingSystemInstallPackage
    • Get-SCCMBootImagePackage

      These methods all take an optional “-filter” parameter (see above) and retrieve a list of the specified type of items.
    • Get-SCCMSiteDefinition

      This retrieves the site definition properites, used by the next function.
    • Get-SCCMIsR2

      This returns true if the site is running ConfigMgr R2 and false if it isn’t.

    You can do fancier things with these too, if you want to get creative.  For example, assume you want to delete all drivers.  You could do something like this:

    Import-Module C:\SCCM.PSM1

    Connect-SCCMServer -serverName MYSERVER

    Get-SCCMDriver  | % {$_.Delete()}

    Here’s the actual script.

    --- Snip ---

    function Connect-SCCMServer {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $serverName,
            [Parameter(Position=2)] $siteCode
        )

        # Clear the results from any previous execution

        Clear-Variable -name sccmServer -errorAction SilentlyContinue
        Clear-Variable -name sccmNamespace -errorAction SilentlyContinue
        Clear-Variable -name sccmSiteCode -errorAction SilentlyContinue
        Clear-Variable -name sccmConnection -errorAction SilentlyContinue

        # If the $serverName is not specified, use "."

        if ($serverName -eq $null -or $serverName -eq "")
        {
            $serverName = "."
        }

        # Get the pointer to the provider for the site code

        if ($siteCode -eq $null -or $siteCode -eq "")
        {
            Write-Verbose "Getting provider location for default site on server $serverName"
            $providerLocation = get-wmiobject -query "select * from SMS_ProviderLocation where ProviderForLocalSite = true" -namespace "root\sms" -computername $serverName -errorAction Stop
        }
        else
        {
            Write-Verbose "Getting provider location for site $siteName on server $serverName"
            $providerLocation = get-wmiobject -query "select * from SMS_ProviderLocation where SiteCode = '$siteCode'" -namespace "root\sms" -computername $serverName -errorAction Stop
        }

        # Split up the namespace path

        $parts = $providerLocation.NamespacePath -split "\\", 4
        Write-Verbose "Provider is located on $($providerLocation.Machine) in namespace $($parts[3])"
        $global:sccmServer = $providerLocation.Machine
        $global:sccmNamespace = $parts[3]
        $global:sccmSiteCode = $providerLocation.SiteCode

         # Make sure we can get a connection

        $global:sccmConnection = [wmi]"${providerLocation.NamespacePath}"
        Write-Verbose "Successfully connected to the specified provider"
    }

    function Get-SCCMObject {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $class,
            [Parameter(Position=2)] $filter
        )

        if ($filter -eq $null -or $filter -eq "")
        {
            get-wmiobject -class $class -computername $sccmServer -namespace $sccmNamespace
        }
        else
        {
            get-wmiobject -query "select * from $class where $filter" -computername $sccmServer -namespace $sccmNamespace
        }
    }

    function Get-SCCMPackage {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_Package $filter
    }

    function Get-SCCMCollection {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_Collection $filter
    }

    function Get-SCCMAdvertisement {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_Advertisement $filter
    }

    function Get-SCCMDriver {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_Driver $filter
    }

    function Get-SCCMDriverPackage {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_DriverPackage $filter
    }

    function Get-SCCMTaskSequence {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_TaskSequence $filter
    }

    function Get-SCCMSite {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_Site $filter
    }

    function Get-SCCMImagePackage {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_ImagePackage $filter
    }

    function Get-SCCMOperatingSystemInstallPackage {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_OperatingSystemInstallPackage $filter
    }

    function Get-SCCMBootImagePackage {

        [CmdletBinding()]
        PARAM
        (
            [Parameter(Position=1)] $filter
        )

        Get-SCCMObject SMS_BootImagePackage $filter
    }

    function Get-SCCMSiteDefinition {

        # Refresh the site control file

        Invoke-WmiMethod -path SMS_SiteControlFile -name RefreshSCF -argumentList $sccmSiteCode -computername $sccmServer -namespace $sccmNamespace

        # Get the site definition object for this site

        $siteDef = get-wmiobject -query "select * from SMS_SCI_SiteDefinition where SiteCode = '$sccmSiteCode' and FileType = 2" -computername $sccmServer -namespace $sccmNamespace

        # Return the Props list
        $siteDef | foreach-object { $_.Props }
    }

    function Get-SCCMIsR2 {

        $result = Get-SCCMSiteDefinition | ? {$_.PropertyName -eq "IsR2CapableRTM"}
        if (-not $result)
        {
            $false
        }
        elseif ($result.Value = 31)
        {
            $true
        }
        else
        {
            $false
        }
    }

    --- Snip ---

    Save the text between the “--- Snip ---” lines (without actually including those lines) to a file named “SCCM.PSM1”.  Then run PowerShell (either the GUI or command line interfaces), load the script, connect to the site, and run a query or two:

    Import-Module C:\SCCM.psm1

    Connect-SCCMServer -serverName MYSERVER -siteCode CEN

    Get-SCCMPackage | out-GridView

    Get-SCCMDriver -filter "DriverProvider='Broadcom' "

    All of this is warm-up for MMS 2009 at the end of this month…

  • Michael Niehaus' Windows and Office deployment ramblings

    Microsoft Deployment, ConfigMgr, Boot Media, Unknown Computers, Web Services

    • 12 Comments

    Did you ever read the title for a blog entry and have no idea what the posting is about?  Well, this one might fall into that category.  So first, some background information straight from the Microsoft System Center Configuration Manager 2007 documentation (http://technet.microsoft.com/en-us/library/bb633291.aspx):

    To deploy an operating system to a new computer without stand-alone media that is not currently managed by Configuration Manager 2007, the new computer must be added to the Configuration Manager 2007 database prior to initiating the operating system deployment process. Although Configuration Manager 2007 can automatically discover computers on your network that have a Windows operating system installed, if the computer has no operating system installed you will need to import the new computer information by using the Import Computer Information Wizard. This wizard supports importing information about a single computer, or importing information about one or more computers from an external .csv file.

    Simple enough, but not very convenient: in order to do the import you need to have the MAC address and optionally the SMBIOS UUID of the computer.  To get the MAC address of a computer that doesn't yet have an OS, you'd probably need to turn on the computer and go into the BIOS setup, write down the 12-character hex value, then go back to the server and type it in -- accurately.

    So ideally we would like to automatically add the computer to the ConfigMgr database just-in-time.  Now, there are two scenarios that can be used with ConfigMgr to deploy an OS to a new computer:

    • Boot media: inserting a CD or USB key into a computer containing a ConfigMgr-customized version of Windows PE that starts the deployment process.
    • PXE boot: network booting a ConfigMgr-customized version of Windows PE that starts the deployment process.

    There are different challenges in each of these scenarios, so we'll focus on only the first one for now.  When you boot a computer using ConfigMgr boot media, a wizard will start.  The first screen don't require that the computer be present in the ConfigMgr database, but in order to complete the wizard it must be.  So how can we hook into this wizard to do something about this?  That's where the pre-execution hook, described at http://technet.microsoft.com/en-us/library/bb694075.aspx, comes in.

    Microsoft Deployment provides a pre-execution hook script that runs a wizard of its own that will call web services to add the computer to the ConfigMgr database, as well as adding the computer to a collection for a task sequence advertisement.  After that's complete, then the rest of the ConfigMgr boot media wizard can be completed and the task sequence starts.

    So that brings us to the next challenge: setting up the web services.  See the documentation at http://technet.microsoft.com/en-us/library/bb978399.aspx for the details, although note that step #2 assumes you are using Windows Server 2008, so the steps are slightly different for Windows Server 2003.

    Now, for an experiment.  Instead of just trying to explain those steps, I thought it would be useful to record a screencast of the entire configuration process.  So you can play the video below for the whole walk-through, which is about 13 minutes long.

    Web Service Configuration and Troubleshooting Walkthrough

    Assuming you can get this far, everything should be set up properly.  (There are some potential additional complications: if you have a larger hierarchy, you may need to verify security to connect to each site, since the computer needs to be present in the ConfigMgr database for the computer's assigned site.)  Then you just need to create a new boot image, enabling the pre-execution hook and specifying the URL of the web services.  Yes, it's not a trivial setup.  And yes, troubleshooting is more difficult than it should be.  We'll work on that :-)

    Going back to the experiment, if you think screencast recordings like this are useful, please let me know and suggest what additional ones you'd like to see (and hear - adding the audio is the most difficult part).

  • Michael Niehaus' Windows and Office deployment ramblings

    Dumping Task Sequence Variables

    • 1 Comments

    Several people asked me after the troubleshooting session I presented at MMS 2010 how to write a script to dump out all the task sequence variables.  Here are a few samples showing how to do just that.  (These examples work for ConfigMgr and MDT Lite Touch task sequences.)

    First, the absolute “bare bones” approach:


    Set env = CreateObject("Microsoft.SMS.TSEnvironment")
    For each v in env.GetVariables
       WScript.Echo v & " = " & env(v)
    Next

    Save that as “DumpVar.vbs” and run it via the task sequence, redirecting the output to a text file.  For example, if you saved this script in the MDT “Scripts” folder, you could use a command line like this:

    cmd.exe /c cscript.exe "%ScriptRoot%\DumpVar.vbs" >> %Temp%\DumpVar.txt

    If you want to get fancier, you can use MDT’s logging capabilities:


    <job id="ZTIConnect">
       <script language="VBScript" src="ZTIUtility.vbs"/>
       <script language="VBScript">

       Set env = CreateObject("Microsoft.SMS.TSEnvironment")
       For each v in env.GetVariables
          oLogging.CreateEntry v & " = " & env(v), LogTypeInfo
       Next

       </script>
    </job>


    Save that as “DumpVar.wsf” in the MDT “Scripts” folder, and run it with a simpler command line:

    cscript.exe "%ScriptRoot%\DumpVar.wsf"

    If you would prefer to use PowerShell, the same thing can be done with it:


    # Determine where to do the logging
    $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
    $logPath = $tsenv.Value("_SMSTSLogPath")
    $logFile = "$logPath\$($myInvocation.MyCommand).log"

    # Start the logging
    Start-Transcript $logFile

    # Write all the variables and their values
    $tsenv.GetVariables() | % { Write-Host "$_ = $($tsenv.Value($_))" }

    # Stop logging
    Stop-Transcript


    Save that as “DumpVar.ps1” in the MDT “Scripts” folder, and run it using PowerShell.exe (as long as execution of scripts has been enabled):

    PowerShell.exe –File "%ScriptRoot%\DumpVar.ps1"

    Here are some related links:

    http://blogs.technet.com/deploymentguys/archive/2008/08/29/outputting-all-the-configuration-manager-task-sequence-variables.aspx

    http://blogs.technet.com/mniehaus/archive/2009/09/22/running-powershell-scripts-as-part-of-a-task-sequence.aspx

    A few people commented on how they could see my Administrator account and password details in the output of the script I was running, as I had specified that account for my ConfigMgr network access account.  That’s definitely not a best practice – you should specify an account that has the minimum rights required, typically just enough to connect to your distribution point shares.  It should never have domain admin rights.  (Yes, I was lazy and just reused the only account I set up in my demo VMs.)

    You might wonder why the example script above that uses ZTIUtility.vbs doesn’t log the password.  That’s because we have specific logic in that script that refuses to log any line that contains the word “password” as a security feature.

  • Michael Niehaus' Windows and Office deployment ramblings

    Windows Thin PC: Another flavor of Windows 7

    • 2 Comments

    As I discovered in recent TechEd presentations in Australia and New Zealand, not too many people are familiar with the newest members of the Windows 7 family.  So let’s explore one of those in more detail, called Windows Thin PC. For the full marketing overview, you can review these pages:

    http://www.microsoft.com/windows/enterprise/solutions/virtualization/products/thinpc.aspx

    http://www.microsoft.com/licensing/software-assurance/windows-thin-pc.aspx

    To summarize, Windows Thin PC is a modified version of Windows 7 (built from a Windows Embedded Standard 7 base) that is available as a Software Assurance benefit (for anyone with Software Assurance on their desktop operating systems).  It has a reduced footprint (1.1GB compressed WIM, under 5GB when expanded on disk), and as a result has lighter hardware requirements:

    • 1GHz processor
    • 1GB RAM
    • 16GB hard disk space

    So it should come as no surprise that it is designed to be used as a thin client OS, enabling older or lesser hardware to connect to your VDI or terminal services infrastructure to run most applications.

    Windows Thin PC has licensing restrictions that allows very few applications to be installed and used locally.  From the Thin PC FAQ:

    Can I run applications on WinTPC?

    Yes, you can run applications that fall into one of the following categories:

    • Security
    • Management
    • Terminal emulation
    • Remote Desktop and similar technologies
    • Web browser
    • Media player
    • Instant messaging client
    • Document viewers
    • .NET Framework and Java Virtual Machine

    However, you cannot run any productivity applications, such as Microsoft Office or similar applications.

    Again, this is pretty consistent with what you could do with dedicated thin client hardware,

    So what is it like to deploy this operating system?  It deploys just like any other version (SKU) of Windows 7.  MDT 2012 will officially support deploying this OS (since that where we’ve done all of our testing), but it’s not hard to get MDT 2010 Update 1 to deploy it too by removing the <UpgradeData> section from the unattend.xml that you use to deploy Windows Thin PC.

    What does it look like once installed?  Just like Windows 7, but with fewer items on the start menu:

    image

    So it’s not an operating system for everyone, but it does have its place.

  • Michael Niehaus' Windows and Office deployment ramblings

    MDT 2010 New Feature #7: Boot image creation optimized

    • 0 Comments

    With MDT 2008, there were two actions in Deployment Workbench:  “Update” and “Update (files only)”.  With MDT 2010, there is now only one called “Update Deployment Share”.  This action’s purpose is to generate the Windows PE boot images and ISOs needed to perform a deployment.  It will figure out what actions need to be performed to get the images updated and will only perform those actions.  So generally the first time you run “Update Deployment Share” it will take a while to generate the boot image; the next time it will see that nothing needs to be done and quickly finish.

    We also modified the configuration for these boot images.  There are now separate settings for x86 and x64 boot images.  You can also specify ISO file names, image descriptions (useful if you are importing the Lite Touch WIMs into WDS), RAMdisk scratch space size (useful for those pesky huge nVidia drivers that you want to inject into Windows Vista), etc.

    image

    image

    When you perform the “Update Deployment Share” process, Deployment Workbench will compare the current boot image configuration against the previous configuration.  If there are only minor changes, it will copy the WIM locally, make the necessary updates (e.g. injecting new drivers, updating the Bootstrap.ini, adding new components), save the updated WIM, and (optionally) generate a new ISO file.  If there are major changes, the boot image will be recreated from scratch.  You can force a full update in the “Update Deployment Share” wizard by selecting “Completely regenerate the boot images”:

    image

    Because adding and removing drivers, components, patches, etc. can slowly cause the size of the Windows PE boot WIMs to increase, you can also choose to compress the boot image, which will export the WIM contents to a new WIM to get the size back to the smallest possible.

    With MDT 2008, Deployment Workbench would always use the “winpe.wim” files from the Windows Automated Installation Kit as the source for all boot images that it would generate.  With MDT 2010, Deployment Workbench will look for a “boot.wim” file from one of the imported operating systems that has the same build number as Windows AIK (e.g. “boot.wim” from a Windows 7 RC, build 7100, operating system to go with the Windows AIK for Windows 7 RC).  If it finds a match, it will use that WIM instead.  Why do we do this?  Because the “boot.wim” contains the Windows Recovery Environment (Windows RE), a component that isn’t available in Windows AIK.

    Another enhancement in this process:  you can now abort the “Update Deployment Share” process at any point, so if you decide you would rather do the update later you can.  It might take a while for the process to clean up after itself (e.g. unmount any mounted WIMs) so the machine is left in a good state, so be patient.

  • Michael Niehaus' Windows and Office deployment ramblings

    MDT 2010 New Feature #8: No more visible command windows when booting Lite Touch Windows PE

    • 22 Comments

    In MDT 2008, the Windows PE startup process was something close to this:

    1. Windows PE started CMD.EXE to run STARTNET.CMD.
    2. STARTNET.CMD started WPEINIT.EXE.
    3. WPEINIT.EXE initialized networking and optional components, then ran “WSCRIPT.EXE X:\Deploy\Scripts\LiteTouch.wsf”.
    4. LiteTouch.wsf started a minimized CMD.EXE, for troubleshooting, then runs the Welcome or Deployment Wizard.

    That meant that there was always a command window visible on the screen, as well as another minimized one that could be used for troubleshooting.  Some didn’t like that cluttered look, so they hooked in utilities to hide these command windows.

    With MDT 2010, that will no longer be necessary.  The startup process has been modified:

    1. Windows PE starts BDDRUN.EXE.
    2. BDDRUN.EXE starts WPEINIT.EXE.
    3. WPEINIT.EXE initialized networking and optional components, then ran “WSCRIPT.EXE X:\Deploy\Scripts\LiteTouch.wsf”.
    4. LiteTouch.wsf runs the Welcome or Deployment Wizard.

    That means no command windows at all:

    image

    Well, what if you really want a command prompt so that you can do some troubleshooting (e.g. checking if a network driver has been installed)?  Simple, press the F8 key and one will be started for you.  (This command prompt should behave like the one in ConfigMgr 2007: as long as you have a command prompt open, the machine won’t reboot.  However, there is a problem with that in MDT 2010 Beta 2 so the machine will reboot even with the command prompt open.  That should be fixed before the final release of MDT 2010.)

  • Michael Niehaus' Windows and Office deployment ramblings

    MDT 2012 New Feature: Monitoring

    • 17 Comments

    I was going to do a blog posting talking about how to troubleshoot issues with the new monitoring feature available in MDT 2012 for Lite Touch deployments, but then I realized I’ve not yet done an initial post talking about the feature (although I did mention it in a previous blog posting talking about DaRT integration).  So I guess I need to start with more of an overview.

    Over the years, there have been requests for a way to see what deployments are presently in progress.  Way back when, we had a MOM management pack that tried to do this, but there were numerous challenges with that so we ended up removing it – we needed something much simpler.  So with MDT 2012, we implemented something simpler to monitor Lite Touch deployments.  To enable this, just check one box in the deployment share properties:

    image

    When you do this, two things happen:

    1. A new service, the “Microsoft Deployment Toolkit Monitor Service” (short name MDT_Monitor), is installed on the computer.  This service receives events from the computers being monitored, tracking each computer and how far it is in the deployment process.  It also provides this tracking data to Deployment Workbench for you, the administrator, to see.
    2. The CustomSettings.ini file is modified to add a new entry specifying the URL (a combination of the host name and port specified in the deployment share settings) to be used for monitoring.  This is how clients know where to send information.  The MDT scripts (through their use of ZTIUtility.vbs) will automatically send events to this URL.

    That’s all there is to it.  Once you do that, you should be able to track all subsequent deployments via the “Monitoring” node in Deployment Workbench:

    image

    If you look at the properties of any of the computers being monitored, you can see the details:

    image

    You’ll notice that the display automatically updates every 10 seconds, so you can watch the computer progress.  Also, there are three possible buttons (two of which are shown below):

    • Remote Desktop.  This button runs the Remote Desktop Client (MSTSC.EXE), specifying the host name to connect to on the command line.  (This will only work if the computer is presently in a full OS and remote desktop is enabled and accessible through the firewall.  It won’t work if the computer is in Windows PE.)
    • VM Connection.  This button will only show up if you are using a Hyper-V VM.  If you click it, it will run the Hyper-V connection tool (VMConnect.exe) to connect to the host and VM name of the machine.  (We gather that information from the Hyper-V integration components from ZTIGather.wsf and pass those values along to the monitor service.  Because the integration components don’t run in Windows PE, we can only get this information when in a full OS, so this button will not be enabled when starting a new computer deployment from Windows PE.  Also, this requires that the Hyper-V host be accessible from the computer running Deployment Workbench.)
    • DaRT Remote Control.  This button will only show up if DaRT has been integrated into the MDT Lite Touch boot image.  It will run the DaRT Remote Control Viewer, passing along the computer’s IP address, DaRT ticket number, and listening port number, using those values to automatically initiate a remote control session.  (This will only work when the computer is in Windows PE, because the DaRT remote control agent only runs in Windows PE.)  See http://blogs.technet.com/b/mniehaus/archive/2011/11/28/mdt-2012-new-feature-dart-integration.aspx for more information about the DaRT integration.

    A few other details:

    • The computers will be automatically removed after three days, to keep the database from getting too big.
    • If the monitoring service doesn’t hear from a computer for more than four hours, it considers the machine “unresponsive” – so if you see that status in the Workbench list, that’s why.
    • Every time a deployment task sequence starts, completes, or fails, an event log message will be written by the service.  So if you want to trigger some activity based on these events, you can easily do so.
    • You might think that IIS would be required for the MDT_Monitor service, but it’s not.  It’s leveraging features of the .NET Framework to run a “mini web server” as part of the service itself.
    • You might also think that a SQL database would be required to store the details.  Well, there is one, but you don’t need to install SQL Server to use it.  MDT uses a SQL Compact database; all the files needed are installed as part of MDT (and only used if monitoring is enabled).

    That’s the quick overview.

  • Michael Niehaus' Windows and Office deployment ramblings

    MDT 2010 New Feature #17: Customizable boot image process

    • 5 Comments

    I mentioned before that the boot image creation process used by the Deployment Workbench is significantly enhanced in MDT 2010 Beta 2, but didn’t really talk too much about how the process works behind the scenes.  Now, this is template-based, with XML files that specify exactly what should be included in each boot image that we generate:

    • LiteTouchPE.xml.  This defines all the components, files, and settings that should be included in any Lite Touch boot images generated by Deployment Workbench.
    • Generic.xml.  This defines all the components, files, and settings that should be included in any “generic” boot images generated by Deployment Workbench.

    When you perform the “Update Deployment Share” process, the Deployment Workbench will take these XML files (located in C:\Program Files\Microsoft Deployment Toolkit\Templates), add some additional items to them (e.g. settings you specified on the deployment share properties such as optional components to add, settings like RAMdisk size, etc.), and then use that to build the new boot image.  (As mentioned in the previous article, the process is optimized to only do the minimum amount of work – it does this by comparing the new XML file against the one generated the last time the boot image was generated.  It then figures out what needs to be done based on the difference between the two.)

    So what if you want to add your own files into our boot images?  Just modify the template to tell us where to get them and where to put them in the image and the “Update Deployment Share” process will take care of it.

    That’s fine for simple additions like adding files, but what if you want to do something more substantial?  That’s where exit scripts come in.  (I call this the “Johan feature”.)  You’ll notice that the existing templates specify a sample exit:

    <!-- Exits -->
    <Exits>
      <Exit>cscript.exe "%INSTALLDIR%\Samples\UpdateExit.vbs"</Exit>
    </Exits>

    When the “Update Deployment Share” process runs, this exit script will be called multiple times for each phase of the process, allowing you to make customizations to the process.  Variables will be passed along so that you know where everything is located, what is currently going on, etc.  The phases:

    • “WIM”.  The exit script is called after the WIM has been mounted and customized, just before the changes are going to be committed.  At this point, you can manipulate the WIM contents (copy files, create folders, mount the registry, add registry keys – anything you would like).
    • “ISO”.  The exit script is called just before the boot ISO is being created.  This lets you add files to the boot ISO without sticking them into the RAMdisk.
    • “POSTISO”.  The exit script is called one more time after the ISO file has been created and before that ISO has been copied back to the deployment share.  At this point, you might choose to copy it to a public share, automatically burn it to a CD, etc.

    In each of the phases, various environment variables are defined:

    • INSTALLDIR.  This points to the MDT 2010 installation directory, e.g. “C:\Program Files\Microsoft Deployment Toolkit”.
    • DEPLOYROOT.  This points to the deployment share currently being updated, e.g. “\\SERVER\DeploymentShare$”.
    • PLATFORM.  This will be set to either “x86” or “x64”, depending on which boot image is being generated.
    • ARCHITECTURE.  This will be set to either “x86” or “amd64”, depending on which boot image is being generated.  (Sometime its useful to have the “x64” value and other times “amd64” is more useful, so we report both.)
    • TEMPLATE.  This indicates whether a Lite Touch boot image is being generated (LiteTouchPE.xml) or a generic boot image is being generated (Generic.xml).
    • CONTENT.  This tells you where to find the content for this phase:
      • For the WIM phase, it points to the mount location for the WIM (a temporary folder where you can manipulate the contents of the mounted WIM).
      • For the ISO phase, it points to the folder that will be used to create the ISO (again a temporary folder).
      • For the POSTISO phase, it will point to the created ISO file (located on the local machine, before it is copied back to the deployment share).
    • STAGE.  WIM, ISO, or POSTISO, as described above.

    The “C:\Program Files\Microsoft Deployment Toolkit\Samples” directory does contain the UpdateExit.vbs script described above, which demonstrates all the variables I described.

    There is one bug in MDT 2010 Beta 2 that I have to point out though: the “STAGE” variable is always set to “WIM”, so it’s kind of hard to figure out which phase you are currently in.  That’s been fixed for the released version of MDT 2010.

  • Michael Niehaus' Windows and Office deployment ramblings

    Tips for Integrating USMT 3.0 into BDD 2007

    • 2 Comments

    First, some background information.

    We use the User State Migration Tool 3.0 as part of the user state migration process in BDD 2007 (both Lite Touch and Zero Touch deployments).  Unlike previous versions of BDD, we don't run USMT from the network.  Instead, we install USMT 3.0 locally on the computer, first in the old operating system for capturing user state, and later in the new operating system for restoring it.  Why install it locally?  Well, there are four main reasons:

    • The USMT 3.0 installation contains subfolders with "migration plug-in DLLs" and manifest files used for the XP/2K-to-Vista migration process.  Because of limitations in the SMS 2003 OS Deployment Feature Pack (OSD), there is no way to retain this folder structure in an OSD package.  So it's easiest to just include the single-file installers in the OSD package.
    • Some customers experienced issues where network glitches during migrations caused USMT failures, even when USMT itself contained retry logic when writing user state to the network.  This happened because the USMT executables and DLLs were no longer available because of the network glitch, causing USMT to crash before it could retry.  (Yes, I would be very afraid to be having to deploy a new OS on such a network, but sometimes you have no choice...)  With the USMT files installed locally, they will always be available.
    • You may need to support a migration from x86 to x64.  Since the file names for the two different platform versions of USMT are the same, there is no way to have both sets of files in a single OSD package.
    • It's possible that a patch could be provided for USMT 3.0 at some point.  This patch could be installed dynamically on top of the installed version of USMT.

    But there was one complication and one glitch in the process.  First, the complication:  There are four different installers:

    • InstallUSMT30_x86_2000andXP.exe, for Windows 2000 and Windows XP (x86 verion).
    • InstallUSMT30_x64_XP.exe, for Windows XP x64 only.
    • InstallUSMT30_x86_vista.msu, for Windows Vista x86.  (MSU files are the subject for another posting.)
    • InstallUSMT30_x64_vista.msu, for Windows Vista x64.

    So in most cases, you'll need at least two of these for any migration.  That's simple enough, since the ZTIUserState.wsf script figures out which one is needed and knows how to install each one.  Then there's the glitch:  Due to a bug in the Vista installation program, WUSA.EXE (used to install MSU files), USMT 3.0 would not install quietly using the standard "/quiet" switch.  This resulted in a workaround implemented in the ZTIUserState.wsf script and described in the BDD 2007 release notes (which hopefully you've read):

    • An issue exists in which BDD 2007 is unable to install USMT 3.0 on computers silently during deployment. Until this issue is resolved in USMT 3.0, repeat the following steps for the x86 and x64 versions of USMT 3.0 to repackage their files in to cabinet files from which BDD 2007 can extract USMT 3.0:

      1. Manually install the x86 or x64 version USMT 3.0 on a computer running Windows XP or Windows Vista.
      2. Copy C:\Program Files\BDD 2007\Samples\USMT30_platform.ddf, where platform is either x86 or x64, from a computer on which BDD 2007 is installed. If USMT 3.0 is installed in a location other than the default (C:\Program Files\USMT30), edit USMT30_platform.ddf to indicate its path.
      3. Run the command makecab /F USMT30_platform.ddf; then, copy the .cab file it creates (USMT30_platform.cab) to \Tools\platform folder in the BDD 2007 distribution share.

    Fortunately, since the release of USMT 3.0 there has been a hotfix made available for Windows Vista to fix this "/quiet" installation problem, so if you include this fix in your Windows Vista image you won't need to worry about the workaround above.  See http://support.microsoft.com/kb/929761/en-us for more information on that.

    Now, let's talk some about customization.

    You might not want to use the default USMT 3.0 settings for your deployment.  You may choose to create your own XML files, or to customize the provided XML files.  Some examples of the types of changes you might want to make:

    • Capturing an additional document type by specifying the file extension to look for.
    • Adding an additional set of application settings (via registry keys) to capture.
    • Specifying a directory for USMT to grab.

    One customization you probably don't want to make: removing stuff from the default XML files.  It's better to use a CONFIG.XML file to do that instead, but more on that later.  Going into the specifics of how to make the XML customizations like those I've listed above could be the subject of a book in itself (any takers?), so let's focus instead on the process of making use of the files that you've created or customized.  First, test your changes before trying to add them into a real deployment.  You can run "scanstate.exe" manually to figure out if your customizations actually work - that's a lot easier than going through an hour-long process just to figure out that you missed something.

    Once you've verified that your customizations work as expected, now you need to be able to tell BDD and USMT to use those new XML files.  So how do you do that?  Well, you need to specify the list of files on the command line that executes "scanstate.exe".  But the BDD ZTIUserState.wsf script builds that command line on the fly.  It uses a list property to figure out what XML files should be specified through "/i" parameters to "scanstate.exe".  But if you don't specify any values for that list property, it assumes that it should use the three default files:

    • miguser.xml
    • migapp.xml
    • migsys.xml

    Remember the discussion above about USMT 3.0 being installed locally?  Well, by default the original copies of these three files are installed with it.  So, if you have customized these files you need to place the updated versions somewhere that the ZTIUserState.wsf script can find them.  For Lite Touch, it checks a variety of locations on the deployment point:

    • In the "USMT" directory (e.g. \distribution\usmt)
    • In the "Tools" directory or a platform specific directory under it (e.g. \distribution\tools, \distribution\tools\x86)
    • In the "Templates" directory (e.g. \distribution\templates)
    • In the "Scripts" directory (e.g. \distribution\scripts)

    Take your pick.  The same applies for new files: just copy them into one of these folders.  But for Zero Touch, it's a little more complicated, as the files need to be part of the OSD package.  I would suggest the following steps:

    1. Copy the new or updated files into \distribution\tools\x86.
    2. Update the OSD deployment point, which causes the files to be replicated to each of the ZTI build directories, e.g. \zti\mybuild.
    3. From the SMS 2003 MMC, edit the OSD program properties.  On the existing ZTI custom action, add the new or updated files to the list of files required for the custom action.
    4. Refresh the SMS distribution points for this package.

    After doing this, the updated XML files should be in the package directory on all of the SMS distribution points, and the ZTIUserState.wsf script knows to look for them there.

    But how do you let the ZTIUserState know that you have new XML files that need to be added to the "scanstate" command line?  Well, that goes back to the "list property" that I described above.  The name of this parameter is "USMTMigFiles" and it is described in the "Configuration Reference" document like so:

    List of files in XML format that are used by USMT (ScanState.exe) to identify user state migration information to be saved. When this property is not specified, the ZTIUserState.wsf script uses MigApp.xml, MigUser.xml, and MigSys.xml. Otherwise, ZTIUserState.wsf uses the files explicitly referenced in this property. The USMTMigFiles property has a numeric suffix (for example, USMTMigFiles1 or USMTMigFiles2).

    Note:   Use this property to specify the .xml files to be used by ScanState.exe instead of using the /I parameter in the ScanStateArgs property. This prevents the ZTIUserState script from potentially duplicating the same list of .xml files.

    So, that means you need to configure the CustomSettings.ini rules to specify what files you want the ZTIUserState.wsf script to use.  And if you specify one file, it overrides the default list of three.  So let's assume that you want to use four files, the original three plus one new custom one that you've created.  In this case, you'd need entries in CustomSettings.ini like so:

    [Default]
    USMTMigFiles1=migapp.xml
    USMTMigFiles2=migsys.xml
    USMTMigFiles3=miguser.xml
    USMTMigFiles4=MyCustomFile.xml

    The ZTIUserState.wsf script would look for each of these files (in the directories specified above).  If found, it will copy them as long as the file doesn't already exist in the USMT installation directory on the local computer, by default C:\Program Files\USMT30.  If the files do exist, but the file in the installation directory is older than the one that the ZTIUserState found on the network, the script will overlay the older file.

    Now, back to the comment about config.xml above.  USMT 3.0 has the ability to generate and use a configuration file which says what components from the XML file should actually be processed.  By default, they all are.  But if you wanted to limit that, e.g. don't migrate a particular application's settings or files, you could do that by turning off that component.  The best way to go about this is to run "scanstate.exe" manually with /i parameters for each of the XML files you want to use, then specify the /genconfig parameter.  This will generate an XML file with all the components that would be migrated on the current computer, but not a complete list of the available entries.  Here's an example command:

    scanstate.exe /i:migsys.xml /i:miguser.xml /i:migapp.xml /genconfig:config.xml

    You would want to run this on a machine with most of the components present so that the config.xml has the largest number of entries, but it doesn't have to have all of them.  What you will want to do then is remove the components that you want to capture, then change only the remaining entries to say that you don't want to capture them (migrate="no").  For example, if I did not want to capture Windows Media Player settings, I would end up with a config.xml file that looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
      <Applications>
        <component displayname="Windows Media Player" migrate="no" ID="Settings|http://www.microsoft.com/migration/1.0/migxmlext/migapp/Windows Media Player/settings||||"/>
      </Applications>
    </Configuration>

    That brings us to the next challenge: making use of this customized config.xml file.  Unfortunately, the BDD 2007 ZTIUserState.wsf script does not provide a simple way of specifying that a config.xml file should be specified on the dynamically-generated "scanstate.exe" command line.  So, to use this config.xml file you will need to modify the ZTIUserState.wsf script.  Fortunately, someone has already done that, so you can check out Jason Scheffelmaer's blog entry at http://www.deployvista.com/Blog/tabid/70/EntryID/22/Default.aspx for more details.  Rest assured, we'll have this built into the next version of BDD.  (At the time we released, we didn't know you could build a "subset" config.xml file, so we thought the file was machine-specific.  Later we found out that wasn't true.)

    See, it's all really simple :-)

Page 3 of 27 (265 items) 12345»