Archive for September, 2009|Monthly archive page
USB Boot Disk
We’re building a load of laptop kit. Problems with the WAN make PXE booting impossible for now, and the laptops don’t have optical drives. Obviously a USB Flash boot disk is the answer. It’s worth a quick note as to how to create these:
Insert the USB Stick into a computer running the Vista or Windows 7, then use diskpart:
diskpart
select disk 2*
clean
create partition primary
select partition 1
active
format fs=fat32
assign
exit
Now create Task Sequence media boot ISO. Mount the ISO and copy the contents to the USB stick.
Easy as that!
*NB: The value of disk 2 is the USB Stick’s disk ID. You can find this in Disk Manager.
Package Mapping in the Replace Computer Scenario
The MDT Package Mapping approach is a great bit of OS deployment technology and can help to provide an excellent deployment rate when it comes to large-scale zero touch deployment projects. One limitation that currently exists is that package mapping only works in the refresh computer scenario, i.e. I’m moving from XP to Vista, when I install my Vista image, put back the applications which I used to have.
For the Replace Computer scenario, where we’re deploying new hardware, out of the box, package mapping does nothing for us.
In the ConfigMgr Replace Computer scenario we use ConfigMgr Computer Associations to provide the capability to recover the user state (via a state migration point) from the OLDCOMPUTER to the NEWCOMPUTER during the build process. We run the Replace Computer Scenario task sequence on the OLDCOMPUTER, this captures the user state, then the NEWCOMPUTER state restore phase magically recovers this. All good stuff, but it doesn’t help us with the apps…
But it can. A small change to the PackageMapping stored procedure can use the same Computer Association record to migrate the applications across machines in the same way as we migrate the user state. It’s a shame that this isn’t integrated in the ConfigMgr console as elegantly as the Computer Associations are, but it works…
First we need to import the NEWCOMPUTER into ConfigMgr using the Import Computer Information wizard. Select the OLDCOMPUTER as the Source for the NEWCOMPUTER (obviously this can be done on a large-scale by populating a CSV file with these entries).
Next we need to modify the PackageMapping process so that it runs against the MACAddress of the OLDCOMPUTER rather than the NEWCOMPUTER.
In SQL Management Studio, browse to the PackageMapping stored procedure and select to modify it. Replace the entry shown with this text (replace SMS_JON with the name of your SMS database)
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[RetrievePackages] @MacAddress CHAR(17) AS SET NOCOUNT ON /* Select and return all the appropriate records based on OLDCOMPUTER inventory */ SELECT * FROM PackageMapping WHERE ARPName IN ( SELECT ProdID0 FROM SMS_JON.dbo.v_GS_ADD_REMOVE_PROGRAMS a, SMS_JON.dbo.v_GS_NETWORK_ADAPTER n WHERE a.ResourceID = n.ResourceID AND MACAddress0 = (select sourceMACAddresses from SMS_JON.dbo.v_statemigration where restoreMACAddresses=@MacAddress) AND n.ResourceID IN (Select ResourceID from SMS_JON.dbo.v_R_System_Valid))
A little explanation of what is happening here:

With a thorough PackageMapping database and thorough User State Migration profile and very good planning in terms of assigning the OLDCOMPUTER and NEWCOMPUTERs through Computer Associations we can achieve a near seamless and very high performance desktop replacement approach.
Package Mapping v2
The MDT Package Mapping functionality (Scenario 5: Dynamic Computer-Specific Application Installation to give it its MDT name)
provides for the automatic re-installation of ConfigMgr applications during OS re-imaging. This is done via interrogation of the ADD_REMOVE_PROGRAMS SQL view. The deployment database contains a PackageMapping database. This is used to pair an Add/Remove Program inventory entry (ARP) with a ConfigMgr package and program in this way:

