Removing Monitoring Agents (Not Really)

Thanks to my coworker Keith Munson for the core logic.

 

This post is written around the task of removing SCOM and MOM monitoring agents, but those rely on knowing the agent’s MSI installer’s GUID.

The easiest way to get that is to go to a box with the right version of the monitoring agent installed, open the registry, navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall and search for ‘System Center Monitoring Manager’ and look for data of the UninstallString value.

MsiExec.exe /I{25097770-2B1F-49F6-AB9D-1C708B96262A}

The {25097770-2B1F-49F6-AB9D-1C708B96262A} (including the braces) is the GUID in question.

But, enough of that.  Let’s talk Remoting.  Specifically, Invoke-Command.  Invoke-Command can take a –ScriptBlock parameter.  ScriptBlocks are tricky, trying things.  If you want to dynamically create the ScriptBlock, say, by interpolating data stored in a $variable, you can’t simply cast a string to ScriptBlock.

Instead you have to use the $ExecutionContext.InvokeCommand.NewScriptBlock($string) to create the ScriptBlock from a given string.

The output of the Write-Debug statement, which will not be seen by 99% of the people, first attempted to capture the $scriptBlock.ToString() as a “`{{0}`}” –f $ScriptBlock.ToString(), then by “`{$($ScriptBlock.ToString())`}, but neither worked.  I normally hate using the + operator to build a string, but that seems to be the only thing that works.

function Test-MonitoringAgentRegKey {
     param ( 
         [string]$computer,
         [HashTable]$AgentGuid = @{
             "{25097770-2B1F-49F6-AB9D-1C708B96262A}" = 'SCOM2007R2';
             "{5155DCF6-A1B5-4882-A670-60BF9FCFD688}" = 'SCOM2007';
             "{E7600A9C-6782-4221-984E-AB89C780DC2D}" = 'SCOM2007SP1'; # SP1 slipstream
             "{768DB8BD-CB3A-43F4-9A4C-BA2921D27AD3}" = 'SCOM2007SP1'; # RTM to SP1
             "{F692770D-0E27-4D3F-8386-F04C6F434040}" = 'MOM'
         }
     );

     $key = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
     $compRegKey = $null;
    
     if ($computer) {
         if (!$compRegKey) {    
             try {
                 $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computer);
             } 
             catch {
                 Write-Warning "Unable to open remote registry on -computerName $computer.  Skipping.";
                 return -1;
             }
             foreach ($guid in ($AgentGuid.Keys | Sort-Object)) {
                 $compRegKey = $reg.OpenSubKey("$key\$guid", $false);
                 break;
             }
             if (!$compRegKey) { $guid = $null; }
         }
     }
    
     if ($guid) {
         Write-Debug "$computer $guid $($AgentGuid.$guid)";
     } else {
         Write-Debug "$computer MonitoringAgentUninstalled";
     }
    
     $guid;
}

function Test-MonitoringAgent {
     param (
         [Parameter( 
             Position = 0,  
             ValueFromPipeline = $true, 
             ValueFromPipelineByPropertyName = $true 
         )][string[]]$ComputerName = @(),
         [HashTable]$AgentGuid = @{
             "{25097770-2B1F-49F6-AB9D-1C708B96262A}" = 'SCOM2007R2';
             "{5155DCF6-A1B5-4882-A670-60BF9FCFD688}" = 'SCOM2007';
             "{E7600A9C-6782-4221-984E-AB89C780DC2D}" = 'SCOM2007SP1'; # SP1 slipstream
             "{768DB8BD-CB3A-43F4-9A4C-BA2921D27AD3}" = 'SCOM2007SP1'; # RTM to SP1
             "{F692770D-0E27-4D3F-8386-F04C6F434040}" = 'MOM'
         }
     );
    
     begin {
         trap { 
             if ($DebugPreference -eq 'continue') { $Host.EnterNestedPrompt(); }
         }
     }
    
     process {
         $ComputerName | Select-Object @{
             n = 'ComputerName';
             e = { $_; }
         }, @{
             n = 'installed';
             e = { 
                 $guid = Test-MonitoringAgentRegKey $_ -AgentGuid $AgentGuid;
                 if (!$guid) { 
                     "NotInstalled"; 
                 } elseif ($guid -eq -1) {
                     "ERROR";
                 } else {
                     $AgentGuid.$guid;
                 }
             }
         }        
     }
}

function Remove-MonitoringAgent {
     param (
         [Parameter( 
             ValueFromPipeline = $true
         )][string[]]$ComputerName = @(),
         [HashTable]$AgentGuid = @{
             "{25097770-2B1F-49F6-AB9D-1C708B96262A}" = 'SCOM2007R2';
             "{5155DCF6-A1B5-4882-A670-60BF9FCFD688}" = 'SCOM2007';
             "{E7600A9C-6782-4221-984E-AB89C780DC2D}" = 'SCOM2007SP1'; # SP1 slipstream
             "{768DB8BD-CB3A-43F4-9A4C-BA2921D27AD3}" = 'SCOM2007SP1'; # RTM to SP1
             "{F692770D-0E27-4D3F-8386-F04C6F434040}" = 'MOM'
         }
     );
    
     process {
         foreach ($computer in $ComputerName) {
             $guid = Test-MonitoringAgentRegKey -Computer $computer -AgentGuid $AgentGuid;
             if ($guid) {
                 Write-Progress (Get-Date) "Removing $($AgentGuid.$guid) from $computer";
                
                 $cmd = "msiexec.exe /x '$guid' /qn /noreboot";
                 $scriptblock = $ExecutionContext.InvokeCommand.NewScriptBlock($cmd);
                 Write-Debug ("Invoke-Command -ComputerName $computer -ScriptBlock `{" + $scriptblock.ToString() + "`}");

                 Invoke-Command -ComputerName $computer -ScriptBlock $scriptBlock;
             }
             Test-MonitoringAgent -ComputerName $computer;
         }
     }
}