Scripting

One of the biggest challenges with OS Deployment is keeping track of all the different deployments and everything that changed between the deployments. This post will focus on the first part, keeping track of all the different deployments. I will do that by showing a way to write information to the registry, creating a hardware inventory for those registry keys and building a report on the inventory data. For the second part, keeping track of all the changes, take a look at this great post of Maik Koster.

Create registry keys

The first thing is to create a script that will write information about the deployment to the registry. As a deployment is much more then just the image, we need information about the task sequence. There are multiple ways to put a version number somewhere in the task sequence. I choose to write a version number in the task sequence name. Besides that I also write some extra information to the registry about the different Id’s and how it was deployed (see picture). To do this I use a very basic script like this (change PETERTEST to something different, like a company name):

Now to run this script, save it as a vbs file and add it to a package. In the task sequence (see picture) add a Run Command Line –step, select Package and Browse to the package with the new script. In the Command line add cscript.exe <ScriptName> and select Disable 64-bit file system redirection. This last action makes sure that the registry information will be written to the same key on all systems, so there is no need for multiple inventory classes.

Extend Hardware Inventory

The second thing is to create a hardware inventory for the newly created registry keys. There are two ways to do this. The first one is to create our own extensions and the second one is to use the tool RegKeyToMof. I choose to use the second way, as that tool makes my life a whole lot easier. On a computer, which has run the task sequence, open the tool RegKeyToMOFv31 and browse in the top screen to the new registry key. In the bottom screen it will now show the necessary extensions for the different MOF files. Also fill in a good Class Name (I use DeploymentVersion), as this will also be part of the table and view names in the database.

Now go to <InstallDir>\inboxes\clifiles.src\hinv, open the configuration.mof, go all the way to the bottom of this file and add the content of the configuration.mof –tab between the lines Added extensions start and Added extensions end. Assuming this is the first extensions, it will make it look similar to this (remember that PETERTEST might be different, when it’s changed in the initial script):

After this go to the to import in Admin/AgentSettings/HardwareInventory/SetClasses/Import –tab and add the content to a new (temporary) MOF file. This will create a MOF file with the following content:

Now open the Configuration Manager Console and navigate to Administration > Client Settings. Open (for example) the Default Client Settings, go to Hardware Inventory and click Set Classes. In the Hardware Inventory Classes, click Import and Open the new (temporary) MOF file. This will show the new class for the inventory.

Create report

The third, and last, thing to do is to create a report based on the new registry information. This is probably a lot easier then you might think, because adding a new class to the hardware inventory also creates new tables and views in the database. As I used DeploymentVersion, as the class name for the extension of the hardware inventory, the view in the database with the information is named v_GS_DeploymentVersion. So to get the new information in a report, including computer name, we need the following query:

Now to put all the pieces together, open SQL Server Report Builder 3.0 and create a new report. Add a Data Source to the ConfigMgr database and create a DataSet with the previously mentioned query. The last things to do is add a table to report, add the necessary fields and save the report between the other ConfigMgr Reports. Open the Configuration Manager Console, navigate to Monitoring > Overview > Reporting > Reports and that’s where the new report will show up.

Result

Wondering what the end result looks like? Well, here is a basic example of what it will look like:

In a previous post I showed a script to remove a computer from a collection. This post will be an add-on to that previous post. As we are removing the computer from the collection anyway, we can as well perform a Clear Last PXE Advertisement –action. By doing this, it’s not necessary to perform a manual action the next time the computer needs to be re-imaged.

An easy way to do this is to run a script at the end of a Task Sequence that will clear the last PXE Advertisement. This makes sure that a computer can get re-imaged as soon it gets added to the correct collection. For this you can use the script from this post.

The usage of this script is cscript <ScriptName>.vbs /ComputerName:[ComputerName]. Keep in mind that it needs to be run with an account that has enough rights in ConfigMgr. See also this picture for an example.

‘====================================
‘ Function to RETURN a Connection to the SMS Provider
‘====================================
Function ConnectToSMSProvider(ServerName)
Set objSWbemLocator = CreateObject(“WbemScripting.SWbemLocator”)
Set objSWbemServices = objSWbemLocator.ConnectServer(ServerName, “root\sms”)
Set ProviderLocation = objSWbemServices.InstancesOf(“SMS_ProviderLocation”)
For Each Location In ProviderLocation
If Location.ProviderForLocalSite = True Then
Set objSWbemServices = objSWbemLocator.ConnectServer(Location.Machine, “root\sms\site_” + Location.SiteCode)
Set ConnectToSMSProvider = objSWbemServices
End If
Next
End Function

