Tag Archives: Windows Server 2003

Reporting On Installed Windows Programs Via The Registry

Quite a common request for working with Windows machines is to report the software installed on them. If you don’t have a centralised system for reporting on client software (many places don’t) then you may turn to some form of scripted method to obtain this information.

Most people tend to head to Add / Remove Programs when thinking about what software is installed in Windows. However, not all applications will always populate information in there, depending on how they have been installed. Additionally, to query that information you would typically query the WMI class Win32_Product, however this can lead to performance issues.

A better approach if going down this route is to look in the registry and the key  HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall.

The following function illustrates how to access this data by using this .NET approach to retrieve registry data. Note: this also works with remote computers.


We check for the DisplayName on each subkey before adding the result to the output, since for some reason some keys are empty.

$DisplayName = $SubKeyValues.GetValue('DisplayName')<br />if ($DisplayName){........

Here’s the function which you could flesh out further for your own requirements.

Update 03/02/2014: As Peter points out in the notes, if you have 32bit software installed you have an extra place to check when using this method, so you will also need to make the same checks in the following key:


function Get-InstalledSoftware {
 Retrieve installed software from the registry

 Retrieve installed software from the registry

 .PARAMETER ComputerName
 Name of the computer to check



 PS> Get-InstalledSoftware -Computer Server01

 PS> "Server01","Server02" | Get-InstalledSoftware





begin {

 $OutputObject = @()

 process {

try {
 foreach ($Computer in $ComputerName){

 $Registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Localmachine',$Computer)
 $UninstallTopKey = $Registry.OpensubKey("Software\Microsoft\Windows\CurrentVersion\Uninstall",$false)
 $UninstallSubKeys = $UninstallTopKey.GetSubKeyNames()

ForEach ($SubKey in $UninstallSubKeys){

 $Path = "Software\Microsoft\Windows\CurrentVersion\Uninstall\$SubKey"
 $SubKeyValues = $Registry.OpensubKey($Path,$false)

$DisplayName = $SubKeyValues.GetValue('DisplayName')

if ($DisplayName){

 $Object = [pscustomobject]@{

 ComputerName = $Computer
 DisplayName = $DisplayName
 DisplayVersion = $SubKeyValues.GetValue('DisplayVersion')
 UninstallString = $SubKeyValues.GetValue('UninstallString')
 Publisher = $SubKeyValues.GetValue('Publisher')
 InstallDate = $SubKeyValues.GetValue('InstallDate')


 $OutputObject += $Object

 catch [Exception]{

 throw "Unable to get registry data....."
 end {
 Write-Output $OutputObject

“Unable to Find a Volume for File Extraction…..” When Installing KB2638806 on Windows Server 2003 Clusters

OK, bit of an obscure one this, but if you have the issue then hopefully this will help you. While attemping to install KB2638806 on Windows Server 2003 Clusters I consistently received the below error:

“Unable to find a volume for file extraction. Please verify you have the proper permissions.”

The cluster node had been cleared of resources and rebooted prior to patching, however the patch would not install. After some troubleshooting it turned out that an additional step of stopping the Cluster service on the affected node allowed the patch to be installed.

I did not have this issue with other patches released in January 2012, but can’t rule out that others would be affected.

Using PowerShell To Check That Windows Server Services Set To Automatic Have Started

Following on from the blog post Testing TCP Port Response from PowerShell  which provided a means to check that servers had fully rebooted after a patching and reboot cycle, I needed to take this one step further and check that all of the Windows Services set to Automatic successfully started after the reboot.

This should be pretty straightforward since we have a Get-Service cmdlet. Unfortunately however, this cmdlet does not return a StartMode parameter, i.e. it’s not possible to tell whether the Startup Type has been set to Automatic, Manual or Disabled. This is quite a large gap in my opinon – if you agree with me you can vote to get it included in a future release here. Of course with PowerShell there’s usually another way to achieve the same objective and using Get-WMIObject it is possible to find out the Startup Type of the service.

Get-WmiObject Win32_Service -ComputerName $ComputerName -Filter "StartMode='Auto' AND State='Stopped' AND Name!='SysmonLog'"

Notice that we filter out the Perfmon service (SysmonLog) since it is rarely in a started state.

One other thing to watch out for in this script is that the section

catch [System.Exception]

which is there to catch any WMI queries that fail, e.g. the server hasn’t rebooted properly or the correct permissions do not exist to make the WMI query, will not pick up any of these failures. This is because try / catch will only catch terminating errors and the WMI failures are non terminating. We can work around this by setting:

$ErrorActionPreference = "Stop"

and then back to normal afterwards:

$ErrorActionPreference = "Continue"

The script accepts pipeline input, so for example you could run it like:

Get-Content servers.txt | ./Get-AutomaticServiceState.ps1

Here it is:

Retrieves any Windows services set to Automatic and are not running

Retrieves any Windows services set to Automatic and are not running

.PARAMETER  ComputerName
Name of the computer to test the services for

PS C:\> Get-AutomaticServiceState -ComputerName Server01

PS C:\> Get-Content servers.txt | Get-AutomaticServiceState

Author: Jonathan Medd
Date: 11/01/2012

[Parameter(Position=0,Mandatory=$true,HelpMessage="Name of the computer to test",

process {

try {

# Set ErrorActionPreference to Stop in order to catch non-terminating WMI errors
$ErrorActionPreference = "Stop"

# Query the server via WMI and exclude the Performance Logs and Alerts Service
$WMI = Get-WmiObject Win32_Service -ComputerName $ComputerName -Filter "StartMode='Auto' AND State='Stopped' AND Name!='SysmonLog'"


catch [System.Exception]

$WMI = “” | Select-Object SystemName,Displayname,StartMode,State
$WMI.SystemName = $ComputerName
$WMI.Displayname = "Unable to connect to server"
$WMI.StartMode = ""
$WMI.State = ""

finally {

$ErrorActionPreference = "Continue"


if ($WMI){

foreach ($WMIResult in $WMI){

$MYObject = “” | Select-Object ComputerName,ServiceName,StartupMode,State
$MYObject.ComputerName = $WMIResult.SystemName
$MYObject.ServiceName = $WMIResult.Displayname
$MYObject.StartupMode = $WMIResult.StartMode
$MYObject.State = $WMIResult.State

Running AD Schema Update for 2008 R2 in a 32-bit DC Environment

To upgrade Active Directory from Windows Server 2003 to Windows Server 2008 R2 requires the usual AD schema upgrade first of all. Windows Server 2008 R2 is 64-bit only, so if you try running the usual command to upgrade the schema from a 32-bit Domain Controller:

adprep /forestprep

you get the following result, “adprep.exe is valid, but if for a machine type other than the current machine.”:

An alternative is to try running it from a 64-bit machine that is not a DC, but then you discover that this process absolutely must be run from a DC:

So what do you do? The answer is that you run adprep32.exe, a 32-bit version of adprep, which is included in the same folder:

adprep32 /forestprep