11 July 2016

PowerShell: Installed Applications Report

While working on the new Windows 10 build for my firm, it came up about updating the old script that generates a custom list of installed applications to a .CSV file on a weekly basis. The purpose of this report is so the build team has a concise list of optional applications they need to install during a replacement build for a user. Yes, they do have access to the SCCM Resource Manager, but the problem with that is combing through the list of a LOT of apps and trying to filter out which ones they need to install that are not included with the standard image. Our build team has really liked this script. This script filters all of the unnecessary apps out of the list. It will query a list of all installed apps from the add/remove programs entries within the registry. There is an external ExclusionList.txt file the script reads. This file contains a list of the applications you do not want to be included in the report. The application in the file need to be exactly how they appear in the report. You can copy and paste the apps from the report to the ExclusionList.txt file.

Thanks to Sapien's PowerShell Studio, I have been able to easily add some great new features to the script giving it the ability to rewrite the ExclusionList.txt file, thereby allowing it to be alphabetically sorted. It also removes copies of application names. To get around a bunch of systems writing to the same file at once, I used a Try | Catch encapsulated in a Do | While statement for writing to the file so errors will not pop up and if another system has already sorted and rewritten the ExclusionList.txt file, it will not occur again.

The script will write both to the screen and to the .CSV file. I added two parameters that allow you to define where the .CSV file is to be written and what filename you want it to be. Unlike the original script, this gives you the ease to write the logs to a network share instead of locally in the event a system failure occurs and you want the report for building a new system.

To use the script, I have it executed by an SCCM package once a week during prime business hours so that it runs on the maximum number of machines possible. The build team reports to me when new, unnecessary apps appear in the report so they can be added to the ExclusionList.txt file. If for some reason there is not a current report, such as a laptop has been offline for quite a long time, the script can be manually executed on a machine.

You can download the app from here.

InstalledApplications.ps1