The database supplied with the deployment database does not contain the Comment and ID tables shown above, but I’m finding these are pretty useful. Comments are handy as the database gets larger and the ID field is used as a primary key on the table so that we can update the database from a Microsoft Access front end.
Populating the database with new mapping entries is somewhat error-prone… The ARP entries are often GUIDs, and the Packages entry requires the package ID and exact program name. Any of these entered incorrectly results in a failed build which can be awkward to troubleshoot. The only minor complexity on this is that the ID table should be configured as IsIdentity (AutoNumber) in SQL:
To reduce the risk of incorrect entries being added I have knocked up a quick MS Access form to allow selection of the ARP name and Install Package entry. To build this all we need are a couple of ODBC entries one "PackageMapping" connected to the DEPLOYMENT database and another "ARPData" connected to the ConfigMgr database.
Now we just need some linked tables in Access.
|
|
The PackageMapping table is from the DEPLOYMENT database. The others are SQL views from ConfigMgr The field highlighted in red builds the MappingEntry field to |
|
This structure allows us to select the PackageID from a list of all Packages, but displays the friendly package name.
Some Minor Package Mapping Improvements
The MDT Package Mapping functionality is an excellent way of providing application migration during zero touch OS deployment. Coupled with a decent USMT configuration you can get some really good results to provide a seamless OS refresh.
We’re using Package Mapping extensively on a current Zero-Touch project and have come across some minor issues related to obsolete resource records.
For example, machine PC001 has ten applications which are in-scope for package mapping (i.e. the Add/Remove Program (ARP) entries they have are mapped to ConfigMgr packages in the MDT PackageMapping table). PC001 has a problem and is rebuilt using the legacy Ghost approach by IS support. Of the ten applications which were installed previously, only three are actually required by the user, so only these three are replaced.
A couple of months go by… We’re finally in a position to deploy our new ZTI image to PC001, the install goes fine, but ten apps are re-installed to the machine when the image is installed. Checking the ARP record in Resource Explorer for the machine previously revealed only three in-scope apps, so what’s happened?
Pretty straightforward stuff, the stored procedure used to populate the PackageMapping entries (PACKAGESxxx) in the image installation task sequence does a lookup for the ConfigMgr ResourceID using the host machine’s MAC Address; this ResourceID is then used to interrogate the ARP entries table for all apps at last hardware inventory cycle. The problem is that when the query for the ResourceID is executed, it gets two results, the one from before the machine was re-Ghosted and the new record created when the machine re-joined the infrastructure. The old record will ultimately be aged out of the database (after 90 days) but in the mean time it’s hanging around, even though the old resource has been removed from the Admin Console.
The consequence of this is that the obsolete ResourceID is used by the PackageMapping process and thus the wrong apps are re-installed to the client. The same problem occurs in the lab when re-imaging test machines; even when the test machine’s record is deleted from the admin console, its inventory data remains and will be used by the PackageMapping process.
The fix for this is to modify the MDT RetrievePackages stored procedure to validate the ResourceID against the new ConfigMgr R_System_Valid view.
To do this using SQL Server Management Studio browse to the stored procedure, right click – modify, then add the following to the end of the supplied code:
AND n.ResourceID IN (Select ResourceID from SMS_xxx.dbo.v_R_System_Valid )
Alternatively, replace the provided stored procedure by executing:
use [Deployment]
go
if exists (select * from dbo.sysobjects where id = object_id(N’[dbo].[RetrievePackages]‘) and OBJECTPROPERTY(id, N’IsProcedure’) = 1)
drop procedure [dbo].[RetrievePackages]
go
CREATE PROCEDURE [dbo].[RetrievePackages]
@MacAddress CHAR(17)
AS
SET NOCOUNT ON
/* Select and return all the appropriate records based on current inventory */
SELECT * FROM PackageMapping
WHERE ARPName IN
(
SELECT ProdID0 FROM SMS_xxx.dbo.v_GS_ADD_REMOVE_PROGRAMS a, SMS_xxx.dbo.v_GS_NETWORK_ADAPTER n
WHERE a.ResourceID = n.ResourceID AND
MACAddress0 = @MacAddress
AND n.ResourceID IN (Select ResourceID from SMS_xxx.dbo.v_R_System_Valid ))
go
Now when Package Mapping is called, only non-obsolete data will be used and everything will function as expected. This has the added advantage in a lab of allowing you to delete the resource record of a test PC from the console and have that machine return no results from Package Mapping.
Thanks to John Nelson for his help with this on MyITForum.
Modify Package Source
We’re using Kim Oppalfens’ rather wonderful approach for migrating to ConfigMgr from a large SMS 2003 implementation. We don’t want to take the SMS hardware, but we do want the investment we’ve made in the development in the console (hundreds of packages, collections and advertisements which would take us a long time to set up again).
Kim’s approach implements a new child Primary SMS 2003 server. The package, collection and advertisement content is replicated to the child. We copy the package source across to the new server, detach from the parent and the packages etc become ‘owned’ by the new SMS site. This site can then be upgraded to ConfigMgr. This is great, one slight fly in the ointment is that on the old server the packages are stored in G:\DIST_Source\Vendor\Appname and on the new server they’ll be in D:\packages\Vendor\Appname.
Once the child site has been detached, the package source must be modified. This can be done using Transact-SQL and the most efficient (in terms of code) way of doing this in SQL 2005 is using REPLACE command.
USE SMS_XXX
UPDATE SMSPackages
SET Source = REPLACE(CAST(Source AS NVARCHAR(MAX)),
‘G:\DIST_source’,
‘D:\Packages’)
Note it’s important to cast ‘Source’ as NAVCHAR as REPLACE won’t work on STRING types.
Setting the Local Administrator Password with ConfigMgr Collection Variables
ConfigMgr provides an elegant opportunity to manage the local administrator password using a task sequence, collection variable, a package and a little bit of VBScript.
At the most basic level, we want to be able to manage the password of the local administrator account. We want to be able to set the password to be the same across all machines (security issues aside…). To do this we create a collection variable on the “All Windows Workstation or Professional Systems” ADMINPASSWORD=ourpassword.
This is obfuscated in the console, so can’t be read.
We have a package that just contains a single VBScript:
sNewPassword = Wscript.Arguments(0)
Set oWshNet = CreateObject(“WScript.Network”)
sComputer = oWshNet.ComputerName
sAdminName = GetAdministratorName
On Error Resume Next
Set oUser = GetObject(“WinNT://” & sComputer & “/” & sAdminName & “,user”)
oUser.SetPassword sNewPassword
oUser.SetInfo
On Error Goto 0
Function GetAdministratorName()
Dim sUserSID, oWshNetwork, oUserAccount
Set oWshNetwork = CreateObject(“WScript.Network”)
Set oUserAccounts = GetObject( _
“winmgmts://” & oWshNetwork.ComputerName & “/root/cimv2″) _
.ExecQuery(“Select Name, SID from Win32_UserAccount” _
& ” WHERE Domain = ‘” & oWshNetwork.ComputerName & “‘”)
On Error Resume Next
For Each oUserAccount In oUserAccounts
If Left(oUserAccount.SID, 9) = “S-1-5-21-” And _
Right(oUserAccount.SID, 4) = “-500″ Then
GetAdministratorName = oUserAccount.Name
Exit For
End if
Next
End Function
Our task sequence has a single step to call this script from the package we’ve created. The script takes a single parameter of %ADMINPASSWORD%, read by the task sequencing engine from the collection variable created above.
Obviously, this can be advertised out on a recurring schedule to reset password regularly and the only administrative change required is to replace the collection variable value. It is also easily possible to create different collection variable values for different collections, or even on a per-machine basis if desired, simply set the precedence on the new entry to be higher than the default.
Creating Collections from the Command Line
I’ve not done much work with the ConfigMgr SDK before, but a project I’m working on at the moment called for a large number of collections to be created for application distribution purposes. This is a direct replacement for ZEN Works, so to try to minimize the impact on the helpdesk we’ve decided to populate AD security groups with computer accounts to drive the population of the ConfigMgr collections. It’s not an approach that I’m particularly in favour of as it introduces latency:
|
Using AD Security Groups for Collection Population |
Using Direct Membership in the ConfigMgr Console |
|
|
|
|
|
|
Assuming the worst-case scenario this approach could take: AD Replication – 15 mins System group Discovery – 60 mins Colleval – 60 mins Computer Client update – 60 mins Maximum possible latency=3hrs 15 minutes |
Assuming the worst case scenario this approach would take: Computer Client update – 60 mins Maximum possible latency=60 minutes |
|
These issues aside, I decided to have a go at creating my many application based collections using a bit of VBScript from the SDK.
I always like to create a clean collection structure from the outset with a small number of root collections with sub collections. I normally break these down as shown:

This approach keeps the collection structure tidy, but means that creating collections using COLLADD won’t work as this script doesn’t set the parent collection, creating everything in COLLROOT. If you’re going to have to move them all manually later (by linking and then deleting the original) then you may as well create them manually in the first place.
Fortunately the SDK provides great samples on creating objects in the console, and the CreateDynamicCollection function automatically expects the Collection ID of the parent collection.
The script I have used is copied verbatim from the SDK with one minor modification to allow for escaping of the quotes around the AD System group Name:
Script1
‘ Setup a connection to the local provider.
Set swbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set swbemconnection= swbemLocator.ConnectServer(".", "root\sms")
Set providerLoc = swbemconnection.InstancesOf("SMS_ProviderLocation")
For Each Location In providerLoc
If location.ProviderForLocalSite = True Then
Set swbemconnection = swbemLocator.ConnectServer(Location.Machine, "root\sms\site_" + Location.SiteCode)
Exit For
End If
Next
Call CreateDynamicCollection(swbemconnection, "XXX0001B", "App Blueprint", "Members will receive the application", true, "SELECT * from SMS_R_System where SMS_R_System.SystemGroupName = ""MYDOMAIN\App Blueprint""", "App Blueprint")
‘NB As the AD Group Names may have spaces in them it is necessary to escape the quotes. The above query line is wrapped for legibility.
Sub CreateDynamicCollection(connection, existingParentCollectionID, newCollectionName, newCollectionComment, ownedByThisSite, queryForRule, ruleName)
‘ Create the collection.
Set newCollection = connection.Get("SMS_Collection").SpawnInstance_
newCollection.Comment = newCollectionComment
newCollection.Name = newCollectionName
newCollection.OwnedByThisSite = ownedByThisSite
‘ Save the new collection and save the collection path for later.
Set collectionPath = newCollection.Put_
‘ Define to what collection the new collection is subordinate.
‘ IMPORTANT: If you do not specify the relationship, the new collection will not be visible in the console.
Set newSubCollectToSubCollect = connection.Get("SMS_CollectToSubCollect").SpawnInstance_
newSubCollectToSubCollect.parentCollectionID = existingParentCollectionID
newSubCollectToSubCollect.subCollectionID = CStr(collectionPath.Keys("CollectionID"))
‘ Save the subcollection information.
newSubCollectToSubCollect.Put_
‘ Create a new collection rule object for validation.
Set queryRule = connection.Get("SMS_CollectionRuleQuery")
‘ Validate the query (good practice before adding it to the collection).
validQuery = queryRule.ValidateQuery(queryForRule)
‘ Continue with processing, if the query is valid.
If validQuery Then
‘ Create the query rule.
Set newQueryRule = QueryRule.SpawnInstance_
newQueryRule.QueryExpression = queryForRule
newQueryRule.RuleName = ruleName
‘ Add the new query rule to a variable.
Set newCollectionRule = newQueryRule
‘ Get the collection.
Set newCollection = connection.Get(collectionPath.RelPath)
‘ Add the rules to the collection.
newCollection.AddMembershipRule newCollectionRule
‘ Call RequestRefresh to initiate the collection evaluator.
newCollection.RequestRefresh False
End If
End Sub
When executed the script automatically creates the required collection beneath my "Applications" parent collection (XXX0001B) with the query which enumerates all machines in the "APP Blueprint" AD group.
MDT Lite Touch Driver Management
We’ve had some problems over the past couple of weeks with our RTM Windows 7 rollout. Everything was going fine and then the gremlins seem to creep in and suddenly the install of Windows 7 would just hang at the “Completing Installation” phase of the image install. This didn’t appear to be anything to do with MDT as Windows is off on its own at this point.
I eventually realised that I’d made a mess of the driver management in the MDT Workbench. We have been using MDT to build both XP and Windows 7 whilst Windows 7 was in Beta and Release Candidate. We’re now ending our XP deployments, but are keeping the build in the workbench for now for legacy support reasons (and VM builds…). We have a massive Windows XP driver repository which, in truth, we could have managed better. Windows 7 on the other hand is fairly tidy as we need very few drivers at the moment (over 89% of the devices on our network are supported on the Windows 7 RTM media according to our MAP assessments). I’d separated XP and Windows 7 drivers out into separate folders in the workbench:
But this was as far as my separation had got. Quite how I thought MDT was going to sort through all this I’m not sure… Anyway, the point of this post is that we can now use MDT’s new Selection Profiles to manage which drivers are added to which machines in the Task Sequence. There’s a couple of things we have to do…
First, create a folder structure for your drivers such as that above (I also split drivers out by machine model below the OS folder for better management; in large environments this is crucial).
Next Create a selection profile per OS:
Each selection profile allows you to select the driver folder you want to be included
Now in the task sequence for Windows 7 we can force the Apply Drivers task to only reference the “Windows 7 Drivers” selection profile:
Now when the install of the image runs, we only attempt to inject Windows 7 drivers. It speeds up the build process and fixes the hanging issue…
MDT 2010 RTM
MDT 2010 RTM’d yesterday, so when better to install?
RTM is version 5.0.1641.0

It (naturally) wants the release version of WAIK 3.0:

Once the old WAIK is removed and the new WAIK installed:

Sort out the wimgapi.dll clash and we’re away… (well, almost)

Got to upgrade the deployment share again (this is the third time, from beta to RC to release. Nice job that the deployment team support upgrade this far, it’s saved us recreating anything every time…)

Once that’s done we’ll update the deployment share to update our boot images etc: The update process detects that there’s a new WAIK version, so opts to update the boot image

Following this and copying the updated boot image to our WDS server, we’re off building machines again!
A Portable Highly Available Hyper-V and System Center Demo Environment – Shopping for kit…
The Windows 7 work that’s been going on internally recently has kept me pretty busy, but along with that I’ve also been sticking my oar into expanding our System Center offerings. We already participate heavily in delivery of Desktop Deployment Planning Services (DDPS), essentially a Solution Accelerator for the implementation of Microsoft Deployment Toolkit and System Center Configuration Manager for large-scale (oftentimes remote) OS deployment and desktop optimization. We also participate in DOVO, an offering from Microsoft around adoption of Vista and Office 2007 and in SMO, Service Management Optimization, which is a System Center Operations Manager adoption approach in the same solution catalogue as DOVO.
At MMS this year Microsoft (and others) demonstrated some pretty cool stuff with Hyper-V R2 and System Center combining to provide superb functionality. Much of this new functionality relies on the latest of everything, including the R2 System Center releases and the latest server platforms (for example HP’s G6 models). The hardware aspects are interesting as they deliver advanced environmental monitoring which is exposed to OpsMgr. This in turn enables OpsMgr to communicate with VMM to make intelligent placement suggestions via PRO. For example, we might set a power SLA for a particular server, or a particular rack and should the virtual machine load on the server result in the power SLA being exceeded, OpsMgr can inform VMM via PRO, VMM can then Live Migrate VM(s) to less utilised servers to bring the SLA back into compliance.
This is all great, and certainly something that customers are very interested in, but to demo it’s pretty complex. We have a decent demonstration suite at our Head Office, but I want to be able to take this stuff on the road to show to customers, so a portable environment is required.
The first new aspect to all of this stuff is a need for shared storage. iSCSI is the obvious solution and after a bit of research, the QNAP TS-119 looked as good a choice as any… This has so far proved to be a good choice, the build quality is superb which for a portable device is very important of course and with 1TB storage it comes in under £300 which is a great result.
Then I need something to boot into Hyper-V. I already have an excellent (if now slightly old) HP Compaq NW9440 laptop with 4GB RAM which I use every day, this will ably act as one host, but obviously for high availability I need another, my purchase req for that is in at the moment. In the mean time I need a way to boot this machine into Hyper-V. I don’t particularly want to dual boot Windows 7, and fortunately I don’t need to. Windows Server 2008 R2 is fully supported booting from removable media, so a couple of 16GB Kingston USB memory sticks are required. While we’re at it, I need a way of hooking the computers to the NAS. This Netgear 5 port Gigabit switch is slightly smaller than two packs of cards, supports Jumbo Frames and again boasts excellent build quality, excellent for £56.
Lovely.
Now to make it work!
Comments (2)

