Sep 11

ConfigMgr 2007 and creating a non-recurring Maintenance Window by script

At my current customer they’re not using the Software Updates of ConfigMgr 2007 (yet), but there was a wish for a more controlled company-wide deployment without having to change all the current advertisements (and the whole deployment system). So the idea came to create (and delete) maintenance windows by script (when needed).

Luckily the ConfigMgr 2007 SDK has some pretty straight forward examples of creating and deleting maintenance windows (see also the links at the end of this post). Deleting a maintenance window was almost just copy-paste from the SDK, the tricky part was creating a maintenance window and then especially the non-recurring schedule. At the end, this is (the short version of) what we ended up with:

‘====================================================
‘ MAIN – Set connection, schedule and call
‘====================================================
Set Connection = ConnectToSMSProvider("SiteServerName")
Schedule = NonRecurringScheduleString(connection, 3, “StartTimeInWMIFormat”, FALSE)
CreateMaintenanceWindow(connection, "CollectionID", "Name of Maintenance Window", "", Schedule, TRUE, 1)

‘====================================================
‘ Sub to add a Maintenance Window to a Collection
‘====================================================
Sub CreateMaintenanceWindow(connection, targetCollectionID, newMaintenanceWindowName, newMaintenanceWindowDescription, newMaintenanceWindowServiceWindowSchedules, _
                            newMaintenanceWindowIsEnabled, newMaintenanceWindowServiceWindowType)
    Set allCollectionSettings = connection.ExecQuery("Select * From SMS_CollectionSettings Where CollectionID = ‘" & targetCollectionID & "’")
    If allCollectionSettings.Count = 0 Then
        Set collectionSettingsInstance = connection.Get("SMS_CollectionSettings").SpawnInstance_
        collectionSettingsInstance.CollectionID = targetCollectionID
        collectionSettingsInstance.Put_
    End If 
    Set collectionSettingsInstance = connection.Get("SMS_CollectionSettings.CollectionID=’" & targetCollectionID &"’" )
    Set tempServiceWindowObject = connection.Get("SMS_ServiceWindow").SpawnInstance_
    tempServiceWindowObject.Name = newMaintenanceWindowName
    tempServiceWindowObject.Description = newMaintenanceWindowDescription
    tempServiceWindowObject.ServiceWindowSchedules = newMaintenanceWindowServiceWindowSchedules
    tempServiceWindowObject.IsEnabled = newMaintenanceWindowIsEnabled
    tempServiceWindowObject.ServiceWindowType = newMaintenanceWindowServiceWindowType
    tempServiceWindowArray = collectionSettingsInstance.ServiceWindows
    ReDim Preserve tempServiceWindowArray (Ubound(tempServiceWindowArray) + 1)
    Set tempServiceWindowArray(Ubound(tempServiceWindowArray)) = tempServiceWindowObject
    collectionSettingsInstance.ServiceWindows = tempServiceWindowArray
    collectionSettingsInstance.Put_
End Sub

‘====================================================
‘ Function to RETURN a Non Recurring Schedule
‘====================================================
Function NonRecurringScheduleString(connection, hourDuration, startTime, isGmt)
    Set recurInterval = connection.Get("SMS_ST_NonRecurring").SpawnInstance_()
    recurInterval.StartTime = startTime
    recurInterval.DayDuration = 0
    recurInterval.HourDuration = hourDuration
    recurInterval.MinuteDuration = 0
    recurInterval.IsGMT = isGmt
    Set clsScheduleMethod = connection.Get("SMS_ScheduleMethods")
    clsScheduleMethod.WriteToString Array(recurInterval), scheduleString
    NonRecurringScheduleString = scheduleString
End Function

‘====================================================
‘ Function to RETURN a Date/Time in WMI Format
‘====================================================
Function ConvertToWMIDate(strDate)
    strYear = year(strDate):strMonth = month(strDate)
    strDay = day(strDate):strHour = hour(strDate)
    strMinute = minute(strDate)
    If len(strmonth) = 1 Then strMonth = "0" & strMonth
    If len(strDay) = 1 Then strDay = "0" & strDay
    If len(strHour) = 1 Then strHour = "0" & strHour
    If len(strMinute) = 1 Then strMinute = "0" & strMinute
    ConvertToWMIDate = strYear & strMonth & strDay & strHour & strMinute & "00.000000+***"
End Function

‘====================================================
‘ 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

More information about creating a maintenance window: http://msdn.microsoft.com/en-us/library/cc146686.aspx
More information about deleting a maintenance window: http://msdn.microsoft.com/en-us/library/cc143140.aspx

Share
Jan 31

ConfigMgr 2007 and clearing a Computers’ Last PXE Advertisement by script

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.

ClrLstPXEAdvAn 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.

Option Explicit

