MSEndpointMgr

Automate Scripts in ConfigMgr using PowerShell

I’ve touched very briefly on the subject of this post in a previous post about the Run a script feature in ConfigMgr 1706 Technical Preview. Since the first iteration of this new feature has recently been introduced in ConfigMgr 1706, it’s time to dig a little bit deeper into how we can automate the new Scripts (yes, that’s a Script instance/object/item in ConfigMgr) feature.

As this feature evolves within the next releases of ConfigMgr, the current capabilities allows us to do the following:

  • Create a Script
  • Set approval state for a Script
  • Run a Script for all systems in a collection

If you want to read the available documentation for this feature, you can find it here:

https://docs.microsoft.com/en-us/sccm/apps/deploy-use/create-deploy-scripts

Exploring the possibilities for automation

Whenever there’s new functionality introduced in ConfigMgr Current Branch, it’s always interesting to fire up WMI Explorer and have a look in the SMS Provider for new classes. As of writing this post, there are no cmdlets available for this feature in the ConfigMgr PowerShell module, which leaves us with the good old SMS Provider to rely on.

NOTE – There are currently no documentation available for the new classes introduced in ConfigMgr 1706 relating to the feature in mention. Hopefully this will be added soon, so for now we’d have to reverse engineer and rely on logs and what can be discovered through the SMS Provider.

There are couple of new classes that we need to be aware of if we want to automate this feature. They’re called SMS_Scripts and SMS_ScriptsExecutionStatus. SMS_Scripts holds the instances of the Scripts created in the console and SMS_ScriptsExecutionStatus is pretty much self explanatory, holding the execution status sent back from the clients for any of the executed Scripts.

Digging into the methods available for the SMS_Scripts class, we can see that we currently have two to work with:

  • CreateScripts (static)
  • UpdateApprovalState (non-static)

With this information at hand, let’s attempt to invoke these two methods in order to automate the Scripts feature. Below you’ll find a more detailed description of how to use these different methods.

Create a Script object

Creating a new Script instance with PowerShell would require us to invoke the method that we discovered in the SMS_Scripts class called CreateScripts. Exploring the properties available and required for creating a new instance, leading to a new Scripts object in ConfigMgr, have been summarized in the list bellow:

  • ApprovalState
  • Approver
  • Author (required)
  • Comment
  • LastUpdateTime
  • Parameterlist
  • ParameterlistXML
  • Script (required)
  • ScriptGuid (required)
  • ScriptHash
  • ScriptHashAlgorithm
  • ScriptName (required)
  • ScriptType
  • ScriptVersion

Now that we know which properties we need to use when creating a new instance, let’s take a look at an example of how the instance creation could look with PowerShell. In the example code below, we’ll be using the Invoke-CimMethod cmdlet and create the required code for it properly create a new instance.

First off we need set a few static ConfigMgr environment variables for the Site Code and Site server:

# Site information
$SiteServer = "CM01"
$SiteCode = "P01"

After that we need to create a here-string containing the actual PowerShell script block that will be invoked when the Script is executed on the systems. This can be accomplished with the following example code:

# Here-string containing the PowerShell script
$ScriptCode = @"
Get-Process | Select-Object -Property Name
"@

Next thing would be to construct hash-table for the Invoke-CimMethod cmdlet using the required properties for the creation of a new instance in the SMS_Scripts class:

# Input parameters for method execution
$ScriptArgs = @{
    Author = "DOMAIN\username"
    Script = $ScriptCode
    ScriptGuid = ([System.Guid]::NewGuid()).Guid
    ScriptName = "Get Processes"
    ScriptVersion = "1.0" # Not required, but convenient
    Comment = "Created with PowerShell" # Not required, but convenient
}

As you may have noticed in the code above, there’s two addition properties added, ScriptVersion and Comment. These are not required, however they may be convenient to use hence why they’ve been added.

NOTE – Make sure that you amend the Author property and define a valid domain and user.

Now that we have all the required code to call Invoke-CimMethod, let’s see how that can be accomplished:

# Invoke CreateScripts method
Invoke-CimMethod -Namespace "root\SMS\site_$($SiteCode)" -ClassName SMS_Scripts -MethodName "CreateScripts" -Arguments $ScriptArgs

Below is the whole example code that we’ve just broken down into different parts, combined in a single script:

# Site information
$SiteServer = "CM01"
$SiteCode = "P01"

# Here-string containing the PowerShell script
$ScriptCode = @"
Get-Process | Select-Object -Property Name
"@

# Input parameters for method execution
$ScriptArgs = @{
    Author = "DOMAIN\username"
    Script = $ScriptCode
    ScriptGuid = ([System.Guid]::NewGuid()).Guid
    ScriptName = "Get Processes"
    ScriptVersion = "1.0" # Not required, but convenient
    Comment = "Created with PowerShell" # Not required, but convenient
}

# Invoke CreateScripts method
Invoke-CimMethod -Namespace "root\SMS\site_$($SiteCode)" -ClassName SMS_Scripts -MethodName "CreateScripts" -Arguments $ScriptArgs

