Scan list of PCs to uninstall software with a report

I’m new to Powershell and like what it can do, but I’m having issues trying to get it to do what I want lol.
I’m trying to come up with a Powershell script to scan our domain for PCs that have any version of Quicktime installed. If it’s found then uninstall, either way I’m looking to have it export to a log file with the computer name and if it was uninstalled or can’t connect. The below script works, but it shows the GENUS info and there’s nothing to identify it with the PC it was run on. If the software isn’t on there, the script give me “You cannot call a method on a null-valued expression.” on the second line. Any ideas? Thanks

$app = Get-WmiObject -Class Win32_Product -ComputerName (Get-Content "C:\Users\name\Desktop\pstest\test2list.txt") | Where-Object {$_.Name -like “*Quicktime*”}
$app.Uninstall() | Out-File C:\Users\name\Desktop\pstest\test2listout.txt

First, you should do a search, try “win32_product” and you will see results that start with evil, bad, alternatives, etc., because there are hidden issues using Win32_Product. Unfortunately, the alternatives without a management suite like SCCM, KACE, Altiris, Automation Manager, etc., are not going to be a couple lines of code. You can get installed software from registry and use WMI to create a process to uninstall the software. Take a look at this example:

http://techibee.com/powershell/powershell-uninstall-software-on-remote-computer/1400

As for why you are getting the null error, there are numerous issues. The .Uninstall() method exists in the context of a single WMI object. When you run your WMI call against multiple computers, you are creating a collection of results. Additionally, you are returning ALL software and then filtering with WHERE, which would most likely convert these from WMI objects into Powershell objects, which do not have an UnInstall() method. Again, you should really avoid the Win32_Product class, but I want you to understand some basic concepts of how you would implement this:

# Get a list of computers
$computers = Get-Content "C:\Computers.txt"

# Although you can pass a list of computers to Get-WMIObject, to call the method, WMI need to be connected to the
# computer when calling it. So, we need to loop through each computer and connect
foreach ( $computer in $computers ) {
    # Now here, I would normally ping the computer prior to connecting, but we're doing a high-level example.
    # We connect to the computer with WMI and our Filter is being done in WMI, so it will only return a result if
    # a product name contains quicktime. You want to filter as soon as possible and only return what you need.
    $quicktime = Get-WMIObject -Class Win32_Product -Filter "Name Like '%quicktime%'" -ComputerName $computer
    # Here, if you search a computer and quicktime is not installed, $quicktime will be null.  So, we need to 
    # check if the object is null before we attempt to call the method
    if ($quicktime) {
        "Found {0} on {1}" -f $quicktime.Name, $computer
        # if you look at the documentation for Win32_Product, the UnInstall() method returns 0 for success and
        # any other code would be a failure (except may 3010 which is reboot required), so we check the return
        $result = $quicktime.Uninstall()
        if ($result -eq 0) {
            "Uninstall successful on {0}" -f $computer
        }
        else {
            "Uninstall failed on {0}" -f $computer
        }
    }
    else {
        "Quicktime is not found on {0}" -f $computer
    }
}

Thanks Rob! This will help me out.

nthnu,

what infrastructure do you use to maintain your desktops? I love Powershell, and we had to get Quicktime Player out of the Domain ASAP due to the security bulletin.

We used a one line SCCM Task sequence to remove it across 1500 desktops / laptops using the good old MsiExec /X switch. This comes with all the built in reporting.

As some of the more experienced guys on this forum might say - pick your tool, sometimes Powershell, although awesome isn’t the right tool for the job, if like me you needed Quicktime gone, and couldn’t script this quickly - SCCM was sitting there all along for this specific task where I work.

Just Adding my 2 pence.

Win32_Product is not query optimized. Queries such as “select * from Win32_Product where (name like ‘Sniffer%’)” require WMI to use the MSI provider to enumerate all of the installed products and then parse the full list sequentially to handle the “where” clause. This process also initiates a consistency check of packages installed, verifying and repairing the install. With an account with only user privileges, as the user account may not have access to quite a few locations, may cause delay in application launch and an event 11708 stating an installation failure. For more information, see KB Article 794524.

If the users has a lot of applications installed this might take a while and could impact the users performance.

Taken from https://msdn.microsoft.com/en-us/library/aa394378(v=vs.85).aspx

Also, here is my take on it: http://tatux.co.uk/2015/03/20/get-ntsoftware/

After all that you still use Win32_Product in your script? Lol

I never once said I wouldn’t use it, I just added more information. Why is that funny?

I was asked to uninstall some applications from n number of machines. So I came up with the below PowerShell function and then I call the function in ForEach loop.
function Uninstall-Application

{
    Param
    (
        $ApplicationName
    )

    Begin
    {
        $isAvailable=Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -match $ApplicationName }
    }
    Process
    {
        if($isAvailable.Count -eq 1){
            $isAvailable.Uninstall();
            $output="Application uninstalled successfully."
        }else{
            $output="Application not found"
        }
    }
    End
    {
        return $output
    }
}

I know I am a bit late, hoping that it will help some one else.