Category Archives: Windows Server 2008 R2

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

Windows Management Framework (PowerShell) 4.0 is now available – ensure you already have .NET 4.5

Update 30/10/2013: There’s an updated post on the PowerShell Team Blog which now describes this situation with .NET 4.5 as a pre-requisite in more detail.


PowerShell 4.0 which shipped as part of Windows Server 2012 R2 and Windows 8.1 is now available for down-level Windows versions via the downloadable Windows Management Framework 4.0.

WMF 4.0 contains updated versions of the following features:

Windows PowerShell
Windows PowerShell Integrated Scripting Environment (ISE)
Windows PowerShell Web Services (Management OData IIS Extension)
Windows Remote Management (WinRM)
Windows Management Infrastructure (WMI)

Additionally, we have added a new and exciting Windows PowerShell feature which is available in WMF 4.0: Windows PowerShell Desired State Configuration (DSC)

To use this updated management infrastructure to manage Windows 7 SP1, Windows Embedded 7, Windows Server 2008 R2 SP1, and Windows Server 2012, WMF 4.0 must be installed on computers that are running the previously-released operating systems.

For this Release, WMF 4.0 installs only on the following operating systems:

Operating System Service Pack Level Editions
Windows 7 Service Pack 1 All
Windows Server 2008 R2 Service Pack 1 All except IA64
Windows Server 2012   All except IA64
Windows Embedded 7   All

Note that Windows 8 is not listed and you are required to take the free upgrade to Windows 8.1 to get PowerShell 4.0.

One important requirement that is worth taking particular notice of is that .NET Framework 4.5 is a pre-requisite. While you may have installed this on your Windows 7 machine, it maybe not that likely that you have installed it on your server installations.

While this information is in the release notes, there is nothing in the installation that warns you of this requirement and an installation attempt without it results in (IMHO) a slightly  bizarre outcome.

In this example I installed WMF 4.0 on a Windows Server 2008 R2 system with the WMF 2.0 / PowerShell 2.0 combination that ships as part of the OS.

The OS currently contains .NET Framework 3.5.


Tip: You can quickly find your latest .NET version with the following one-liner

<br /><br />&amp;nbsp;<br /><br />Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | Get-ItemProperty -name Version -EA 0 | Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} | Sort-Object version -Descending | Select-Object -ExpandProperty Version -First 1<br /><br />

Having downloaded the correct WMF 4.0 version for Windows Server 2008 R2 I’ve started the installation:




Once the installation is complete, I check the version of PowerShell and discover that it is still 2.0.

<br /><br />$psversiontable<br /><br />


So nothing much seems to have changed! If you look carefully in the release notes though, installing without .NET Framework 4.5, results in two QFE hotfixes being installed.

Note: When you run the WMF 4.0 installation package, the following updates are installed first:

Examining these hotfixes we can see two hotfixes have been installed:


(Confusingly, one of these KB2809215, is actually the KB2823180 mentioned in the release notes.)

If we attempt to install WMF 4.0 again we are told that it already has been installed:


So, let’s see what happens if we install the .NET Framework 4.5 pre-requisite:



Test the install:


Now try the install again




After reboot, we can confirm we now have PowerShell 4.0.


Got a headache yet? The crux of the story is make sure you have .NET Framework 4.5 before installing WMF 4.0 🙂

Automating the Pre-Requisites for vCAC 5.2

The other day I noticed some comments on Twitter around the time taken to install VMware vCloud Automation Center 5.2


Being of curious nature I decided to check it out further and in doing so discovered this extensive installation guide from Jad El-Zein. Seeing as a lot of the pre-requisites are installing Windows Roles / Features and configuring IIS, I figured this would make a good candidate for some PowerShell work and might save you some time if you need to do this yourself.

By following the above install guide and using the vCAC Prereq Checker, I put together the below script which will complete the pre-reqs for you on Windows Server 2008 R2 and give you green ticks in the vCAC Prereq Checker.

Note: You need .NET 4.5 to install the  vCAC Prereq Checker – the below script will attempt to download and install .NET 4.5 for you if you don’t have it, since it’s a requirement for the full install of vCAC.


Slightly confusingly (to me anyway!), if you run the  vCAC Prereq Checker before doing anything else, it doesn’t actually show you that you are missing any of the IIS components / configuration items.


