Search code examples
powershellwmicimpowershell-5.1

Get-WMIObject Uninstall vs Get-CIMInstance Uninstall


Probably a dumb question but, I'm just curious.

Is there a difference between Get-CIMInstance and Get-WMIObject when Invoking an Uninstall for an application under the Win32_Product class? Only reason I ask is because:

  • Using Get-CIMInstance to uninstall an application, will reboot my computer with certain programs.
  • Using Get-WMIObject to uninstall an application just runs without rebooting.

Also, piping a Get-Member to any Get-CIMInstance product, doesn't give me a method to uninstall but, it does using Get-WMIObject. Is this just how the developers wrote it? Although, Invoke-CIMMethod -Name Uninstall still works.

Get-CIMInstance / Uninstall

Heres what I was doing to uninstall multiple apps using Get-CIMInstance/Invoke-CIMMethod -Name Uninstall:

Get-CimInstance -ClassName win32_product | Where-Object Name -Match "Visual" | 
    ForEach-Object -Process { 
        Invoke-CimMethod -InputObject $_ -Name Uninstall 
                            }
#Methods Returned
<#
Get-CimInstance -ClassName win32_product | Where-Object Name -Match "Visual" | Get-Member -MemberType Method


   TypeName: Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Product

Name                      MemberType Definition
----                      ---------- ----------
Clone                     Method     System.Object ICloneable.Clone()
Dispose                   Method     void Dispose(), void IDisposable.Dispose()
Equals                    Method     bool Equals(System.Object obj)
GetCimSessionComputerName Method     string GetCimSessionComputerName()
GetCimSessionInstanceId   Method     guid GetCimSessionInstanceId()
GetHashCode               Method     int GetHashCode()
GetObjectData             Method     void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Ser...
GetType                   Method     type GetType()
ToString                  Method     string ToString()
#>

Get-WMIObject / Uninstall

Get-WMIObject -ClassName win32_product | Where-Object Name -Match "Visual" | 
    ForEach-Object -Process { 
        Invoke-WMIMethod -InputObject $_ -Name Uninstall 
                            }
#Methods Returned
<#
Get-WMIObject -Class win32_product | Where-Object Name -Match "Visual" | Get-Member -MemberType Method


   TypeName: System.Management.ManagementObject#root\cimv2\Win32_Product

Name      MemberType Definition
----      ---------- ----------
Configure Method     System.Management.ManagementBaseObject Configure(System.UInt16 InstallState, System.UInt16 InstallLevel, S...
Reinstall Method     System.Management.ManagementBaseObject Reinstall(System.UInt16 ReinstallMode)
Uninstall Method     System.Management.ManagementBaseObject Uninstall()
Upgrade   Method     System.Management.ManagementBaseObject Upgrade(System.String PackageLocation, System.String Options)
#>

Pardon the long post, just a curious mind.

Please delete/close if not allowed.


Solution

  • There are lots of differences between using the WMI cmdlets and the newer CIM cmdlets. Get-WMIObject is deprecated in windows PowerShell and has been removed from PowerShell Core, so the general recommendation is to go with CIM. The methods shouldn't behave differently though, so I can't explain the reboot behavior you mentioned.

    The objects returned by Get-CimInstance don't have the methods, but you can pass them to Invoke-CimMethod`.

    $instance = Get-CimInstance win32_process -Filter "Name = 'powershell_ise.exe'"
    $instance | Invoke-CimMethod -MethodName 'Terminate'
    

    You can discover methods using Get-CimClass

    (Get-CimClass win32_process ).CimClassMethods
    

    If you need arguments for a given method they can be passed via the -Arguments parameter using a hash table as the argument. You can find examples in the help file or here

    You can use Invoke-WMIMethod directly too:

    Invoke-CimMethod -Query "SELECT * FROM Win32_Process WHERE Name = 'powershell_ise.exe'" -MethodName Terminate
    

    I usually don't do it that way because it's a little less verbose to use -Filter with -CLassName, and -Filter is missing isn't available with Invoke-CimMethod However, these are just personal preferences.

    I recommend you read Introduction to CIM Cmdlets as well

    Also, Win32_Product has a bad reputation. If you google it you can get more information but here's an article I quickly found through SO questions: Why Win32_Product is Bad News

    As a general rule you should move filtering left in the command. Use the -Query or -Filter parameters rather than getting all instances and using a Where{} afterward. Especially considering the known performance issues with Win32_Product.