Menu Close

Delete a large number of agents in SCOM from a text file

image

I have had this request from several customers, just want to document a PowerShell script example of this for the community.

Sometimes I have customers who end up with a large number of agents that are decommissioned, or we want to remove large numbers of agents because we migrated them to a different management group.  Sometimes we just need an automation example to use in a scripted decommission process.  In PowerShell, we don’t have a cmdlet to delete SCOM agents.  However, we do have a method we can leverage under ManagementGroupAdministration, called:  DeleteAgentManagedComputers

https://docs.microsoft.com/en-us/dotnet/api/microsoft.enterprisemanagement.administration.managementgroupadministration.deleteagentmanagedcomputers?view=sc-om-dotnet-2016

Here is a script example.  This is designed to be run on a SCOM management server locally, but can be modified to run remotely.

######################################################################## # Example: .\SCOMDeleteAgentsFromFile.ps1 -File "C:\temp\servers.txt" ######################################################################## param([string]$File) # If you want to hard code the path to the file # $File = "C:\temp\servers.txt" # Gather the start time of the script $StartTime = Get-Date #Clear the screen Clear-Host Write-Host `n"Starting Agent Delete Script" #Check to make sure we got some parameters IF (!($File)) { Write-Host `n"You must specify a full path to a file using the -File parameter to the script." Write-Host `n"Example: .\SCOMDeleteAgentsFromFile.ps1 -File ""C:\temp\servers.txt"""`n PAUSE EXIT } Write-Host `n"Full File Path: $File" Import-Module OperationsManager New-SCOMManagementGroupConnection -ComputerName Localhost # Load MG Administration object $MG = Get-SCOMManagementGroup $Admin = $MG.GetAdministration() #Get Server list Write-Host `n"Getting serverlist file content....." [array]$ServerList = Get-content $File IF (!($Serverlist)) { Write-Host `n"Getting serverlist file content FAILED"`n PAUSE EXIT } ELSE { $ServerlistCount = $ServerList.count Write-Host `n"Found ($ServerListCount) servers in serverlist file" } # Get all the Windows Computers into my Array Write-Host `n"Getting All Windows Computer objects in Management Group....." Write-Host `n"This can take a few minutes" [array]$WCarr = Get-SCOMClass -Name "Microsoft.Windows.Computer" | Get-SCOMClassInstance IF (!($WCArr)) { Write-Host `n"Getting all Windows Computer objects FAILED"`n PAUSE EXIT } ELSE { $WCCount = $WCArr.count Write-Host `n"Found ($WCCount) Windows Computer objects in Management Group" } # Create an empty Hashtable $HashTable = @{} # Fill the hashtable from the array using the unique FQDN as the Key FOREACH($WC in $WCarr) { $HashTable.Add("$($WC.DisplayName)",$WC) } #Start MM Loop Write-Host `n"Starting Agent Delete loop for servers in file....." FOREACH ($Server in $ServerList) { # Retrieve the individual matching object from the Hashtable $WCobj = $HashTable.($Server) IF (!($WCobj)) { Write-Host `n"Warning: $Server was not found as a Windows Computer object in SCOM. Skipping......"`n } ELSE { Write-Host `n"Deleting: $Server" $AMCguid = $WCobj.Id.Guid $query = [string]::Format("Id = '{0}'", $AMCguid.Trim()) #Create criteria for Agent Managed Computer $AMCCriteria = New-Object Microsoft.EnterpriseManagement.Administration.AgentManagedComputerCriteria($query) #Get Agent Managed Computer $AMCarr = ($Admin.GetAgentManagedComputers($AMCCriteria)) # Define generic collection list which is required parameter for the SDK delete command $AgentManagedComputerType = [Microsoft.EnterpriseManagement.Administration.AgentManagedComputer]; $GenericListType = [System.Collections.Generic.List``1] $GenericList = $GenericListType.MakeGenericType($AgentManagedComputerType) $AMCList = new-object $GenericList.FullName # Add each AMC in the array to the collection list FOREACH ($AMC in $AMCarr) { $AMCList.Add($AMC) } # Delete the agent in the collection $Admin.DeleteAgentManagedComputers($AMCList) } } #Log an event for script ending and total execution time. $EndTime = Get-Date $ScriptTime = ($EndTime - $StartTime).TotalSeconds Write-Host `n"Script Completed" Write-Host `n"Script Runtime: ($ScriptTime) seconds."`n #End of script

8 Comments

  1. Vicky

    Thanks for this, would be nice if you could come up with another variation (or built in) to remove Unix/Linux agents as well

  2. Andy Perry

    Thanks Kevin!

    Is there a way to catch any that fail to delete when the batch list is processed by the DeleteAgentManagedComputers?

    I can loop through the original $AMCList later checking if they have gone, but just wondering if any way to intercept during the batch job.

    Thank you

    Andrew

    • Andy Perry

      Also, apologies if I am mis-understanding…just trying to work through it all to learn and understand the flow.

      This looks like the call to the $Admin.DeleteAgentManagedComputers would run each time for each server in ServerList? Shouldn’t this just run once outside of the FOREACH loop?

      I assume the idea is to do a batch delete on all of the items in the $AMCList once. Or is it intentionally just deleting one at a time? If so, this might answer my first question πŸ™‚

      Thanks

      Andrew

      • Kevin Holman

        I chose to do a FOREACH LOOP through each server in the list, and doing individual deletes instead of creating a large collection, then deleting the collection in batch. I have had issues with batch deletes in the past, so to try and see if this would result in fewer orphaned objects, I chose to not batch delete the collection, but call the delete for each computer individually. I am not sure which is more reliable, but the goal was to reduce an odd anomaly I see sometimes where some components of a computer get left behind using this method. I didn’t check with an Escalation Engineer who looked at the code, and deleting an agent from agent managed does exactly the same as this, so I felt this was MOST reliable, albeit a bit slower than a batch delete. Speed was not my goal, reduced orphans was.

  3. Joe Thompson

    Kevin, thank you for this script. I am using it for a side-by-side upgrade from 2012R2 to 2019. We are upgrading the agents to 2019, and then calling this code after updating the management group in the agent. Instead of a text file with a server list, I replaced that code with $ServerList = Get-SCOMAgent |Where-Object {$_.Version -like ’10*’} |Select DisplayName

    Further down in the code, just need to make sure to use $Server.DisplayName instead of $Server

    So far, it has worked well in testing! Thanks again!

  4. BN

    The Operator role can not delete Agents using this PowerShell method? I’m trying to find a way for Operators to delete old Agents (since the Administration workspace is not available to them in the console) but the Operator role does not seem to grant the necessary permissions to delete agents. Is there any way to give an Operator role permission to delete agents or do you have to be a full admin to delete agents?

Leave a Reply

Your email address will not be published. Required fields are marked *