Post-IIS install you now see the set of requirements you need to match:


A number of IIS configuration items on the check list are red even though they are the default values in IIS. I’m not sure if this is an issue with the vCAC Prereq Checker or IIS, but setting them away from the default value and then back to that value (Have you tried turning it off and on again?!), followed by re-running the checks gives them a green tick – this is also mentioned in the above manual install guide.


For instance the  vCAC Prereq Checker thinks that:

WindowsAuthenticationExtendedProtection is Enabled

WindowsAuthenticationKernelMode is Disabled


Looking at IIS before making any changes, the reverse appears to be true:


Also, the  vCAC Prereq Checker reports that the Negotiate and NTLM Providers are Disabled:


Looking at IIS before making any changes, the reverse appears to be true:


So the script will resolve this for you and make the vCAC Prereq Checker happy 🙂

One final thing to note is that we need to set the vCAC AD service account being used to the Local Security Policy User Right Assignment ‘Log on as a batch job’. There is no native way to do this yet in PowerShell so here I have used the tool ntrights.exe from Windows 2003 (!) Resource Kit. (Even though I don’t typically like placing additonal requirements the alternative using secedit was messy and overkill for changing one setting).


Before running the script, ensure you have set your PowerShell execution policy away from the default of Restricted so that you can run the script.

Set-ExecutionPolicy RemoteSigned

While Googling ‘vCAC’ and ‘vCloud Automation Center’ to ensure I was using the correct ‘v’ sign for this post I discovered Randy Stanley had already created something similar for vCAC 5.1. You may well want to check out this effort too since it includes some additional options around which roles of vCAC you are installing.

You can run the script like so:

./Install-vCACPreReqs.ps1 -DomainAccount Sunnydale\vcacsvc -NTRightsExe C:\Scripts\ntrights.exe

and you should then be presented with some nice green ticks:


Update 02/12/13: Following some great feedback from Michael Poore I’ve updated the code with some changes including adding “SeServiceLogonRight” as a default user right to configure, adding the option to specify a path to the .NET 4.5 install exe and some additional verbose feedback.


 Install the Pre-requisites for vCAC 5.2

 Install the Pre-requisites for vCAC 5.2

.PARAMETER DomainAccount
 Name of the Windows Domain Account to use for the vCAC install

 Path to the NTRights.exe file (used to set Local User Rights Assignments)

 Path to the .NET Install file

 User Rights to assign the DomainAccount to "SeBatchLogonRight"

 Leave Windows Firewall turned on and create an exception rule for Distributed Transaction Coordinator

 ./Install-vCACPreReqs.ps1 -DomainAccount Sunnydale\vcacsvc -NTRightsExe C:\Scripts\ntrights.exe

 ./Install-vCACPreReqs.ps1 -DomainAccount Sunnydale\vcacsvc -NTRightsExe C:\Scripts\ntrights.exe -DotNetExe C:\Downloads\dotnetfx45_full_x86_x64.exe -Verbose




	[String[]]$UserRights = ("SeBatchLogonRight","SeServiceLogonRight"),


