widsnet.com
20Dec/170

Check if IP is between range (Boundaries)

Check if an IP address is inside an existing boundary.

$SiteServer = ""
$SiteCode = ""

Function Get-MatchingBoundary {
    Param(
    [parameter(Mandatory=$true)]$Boundaries,
    [parameter(Mandatory=$true)]$IPAddress)

    $Result = 0

    ForEach ($Boundary in $AllBoundaries) {
        $BoundaryName = $Boundary.DisplayName
        $IPRangeStart, $IPRangeEnd = $Boundary.Value.Split("-")

        $ParseIP = [System.Net.IPAddress]::Parse($IPAddress).GetAddressBytes()
        [Array]::Reverse($ParseIP)
        $ParseIP = [System.BitConverter]::ToUInt32($ParseIP, 0)

        $ParseIPStart = [System.Net.IPAddress]::Parse($IPRangeStart).GetAddressBytes()
        [Array]::Reverse($ParseIPStart)
        $ParseIPStart = [System.BitConverter]::ToUInt32($ParseIPStart, 0)

        $ParseIPEnd = [System.Net.IPAddress]::Parse($IPRangeEnd).GetAddressBytes()
        [Array]::Reverse($ParseIPEnd)
        $ParseIPEnd = [System.BitConverter]::ToUInt32($ParseIPEnd, 0)

        if (($ParseIP -ge $ParseIPStart) -and ($ParseIP -le $ParseIPEnd)) {
            if ($BoundaryName.Length -ge 1) {
                $Results = 1
                Write-Output "$IPAddress is within: $BoundaryName"
            }
            else {
                $Results = 1
                Write-Output "$IPAddress is within: Range $($Boundary.Value)"
            }
        }
    }
    if ($Results -eq 0) {
        Write-Output "$IPAddress is not in any boundary"
    }
}

[Net.IPAddress]$IPaddress = "10.89.184.85"

# Get all boundaries from SCCM
$AllBoundaries = Get-WMIObject -computer "$SiteServer" -Namespace "Root\SMS\Site_$SiteCode" -Class "SMS_Boundary" -Filter "BoundaryType = 3"

Get-MatchingBoundary -Boundaries $AllBoundaries -IPAddress $IPaddress
22Aug/170

Offline servicing fails with error 2095

The solution can be found here: http://www.syswow64.co.uk/2015/12/sccm-2012-r2-offline-servicing-error.html
Basically its the wim file that wants to reboot.

dism /mount-wim /wimfile:C:\temp\install.wim /index:1 /mountdir:c:\temp\mount

reg load HKLM\MyKey c:\temp\mount\windows\system32\config\software
regedit

Find the registry key
HKLM\MyKey\Microsoft\Windows\CurrentVersion\Compnent Based Servicing\SessionsPending
Take ownership of root Key
Assign Full Control to Administrator
Edit the DWORD Exclusives to value 0 (in my case it was 3)

Unload the registry
reg unload HKLM\MyKey

Commit the changes to the wim
dism /unmount-wim /mountdir:c:\temp\mount /commit

20Apr/170

Create regvalues from TS variables

script to add in a TS to save certain task sequence variables to the registry, for whatever reason ...
Syntas looks like this. First argument is the start name of the variables. Second argument is the registry key to store the variables:
cscript CreateRegvaluesFromTSVariables.vbs "PostTS" "Software\HM\PostTSInstall"

Const HKEY_LOCAL_MACHINE = &H80000002

Set oRegistry = GetObject("winmgmts:\\.\root\default:StdRegProv")
Set oArguments = WScript.Arguments

If oArguments.Count <> 2 Then
	WScript.Echo "Usage:"
	WScript.Echo "cscript " & Wscript.ScriptName & " ""variableName"" ""RegKey"""
	WScript.Echo " variableName" & vbTab & "Ex: ""HM"" if TS variables are Called HMIPNetmask and HMIPServer"
	WScript.Echo " RegKey" & vbTab & "Ex: Software\HM\ (Always under HKLM)"
	WScript.Echo ""
	WScript.Echo "The name after variableName will be created in the registry under RegKey with the value specified for the variable."
	WScript.Echo "Ex: If Task Sequence Variable HMIPNetmask is set to 255.255.255.0"
	WScript.Echo """IPNetMask"" will be created as a string under RegKey with Value ""255.255.255.0"""
	WScript.Quit 10022 'An invalid argument was supplied.
End If

sVariable = oArguments.Item(0)
sRegKey = oArguments.Item(1)

