Mark Minasi's Tech Forum
Sign up Calendar Latest Topics
 
 
 


Reply
  Author   Comment  
meloao

Senior Member
Registered:
Posts: 109
Reply with quote  #1 
I wrote a script that attempts to uninstall the Rapid7 Insight Agent from a list of servers in a text file.   However, the command within the ForEach loop is giving me the following error:

"You cannot call a method on a null-valued expression."

 


<code>

$filePath="C:\scripts\server-list.txt"

$servers=Get-Content-Path$filePath

foreach($server in $servers) {

(Get-WmiObject-ClassWin32_Product-ComputerName$server|Where-Object{$_.Name -eq "Rapid 7 Insight Agent"}).uninstall()

}

</code>

 

0
cj_berlin

Avatar / Picture

Senior Member
Registered:
Posts: 421
Reply with quote  #2 
Well, let's see...

First off, if we knew for certain that Rapid7 is installed on every computer in that file, you wouldn't need a loop since -ComputerName happily takes an array of names:


(Get-WmiObject -Class Win32_Product -ComputerName $servers | Where-Object {$_.Name -eq "Rapid 7 Insight Agent"}).Uninstall()


BUT.

Second off, those zero-reference warnings are bound to come from the computers where the software isn't installed or maybe has a different name. To mitigate those, you would rewrite the one-liner in the loop into first getting the object and second calling the method:


foreach ($server in $servers) {
    $r7 = Get-WmiObject -Class Win32_Product -ComputerName $server | Where-Object {$_.Name -eq "Rapid 7 Insight Agent"}
    if ($null -ne $r7) {
        $r7.Uninstall()
    }
}


or even


$r7instances = Get-WmiObject -Class Win32_Product -ComputerName $servers | Where-Object {$_.Name -eq "Rapid 7 Insight Agent"}
foreach ($r7 in $r7instances) {
    $r7.Uninstall()
}


However, this is highly inefficient: You pull down all the thousands of Add-Remove-Program strings and then filter for the one you really need. Always filter at the source, if possible:


$r7instances = Get-WmiObject -Class Win32_Product -Filter 'Name="Rapid 7 Insight Agent"' -ComputerName $servers
foreach ($r7 in $r7instances) {
    $r7.Uninstall()
}


And since I have seen mixed results calling WMI methods on remote objects, I'd like to throw in one last one:

Invoke-Command -ComputerName $servers -ScriptBlock { $r7 = Get-WmiObject -Class Win32_Product -Filter 'Name="Rapid 7 Insight Agent"'; if ($r7) { $r7.Uninstall() }}


This way, all the processing is done on the remote machines and no WMI data is transferred over the wire.

__________________
Evgenij Smirnov

My personal blog (German): http://www.it-pro-berlin.de/
My stuff on PSGallery: https://www.powershellgallery.com/profiles/it-pro-berlin.de/
0
meloao

Senior Member
Registered:
Posts: 109
Reply with quote  #3 
This is very helpful with the various ways to approach this.  I get an understanding of your thought process.

Thanks again as always.  I will keep you posted on the results.
0
Previous Topic | Next Topic
Print
Reply

Quick Navigation:

Easily create a Forum Website with Website Toolbox.