Welcome,
There are many questions on the web about remotely calling SCCM client actions through scripts.
There is absolutely nothing in the official SDK for SCCM 2012 about such a possibility. In the version for SCCM 2007 there is an example of a script executed locally, calling COM class objects CPAppletMgr
andUIResourceMgr
. Unfortunately, the DCOM configuration that would allow remote use of these objects is cumbersome to say the least, and useless in the long run, as it would be ludicrous to believe that these classes (and especially GUIDs) will not change in the future.
A more natural form of integration with SCCM is to make WMI calls.
And here again Microsoft has laid a cuckoo egg for all script writers - in the SDK for the 2012 version there is only a dry description of the WMI classes available in the client and server, however, any guidance on how to use them is missing.
After a long search, I found a fantastic tool: SMSCLICTR, which collects all possible settings and calls into easy-to-use .NET libraries. These can also be used in powershell, however, often the use of external data types in PS is prohibited by system security policies.
In the end, there was nothing left to do but to create a custom piece of code that would perform the required actions.
- First, it is necessary to call the refresh of SCCM client policies. This can be done by the following function:
function ForceMachinePolicyRefresh
{
param($clientname, $username, $userpass, $PolicyID)
$ms = new-object system.management.managementscope
$ms.Path = "\TP4Tclientname".
$ms.options.username = $username
$ms.options.password = $userpass
$mc = new-object system.management.managementclass($ms, 'SMS_Client', $null)
$mc.invokeMethod("TriggerSchedule", $PolicyID)
return $mc
}A couple of comments on the above code:
- The connection to the WMI namespace is made in direct form, without the use of casting, available in powershell for the class
[wmi]
, due to the need to pass credentials. This code can invoke WMI remotely by using the$ms.options.username
Which is only supported for remote connections. - This is a general function that allows you to force the invocation of any scheduled action. Thus, it can be used not only to refresh the computer's policy, but also to apply local configuration settings, as will be shown in a moment.
- One last thing about this little piece of code is that it can be used as a template to manipulate any properties and methods published by the WMI class
SMS_Client
. Only now can the SDK prove helpful.
- The connection to the WMI namespace is made in direct form, without the use of casting, available in powershell for the class
- So with this auxiliary procedure defined, we can get to the point. The following function is used to run the forced publication of the package or application specified in the argument. The function takes all the required arguments, so that it is completely independent of the context in which it is executed:
function InvokeOptionalAdvertisement
{
Param($clientname, $username, $userpass, $advertID, $packID)
$mc = ForceMachinePolicyRefresh –clientname $clientname –username $username –userpass $userpass –PolicyID „{00000000-0000-0000-0000-000000000021}”
$ms = new-object system.management.managementscope
$ms.path = "\TP4Tclientname".
$ms.options.username = $username
$ms.options.userpass = $userpass
$query =new-object System.Management.ObjectQuery
$query.QueryString = "Select * From CCM_SoftwareDistribution where ADV_AdvertisementID = '$advertID' and PKG_PackageID = '$packID'".
$searcher = new-object system.management.managementobjectsearcher($query)
$searcher.Scope = $ms
$advs = $searcher.Get
$enum = $advs.GetEnumerator()
$enum.MoveNext()
$adv = $enum.Current
$adv.SetPropertyValue("ADV_RepeatRunBehavior"., "RerunAlways")
$adv.SetPropertyValue("ADV_MandatoryAssignments"., "True")
$adv.Put()
$query1 = new-object System.Management.ObjectQuery
$query1.QueryString = "Select ScheduledMessageID FROM CCM_Scheduler_ScheduledMessageID like '" + $adv.ADV_AdvertisementID + „-„ + $adv.PKG_PackageID + „%'”
$searcher1 = new-object System.management.managementobjectsearcher($query1)
$searcher1.scope = $ms
$scheds = $searcher1.Get()
$scheds | Foreach-Object { $mc[1].invokeMethod("TriggerSchedule", $_.ScheduledMessageID) }
return $adv
}And, of course, a word of commentary on the above code:
- First, we invoke a refresh of the computer's policy to make sure we are working on current publication data downloaded from SCCM. We perform this action using our helper procedure.
- Next, we define a new WMI management context that includes the currently loaded SCCM client configuration.
- Next, we create an instance of the class
ObjectQuery
, which will represent a WMI query. This query retrieves from the space all objects of classCCM_SoftwareDistribution
Which fit the requirements communicated. - By calling the method
$searcher.Get
we put in the variable$advs
All objects that are the result of the query. - By using the trick of downloading an enumerator and its properties
$enum.Current
we only get a single object, instead of a collection containing that object. - Now it is time to perform the main task. Two properties of the peeled object are modified, making it mandatory instead of optional publication on this particular client, and it will be executed the next time the schedule for this publication is called.
- The last part of the script lists all the schedule objects registered in the system and forces them to run. This also calls the schedule action for our publication that we want to force.