Calling a CM script via the Admin Service

Knowing is half the battle

Did you know that you can run a CM script on a client via the admin service? Neither did I until a few days ago.

Earlier this week I was checking out the available items from the CM 2006 administration service REST API. I went to the metadata page at https://<provider FQDN>/AdminService/v1.0/$Metadata and started looking through the returned XML. I stumbled on to a RunScript function. I went back and looked at a 2002 CM server and it wasn’t listed there. I then checked the 2006 admin service release notes, no mention of it there either.

Time to see if this works. It looks like I need a device as a binding parameter and then a script GUID. I will be using a script I already have defined in CM, the only restriction is that currently we have no option to pass script parameters.

Let’s get started.

My URL to call the function with the device as the binding parameter should look like https://<provider FQDN>/AdminService/v1.0/Device(<MachineID>)/AdminService.RunScript

I do not have all my ResourceIDs memorized, so I need a way to give the computer name and get that information. Since I am using the admin service anyway, let’s stay with it. I know I can query for all devices using https:// <provider FQDN>/AdminService/V1.0/Device

I will be querying via PowerShell, so let’s start building our script.

We’ll start by defining our device name, but we won’t be using it right away.

$devicename = "CL2"

Let’s query for all devices

Invoke-RestMethod 'https://<provider FQDN>/AdminService/V1.0/Device' -UseDefaultCredentials

We get back all devices, but they are in the “value” attribute.

Let’s modify our line to get back only the “value” attribute.

(Invoke-RestMethod 'https://<provider FQDN>/AdminService/V1.0/Device' -UseDefaultCredentials).value

That get’s us the results but we only need one device, so let’s add logic to filter. This is where we’ll start to use the devicename variable we set.

(Invoke-RestMethod 'https://<provider FQDN>/AdminService/V1.0/Device' -UseDefaultCredentials).value | where-object{$_.Name -eq $devicename}

That returns just the one system. More accurately, it returns all systems then filters down to the one we want. I make that point because the more systems you have the longer the process will take.

From the one system, we need the ResourceID/MachineID and really we want it in a variable. Let’s take our script line and expand out the MachineID, loading it in to a variable of its own.

$DeviceID = ((Invoke-RestMethod 'https://<provider FQDN>/AdminService/V1.0/Device' -UseDefaultCredentials).value | where-object{$_.Name -eq $devicename}).MachineId

We still need the script GUID, so we’ll follow the same format as we did for the device.

$scriptname = "PFE - Install ALL Available Updates"
$scriptGuid = ((Invoke-RestMethod 'https://<provider FQDN>/AdminService/V1.0/Script?' -UseDefaultCredentials).value | where-object{$_.ScriptName -eq $scriptname}).ScriptGuid

I mentioned the Uri to call the script earlier, now let’s assemble the full line with our variables.

Invoke-RestMethod -Method Post -Uri "https://<provider FQDN>l/AdminService/v1.0/Device($($DeviceID))/AdminService.RunScript" -Body "{ `"ScriptGuid`" : `"$scriptGuid`" }" -ContentType 'application/json' -UseDefaultCredentials

We can put it all together for a better look.

$devicename = "CL2"
$DeviceID = ((Invoke-RestMethod 'https://<provider FQDN>/AdminService/V1.0/Device' -UseDefaultCredentials).value | where-object{$_.Name -eq $devicename}).MachineId

$scriptname = "PFE - Install ALL Available Updates"
$scriptGuid = ((Invoke-RestMethod 'https://<provider FQDN>/AdminService/V1.0/Script?' -UseDefaultCredentials).value | where-object{$_.ScriptName -eq $scriptname}).ScriptGuid

Invoke-RestMethod -Method Post -Uri "https://<provider FQDN>/AdminService/v1.0/Device($($DeviceID))/AdminService.RunScript" -Body "{ `"ScriptGuid`" : `"$scriptGuid`" }" -ContentType 'application/json' -UseDefaultCredentials

Now that raw code works and you can pick and choose the parts you want. Maybe you already know the ResourceID or Script GUID via other methods. That said, I hate to leave it unpolished so I am going to turn it into a function, add the standard disclaimer, etc.

# Microsoft provides programming examples for illustration only, 
# without warranty either expressed or implied, including, but not 
# limited to, the implied warranties of merchantability and/or 
# fitness for a particular purpose. 
# This sample assumes that you are familiar with the programming 
# language being demonstrated and the tools used to create and debug 
# procedures. Microsoft support professionals can help explain the 
# functionality of a particular procedure, but they will not modify 
# these examples to provide added functionality or construct 
# procedures to meet your specific needs. If you have limited 
# programming experience, you may want to contact a Microsoft 
# Certified Partner or the Microsoft fee-based consulting line at 
# (800) 936-5200. 
# For more information about Microsoft Certified Partners, please 
# visit the following Microsoft Web site:

Function Invoke-AdminServiceRunScript{
        [Parameter(Mandatory = $true,Position=0)]$CMProvider,
        [Parameter(Mandatory = $true,Position=1)]$devicename,
        [Parameter(Mandatory = $true,Position=2)]$scriptname

    $DeviceID = ((Invoke-RestMethod "https://$($CMProvider)/AdminService/V1.0/Device" -UseDefaultCredentials).value | where-object{$_.Name -eq $devicename}).MachineId
    $scriptGuid = ((Invoke-RestMethod "https://$($CMProvider)/AdminService/V1.0/Script" -UseDefaultCredentials).value | where-object{$_.ScriptName -eq $scriptname}).ScriptGuid

    Invoke-RestMethod -Method Post -Uri "https://$($CMProvider)/AdminService/v1.0/Device($($DeviceID))/AdminService.RunScript" -Body "{ `"ScriptGuid`" : `"$scriptGuid`" }" -ContentType 'application/json' -UseDefaultCredentials

Invoke-AdminServiceRunScript -CMProvider "CM1.corp.cmpfe.local" -devicename "CL6" -scriptname "PFE - Install ALL Available Updates"

A quick test and we can see it runs great.

Now you too know we can run a CM script via the admin service.