1:  <#  
2:       .SYNOPSIS  
3:            Installed Applications  
4:         
5:       .DESCRIPTION  
6:            This will retrieve the list of installed applications from add/remove programs and write the list to a .CSV file. The tool is executed on machines once a week via an SCCM Application deployment. It's purpose is to provide a custom report to a build team for when they need to rebuild systems without having to comb through the typical SCCM Add/Remove Programs report. The reports are customized by excluding applications that are written to the ExclusionList.txt file.  
7:         
8:       .PARAMETER ReportFile  
9:            Name of the report file to be created. The report file should have the extension .CSV since this script writes to the file using UTF8 and in Excel format  
10:         
11:       .PARAMETER ReportFileLocation  
12:            The directory where the report file is located  
13:         
14:       .EXAMPLE  
15:            powershell.exe -executionpolicy bypass -file InstalledApplications.ps1  
16:         
17:       .NOTES  
18:            ===========================================================================  
19:            Created with:     SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.124  
20:            Created on:       7/8/2016 1:29 AM  
21:            Created by:       Mick Pletcher  
22:            Organization:  
23:            Filename:         InstalledApplications.ps1  
24:            ===========================================================================  
25:  #>  
26:  [CmdletBinding()]  
27:  param  
28:  (  
29:            [ValidateNotNullOrEmpty()][string]$ReportFile = 'Applications.csv',  
30:            [ValidateNotNullOrEmpty()][string]$ReportFileLocation = 'c:\windows\waller'  
31:  )  
32:    
33:    
34:  function Get-AddRemovePrograms {  
35:  <#  
36:       .SYNOPSIS  
37:            Retrieve a list of the Add/Remove Programs  
38:         
39:       .DESCRIPTION  
40:            Retrieves the Add/Remove Programs list from the registry  
41:         
42:       .NOTES  
43:            Additional information about the function.  
44:  #>  
45:         
46:       [CmdletBinding()][OutputType([string])]  
47:       param ()  
48:         
49:       $Architecture = Get-Architecture  
50:       if ($Architecture -eq "32-bit") {  
51:            $Applications = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" | ForEach-Object -Process { $_.GetValue("DisplayName") }  
52:       } else {  
53:            $Applicationsx86 = Get-ChildItem -Path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\" | ForEach-Object -Process { $_.GetValue("DisplayName") }  
54:            $Applicationsx64 = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" | ForEach-Object -Process { $_.GetValue("DisplayName") }  
55:            $Applications = $Applicationsx86 + $Applicationsx64  
56:       }  
57:       $Applications = $Applications | Sort-Object  
58:       $Applications = $Applications | Select-Object -Unique  
59:       Return $Applications  
60:  }  
61:    
62:  function Get-Architecture {  
63:  <#  
64:       .SYNOPSIS  
65:            Get-Architecture  
66:         
67:       .DESCRIPTION  
68:            Returns whether the system architecture is 32-bit or 64-bit  
69:         
70:       .EXAMPLE  
71:            Get-Architecture  
72:         
73:       .NOTES  
74:            Additional information about the function.  
75:  #>  
76:         
77:       [CmdletBinding()][OutputType([string])]  
78:       param ()  
79:         
80:       $OSArchitecture = Get-WmiObject -Class Win32_OperatingSystem | Select-Object OSArchitecture  
81:       $OSArchitecture = $OSArchitecture.OSArchitecture  
82:       Return $OSArchitecture  
83:  }  
84:    
85:  function Get-RelativePath {  
86:  <#  
87:       .SYNOPSIS  
88:            Get the relative path  
89:         
90:       .DESCRIPTION  
91:            Returns the location of the currently running PowerShell script  
92:         
93:       .NOTES  
94:            Additional information about the function.  
95:  #>  
96:         
97:       [CmdletBinding()][OutputType([string])]  
98:       param ()  
99:         
100:       $Path = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent) + "\"  
101:       Return $Path  
102:  }  
103:    
104:  function New-LogFile {  
105:  <#  
106:       .SYNOPSIS  
107:            Create a new log file  
108:         
109:       .DESCRIPTION  
110:            Delete the old log file if it exists and/or create a new one  
111:         
112:       .NOTES  
113:            Additional information about the function.  
114:  #>  
115:         
116:       [CmdletBinding()]  
117:       param ()  
118:         
119:       If ($ReportFileLocation[$ReportFileLocation.Count - 1] -eq '\') {  
120:            $File = $ReportFileLocation + $ReportFile  
121:       } else {  
122:            $File = $ReportFileLocation + '\' + $ReportFile  
123:       }  
124:       if ((Test-Path $File) -eq $true) {  
125:            Remove-Item -Path $File -Force | Out-Null  
126:       }  
127:       if ((Test-Path $File) -eq $false) {  
128:            New-Item -Path $File -ItemType file -Force | Out-Null  
129:       }  
130:  }  
131:    
132:  function New-Report {  
133:  <#  
134:       .SYNOPSIS  
135:            Generate a new Add/Remove programs report  
136:         
137:       .DESCRIPTION  
138:            This will generate the list of Add/Remove programs and write to the .CSV file.  
139:         
140:       .PARAMETER Applications  
141:            List of Add/Remove programs applications  
142:         
143:       .NOTES  
144:            Additional information about the function.  
145:  #>  
146:         
147:       param  
148:       (  
149:                 [ValidateNotNullOrEmpty()][object]$Applications  
150:       )  
151:         
152:       If ($ReportFileLocation[$ReportFileLocation.Count - 1] -eq '\') {  
153:            $File = $ReportFileLocation + $ReportFile  
154:       } else {  
155:            $File = $ReportFileLocation + '\' + $ReportFile  
156:       }  
157:       If ((Test-Path $File) -eq $true) {  
158:            $Applications  
159:            Out-File -FilePath $File -InputObject $Applications -Append -Force -Encoding UTF8  
160:       } else {  
161:            Write-Host "Report File not present to generate report" -ForegroundColor Red  
162:       }  
163:  }  
164:    
165:  function Update-AppList {  
166:  <#  
167:       .SYNOPSIS  
168:            Generate updated list of Apps  
169:         
170:       .DESCRIPTION  
171:            Generate an updated list of apps by removing the apps listed in the exclusions.txt file. This function also sorts and rewrites the exclusion list back to the exclusion.txt file in the event new exclusions have been added.  
172:         
173:       .PARAMETER Applications  
174:            List of Add/Remove programs applications  
175:         
176:       .EXAMPLE  
177:            PS C:\> Update-AppList  
178:         
179:       .NOTES  
180:            Additional information about the function.  
181:  #>  
182:         
183:       [CmdletBinding()][OutputType([object])]  
184:       param  
185:       (  
186:                 [ValidateNotNullOrEmpty()][object]$Applications  
187:       )  
188:         
189:       $RelativePath = Get-RelativePath  
190:       $File = $RelativePath + "ExclusionList.txt"  
191:       If ((Test-Path $File) -eq $true) {  
192:            $Exclusions = Get-Content -Path $File  
193:            $SortedExclusions = $Exclusions | Sort-Object  
194:            $SortedExclusions = $SortedExclusions | Select-Object -Unique  
195:            $Sorted = !(Compare-Object $Exclusions $SortedExclusions -SyncWindow 0)  
196:            If ($Sorted -eq $false) {  
197:                 Do {  
198:                      Try {  
199:                           $Exclusions = Get-Content -Path $File  
200:                           $SortedExclusions = $Exclusions | Sort-Object  
201:                           $SortedExclusions = $SortedExclusions | Select-Object -Unique  
202:                           $Sorted = !(Compare-Object $Exclusions $SortedExclusions -SyncWindow 0)  
203:                           If ($Sorted -eq $false) {  
204:                                Out-File -FilePath $File -InputObject $SortedExclusions -Force -Encoding UTF8 -ErrorAction SilentlyContinue  
205:                           }  
206:                           $Success = $true  
207:                      } Catch {  
208:                           $Success = $false  
209:                      }  
210:                 }  
211:                 while ($Success -eq $false)  
212:            }  
213:            $Applications = $Applications | Where-Object { ($_ -notin $SortedExclusions) -and ($_ -ne "") -and ($_ -ne $null) }  
214:       }  
215:       Return $Applications  
216:  }  
217:    
218:  Clear-Host  
219:  New-LogFile  
220:  $Apps = Get-AddRemovePrograms  
221:  $Apps = Update-AppList -Applications $Apps  
222:  New-Report -Applications $Apps  
223:    

0 comments:

Post a Comment