Prof. Powershell
Practical PowerShell Part 3: Create Custom Objects Quickly
- By Jeffery Hicks
- 07/22/2014
More on this topic:
This week we continue our exploration of what we can do with PowerShell. If you are just joining us, take a few minutes to get caught up. In the last lesson I demonstrated how to use Select-Object to create a custom object. It works, but that approach can get cumbersome and sometimes inefficient. Instead, I might try something like this using the ForEach enumerator.
foreach ($entry in $props) {
#create the registry path to check
$valuepath = Join-Path -path "HKLM:" -child $regentry.$entry
Try {
#follow the value to the corresponding registry key
$app = Get-ItemProperty -path $valuepath -ErrorAction Stop |
Select ApplicationDescription,ApplicationName
}
Catch {
$app=$Null
}
#write an object to the pipeline
New-Object -TypeName psobject -Property @{
RegisteredApp = $entry
RegisteredPath = $regentry.$entry
AppDescription = $app.ApplicationDescription
AppName = $app.ApplicationName
}
}
With this approach, I only need to get the corresponding capabilities registry key once. I create the path one time and save the results from Get-ItemProperty to a variable. I am using a Try/Catch block so that if there is nothing at $valuepath, PowerShell won't write an ugly error. Unless of course you want to see that. Instead I'm simply setting $app to $null.
Finally, I use New-Object to create a custom object for each registered application from a hashtable of property values. Each hashtable key will become an object property name. You can see my results in Figure 1.
At this point, I have a functional solution so let's put it in a script file to save some typing the next time I want to run this.
#requires -version 3.0
#define registry property values to ignore
$exclude = "PSParentPath","PSChildName","PSDrive","PSProvider","PSPath"
$regentry = Get-ItemProperty -Path HKLM:\SOFTWARE\RegisteredApplications | Select -Property * -ExcludeProperty $exclude
#get property names
$props = $regentry.psobject.properties.name
foreach ($entry in $props) {
#create the registry path to check
$valuepath = Join-Path -path "HKLM:" -child $regentry.$entry
Try {
#follow the value to the corresponding registry key
$app = Get-ItemProperty -path $valuepath -ErrorAction Stop |
Select ApplicationDescription,ApplicationName
}
Catch {
Write-Warning "No registry information found at $valuepath for $entry"
$app=$Null
}
#write an object to the pipeline
New-Object -TypeName psobject -Property @{
RegisteredApp = $entry
RegisteredPath = $regentry.$entry
AppDescription = $app.ApplicationDescription
AppName = $app.ApplicationName
}
}
I added some comments to explain a few points and a warning if no additional registry settings are found. Now I can easily run this:
PS C:\> C:\scripts\get-registeredapps-basic.ps1
Because this writes to the pipeline I can do whatever I want with it.
PS C:\> C:\scripts\get-registeredapps-basic.ps1 | Sort RegisteredPath | Select RegisteredApp,AppDescription | out-gridview -title "Registered Apps"
One thing that you may have noticed if you try this out for yourself is that output is unpredictable. The property names of my custom object are RegisteredApp, RegisteredPath, AppDescription and AppName. But there is no guarantee what order they will be displayed. In our next lesson I'll show you some ways to handle this situation.
About the Author
Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.