When the above code is executed, a return value of 0 should be returned if the execution was successful. Within the ConfigMgr console under Software Library > Scripts we can now see the new Script instance created from the code above.

Set approval state for a Script object

The second method that exists for the SMS_Scripts class is the UpdateApprovalState. This method is a non-static method and requires to be invoked for a given instance. With this method we can simply change the approval state of a Script between the following states:

  • Waiting for approval (0)
  • Declined (1)
  • Approved (3)

None of the available states are currently not documented, but after some simple testing I could determine the proper values shown above. What’s written in parentheses for the list above is the corresponding determined property value for the state. With this information we’re able to change the state of any of the Script objects available in ConfigMgr. Let’s take a look at how that can be accomplished with some more example code.

First we need to set the same ConfigMgr environment variables as for when we created the Script instance:

# Site information
$SiteServer = "CM01"
$SiteCode = "P01"

Next we’d need to identify the Script instance in order to invoke the non-static method to set the approval state. To do that, we could choose to query for either the name of the script or it’s unique identifier, which in this case would be the ScriptGuid property. It seems that different Script objects in ConfigMgr can have the same name, so using the name as the identifier would not seem adequate in this case. There are several methods available to get the ScriptGuid property of the object you want to change the approval state for, either from the ConfigMgr console (by adding the ScriptGuid column in the Scripts node) or by using a WMI Explorer application. Use the ScriptGuid property value for the $ScriptGUID variable.

# Get Script instance for non-static method execution
$ScriptGUID = "E57D2533-C95C-4BDB-ADAE-963D3C5A8963"
$Script = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_Scripts -Filter "ScriptGuid = '$($ScriptGUID)'"

With the instance object stored in the $Script variable, the UpdateApprovalState method can now be invoked with the following code:

# Invoke non-static method UpdateApprovalState for instance
$ApprovalState = 3
$Approver = "DOMAIN\username"
$ApproveComment = "Approved with PowerShell"
$Script.UpdateApprovalState($ApprovalState, $Approver, $ApproveComment)

As shown above, we need to pass the ApprovalState, Approver and ApproveComment as parameter input when invoking this method. When executed, a return value of 0 should be shown meaning that the approval state has been successfully updated.

NOTE – Make sure that you amend the $Approver variable and define a valid domain and user.

Here’s the full example code:

# Site information
$SiteServer = "CM01"
$SiteCode = "P01"

# Get Script instance for non-static method execution
$ScriptGUID = "E57D2533-C95C-4BDB-ADAE-963D3C5A8963"
$Script = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_Scripts -Filter "ScriptGuid = '$($ScriptGUID)'"

# Invoke non-static method UpdateApprovalState for instance
$ApprovalState = 3
$Approver = "DOMAIN\username"
$ApproveComment = "Approved with PowerShell"
$Script.UpdateApprovalState($ApprovalState, $Approver, $ApproveComment)

Earlier when we created the Script, the approval state was automatically (since we didn’t include the ApprovalState property when creating the instance) set to Waiting for approval. Now when we execute the example code above, we can see that the approval state has changed to Approved:

What about running a Script

We’ve now seen how to create a new Script object in ConfigMgr and how to set the ApprovalState property by using PowerShell. Remember in the beginning of this post, it stated that you could also run a Script. I’ve attempted to do this with PowerShell as well, but fallen short unfortunately. Right now the Scripts feature uses different fast channels (Client Notification and other channels) for sending down the script body containing the actual code. When watching what goes on behind the scene by looking in SMSProv.log, you can see that it calls a method called InitiateClientOperationEx from the SMS_ClientOperation class. I’ve tried to invoke the same method, guessing what parameters it requires but unfortunately with no success. It seems to be working from the server side, but when checking the Scripts.log file on a client, the following is shown:

Failed to load xml from message content. Error 0x80004005

My assumption here is that something else not being logged is going on in the background (remember this is the first iteration of this new feature) that we can’t see. Hopefully, in the next version of ConfigMgr we’ll have a new method for the SMS_Scripts class just like the two we’ve talked about in this post, enabling us to trigger any of the Scripts.

(9421)

Nickolaj Andersen

Chief Technical Architect and Enterprise Mobility MVP since 2016. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows devices and deployments including automation. Awarded as PowerShell Hero in 2015 by the community for his script and tools contributions. Creator of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService to name a few. Frequent speaker at conferences such as Microsoft Ignite, NIC Conference and IT/Dev Connections including nordic user groups.

2 comments

  • Hello !

    Great article !!!

    Could you post the code about the “InitiateClientOperationEx” method ? I’m facing this issue actually. I’m intend to write this in c#.

    What I found : you can use this cmdlet : Invoke-CMSCript after loading the configurationmanager module.

    Thanks a lot !
    MHF

  • HI Nick, were you able to find way to trigger scripts using PowerShell on Clients?

Sponsors