DIM objSWbemLocator, objSWbemServices, ProviderLocation, Location, Connection
DIM colResourceID, objResourceID, iResourceID, aResources, InParams
DIM sComputerName, sSiteServerName, objArguments

sSiteServerName = “<SiteServerName>”

‘====================================
‘ Check arguments
‘====================================
Set objArguments = Wscript.Arguments
If WScript.Arguments.Count = 1 Then
   sComputerName = objArguments.Named.Item(“ComputerName”)
Else
   Wscript.Echo “Usage: ClearPxeAdvertisement.vbs /ComputerName:[ComputerName]”
   Wscript.Quit
End If

‘====================================
‘ MAIN Script
‘====================================
Set Connection = ConnectToSMSProvider(sSiteServerName)
iResourceID = GetResourceID(Connection, sComputerName)

aResources = Array(1)
aResources(0) = iResourceID

Set InParams = Connection.Get(“SMS_Collection”).Methods_(“ClearLastNBSAdvForMachines”).InParameters.SpawnInstance_
InParams.ResourceIDs = aResources

Connection.ExecMethod “SMS_Collection”,”ClearLastNBSAdvForMachines”, InParams
WScript.Echo “Cleared PXE advertisement for resource: ” & iResourceID

‘====================================
‘ 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

WScript.Quit(0)

There also exists an (basic) example on MSDN about How to Clear a PXE Advertisement for a Configuration Manager Resource, here: http://msdn.microsoft.com/en-us/library/cc143002.aspx

Share
Dec 27

ConfigMgr 2007 and removing a Computer from a Collection by script

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.

RemCompfrCollThe 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.

Option Explicit

DIM objSWbemLocator, objSWbemServices, ProviderLocation, Location, sSiteServerName
DIM sComputerName, sCollectionID, objCollection, colRuleSet, Rule, objArguments

‘=============================
‘ Check arguments
‘=============================
Set objArguments = Wscript.Arguments
If WScript.Arguments.Count = 2 Then
   sCollectionID = objArguments.Named.Item(“CollectionID”)
   sComputername = objArguments.Named.Item(“ComputerName”)
Else
   Wscript.Echo “Usage: RemoveComputerFromCollection.vbs /CollectionID:[CollectionID] /ComputerName:[ComputerName]”
   Wscript.Quit(0)
End If

‘=============================
‘ MAIN Script
‘=============================
sSiteServerName=”<SiteServerName>”
ConnectToSMSProvider(sSiteServerName)

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

WScript.Quit(0)

Share
Dec 06

ConfigMgr 2007 and changing the Package Source Directory by script

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.

Dim objSWbemServices

Set FSO = CreateObject (“Scripting.FileSystemObject”)
Set logFile = FSO.CreateTextFile (“PkgSourcePathLOG.csv”)

sOldServerShare = “<SERVER>\<SHARE>”
sNewServerShare = “<SERVER>\<SHARE>”
 
ConnectToSMSProvider()
ChangePkgSourcePath(“SMS_Package”)
ChangePkgSourcePath(“SMS_SoftwareUpdatesPackage”)
ChangePkgSourcePath(“SMS_ImagePackage”)
ChangePkgSourcePath(“SMS_OperatingSystemInstallPackage”)
ChangePkgSourcePath(“SMS_DriverPackage”)
ChangeContentSourcePath(“SMS_Driver”)

‘==================================
‘ 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

‘==================================
‘ Sub Routine to Change the Package Source Path
‘==================================
Sub ChangePkgSourcePath(strClass)
   Set colSWbemObjectSet = objSWbemServices.execQuery(“SELECT * FROM ” & strClass)
   For Each objSWbemObject In colSWbemObjectSet
      sOldPkgSourcePath = objSWbemObject.PkgSourcePath
      sNewPkgSourcePath = Replace(sOldPkgSourcePath, sOldServerShare, sNewServerShare)
      logFile.Write “Setting Package Source Path for ” & objSWbemObject.Name & ” from ” & sOldPkgSourcePath & ” to ” & sNewPkgSourcePath
      objSWbemObject.PkgSourcePath = sNewPkgSourcePath
      objSWbemObject.put_
   Next
End Sub

‘==================================
‘Sub Routine to Change the ContentSource of Drivers
‘==================================
Sub ChangeContentSourcePath(strClass)
   Set colSWbemObjectSet = objSWbemServices.execQuery(“SELECT * FROM ” & strClass)
   For Each objSWbemObject In colSWbemObjectSet
      sOldPathString = objSWbemObject.ContentSourcePath
      sNewPathString = Replace(sOldPathString, sOldServerShare, sNewServerShare)
      logFile.Write “Setting Content Source Path for ” & objSWbemObject.LocalizedDisplayName & ” from ” & sOldPathString & ” to ” & sNewPathString
      objSWbemObject.ContentSourcePath = sNewPathString
      objSWbemObject.put_
   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.

Share