Showing posts with label inventory. Show all posts
Showing posts with label inventory. Show all posts

13 January, 2013

Invoke Inventory - SCCM

Continuing one of the SCCM related posts from last year where I showed a way to invoke Machine Policy Retrieval & Evaluation on SCCM clients remotely. Here is a quick script to invoke some other actions as well, namely:



  • Hardware Inventory Cycle (Delta)
  • Hardware Inventory Cycle (Full)
  • Software Inventory Cycle (Delta)
  • Software Inventory Cycle (Full)
  • Discovery Data Collection Cycle (Delta)
  • Discovery Data Collection Cycle (Full)
  • File Collection Cycle (Delta)
  • File Collection Cycle (Full)
  • Software Updates Deployment Evaluation Cycle
  • Software Updates Scan Cycle



An interesting piece of the code is this:
$wmiQuery = "\\$srv\root\ccm\invagt:InventoryActionStatus.InvetoryActionID=$fscheduleID"
$checkdelete = ([wmi]$wmiQuery).Delete()

These two lines take care of the cleanup of an existing WMI instance which tells the SCCM client to perform a delta inventory instead of a full one. While you can invoke client actions on SCCM client's GUI, you can only kick off delta Software and Hardware inventory (although the GUI doesn't say that). So this piece of code give you the opportunity to force a full Hardware or Software inventory remotely.
Why is this important? Because there are cases when you try to troubleshoot why HW or SW inventory data is not flowing into the SCCM database and the best way to do that is enforcing the client to perform a full inventory and look at the logs (like the InventoryAgent.log on the client or the DataTransferService.log on the Management Point...etc.)
Some explanation for the code:

$SMSCli = [wmiclass] \\$srv\root\ccm:SMS_Client
This is for binding the SCCM Client's WMI class, if it's done, then we can invoke the TriggerSchedule method to start an action.

switch ($action) {
...
}
In this section, depending on what action is selected with the -action switch, we set up 2 variables, one is the identifier of the WMI instance which identifies the particular action. The other one is just for displaying the friendly name of the action for the user.

$hostlist = @($Input)
if($($hostlist.length) -gt 0){
   foreach ($srv in $hostlist) {
      if(!$srv){
         executeSCCMAction $srv $action $scheduleID
      }
   }
}
Get the list of hosts from the pipe into an array, go through the array and call the executeSCCMAction  function to create and/or delete the necessary WMI instance.

Clipboard friendly code:
 param ( [string] $action = "") 

function executeSCCMAction ([string]$srv, [string]$action, $fscheduleID){

   #Binding SMS_Client wmi class remotely.... 
   $SMSCli = [wmiclass] "\\$srv\root\ccm:SMS_Client"

   if($SMSCli){
      if($action -imatch "full"){
         #Clearing HW or SW inventory delta flag...
         $wmiQuery = "\\$srv\root\ccm\invagt:InventoryActionStatus.InventoryActionID=$fscheduleID"
         $checkdelete = ([wmi]$wmiQuery).Delete()
      }   
      #Invoking $action ...
      Write-Host "$srv, Invoking action $script:actionName"
      $check = $SMSCli.TriggerSchedule($fscheduleID)
   }
   else{
      # could not get SCCM WMI Class
      Write-Host "$srv, could not get SCCM WMI Class"
   }
}

switch ($action) {
   "hw" {
      $scheduleID = "{00000000-0000-0000-0000-000000000001}"
      $script:actionName = "Hardware Inventory Cycle (Delta)"
   }
   "hwfull" {
      $scheduleID = "{00000000-0000-0000-0000-000000000001}"
      $script:actionName = "Hardware Inventory Cycle (Full)"
   }
   "sw" {
      $scheduleID = "{00000000-0000-0000-0000-000000000002}"
      $script:actionName = "Software Inventory Cycle (Delta)"
   }
   "swfull" {
      $scheduleID = "{00000000-0000-0000-0000-000000000002}"
      $script:actionName = "Software Inventory Cycle (Full)"
   }
   "datadisc" {
      $scheduleID = "{00000000-0000-0000-0000-000000000003}"
      $script:actionName = "Discovery Data Collection Cycle (Delta)"
   }
   "datadiscfull" {
      $scheduleID = "{00000000-0000-0000-0000-000000000003}"
      $script:actionName = "Discovery Data Collection Cycle (Full)"
   }
   "filecollect" {
      $scheduleID = "{00000000-0000-0000-0000-000000000010}"
      $script:actionName = "File Collection Cycle (Delta)"
   }
   "filecollectfull" {
      $scheduleID = "{00000000-0000-0000-0000-000000000010}"
      $script:actionName = "File Collection Cycle (Full)"
   } 
   "swupdatedeploy" {
      $scheduleID = "{00000000-0000-0000-0000-000000000108}"
      $script:actionName = "Software Updates Deployment Evaluation Cycle"
   }
   "swupdatescan" {
      $scheduleID = "{00000000-0000-0000-0000-000000000113}"
      $script:actionName = "Software Updates Scan Cycle"
   }
   default {
      Write-Host -ForegroundColor 'red' "No valid Action is specified. Exiting..."
      exit
   }
}

#getting hostlist from pipe i.e.: PS C:\> gc list.txt | script.ps1
$hostlist = @($Input)

if($($hostlist.length) -gt 0){
   foreach ($srv in $hostlist) {
      if($srv){
         executeSCCMAction $srv $action $scheduleID 
      }
   }
}
else{
   # No hostname or hostlist is specified
}
Let me know your thoughts.
May The Force...
t