CreateKey(sRegKey)

'Gather OSD Variables and create registry values
Set osdVar = CreateObject("Microsoft.SMS.TSEnvironment")  
For Each sVar in osdVar.GetVariables() 
	If LCase(Left(sVar, Len(sVariable))) = LCase(sVariable) Then
		sValueName = Replace(sVar, sVariable, "", 1, 1, vbTextCompare)
		sValue = osdVar(sVar)
		If sValue <> "" Then
			CreateStringValue sRegKey, sValueName, sValue
		End if
	End If
Next

Sub CreateKey(sRegKey)
	oRegistry.CreateKey HKEY_LOCAL_MACHINE, sRegKey
End Sub

Sub CreateStringValue(sRegKey, sValueName, sValue)
	oRegistry.SetStringValue HKEY_LOCAL_MACHINE, sRegKey, sValueName, sValue
End Sub
20Apr/170

Syncronize time in a task sequence

Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set oShell = CreateObject("Wscript.Shell")
Set objOSDEnv = CreateObject("Microsoft.SMS.TSEnvironment")
sLogPath = objOSDEnv("_SMSTSLogPath")

sLogFileName = Replace(WScript.ScriptName, ".vbs", ".log")
logThis "LogFile: " & sLogPath & "\" & sLogFileName

sUser = objOSDEnv("_SMSTSReserved1-000")
sPassword = objOSDEnv("_SMSTSReserved2-000")

logThis "%comspec% /c NET USE \\SERVER\IPC$ """ & "<password>" & """ /USER:" & sUser
Set oExec = oShell.Exec("%comspec% /c ""NET USE \\SERVER\IPC$ " & sPassword & " /USER:" & sUser & """")
logThis oExec.StdOut.ReadAll
logThis oExec.StdErr.ReadAll

logThis "%comspec% /c NET TIME \\SERVER /SET /Y"
Set oExec = oShell.Exec("%comspec% /c NET TIME \\SERVER /SET /Y")
logThis oExec.StdOut.ReadAll
If oExec.StdErr.ReadAll <> "" Then
	logThis oExec.StdErr.ReadAll
	wscript.quit(3912)
End If