‘====================================
‘ Function to RETURN a ResourceID by a ComputerName
‘====================================
Function GetResourceID(Connection, ComputerName)
Set colResourceID = Connection.ExecQuery(“Select ResourceID from SMS_R_System where Name = ‘” & ComputerName & “‘”)
For Each objResourceID in colResourceID
GetResourceID = objResourceID.ResourceID
Next
End Function

I have to admit that it’s just really easy/ handy to create scripts to make life a bit easier. This also counts for this scenario… A customer wants to prevent, at all costs, that a computer can’t get re-imaged “by accident”. It already happened a few times that somebody by accident did a Clear Last PXE Advertisement on a Computer, or even on a Collection.

An easy solution for this scenario is to run a script at the end of a Task Sequence that will remove the Computer directly from the Collection. This makes sure that a computer can’t get re-imaged, as it’s not a member of the collection anymore. For this you can use the script from this post.

The usage of this script is cscript <ScriptName>.vbs /CollectionID:[CollectionID] /ComputerName:[ComputerName]. Keep in mind that it needs to be run with an account that has enough rights in ConfigMgr. See also this picture for an example.

Set objCollection = objSWbemServices.Get(“SMS_Collection='” & sCollectionID & “‘”)
colRuleSet = objCollection.CollectionRules
For Each Rule In colRuleSet
If Rule.Path_.Class = “SMS_CollectionRuleDirect” Then
If LCase(Trim(Rule.RuleName)) = LCase(Trim(sComputerName)) Then
objCollection.DeleteMembershipRule Rule
Wscript.Echo “Succesfully removed ” & sComputerName & ” from collection: ” & sCollectionID
End If
End If
Next

‘=============================
‘ Sub Routine to Connect to the SMS Provider
‘=============================
Sub ConnectToSMSProvider(SiteServerName)
Set objSWbemLocator = CreateObject(“WbemScripting.SWbemLocator”)
Set objSWbemServices = objSWbemLocator.ConnectServer(SiteServerName, “root\sms”)
Set ProviderLocation = objSWbemServices.InstancesOf(“SMS_ProviderLocation”)
For Each Location In ProviderLocation
If Location.ProviderForLocalSite = True Then
Set objSWbemServices = objSWbemLocator.ConnectServer(Location.Machine, “root\sms\site_” + Location.SiteCode)
End If
Next
End Sub

Sometimes there is a good reason to get out of your comfort zone. One of those reasons is moving the Source Directory of all packages to a different server/ share. This means there has to come a script to change the Source Directory of all packages, as it is not a job that you want to do manually, and scripting is not really my thing… But as it cost me some time to create something nice of it, I will share it so everyone can “enjoy it”.

I created three subroutines, one for connecting to the SMS Provider, one for changing the Package Source Path and one for change the Content Source Path. The Package Source Path counts for all the different types of packages and the Content Source Path only counts for Drivers. The only thing that needs to be adjusted is the old and the new location of the Package Source Directory. This script needs to be run from the Site Server.

‘==================================
‘ Sub Routine to Connect to the SMS Provider
‘==================================
Sub ConnectToSMSProvider()
Set objSWbemLocator = CreateObject(“WbemScripting.SWbemLocator”)
Set objSWbemServices = objSWbemLocator.ConnectServer(“.”, “root\sms”)
Set ProviderLocation = objSWbemServices.InstancesOf(“SMS_ProviderLocation”)
For Each Location In ProviderLocation
If Location.ProviderForLocalSite = True Then
Set objSWbemServices = objSWbemLocator.ConnectServer(Location.Machine, “root\sms\site_” + Location.SiteCode)
End If
Next
End Sub

Keep attention to the fact that changing the Source Directory will make the Distribution Point re-process the packages. This is the part that virtual application packages don’t like. They will generate lots of errors in the distrmgr.log and to fix it I had to touch them all and re-select the XML –file from the original project directory.

Award

Subscribe to updates

About

I’m Peter van der Woude, born in 1983 and I’m living together with my wife and two sons in the Netherlands.

Currently I work for KPN Consulting. At this moment my main focus is Enterprise Client Management via Microsoft Intune and/ or System Center Configuration Manager (ConfigMgr 2007/ 2012/ CB) and I love it!