Category Archives: Winter Scripting Games 2014

Testing for the Presence of a Registry Key and Value

There are a number of different ways to test for the presence of a registry key and value in PowerShell. Here’s how I like to go about it. We’ll use an example key HKLM:\SOFTWARE\TestSoftware with a single value Version:

RegistryValue

Check for the key

You can use the Test-Path cmdlet to check for the key, but not for specific values within a key. For example

Test-Path 'HKLM:\SOFTWARE\TestSoftware'

but not

Test-Path 'HKLM:\SOFTWARE\TestSoftware\Version'

RegistryValue02

So for the value we need to work a bit harder. Using the below function we can see if Get-ItemProperty contains the value or not.

function Test-RegistryValue {

param (

 [parameter(Mandatory=$true)]
 [ValidateNotNullOrEmpty()]$Path,

[parameter(Mandatory=$true)]
 [ValidateNotNullOrEmpty()]$Value
)

try {

Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null
 return $true
 }

catch {

return $false

}

}

So for our example:

Test-RegistryValue -Path 'HKLM:\SOFTWARE\TestSoftware' -Value 'Version'
Test-RegistryValue -Path 'HKLM:\SOFTWARE\TestSoftware' -Value 'Banana'

RegistryValue03

 

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.

[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('RegistryHive','ComputerName')

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:

HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

function Get-InstalledSoftware {
<#
 .SYNOPSIS
 Retrieve installed software from the registry

 .DESCRIPTION
 Retrieve installed software from the registry

 .PARAMETER ComputerName
 Name of the computer to check

.INPUTS
 System.String

.OUTPUTS
 System.Management.Automation.PSObject.

.EXAMPLE
 PS> Get-InstalledSoftware -Computer Server01

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

#>
[CmdletBinding()][OutputType('System.Management.Automation.PSObject')]

Param
 (

[parameter(Mandatory=$true,ValueFromPipeline=$true)]
 [ValidateNotNullOrEmpty()]
 [String[]]$ComputerName

)

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
 }
}

Adding and Removing Items from a PowerShell Array

Adding and removing Items from a PowerShell array is a topic which can lead to some confusion, so here are a few tips for you.

Create an array and we will note the type System.Array:

$Fruits = "Apple","Pear","Banana","Orange"

$Fruits.GetType()

Array01

However, if we try to Add or Remove items to the array we get errors that the “Collection was of a fixed size”

$Fruits.Add("Kiwi")
$Fruits.Remove("Apple")
$Fruits.IsFixedSize

Array02

We can see that the array we originally created is of a fixed size. The MSDN page for the ISFixedSize Property helps to explain this. Note it supports the modification of existing elements, but not the addition or removal of others.

Array03

One way to deal with this is to use a System.Collections.ArrayList instead

[System.Collections.ArrayList]$ArrayList = $Fruits
$ArrayList.GetType()

Array04

Now if we try the previous add and remove methods we are successful:

$ArrayList.Add("Kiwi")
$ArrayList
$ArrayList.Remove("Apple")
$ArrayList

Array05

Alternatively, if we had stuck with the original Array object we could do the following to ‘add’ an item to it. (Actually it creates a new array with an additional item)

$New = $Fruits += "Kiwi"
$New
$New.GetType()

Array06

However, we can’t remove items in this way:

$New2 = $Fruits -= "Apple"

Array07

We could instead do this:

$New3 = $Fruits -ne "Apple"
$New3

Array08

 

Update: Thanks to Rob Campbell for pointing out another way to do this.

Taking your initial array you can convert it to a System.Collections.ObjectModel.Collection`1 like this, which may be easier to remember than using the full type name of either a collection or array list:

$Collection = {$Fruits}.Invoke()
$Collection
$Collection.GetType()

Array09

Now we can add and remove items using the Add and Remove methods:

$Collection.Add("Melon")
$Collection
$Collection.Remove("Apple")
$Collection

Array10

Winter Scripting Games 2014

PowerShell-Scripting-Games-Logo

If you’re looking to learn or improve on existing skills as part of a new year goal and one of those in PowerShell, then you may find it useful to check out the Winter Scripting Games 2014. When you are looking to improve your scripting skills it can sometimes be tricky if you don’t have a practical problem to solve. By taking part in these games you will have a number of opportunities to apply your skills to real problems. I know when I first started learning PowerShell that I found these events highly useful, so I’ll be helping to give sometime back this time round by contributing as one of the coaches lending help to entrants with some advice.

This set of events is a team based competition, so you need to find at least one other person to enter with – help is provided on the Scripting Games site if you are looking for a team to join.

The first event starts on Jan 19th 2014 so you need to be registered before then. Hope to see you there.