Private/Get-InstalledSoftware.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
function Get-InstalledSoftware {
<#
.SYNOPSIS
    Pull software details from registry on one or more computers

.DESCRIPTION
    Pull software details from registry on one or more computers. Details:
        -This avoids the performance impact and potential danger of using the WMI Win32_Product class
        -The computer name, display name, publisher, version, uninstall string and install date are included in the results
        -Remote registry must be enabled on the computer(s) you query
        -This command must run with privileges to query the registry of the remote system(s)
        -Running this in a 32 bit PowerShell session on a 64 bit computer will limit your results to 32 bit software and result in double entries in the results

.PARAMETER ComputerName
    One or more computers to pull software list from.

.PARAMETER DisplayName
    If specified, return only software with DisplayNames that match this parameter (uses -match operator)

.PARAMETER Publisher
    If specified, return only software with Publishers that match this parameter (uses -match operator)

.EXAMPLE
    #Pull all software from c-is-ts-91, c-is-ts-92, format in a table
        Get-InstalledSoftware c-is-ts-91, c-is-ts-92 | Format-Table -AutoSize

.EXAMPLE
    #pull software with publisher matching microsoft and displayname matching lync from c-is-ts-91
        "c-is-ts-91" | Get-InstalledSoftware -DisplayName lync -Publisher microsoft | Format-Table -AutoSize

.LINK
    http://gallery.technet.microsoft.com/scriptcenter/Get-InstalledSoftware-Get-5607a465

.FUNCTIONALITY
    Computers
#>

    param (
        [Parameter(
            Position = 0,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true,
            ValueFromRemainingArguments=$false
        )]
        [ValidateNotNullOrEmpty()]
        [Alias('CN','__SERVER','Server','Computer')]
            [string[]]$ComputerName = $env:computername,

            [string]$DisplayName = $null,

            [string]$Publisher = $null
    )

    Begin
    {
        #define uninstall keys to cover 32 and 64 bit operating systems.
        #This will yeild only 32 bit software and double entries on 64 bit systems running 32 bit PowerShell
            $UninstallKeys = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
                "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"


        function Get-SoftwareKey {
            [cmdletbinding()]
            param(
                $Reg,
                $UninstallKey,
                $Hive
            )
            Try
            {
                if($UninstallKey -like 'SOFTWARE\\Wow6432Node*')
                {
                    $Arch = '32'
                }
                else
                {
                    $Arch = '64'
                }

                $regkey = $null
                $regkey = $reg.OpenSubKey($UninstallKey)

                #If the reg key exists...
                if($regkey)
                {
                    #Retrieve an array of strings containing all the subkey names
                    $subkeys = $regkey.GetSubKeyNames()

                    #Open each Subkey and use GetValue Method to return the required values for each
                    foreach($key in $subkeys)
                    {
                        #Build the full path to the key for this software
                            $thisKey = $UninstallKey+"\\"+$key

                        #Open the subkey for this software
                            $thisSubKey = $null
                            $thisSubKey=$reg.OpenSubKey($thisKey)

                        #If the subkey exists
                        if($thisSubKey){
                            try
                            {
                                #Get the display name. If this is not empty we know there is information to show
                                    $dispName = $thisSubKey.GetValue("DisplayName")

                                #Get the publisher name ahead of time to allow filtering using Publisher parameter
                                    $pubName = $thisSubKey.GetValue("Publisher")

                                #Collect subset of values from the key if there is a displayname
                                #Filter by displayname and publisher if specified
                                if( $dispName -and
                                    (-not $DisplayName -or $dispName -match $DisplayName ) -and
                                    (-not $Publisher -or $pubName -match $Publisher )
                                )
                                {

                                    #Display the output object, compatible with PowerShell 2
                                    New-Object PSObject -Property @{
                                        ComputerName = $computer
                                        DisplayName = $dispname
                                        Publisher = $pubName
                                        Version = $thisSubKey.GetValue("DisplayVersion")
                                        UninstallString = $thisSubKey.GetValue("UninstallString")
                                        InstallDate = $thisSubKey.GetValue("InstallDate")
                                        Hive = $Hive
                                        Arch = $Arch
                                    } | Select-Object ComputerName, DisplayName, Publisher, Version, Hive, Arch, UninstallString, InstallDate
                                }
                            }
                            Catch
                            {
                                #Error with one specific subkey, continue to the next
                                Write-Error "Unknown error: $_"
                                Continue
                            }
                        }
                    }
                }
            }
            Catch
            {
                #Write verbose output if we couldn't open the uninstall key
                Write-Verbose "Could not open key '$uninstallkey' on computer '$computer': $_"

                #If we see an access denied message, let the user know and provide details, continue to the next computer
                if($_ -match "Requested registry access is not allowed"){
                    Write-Error "Registry access to $computer denied. Check your permissions. Details: $_"
                    continue computerLoop
                }
            }
        }
    }
    Process
    {
        #Loop through each provided computer. Provide a label for error handling to continue with the next computer.
        :computerLoop foreach($computer in $computername)
        {
            Try
            {
                #Attempt to connect to the localmachine hive of the specified computer
                $reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$computer)
            }
            Catch
            {
                #Skip to the next computer if we can't talk to this one
                Write-Error "Error: Could not open LocalMachine hive on $computer`: $_"
                Write-Verbose "Check Connectivity, permissions, and Remote Registry service for '$computer'"
                Continue
            }

            #Loop through the 32 bit and 64 bit registry keys
            foreach($uninstallKey in $UninstallKeys)
            {
                Write-Verbose "Checking [LocalMachine] [$uninstallKey] on [$computer]"
                Get-SoftwareKey -Reg $Reg -UninstallKey $uninstallKey -Hive 'HKLM'
            }

            Try
            {
                #Attempt to connect to the localmachine hive of the specified computer
                $reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('CurrentUser',$computer)
            }
            Catch
            {
                #Skip to the next computer if we can't talk to this one
                Write-Error "Error: Could not open LocalMachine hive on $computer`: $_"
                Write-Verbose "Check Connectivity, permissions, and Remote Registry service for '$computer'"
                Continue
            }

            #Loop through the 32 bit and 64 bit registry keys
            foreach($uninstallKey in $UninstallKeys)
            {
                Write-Verbose "Checking [CurrentUser] [$uninstallKey] on [$computer]"
                Get-SoftwareKey -Reg $Reg -UninstallKey $uninstallKey -Hive HKCU
            }
        }
    }
}