I think maybe you’re letting yourself get overwhelmed by trying to do too many things at once. You can break your description down into several smaller tasks, each of which has a pretty straightforward answer in code:
[ul]
[li]
Check a list of 5 known applications one at a time. This is some sort of collection (possibly an array, but it doesn’t really matter) and a foreach loop:
$apps = 'App 1', 'App 2', 'App 3', 'App 4', 'App 5'
foreach ($app in $apps)
{
# Do something with this $app
}
[/li]
[li]
Check to see if an app is installed. You already know how to do this by checking the registry; nothing new to see here. (The values in the array will probably contain the registry key name for each app):
$isInstalled = Test-Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$appKey"
[/li]
[li]
Check to see if logging is enabled. This is another registry check, except instead of just doing a Test-Path, you need to extract a value. If you want to use the Registry PSProvider for this, then you use Get-ItemProperty:
$regValue = (Get-ItemProperty -Path "HKLM:\$appRegistryPath" -Name DebugLog).DebugLog
if ($regValue -eq 1)
{
$loggingStatus = 'Enabled'
}
else
{
$loggingStatus = 'Disabled'
}
[/li]
[li]
Getting the logging path. Another registry value fetch just like the last one:
$loggingPath = (Get-ItemProperty -Path "HKLM:\$appRegistryPath" -Name DebugLogPath).DebugLogPath
[/li]
[li]
Create a new PSObject with the properties you want. You know how to do this as well, by building a hashtable and passing it to New-Object (or casting to [pscustomobject], in PowerShell 3.0 or later):
$properties = @{
Name = $appName
LoggingStatus = $loggingStatus
LogPath = $loggingPath
}
New-Object psobject -Property $properties
[/li]
[/ul]
Now, I used some placeholder variables there because I don’t know everything about where your registry keys are stored, but if you put it all together, you get something like this:
function Get-AppLogInfo
{
$apps = @(
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba9-4c15-a079-8bc25b6b0e29'
Name = 'App1'
RegPath = 'HKLM:\Software\App1'
}
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba1-4c15-a079-8bc25b6b0e29'
Name = 'App2'
RegPath = 'HKLM:\Software\App2'
}
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba2-4c15-a079-8bc25b6b0e29'
Name = 'App3'
RegPath = 'HKLM:\Software\App3'
}
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba3-4c15-a079-8bc25b6b0e29'
Name = 'App4'
RegPath = 'HKLM:\Software\App4'
}
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba4-4c15-a079-8bc25b6b0e29'
Name = 'App5'
RegPath = 'HKLM:\Software\App5'
}
)
# Enumerate the array
foreach ($app in $apps)
{
# Only produce output if the app is installed
$isInstalled = Test-Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$($app.InstallerGuid)"
if ($isInstalled)
{
# Set up default values for logging status / path
$loggingStatus = 'Disabled'
$loggingPath = ""
# Check this app's logging status
$regValue = (Get-ItemProperty -Path $app.RegPath -Name DebugLog).DebugLog
if ($regValue -eq 1)
{
# Logging is enabled; also fetch the log path for this app, overwriting the default values
$loggingStatus = 'Enabled'
$loggingPath = (Get-ItemProperty -Path $app.RegPath -Name DebugLogPath).DebugLogPath
}
# Build the PSObject using a hashtable with the information we've found
$properties = @{
Name = $app.Name
LoggingStatus = $loggingStatus
LogPath = $loggingPath
}
New-Object psobject -Property $properties
}
}
}
Now, that code is starting to get a bit long, at 60+ lines for a single function, with lots of nested loops and conditions. It helps to split some of the code out into its own function, giving that function a descriptive name. Overall, the code might get longer, but it’s broken up into much smaller bits that are very easy to understand on their own. If you name your functions and parameters well, you can figure out what a function does just by looking at the calls to it; it should do pretty much just what you expect. This is more of a software craftsmanship concern; you could keep the above example as-is, if it suits your needs. Many scripts out there don’t even look as organized as that, and if it works, you could be happy.
However, if you get to a point where you want to produce quality code works AND is easy to read, you could break that original code down into something like this:
function Get-AppLogInfo
{
foreach ($app in Get-AppsToCheck)
{
if (Test-IsAppInstalled -AppInfo $app)
{
Get-LogInfoForSingleApp -AppInfo $app
}
}
}
function Get-AppsToCheck
{
# This is hard-coded for now, but you could even move this data out
# into a database, CSV file, or whatever.
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba9-4c15-a079-8bc25b6b0e29'
Name = 'App1'
RegPath = 'HKLM:\Software\App1'
}
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba1-4c15-a079-8bc25b6b0e29'
Name = 'App2'
RegPath = 'HKLM:\Software\App2'
}
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba2-4c15-a079-8bc25b6b0e29'
Name = 'App3'
RegPath = 'HKLM:\Software\App3'
}
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba3-4c15-a079-8bc25b6b0e29'
Name = 'App4'
RegPath = 'HKLM:\Software\App4'
}
New-Object psobject -Property @{
InstallerGuid = '4a7f8aa5-8ba4-4c15-a079-8bc25b6b0e29'
Name = 'App5'
RegPath = 'HKLM:\Software\App5'
}
}
function Test-IsAppInstalled($AppInfo)
{
return Test-Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$($AppInfo.InstallerGuid)"
}
function Get-LogInfoForSingleApp($AppInfo)
{
if (Test-AppLoggingIsEnabled -AppInfo $AppInfo)
{
$loggingStatus = 'Enabled'
$loggingPath = Get-AppLogPath -AppInfo $AppInfo
}
else
{
$loggingStatus = 'Disabled'
$loggingPath = ""
}
$properties = @{
Name = $app.Name
LoggingStatus = $loggingStatus
LogPath = $loggingPath
}
New-Object psobject -Property $properties
}
function Test-AppLoggingIsEnabled($AppInfo)
{
(Get-ItemProperty -Path $app.RegPath -Name DebugLog).DebugLog -eq 1
}
function Get-AppLogPath($AppInfo)
{
return (Get-ItemProperty -Path $app.RegPath -Name DebugLogPath).DebugLogPath
}
Overall, it’s longer, but it’s much easier to understand when you’re looking at any individual function, none of which are longer than 20 lines (except for Get-AppsToCheck, which is really more of a hard-coded database than lines of actual code.) The main function, Get-AppLogInfo, makes the logic very clear; you almost don’t even have to look at the rest of the code to understand what’s going on. Writing code like this takes some practice, and you will almost never get it right on the first try. The process of taking some complex code and reorganizing it to be easier to understand and maintain is called refactoring.