Showing posts with label sccm 2007. Show all posts
Showing posts with label sccm 2007. Show all posts

23 March, 2014

List SCCM servers in your infrastructure - SCCM

When you have a large infrastructure, you have lots of moving parts, so you might not want to keep track of your servers on  PostIt or in an xls file. Why? It's just overhead and someone always forgets to update it when pulling a server out or installing a new one.

Let's make the inventory dynamic and base it on the infrastructure component itself... meaning, if you have e.g. an SCCM infrastructure with many sites, many servers with different roles (Management points, Site Servers, Fallback status points...etc.) try to gather it from the SCCM infrastructure itself, instead of having a manual list in an xls file somewhere.
Happened one day that I wanted to get the list of SCCM servers in all the sites (sub-sites) with all their roles (SCCM 2007 and SCCM 2012 as well. If you start browsing in the WMI root of SCCM on the site server and look through some of the tables in the database, you will the way eventually, here is the SQL query which lists all SCCM servers and their roles (with some garbage):
Select distinct SiteSystem, SiteCode, Role FROM dbo.Summarizer_SiteSystem ORDER BY SiteCode

To get rid of the garbage and only see the server names, let's do a regex match and some replacing:
[string]$tmpstr = [regex]::Match($sccmSrvObj.sitesystem, \\\\(\w|\.)+\\$)
$sccmServerName = $tmpstr.replace("\", "")

If you want the roles listed as well:
$sccmQueryResult | ?{$_.SiteSystem -imatch $sccmServerName}| %{$sObject.Role += $_.role + ","}

If you have SCCM 2012, be aware that the database naming changed from SMS_sitecode to CM_sitecode, however they also made the DB name available via WMI:
$sccmDB = (gwmi -ComputerName $sccmsrv -Namespace ROOT\SMS\site_$site -Class SMS_SCI_SiteDefinition).SQLDatabaseName

Here is an example script which takes an SCCM server name and a Site code and lists all servers from that site (and sub-sites) with their SCCM roles - as always, you can add logging, error handling...etc.
If you want to make it more sophisticated, you could just get an Active Directory domain name, read the list of SCCM sites registered and then list all SCCM servers... I may put it into another article...

 
 param(     [string] $sccmSrv = "",  
           [string] $site = "")  
   
   
 #### Function for executing a SQL query with integrated authentication    
 function execSQLQuery ([string]$fSQLServer, [string]$db, [string]$query){    
      $objConnection = New-Object System.Data.SqlClient.SqlConnection    
      $objConnection.ConnectionString = "Server = $fSQLServer; Database = $db; trusted_connection=true;"    
      $SqlCmd = New-Object System.Data.SqlClient.SqlCommand $query, $objConnection    
      trap {Write-Host -ForegroundColor 'red' "($sqlsrv/$db not accessible)";continue}    
      $SqlCmd.Connection.Open()    
   
      if ($SqlCmd.Connection.State -ine 'Open') {    
           $SqlCmd.Connection.Close()    
           return    
      }    
      $dr = $SqlCmd.ExecuteReader()    
   
      #get the data    
      $dt = new-object "System.Data.DataTable"    
      $dt.Load($dr)    
      $SqlCmd.Connection.Close()    
      $dr.Close()    
      $dr.Dispose()    
      $objConnection.Close()    
      return $dt    
 }    
   
 $objCollection = @()  
 $sccmCompquery = gwmi -q "Select distinct SiteSystem, Role, SiteCode FROM SMS_SiteSystemSummarizer where role = 'SMS SQL Server' and siteCode = '$site' ORDER BY SiteCode" -namespace "root\sms\site_$site" -ComputerName $sccmSrv  
   
 [string]$tmpstr = [regex]::Match($sccmCompquery.sitesystem, "\\\\(\w|\.)+\\$")  
 $sccmSQLServer = $tmpstr.replace("\", "")  
 $sccmDB = (gwmi -ComputerName $sccmsrv -Namespace ROOT\SMS\site_$site -Class SMS_SCI_SiteDefinition).SQLDatabaseName  
   
 if(!$sccmDB){  
      $sccmDB = "SMS_" + $site  
 }  
   
 $sccmCompquery = "Select distinct SiteSystem, SiteCode, Role FROM dbo.Summarizer_SiteSystem ORDER BY SiteCode"  
 $sccmQueryResult = execSQLQuery.NET $sccmSQLServer $sccmDB $sccmCompquery  
   
 foreach($sccmSrvObj in $sccmQueryResult){  
      [string]$tmpstr = [regex]::Match($sccmSrvObj.sitesystem, "\\\\(\w|\.)+\\$")  
      $sccmServerName = $tmpstr.replace("\", "")  
   
      # if we haven't recorded the given server  
      if(!($objCollection | ?{$_.SiteServer -ieq $sccmServerName})){  
   
           $sObject = new-Object -typename System.Object  
           $sObject | add-Member -memberType noteProperty -name SiteServer -Value $sccmServerName  
           $sObject | add-Member -memberType noteProperty -name SiteCode -Value $sccmSrvObj.SiteCode  
           $sObject | add-Member -memberType noteProperty -name Role -Value ""  
   
           # go through the rows in the query result and pick up each row where our server is listed  
           $sccmQueryResult | ?{$_.SiteSystem -imatch $sccmServerName}| %{$sObject.Role += $_.role + ","}  
           $sObject.Role = $sObject.Role -replace ",$",""  
        
           $objCollection += $sObject  
      }  
 }  
   
 $objCollection  
   


t

07 December, 2013

Add / Remove members of collections - SCCM


Continuing on the managing collections subject in SCCM (List members of SCCM collection, List SCCM collections and their details - SCCM ) I think the next natural step people want to do with a collection - in case you are thinking about using SCCM in a large environment - is to add/remove computers to/from a collection and at the same time, forget about the very colorful, but sluggish mmc console.
Obviously, this is only useful if you are not thinking about creating conditions/filters for a collection membership but you want to manually add loads of servers into a collection based on seemingly no commonalities between them or - the contrary - too many commonalities between them.

There's such a case when you have 8000 servers without a particular software component, but you don't want to install it on all of them at the same time, you want to do it in phases. Why? Because I think it's better to screw up 500 servers spread across the world than either 500 in one location (taking out the service in that location) or all 8000 of them.
You could argue, if you break 500 servers, you better update your CV so why not be brave and effective and target all 8000? I'll leave it with your capable decision making.

If I want to add/remove computers to/from a collection, I will need a couple of things:
  • The ID of the collection - if you want to be nice, you make the script to looks this up based on the collection name, but you can be rude if you want to and make people remember hex number - I think DNS should not have been invented, people should NOT be lazy and they should remember IP addresses!
    $queryResult = execSQLQuery $fsccmSQLServer "SMS_$site" "select CollectionID from v_Collection where name like '$collectionName'"
  • The ID of the computer being added/removed:
    $queryResult = execSQLQuery $fsccmSQLServer "SMS_$site" "select ResourceID from v_R_System where name0 = '$srv'"
    $computerResID = $queryResult.ResourceID
  • Bind the WMI instance of the collection to be able to invoke methods (like AddMembershipRule, DeleteMembershipRule):
    $global:mc = [wmi]"\\$sccmsrv\root\sms\site_$($site):SMS_Collection.CollectionID='$collID'"

If you look at the two functions addComputerToCollection and removeComputerFromCollection  you can see how the wmi methods can be used. There's only one twist in the addComputerToCollection to make sure the given computer exists in SCCM before trying to add an empty membership. This is required because the AddMembershipRule method does not have a very good exception handling, so need to implement it in the script instead.

Needless to say, these are snippets from a much bigger script I use for managing collections which has additional logging, a bit more exception handling, more parameters to be able to use it against multiple SCCM sites...etc. to make it a complete tool. However, the published code snippets can be used as individual scripts.

A script to add/remove computers to/from SCCM collections could look like this:

 param (   
    [string] $hosts = "",  
    [switch] $addcomputer = $false,  
    [switch] $removecomputer = $false,  
    [string] $sccmsrv = "r2d2SCCM",  
    [string] $site = "SW1",  
    [string] $collName = "",  
    [string] $collID = "",  
    [string] $log = "")  
   
   
 #### Function for adding a computer to an SCCM collection  
 function addComputerToCollection ([string]$collectionID, [string]$SccmServer, $fsccmSQLServer, [string]$site, [string]$srv){  
    $found = $false  
   
    # checking if the direct membership for the computer exist or not  
    foreach($member in $global:mc.CollectionRules){  
       if($member.RuleName -ieq $srv){  
          $found = $true  
          break  
       }  
    }  
   
    if($found){  
       $retVal = "host has already got direct membership"  
    }  
    else{  
   
       # getting resource ID of the computer  
       $queryResult = execSQLQuery $fsccmSQLServer "SMS_$site" "select ResourceID from v_R_System where name0 = '$srv'"  
       $computerResID = $queryResult.ResourceID  
   
       if($computerResID){  
   
       # creating DirectRule  
          $objColRuledirect = [WmiClass]"\\$SccmServer\ROOT\SMS\site_$($site):SMS_CollectionRuleDirect"  
          $objColRuleDirect.psbase.properties["ResourceClassName"].value = "SMS_R_System"  
          $objColRuleDirect.psbase.properties["ResourceID"].value = $computerResID  
   
          #target collection  
          $InParams = $global:mc.psbase.GetMethodParameters('AddMembershipRule')  
          $InParams.collectionRule = $objColRuleDirect  
          $R = $global:mc.PSBase.InvokeMethod('AddMembershipRule', $inParams, $Null)  
   
          if($r.ReturnValue -eq 0){$retVal = "OK" }  
          else   {$retVal = "Err"}  
       }  
       else{  
       $retVal = "Computer is not in SCCM DB"  
       }  
    }  
    return $retVal  
 }  
   
   
 #### Function for a computer from an SCCM collection  
 function removeComputerFromCollection ([string]$collectionID, [string]$srv){  
    $found = $false  
   
    foreach($member in $global:mc.CollectionRules){  
       if($member.RuleName -ieq $srv){  
          $res = $global:mc.deletemembershiprule($member)  
          $found = $true  
          break  
       }  
    }  
    if($res.ReturnValue -eq 0){$retVal = "OK" }  
    else   {$retVal = "Err"}  
   
    if(!$found){$retVal = "No direct membership of $srv in collection $collectionID"}  
    return $retVal  
 }  
   
   
   
 #### Function for enumerating ID of an SCCM collection  
 function lookupCollID ([string]$fsccmSQLServer, [string]$site, [string] $collectionName){  
    $queryResult = execSQLQuery $fsccmSQLServer "SMS_$site" "select CollectionID from v_Collection where name like '$collectionName'"  
    $fcount = ($queryResult | Group-Object -Property CollectionID).count  
   
    if($fcount -eq 1){  
       $fcollectionID = $queryResult.CollectionID  
   
       if(!$fcollectionID){  
          exit  
       }  
       else{  
          return $fcollectionID  
       }  
    }  
    elseif($fcount -gt 1){  
       exit  
    }  
    else{  
       exit  
    }  
 }  
   
   
   
 #### Function for executing a SQL query with integrated authentication    
 function execSQLQuery ([string]$fSQLServer, [string]$db, [string]$query){    
    $objConnection = New-Object System.Data.SqlClient.SqlConnection    
    $objConnection.ConnectionString = "Server = $fSQLServer; Database = $db; trusted_connection=true;"    
    $SqlCmd = New-Object System.Data.SqlClient.SqlCommand $query, $objConnection    
    trap {Write-Host -ForegroundColor 'red' "($sqlsrv/$db not accessible)";continue}    
    $SqlCmd.Connection.Open()    
   
    if ($SqlCmd.Connection.State -ine 'Open') {    
       $SqlCmd.Connection.Close()    
       return    
    }    
    $dr = $SqlCmd.ExecuteReader()    
   
    #get the data    
    $dt = new-object "System.Data.DataTable"    
    $dt.Load($dr)    
    $SqlCmd.Connection.Close()    
    $dr.Close()    
    $dr.Dispose()    
    $objConnection.Close()    
    return $dt    
 }    
   
   
   
 ##################################################### Body #####################################################  
   
 # if site is not specified, let's get it from the SCCM server itself  
 if(!$site){  
    $site = (gwmi -ComputerName $sccmsrv -Namespace root\sms -Class SMS_ProviderLocation).sitecode  
 }  
   
   
 #### Collate the host list.  
 $hostlist = @($Input)  
 if ($hosts) {  
    if($hosts -imatch " "){  
       $hostsArr = @($hosts.split(" "))  
       $hostlist += $hostsArr  
    }  
    else{  
       $hostlist += $hosts  
    }  
 }  
   
 # if -collName, we need to enumerate the collection ID  
 if(!$collID -and $collName){  
    $collID = lookupCollID $sccmsrv $site $collName  
 }  
   
 if($($hostlist.length) -gt 0){  
    $global:mc = ""  
    #Binding collection $collID  
    $global:mc = [wmi]"\\$sccmsrv\root\sms\site_$($site):SMS_Collection.CollectionID='$collID'"  
   
    if($global:mc){  
   
       $hostlistlength = $hostlist.length  
       $k = 1  
       $objColl = @()  
   
       foreach ($srv in $hostlist) {  
          $result = $result2 = ""  
   
          if($srv -ne ""){       # if the hostname is not empty  
             Write-Progress -activity "Performing checks" -Status "Processing host $k of $hostlistlength : $srv " -PercentComplete ($k/$hostlistlength * 100) -currentoperation "checking Client state..."  
   
             # if -addcomputer, then we need to add computers to collections (direct membership)  
             if($addcomputer){  
                $sObject = new-Object -typename System.Object  
                $sObject | add-Member -memberType noteProperty -name Hostname -Value $srv  
   
                # adding host to collection $collName $collID  
                $result = addComputerToCollection $collID $sccmsrv $sccmsrv $site $srv  
   
                $sObject | add-Member -memberType noteProperty -name Result -Value $result  
                $objColl += $sObject  
             }  
   
             # if -removecomputer, then we need to remove computers from collections (direct membership)  
             if($removecomputer){  
                $sObject = new-Object -typename System.Object  
                $sObject | add-Member -memberType noteProperty -name Hostname -Value $srv  
   
                # removing host from collection $collName $collID  
                $result = removeComputerFromCollection $collID $srv  
   
                $sObject | add-Member -memberType noteProperty -name Result -Value $result  
                $objColl += $sObject  
             }  
          }  
          $k++  
       }  
    }  
    else{  
    "Could not bind collection"  
    }  
 }  
 else{  
    "No hostname or hostlist is specified."  
 }  
   
 $objColl  

t


24 February, 2013

List Collection membership of computers - SCCM

Continuing from the previous article - where I wrote about SCCM Resource Explorer and how to handle multiple machines when you want to see the inventoried data about them in SCCM - there's another important parameter of computers in SCCM which can be listed: the SCCM Collections computer(s) are member of.

Why is this needed? When you advertise a package or a baseline in Desired Configuration Management, you target collections. You do this for years on a couple of 1000s computers and then one day you get 100 computer names from someone saying, I want to make sure all automated deployments and baselinings stop on these for the next 6 months. Then you would need to look through all 750 collections to see which of them have some of those 100 computers as members. So you want a way to generate a list of collections for each computer.

To do it on the SCCM console, it's not really possible, so let's see a PowerShell way. We need to put some functions and supporting actions into the script, let's have a look at them.

Function for executing SQL query to get data out of SCCM DB:
function execSQLQuery ([string]$fSQLServer, [string]$db, [string]$query){
   $objConnection = New-Object System.Data.SqlClient.SqlConnection
   $objConnection.ConnectionString = "Server = $fSQLServer; Database = $db; trusted_connection=true;"
   $SqlCmd = New-Object System.Data.SqlClient.SqlCommand $query, $objConnection
   trap {Write-Host -ForegroundColor 'red' "($sqlsrv/$db not accessible)";continue}
   $SqlCmd.Connection.Open()
   if ($SqlCmd.Connection.State -ine 'Open') {
      $SqlCmd.Connection.Close()
      return
   }   $dr = $SqlCmd.ExecuteReader()

  
#get the data
   $dt = new-object "System.Data.DataTable"
   $dt.Load($dr)
   $SqlCmd.Connection.Close()
   $dr.Close()
   $dr.Dispose()
   $objConnection.Close()
   return $dt
}

Read SCCM site name from SCCM site server remotely:
$site = (gwmi -ComputerName $sccmsrv -Namespace root\sms -Class SMS_ProviderLocation).sitecode

Read SQL server name from SCCM:
$sccmCompquery = gwmi -q "Select distinct SiteSystem, Role, SiteCode FROM SMS_SiteSystemSummarizer where role = 'SMS SQL Server' and siteCode = '$site' ORDER BY SiteCode" -namespace "root\sms\site_$site" -ComputerName $sccmsrv
[string]$tmpstr = [regex]::Match($sccmCompquery.sitesystem, "\\\\\w+\\$")
$sccmSQLServer = $tmpstr.replace("\", "")


SQL query to list collection memberships of computers
$memberQuery = "SELECT dbo.v_Collection.Name "
$memberQuery += "FROM dbo.v_FullCollectionMembership INNER JOIN dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID "
$memberQuery += "WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('$srv'))"

At the end the script will list the names of computers and list their collection memberships.

The full script looks like:

 param (   [string] $hosts = "",  
       [string] $sccmsrv = "")  
    
  #### Function for executing a SQL query with integrated authentication  
  function execSQLQuery ([string]$fSQLServer, [string]$db, [string]$query){  
    $objConnection = New-Object System.Data.SqlClient.SqlConnection  
    $objConnection.ConnectionString = "Server = $fSQLServer; Database = $db; trusted_connection=true;"  
    $SqlCmd = New-Object System.Data.SqlClient.SqlCommand $query, $objConnection  
    trap {Write-Host -ForegroundColor 'red' "($sqlsrv/$db not accessible)";continue}   
    $SqlCmd.Connection.Open()  
    
    if ($SqlCmd.Connection.State -ine 'Open') {  
       $SqlCmd.Connection.Close()  
       return  
    }  
    $dr = $SqlCmd.ExecuteReader()  
    
    #get the data  
    $dt = new-object "System.Data.DataTable"  
    $dt.Load($dr)  
    $SqlCmd.Connection.Close()  
    $dr.Close()  
    $dr.Dispose()  
    $objConnection.Close()  
    return $dt  
  }  
    
  # read the SCCM site name of the SCCM site server  
  $site = (gwmi -ComputerName $sccmsrv -Namespace root\sms -Class SMS_ProviderLocation).sitecode  
    
  # enumerating SQL server name for the given SCCM site server  
  $sccmCompquery = gwmi -q "Select distinct SiteSystem, Role, SiteCode FROM SMS_SiteSystemSummarizer where role = 'SMS SQL Server' and siteCode = '$site' ORDER BY SiteCode" -namespace "root\sms\site_$site" -ComputerName $sccmsrv  
  [string]$tmpstr = [regex]::Match($sccmCompquery.sitesystem, "\\\\\w+\\$")  
  $sccmSQLServer = $tmpstr.replace("\", "")  
  $objColl = @()  
    
  #### Collate the host list.  
  $hostlist = @($Input)  
  if ($hosts) {  
    if($hosts -imatch " "){  
       $hostsArr = @($hosts.split(" "))  
       $hostlist += $hostsArr  
    }  
    else{  
       $hostlist += $hosts  
    }  
  }  
    
  # going through the list of hosts  
  foreach($srv in $hostlist){  
    $memberQuery = "SELECT dbo.v_Collection.Name "  
    $memberQuery += "FROM dbo.v_FullCollectionMembership INNER JOIN dbo.v_Collection ON dbo.v_FullCollectionMembership.CollectionID = dbo.v_Collection.CollectionID "  
    $memberQuery += "WHERE (LOWER(dbo.v_FullCollectionMembership.Name) = LOWER('$srv'))"  
    
    # running sql query to enumerate list of collections the computer is member of  
    $membership = execSQLQuery $sccmSQLServer "SMS_$site" $memberQuery  
    
    # if we have a result, go through it and build an object collection with the computer name and the collection(s) it is member of  
    if($membership){  
       foreach($enumColl in $membership){  
         $sObject ="" | select ComputerName,Result  
         $sObject.ComputerName = $srv  
         $sObject.Result = $enumColl.name  
         $objColl += $sObject  
       }  
    }  
  }  
    
  $objColl 

May the Force...
t


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