# --- Check for NTRights.exe
if (!($NTRightsExe.Exists)){

    throw "Please supply a valid path to NTRights.exe"

# --- Check for .NET Install File
if ($PSBoundParameters.ContainsKey('DotNetExe')) {

    if (!($DotNetExe.Exists)){

        throw "Please supply a valid path to the DotNet install Exe file"

# --- Check for 64bit PowerShell (needed for ServerManager module)
if (!([IntPtr]::size -eq 8)){

    throw "64bit version of PowerShell required for ServerManager module"

# --- Start the Secondary Logon service
if ((Get-Service seclogon).Status -ne 'Running'){

    Start-Service seclogon

# --- Add the necessary Windows Components
Import-Module ServerManager
Add-WindowsFeature Web-Server,Web-Static-Content,Web-Default-Doc,Web-Dir-Browsing,Web-Http-Errors,Web-HTTP-Redirect,Web-App-Dev,Web-Windows-Auth,WAS,NET-Win-CFAC

# --- Test for the WebAdministration Module and import it
if (Get-Module -ListAvailable WebAdministration){

    Write-Verbose "Importing the WebAdministration Module `n"
    Import-Module WebAdministration
else {

    throw "Required Module WebAdministration is not installed on this system"

# --- Configure IIS Authentication Services
Write-Verbose "Configuring IIS settings `n"

# --- Anonymous Authentication Disabled
Set-WebConfigurationProperty -Filter system.webServer/security/authentication/AnonymousAuthentication -Location 'Default Web Site' -Name Enabled -Value $false

# --- Windows Authentication Enabled
Set-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name Enabled -Value $true

# --- Disable Windows Authentication Extended Protection (turn it on and back off again before the vCAC Pre-Checker will recognise this)
Set-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name extendedProtection.tokenChecking -Value 'Allow'
Set-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name extendedProtection.tokenChecking -Value 'None'

# --- Enable Windows Authentication Kernel-Mode Authentication (turn it off and back on again before the vCAC Pre-Checker will recognise this)
Set-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name useKernelMode -Value $false
Set-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name useKernelMode -Value $true

# --- Set Windows Authentication Providers Negotiate and NTLM Enabled (Remove then add them before the vCAC Pre-Checker will recognise this)
Get-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name providers.Collection | Select-Object -ExpandProperty Value | ForEach-Object {Remove-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name providers.Collection -AtElement @{value=$_}}

Add-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name providers.Collection -AtIndex 0 -Value "Negotiate"
Add-WebConfigurationProperty -Filter system.webServer/security/authentication/WindowsAuthentication -Location 'Default Web Site' -Name providers.Collection -AtIndex 1 -Value "NTLM"

# --- Set a firewall rule for Distributed Transaction Coordinator or turn the firewall off
if ($PSBoundParameters.ContainsKey('FirewallOn')){

    netsh advfirewall firewall set rule group="Distributed Transaction Coordinator" new enable=Yes | Out-Null
else {

    netsh advfirewall set allprofiles state off | Out-Null

# --- Set MSDTC Registry Settings
"NetworkDtcAccess","NetworkDtcAccessClients","NetworkDtcAccessTransactions","NetworkDtcAccessInbound","NetworkDtcAccessOutbound" | ForEach-Object {Set-ItemProperty -Path HKLM:\Software\Microsoft\MSDTC\Security -Name $_ -Value 1}

# --- Add User Rights Assignment
$UserRights | ForEach-Object {Invoke-Expression "$NTRightsExe -u $DomainAccount +r $_"}

# --- Check for .NET 4.5 and attempt to install if not present
$NetVersion = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | Get-ItemProperty -name Version -EA 0 | Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} | Sort-Object version -Descending | Select-Object -ExpandProperty Version -First 1
Write-Verbose ".NET version on this server is $NetVersion `n"

if ($NetVersion -lt 4.5){

    # --- If .NET install location specified as a parameter use that path
    if ($PSBoundParameters.ContainsKey('DotNetExe')) {

        Write-Verbose "Installing .NET 4.5 `n"

        $NetInstall = Start-Process $DotNetExe -ArgumentList "/q" -Wait -PassThru

        if ($NetInstall.ExitCode -eq 0){

            Write-Verbose ".NET 4.5 successfully installed `n"
        else {

            throw "Unable to install .NET 4.5. Please install manually"
    # --- Else attempt to download .NET install from the Internet
    else {

        Write-Verbose "Downloading and Installing .NET 4.5 `n"
        $WebClient = New-Object Net.WebClient

        if (Test-Path .\dotNetFx45_Full_x86_x64.exe){
            $NetInstall = Start-Process ".\dotNetFx45_Full_x86_x64.exe" -ArgumentList "/q" -Wait -PassThru

            if ($NetInstall.ExitCode -eq 0){

                Write-Verbose ".NET 4.5 successfully installed `n"
            else {

                throw "Unable to install .NET 4.5. Please install manually"
        else {

            throw "Unable to download .NET 4.5. Please install manually"

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

SAP Single Sign On Issues with Windows Server 2008 R2 Domain Controllers

By default, Data Encryption Standard (DES) encryption for Kerberos authentication is disabled  in Windows Server 2008 R2, this is a change from Windows Server 2003. If you are running an application which uses DES encryption for Kerberos application, such as SAP, then you may see issues authenticating users against 2008 R2 DCs. You will see errors in the System Log like the below for the users in question:

“While processing a TGS request for the target server %1, the account %2 did not have a suitable key for generating a Kerberos ticket (the missing key has an ID of %3). The requested etypes were %4. The accounts available etypes were %5.”

To resolve this issue you need to make the Group Policy change to allow DES encryption for Kerberos authentication on the DCs, documented in this KB

  1. In the Group Policy Management Console (GPMC), locate the following location:
    Computer Configuration\ Windows Settings\ Security Settings\ Local Policies\ Security Options
  2. Click to select the Network security: Configure encryption types allowed for Kerberos option.
  3. Click to select Define these policy settings and all the six check boxes for the encryption types.
  4. Click OK. Close the GPMC.

To be able to make this change, you need to have first installed the following hotfix, . This fix is included in Windows Server 2008 R2 SP1, so if you have installed that you are already good to go.

A good discussion of this issue and further steps you may need to take with service accounts can be found here:

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

PowerShell ISE: Not Installed By Default in Windows Server 2008 R2

PowerShell 2 is installed by default in Windows Server 2008 R2. However, the other day I went on to a server with this OS and went to use the PowerShell ISE (which I switched to as my default console a year ago) and found that it wasn’t there:

Turns out that the ISE is not installed by default and needs to be added as a Feature:

This is different to a manual install of PowerShell 2 on Windows 2008 / 2003 where the ISE is included as part of the Windows Management Framework Install.

The reason I hadn’t noticed this earlier was that most of the Windows Server 2008 R2 servers I have been working with recently all had Exchange 2010 installed which seems to include the ISE as part of the installation.

Update 19/02/11:

Thanks to the reminder in the comments from Osin Grehan about the ServerManager module in Windows Server 2008 R2, you can get this feature installed via PowerShell.

Import-Module ServerManager
Add-Windowsfeature PowerShell-ISE

Upgrading vCenter Server to 4.1 fails with the error: boolean storageIORMSupported

I had the following issue when upgrading vCenter from 4.0 to 4.1. Whilst the database upgrade and install appeared to complete successfully, the vCenter service would not start once the install was complete.

In the vpxd.log located at C:\Documents and Settings\All Users\Application Data\VMware\VirtualCenter\logs, you see errors similar to:

[2010-07-27 13:42:26.837 03204 error ‘App’] [VpxdMain] Failed to initialize: Not initialized: boolean storageIORMSupported
[2010-07-27 13:42:26.837 03204 error ‘App’] Failed to intialize VMware VirtualCenter. Shutting down…
[2010-07-27 13:43:17.509 03204 info ‘App’] Forcing shutdown of VMware VirtualCenter now

This issue seems to be well known on the communities site and is a bug in the install which should be fixed in a later release. It particular it seems to affect those running vCenter 4.1 in Windows Server 2008 R2, which is quite a common OS people migrate to as part of a 4.1 upgrade because of the 64bit requirement of vCenter 4.1.

Until the updated release comes out there is a workaround using dbuHelper.exe to make a change to the database that will then allow the vCenter service to start – it is documented in this KB article.

Important: Before starting this process you should take another backup of your vCenter database, in addition to the one taken before the initial upgrade.

Once downloaded you need to determine the following parameters to run with dbuHelper.exe


These parameters should be easy to find: <DB_DSN> <DB_USERNAME> <DB_PASSWORD>

<DB_VERSION> can be found with the following SQL query:

select ver_id from vpx_version

If upgrading to 4.1 and you are stuck at this point then you should get a value of 410 returned:

So you can now run dbuHelper:

dbuHelper.exe 410 DSNname Username password

Once successfully complete you should be able to start the vCenter service.


Note: for some great resources on upgrading vCenter to 4.1 check out Gregg Robertson’s page.

Update 11/02/2011:

This is fixed in vCenter 4.1 U1; from the release notes:

  • After an upgrade to vCenter Server 4.1, vCenter Server fails to start and issues an error message

    When this issue occurs, the following error message is logged in the vpxd.log file:

    Failed to initialize: Not initialized: boolean storageIORMSupported

    This issue is resolved in this release.