Sub logThis(strText)
	'Create (if it doesn't exist) and open the logFile for appending
	Set oLogFile = objFSO.OpenTextFile(sLogPath & "\" & sLogFileName, ForAppending, True, 0)
	oLogFile.WriteLine(strText)
	oLogFile.Close	
End Sub
22Jul/140

Nice to have CM2012 vbscripts

Some of these are only slighlty modified from CM SDK. Others are very modified 🙂
Response.Write is for ASP, replace it with Wscript.Echo to use in a script.

First. Connect to CM.

' Set connection = ConnectToCM
Function ConnectToCM
	' Make the connection to CM. Uses constants for servername, username and password
	' Also kind of from the CM SDK. A bit modified
    On Error Resume Next
    Set swbemLocator = CreateObject("WbemScripting.SWbemLocator")
    swbemLocator.Security_.AuthenticationLevel = 6 'Packet Privacy
    
    ' Connect to the server.
    Set swbemServices= swbemLocator.ConnectServer(sCMServer, "root\sms", sCMUser, sCMPassword)
    If Err.Number<>0 Then
        Response.Write "Couldn't connect: " + Err.Description
        Set ConnectToCM = null
        Exit Function
    End If

    ' Determine where the provider is and connect.
    Set providerLoc = swbemServices.InstancesOf("SMS_ProviderLocation")
	For Each location In providerLoc
		If location.ProviderForLocalSite = True Then
			Set swbemServices = swbemLocator.ConnectServer(location.Machine, "root\sms\site_" + location.SiteCode,sCMUser,sCMPassword)
			If Err.Number<>0 Then
				Response.Write "Couldn't connect:" + Err.Description
				Set ConnectToCM = Null
				Exit Function
			End If
			Set ConnectToCM = swbemServices
			Exit Function
		End If
	Next
    Set ConnectToCM = null ' Failed to connect.
End Function

Start with import a new computer. Returns the ResourceID for the new object.

Function AddNewComputer(connection, netBiosName, smBiosGuid, macAddress)
	' Import a new computer into CM. Based on function from CM SDK
	' Returns the ResourceID for the new object
	If (IsNull(smBiosGuid) = True) And (IsNull(macAddress) = True) Then
		Response.Write "smBiosGuid or macAddress must be defined"
		AddNewComputer = False
		Exit Function
	End If     

	If IsNull(macAddress) = False Then
		macAddress = Replace(macAddress,"-",":")
	End If    

	' Obtain an InParameters object specific
	' to the method.
	Set siteClass = connection.Get("SMS_Site")
	Set inParams = siteClass.Methods_("ImportMachineEntry").inParameters.SpawnInstance_()

	' Add the input parameters.
	inParams.Properties_.Item("MACAddress") =  macAddress
	inParams.Properties_.Item("NetbiosName") =  netBiosName
	inParams.Properties_.Item("OverwriteExistingRecord") =  False
	inParams.Properties_.Item("SMBIOSGUID") =  smBiosGuid

	' Add the computer.
	Set outParams = connection.ExecMethod("SMS_Site","ImportMachineEntry", inParams)
	AddNewComputer = outParams.ResourceID
End Function

Create a dynamic collection. Returns the CollectionID for the collection.

'sCollectionID = CreateDynamicCollection(connection, sCollName, sComment, True, "SELECT * FROM SMS_R_System WHERE Name LIKE '" & sCountry & "%'", sCollComment, sLimitingCollection)
Function CreateDynamicCollection(connection, newCollectionName, newCollectionComment, ownedByThisSite, queryForRule, ruleName, limitToCollectionID)
	' Function from CM SDK, slightly modified
    ' Create the collection.
    Set newCollection = connection.Get("SMS_Collection").SpawnInstance_
    newCollection.Name = newCollectionName
    newCollection.Comment = newCollectionComment
    newCollection.OwnedByThisSite = ownedByThisSite
    newCollection.LimitToCollectionID = limitToCollectionID
    
    ' Save the new collection and save the collection path for later.
    Set collectionPath = newCollection.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 True
    End If
	CreateDynamicCollection = newCollection.CollectionID
End Function

Perhaps get the ID of a Folder, based on the name, to put the new collection in.

Function GetCollectionFolderID(connection, sName)
	' Returns FolderID for a folder under "Device Collections" based on Name
	Set oNodeID = connection.ExecQuery("SELECT * FROM SMS_ObjectContainerNode WHERE Name='" & sName & "' AND ObjectType='5000'") '5000 for SMS_Collection_Device
	If oNodeID.Count = 1 Then
		GetCollectionFolderID = oNodeID.ItemIndex(0).ContainerNodeID
	Else
		GetCollectionFolderID = ""
	End If
End Function

Move the collection to the folder.

Sub MoveCollectionToFolder(connection, CollectionID, TargetFolderID)
	ObjectType = 5000 '5000 is SMS_Collection_Device
	SourceFolderID = 0 ' Root folder
	On Error Resume Next
	' Move one collection. 
	sourceItems = Array(CollectionID)
	Set objInstance = connection.Get("SMS_ObjectContainerItem")
	
	' Set up the in parameters 
	Set objInParam = objInstance.Methods_("MoveMembers").inParameters.SpawnInstance_() 
	objInParam.Properties_.Item("InstanceKeys") = sourceItems 
	objInParam.Properties_.Item("ContainerNodeID") = SourceFolderID 
	objInParam.Properties_.Item("TargetContainerNodeID") = TargetFolderID 
	objInParam.Properties_.Item("ObjectType") = ObjectType
	
	' Call the method. 
	Set objOutParams = connection.ExecMethod("SMS_ObjectContainerItem","MoveMembers",objInParam)
End Sub

Create a new variable on the collection.

Sub CreateCollectionVariable(connection, name, value, mask, collectionId, precedence)
	' Sub from CM SDK
	' See if the settings collection already exists. if it does not, create it.
	Set settings = connection.ExecQuery("Select * From SMS_CollectionSettings Where CollectionID = '" & collectionID & "'")
	
	If settings.Count = 0 Then
		'Response.Write "Creating collection settings object"
		Set collectionSettings = connection.Get("SMS_CollectionSettings").SpawnInstance_
		collectionSettings.CollectionID = collectionId
		collectionSettings.Put_
	End If  
	
	' Get the collection settings object.
	Set collectionSettings = connection.Get("SMS_CollectionSettings.CollectionID='" & collectionId &"'" )
	
	' Get the collection variables.
	collectionVariables = collectionSettings.CollectionVariables
	
	' Create and populate a new collection variable.
	Set collectionVariable = connection.Get("SMS_CollectionVariable").SpawnInstance_
	collectionVariable.Name = name
	collectionVariable.Value = value
	collectionVariable.IsMasked = mask
	
	' Add the new collection variable.
	ReDim Preserve collectionVariables (UBound (collectionVariables)+1)
	Set collectionVariables(UBound(collectionVariables)) = collectionVariable
	collectionSettings.CollectionVariables=collectionVariables
	collectionSettings.Put_
End Sub

Get the collectionID based on name.

Function GetCollectionID(sName)
	' Return CollectionID based on Name
	Set oCollection = connection.ExecQuery("SELECT * FROM SMS_Collection WHERE Name='" & sName & "'")
	If oCollection.Count > 0 Then
		GetCollectionID = oCollection.ItemIndex(0).CollectionID
	Else
		GetCollectionID = ""
	End If
End Function

Add computer to a collection with direct membership.

Function AddComputerToCollection(connection, sResourceID, sCollectionID)
	' Add a computer to a collection with direct membership
	On Error Resume Next
	set collection = connection.Get("SMS_Collection.CollectionID='" & sCollectionID & "'")
	set collectionRule = connection.Get("SMS_CollectionRuleDirect").SpawnInstance_

	collectionRule.ResourceClassName = "SMS_R_System"
	collectionRule.ResourceID = sResourceID
	collection.AddMembershipRule collectionRule
	
	AddComputerToCollection = Err.Number
End Function

Two functions to get the ResourceID or the Computername, based on the other OR MAC.

Function GetResourceID(connection, sComputernameOrMAC)
	' Returns the ResourceID for a computer based on MAC or Name
	Set oResource = connection.ExecQuery("SELECT ResourceID FROM SMS_R_System WHERE Name='" & sComputernameOrMAC & "' OR MACAddresses='" & sComputernameOrMAC & "'")
	If oResource.Count > 0 Then 
		GetResourceID = oResource.ItemIndex(0).ResourceID
	Else
		GetResourceID = False
	End If
End Function

Function GetComputername(connection, sResourceIdOrMAC)
	' Returns the computername for a computer based on MAC or ResourceID
	Set oResource = connection.ExecQuery("SELECT Name FROM SMS_R_System WHERE ResourceID LIKE '" & sResourceIdOrMAC & "' OR MACAddresses='" & sResourceIdOrMAC & "'")
	If oResource.Count > 0 Then 
		GetComputername = oResource.ItemIndex(0).Name
	Else
		GetComputername = False
	End If
End Function

Clear last PXE Advertisement for a computer to be able to PXE boot the ocmputer again.

Function ClearPxeAdvertisementResource(connection, sResourceID)
	On Error Resume Next
	' Set up the Resource array parameter.
	resources = Array(1)
	resources(0) = sResourceID

	Set InParams = connection.Get("SMS_Collection").Methods_("ClearLastNBSAdvForMachines").InParameters.SpawnInstance_
	InParams.ResourceIDs = resources
	connection.ExecMethod "SMS_Collection", "ClearLastNBSAdvForMachines", InParams
	
	ClearPxeAdvertisementResource = Err.number
End Function

Is the computer already a member of a collection?

Function IsMemberOfCollection(connection, sCollID, sResourceID)
	' Check if ResourceID is member of CollectionID
	Set oExist = connection.ExecQuery("SELECT * FROM SMS_FullCollectionMembership WHERE CollectionID='" & sCollID & "' AND ResourceID='" & sResourceID & "'")
	If oExist.Count = 1 Then
		IsMemberOfCollection = True
	Else
		IsMemberOfCollection = False
	End If
End Function

Check for valid IP/Subnet/netmask and MAC syntax.

Function isValidIP(sIP)
	' not really ... just checking that the value is between 1.0.0.0 and 255.255.255.255
	' That way this function works for IP, Subnet and Netmask instead of having 3 different functions
	Set regEx = New RegExp
	regEx.Pattern = "^([1-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])([.]([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])){3}$"
	regEx.IgnoreCase = True
	isValidIP = regEx.Test(sIP)
End Function

Function isValidMAC(sMAC)
	' Syntax: XX:XX:XX:XX:XX:XX
	Set regEx = New RegExp
	regEx.Pattern = "^([0-9A-F]{2}[:]){5}([0-9A-F]{2})$"
	regEx.IgnoreCase = True
	isValidMAC = regEx.Test(sMAC)
End Function

And last, delete the computer object.

Function DeleteComputer(connection, sResourceID)
	' Deletes a computer from SCCM
	On Error Resume Next
	Set oResource = connection.Get("SMS_R_System.ResourceID='" & sResourceID  & "'")
	oResource.Delete_
	DeleteComputer = Err.Number
End Function