I wrote a powershell script for inventorying software on all PC's on a windows domain. Below I will show you how to use it and provide you with a copy of the code.
For this program to work you will need a computer running Microsoft Powershell. Windows 7 and 2008 R2 come with powershell pre-built into them. For windows XP, 2003 and 2008 you need to manually download and install the powershell component. This PC must be a member of the domain!
Get powershell from here:
Next you need to configure powershell to allow unsigned scripts to run. By default powershell is set to RemoteSigned meaning it will not run any scripts that have not been signed by an external certificate authority. To digitally sign scripts you need to buy a certificate for each piece of code you want to sign! Open powershell with administrator rights to the local system. You may have to “Run as Administrator” due to UAC!
Close the window and open another powershell window that has domain admin rights. This means you need to run the power shell window as another user. To perform “Run As” on windows 7 or Vista please see:
Running the Script
This powershell script will go through every computer account in active directory, ping the computer name, if it replies then perform the WMI query. This avoids the script failing for computers that are not turned on.
From the powershell session running as a domain admin account, navigate to the folder containing the script and run it.
You can see it will go through and skip any PC’s that are turned off. This data will get pushed into a csv which is placed in your user’s profile. Remember if you’re running as a domain admin, the csv file will be located in the domain admin user’s profile, not yours!
Reviewing the Results
Note: You must not open this file while the script is still running. This will prevent the script being able to write to it as excel takes ownership of it.
Open the CSV file up in excel and format it so it is easier to read. All the software will be listed in order along with which computer the application is installed on. Any PC’s that have any problems with WMI will not be able to perform the audit, however in a healthy windows domain all PC’s should be able to respond to WMI queries.
To be able to query a PC's software you need the Management and Monitoring Tools --> WMI Windows Installer Provider windows component installed from add and remove windows components. This feature is automatically built into windows vista, 2008 and windows 7. If this is not installed the script will return the following error:
You will also recieve errors when you perform manual WMI queries related to software against these machines that do not have this component:
Don't worry I wrote up a blog post on this problem and have developed a way to mass deploy this windows component out to all PC's your trying to audit. Find this here:
Copy of the Script
Here is the full copy of my script:
$datetime = Get-Date -Format "yyyyMMddhhmmss";
$strCategory = "computer";
# Create a Domain object. With no params will tie to computer domain
$objDomain = New-Object System.DirectoryServices.DirectoryEntry;
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher; # AD Searcher object
$objSearcher.SearchRoot = $objDomain; # Set Search root to our domain
$objSearcher.Filter = ("(objectCategory=$strCategory)"); # Search filter
$colProplist = "name";
foreach ($i in $colPropList)
$colResults = $objSearcher.FindAll();
# Add column headers
Add-Content "$Env:USERPROFILE\softwareaudit $datetime.csv" "Computer,Caption,Description,Identifying Number,Installation Date,Installation Date 2,Installation Location,Installation State,Name,Package Cache,SKU Number,Vendor,Version";
foreach ($objResult in $colResults)
$objComputer = $objResult.Properties;
$computer = $objComputer.name;
$ipAddress = $pingStatus.ProtocolAddress;
# Ping the computer
$pingStatus = Get-WmiObject -Class Win32_PingStatus -Filter "Address = '$computer'";
if($pingStatus.StatusCode -eq 0)
Write-Host -ForegroundColor Green "Ping Reply received from $computer.";
write-host "Connecting to $computer..."
$colItems = get-wmiobject -class "Win32_Product" -namespace "root\CIMV2" `
write-host "Computer: " $computer
foreach ($objItem in $colItems)
write-host "Caption: " $objItem.Caption
$caption = $objItem.Caption
write-host "Description: " $objItem.Description
$description = $objItem.Description
write-host "Identifying Number: " $objItem.IdentifyingNumber
$identifier = $objItem.IdentifyingNumber
write-host "Installation Date: " $objItem.InstallDate
$installdate = $objItem.InstallDate
write-host "Installation Date 2: " $objItem.InstallDate2
$installdate2 = $objItem.InstallDate2
write-host "Installation Location: " $objItem.InstallLocation
$installlocation = $objItem.InstallLocation
write-host "Installation State: " $objItem.InstallState
$installstate = $objItem.InstallState
write-host "Name: " $objItem.Name
$name = $objItem.Name
write-host "Package Cache: " $objItem.PackageCache
$packagecache = $objItem.PackageCache
write-host "SKU Number: " $objItem.SKUNumber
$skunumber = $objItem.SKUNumber
write-host "Vendor: " $objItem.Vendor
$vendor = $objItem.Vendor
write-host "Version: " $objItem.Version
$version = $objItem.Version
# Need to add in a special character for " as some of the values from the WMI query has commers in them that mess up the csv file
$sc = [char]34
Add-Content "$Env:USERPROFILE\softwareaudit $datetime.csv" "$sc$computer$sc,$sc$caption$sc,$sc$description$sc,$sc$identifier$sc,$sc$installdate$sc,$sc$installdate2$sc,$sc$installlocation$sc,$sc$installstate$sc,$sc$name$sc,$sc$packagecache$sc,$sc$skunumber$sc,$sc$vendor$sc,$sc$version$sc"
Write-Host -ForegroundColor Red "No Ping Reply received from $computer.";
It automatically pulls the domain information from the local computers domain membership.
Deleting old Computer Accounts
If you find there are hundreds of computer accounts that are no longer in use, and the script is sitting there pinging computer account after computer account taking ages to move through the list you may want to clean up old computer accounts in active directory.
To find all computers that have been inactive for the last four weeks and remove them run the following command on a domain controller:
dsquery computer -inactive 4 | dsrm