07 December, 2012

Machine Policy Retrieval - SCCM

A very efficient way to break tens of thousands of machines is to install something on them using a deployment / configuration management software, such as SCCM.

It's always a bad idea to send out a package on a Friday afternoon - and hope for the best - because the longest afternoons are usually the Friday ones, they can last several days when you need to remediate a couple of 1000 hosts where application installations got corrupted because of your Friday SCCM package. What you want, before hitting the full list of 1000s of servers with a package is to send it out to a couple and quickly see the result. However, if you send out a package it can take up to an hour to see the results in SCCM - depending on your SCCM site settings... How can you make it quicker? Invoke a client action on each host called "Machine Policy Retrieval & Evaluation Cycle".

SCCM Client Actions
I know there are many very good tools out there for SCCM with UI and multiple functions and fancy remote host handling capabilities, however, a couple of years ago - because I like the command line way - I thought I'd write a quick script which is able to invoke SCCM Client side actions on multiple hosts remotely At the same time it would have the capability of pipe'ing the output to another PowerShell script or some file or export it to csv...whatever.

Background:
SCCM client has several agents and those can perform actions, such as downloading policies and packages from the server, perform software or hardware inventories...etc. Because all these agents are built on WMI, you can invoke actions by creating WMI instances of specific WMI classes on the remote machine.


OK, so the idea is there. When you want to break.. khm deploy something on many, many servers, you just pick about 50 or maybe 100 firts, send out the package and then... and this is where powershell comes in: run the following script to invoke the MAchine Policy Retrieval & Evaluation Cycle which will make the client download the package and run it + report back to the SCCM server.

$hostlist = @($Input)

if($($hostlist.length) -gt 0){
    foreach ($srv in $hostlist) {

        # Binding \\$srv\root\ccm:SMS_Client
        $SMSCli = [wmiclass] "\\$srv\root\ccm:SMS_Client"

        if($SMSCli){

            #Invoking $actionName
            $check = $SMSCli.RequestMachinePolicy()
            $check = $SMSCli.EvaluateMachinePolicy()
        }
        else{
            write-host "$srv, Could not bind WMI class SMS_Client"
        }
    }
}


Save it as a something.ps1 file and use it like this:
PS C:\> gc hostlist.txt | something.ps1

Clipboard friendly code:
 $hostlist = @($Input)  
   
 if($($hostlist.length) -gt 0){  
      foreach ($srv in $hostlist) {  
           # Binding \\$srv\root\ccm:SMS_Client  
           $SMSCli = [wmiclass] "\\$srv\root\ccm:SMS_Client"  
           if($SMSCli){  
                #Invoking $actionName   
                $check = $SMSCli.RequestMachinePolicy()  
                $check = $SMSCli.EvaluateMachinePolicy()  
                  
           }  
           else{  
                write-host "$srv, Could not bind WMI class SMS_Client"  
           }  
      }  
 }  




8 comments:

  1. All I get is:

    Cannot convert value "\\thesnypc\root\ccm:SMS_Client" to type "Syste
    m.Management.ManagementClass". Error: "Access is denied. (Exception from HRESUL
    T: 0x80070005 (E_ACCESSDENIED))"
    At C:\temp\mpr.ps1:6 char:32
    + $SMSCli = [wmiclass] <<<< "\\$srv\root\ccm:SMS_Client"
    + CategoryInfo : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

    Regards
    Thomas Ehler
    the@science.au.dk

    ReplyDelete
    Replies
    1. Hi Mia, that can be because of several things:
      - you don't have administrative access to the remote host
      - WMI is broken on the remote host, you can check it by running WMIExplorer and checking if you can open the ccm namespace: http://www.powershellpro.com/wmi-explorer/160/

      Delete
  2. Access is denied -> you should use an adequate account

    ReplyDelete
  3. I liked this so much I turned it into a PowerShell cmdlet with some error checking. Code lives here https://github.com/1RedOne/SCCM-Cmdlets/, and feel free to comment or add to it.

    ReplyDelete
  4. Everyone always assumes a One-to-many setting. If you are that deployment tech waiting for the newly imaged machine you just advertised a bunch of apps to but don't want to wait the possible 20 min, create a batch file with this:

    WMIC /namespace:\\root\ccm path sms_client CALL TriggerSchedule "{00000000-0000-0000-0000-000000000021}" /NOINTERACTIVE

    WMIC /namespace:\\root\ccm path sms_client CALL TriggerSchedule "{00000000-0000-0000-0000-000000000022}" /NOINTERACTIVE

    ReplyDelete
  5. Nice... can add this to my post-build script on my VM templates. Much lighter than vb.

    ReplyDelete