How to Query Installed Programs on Remote Windows Machines Using WMIC and PowerShell


9 views

For Windows environments, WMIC (Windows Management Instrumentation Command-line) offers a built-in way to remotely query installed programs. The basic syntax:

wmic /node:"COMPUTERNAME" product get name,version

To authenticate with different credentials:

wmic /node:"COMPUTERNAME" /user:"DOMAIN\username" /password:"password" product get name,version

For more modern systems with PowerShell remoting enabled:

Invoke-Command -ComputerName REMOTEPC -ScriptBlock { 
    Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | 
    Select-Object DisplayName, DisplayVersion 
}

To run these commands discreetly without user notification:

Start-Process -WindowStyle Hidden -FilePath "wmic.exe" -ArgumentList '/node:"TARGETPC" product get name'

Create a text file with computer names (computers.txt) and run:

foreach ($computer in Get-Content .\computers.txt) {
    Write-Host "Querying $computer" -ForegroundColor Yellow
    wmic /node:$computer product get name | Out-File ".\$computer-software.txt"
}

To find specific applications across your network:

Get-Content .\computers.txt | ForEach-Object {
    if (wmic /node:$_ product get name | Select-String "Adobe") {
        "$_ has Adobe products installed" | Out-File results.txt -Append
    }
}
  • Use encrypted credentials with Get-Credential in PowerShell
  • Consider constrained endpoints for PowerShell remoting
  • Document all remote access for compliance purposes

For Windows environments, WMIC (Windows Management Instrumentation Command-line) provides a lightweight way to inventory installed software across networked machines. The basic syntax for remote querying is:

wmic /node:"REMOTE_PC_NAME" product get name,version

To authenticate with domain credentials:

wmic /node:"REMOTE_PC_NAME" /user:"DOMAIN\username" /password:"password" product get name,version

For more flexibility, PowerShell's Get-WmiObject (or Get-CimInstance in newer versions) works better:

$cred = Get-Credential
Get-WmiObject -Class Win32_Product -ComputerName "REMOTE_PC_NAME" -Credential $cred | 
Select-Object Name,Version

To run silently without user interaction, create a scheduled task:

$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -Command "Get-WmiObject Win32_Product | Select Name,Version | Export-Csv -Path 'C:\temp\software.csv' -NoTypeInformation""
$trigger = New-ScheduledTaskTrigger -At 3am -Daily
Register-ScheduledTask -TaskName "SoftwareInventory" -Action $action -Trigger $trigger -RunLevel Highest

For enterprise-scale queries, process multiple machines from a text file:

$computers = Get-Content "C:\temp\machines.txt"
$results = foreach ($computer in $computers) {
    try {
        Get-WmiObject -Class Win32_Product -ComputerName $computer -ErrorAction Stop |
        Select-Object @{Name='Computer';Expression={$computer}},Name,Version
    }
    catch {
        [PSCustomObject]@{
            Computer = $computer
            Name = "Access Denied"
            Version = $_.Exception.Message
        }
    }
}
$results | Export-Csv -Path "C:\temp\network_software.csv" -NoTypeInformation

For more complete results (including non-MSI packages), query the registry:

Invoke-Command -ComputerName "REMOTE_PC_NAME" -ScriptBlock {
    $paths = @(
        'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
        'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
    Get-ItemProperty $paths | 
    Where-Object { $_.DisplayName } |
    Select-Object DisplayName,DisplayVersion
}