system
December 22, 2014, 6:17am
1
Here is a script that appears to keep looping and I am having issues trying to figure what it is.
If someone can help me on this, I would really appreciate it.
Thanks
Function Get-InstalledApplications
{
$ComputerName = $env:COMPUTERNAME
$NewLine = "`r`n"
$64BitRegExist = Test-Path -Path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
$UninstallRegKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$UninstallRegKey6432 = "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$Array = @()
Foreach ($Computer in $ComputerName)
{
$NewLine
Write-Output "+++++++++ $Computer ++++++++++"
If (Test-Connection -ComputerName $Computer -Count 1 -Quiet)
{
Switch ($64BitRegExist)
{
"True"
{
$NewLine
Write-Output "64-Bit Registry Detected!"
Write-Output "-------------------------"
$NewLine
Write-Output "-----------------------------"
Write-Output "64-Bit Applications Installed"
Write-Output "-----------------------------"
$NewLine
$HKLM = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine', $Computer)
$UninstallRef = $HKLM.OpenSubKey($UninstallRegKey)
$Applications = $UninstallRef.GetSubKeyNames()
Foreach ($AppSubKey in $Applications)
{
$AppRegistryKey = $UninstallRegKey + "\\" + $AppSubKey
$AppDetails = $HKLM.OpenSubKey($AppRegistryKey)
$AppBitVersion = "64-Bit"
$AppDisplayName = $($AppDetails.GetValue("DisplayName"))
$AppGUID = $AppSubKey
$AppInstallDate = $($AppDetails.GetValue("InstallDate"))
$AppInstallLocation = $($AppDetails.GetValue("InstallLocation"))
$AppPublisher = $($AppDetails.GetValue("Publisher"))
$AppUninstallString = $($AppDetails.GetValue("UninstallString"))
$AppVersion = $($AppDetails.GetValue("DisplayVersion"))
$OutputObj = New-Object -TypeName PSobject
$OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
$OutputObj | Add-Member -MemberType NoteProperty -Name AppBitVersion -Value $AppBitVersion
$OutputObj | Add-Member -MemberType NoteProperty -Name AppDisplayName -Value $AppDisplayName
$OutputObj | Add-Member -MemberType NoteProperty -Name AppGUID -Value $AppGUID
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallDate -Value $AppInstallDate
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallLocation -Value $AppInstallLocation
$OutputObj | Add-Member -MemberType NoteProperty -Name AppPublisher -Value $AppPublisher
$OutputObj | Add-Member -MemberType NoteProperty -Name AppUninstallString -Value $AppUninstallString
$OutputObj | Add-Member -MemberType NoteProperty -Name AppVersion -Value $AppVersion
$Array += $OutputObj
$Array #| Where-Object {$_.AppDisplayName -ne $null -and $_.AppGUID -ne $null -and $_.AppPublisher -ne $null -and $_.AppUninstallString -ne $null -and $_.AppVersion -ne $null} | Select-Object -Property ComputerName, AppBitVersion, AppDisplayName, AppGUID, AppInstallDate, AppInstallLocation, AppPublisher, AppUninstallString, AppVersion -Unique
}
$NewLine
Write-Output "-------------------------------------------"
Write-Output "32-Bit SApplications Installed on 64-Bit OS"
Write-Output "-------------------------------------------"
$NewLine
$HKLM = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine', $Computer)
$UninstallRef = $HKLM.OpenSubKey($UninstallRegKey6432)
$Applications = $UninstallRef.GetSubKeyNames()
Foreach ($AppSubKey in $Applications)
{
$AppRegistryKey = $UninstallRegKey + "\\" + $AppSubKey
$AppDetails = $HKLM.OpenSubKey($AppRegistryKey)
$AppBitVersion = "64-Bit"
$AppDisplayName = $($AppDetails.GetValue("DisplayName"))
$AppGUID = $AppSubKey
$AppInstallDate = $($AppDetails.GetValue("InstallDate"))
$AppInstallLocation = $($AppDetails.GetValue("InstallLocation"))
$AppPublisher = $($AppDetails.GetValue("Publisher"))
$AppUninstallString = $($AppDetails.GetValue("UninstallString"))
$AppVersion = $($AppDetails.GetValue("DisplayVersion"))
$OutputObj = New-Object -TypeName PSobject
$OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
$OutputObj | Add-Member -MemberType NoteProperty -Name AppBitVersion -Value $AppBitVersion
$OutputObj | Add-Member -MemberType NoteProperty -Name AppDisplayName -Value $AppDisplayName
$OutputObj | Add-Member -MemberType NoteProperty -Name AppGUID -Value $AppGUID
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallDate -Value $AppInstallDate
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallLocation -Value $AppInstallLocation
$OutputObj | Add-Member -MemberType NoteProperty -Name AppPublisher -Value $AppPublisher
$OutputObj | Add-Member -MemberType NoteProperty -Name AppUninstallString -Value $AppUninstallString
$OutputObj | Add-Member -MemberType NoteProperty -Name AppVersion -Value $AppVersion
$Array += $OutputObj
$Array #| Where-Object {$_.AppDisplayName -ne $null -and $_.AppGUID -ne $null -and $_.AppPublisher -ne $null -and $_.AppUninstallString -ne $null -and $_.AppVersion -ne $null} | Select-Object -Property ComputerName, AppBitVersion, AppDisplayName, AppGUID, AppInstallDate, AppInstallLocation, AppPublisher, AppUninstallString, AppVersion -Unique
}
}
"False"
{
$NewLine
Write-Output "64-Bit Registry NOT Detected!"
Write-Output "-----------------------------"
$NewLine
Write-Output "----------------------"
Write-Output "Applications Installed"
Write-Output "----------------------"
$NewLine
$HKLM = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine', $Computer)
$UninstallRef = $HKLM.OpenSubKey($UninstallRegKey)
$Applications = $UninstallRef.GetSubKeyNames()
Foreach ($AppSubKey in $Applications)
{
$AppRegistryKey = $UninstallRegKey + "\\" + $AppSubKey
$AppDetails = $HKLM.OpenSubKey($AppRegistryKey)
$AppBitVersion = "32-Bit"
$AppDisplayName = $($AppDetails.GetValue("DisplayName"))
$AppGUID = $AppSubKey
$AppInstallDate = $($AppDetails.GetValue("InstallDate"))
$AppInstallLocation = $($AppDetails.GetValue("InstallLocation"))
$AppPublisher = $($AppDetails.GetValue("Publisher"))
$AppUninstallString = $($AppDetails.GetValue("UninstallString"))
$AppVersion = $($AppDetails.GetValue("DisplayVersion"))
$OutputObj = New-Object -TypeName PSobject
$OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
$OutputObj | Add-Member -MemberType NoteProperty -Name AppBitVersion -Value $AppBitVersion
$OutputObj | Add-Member -MemberType NoteProperty -Name AppDisplayName -Value $AppDisplayName
$OutputObj | Add-Member -MemberType NoteProperty -Name AppGUID -Value $AppGUID
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallDate -Value $AppInstallDate
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallLocation -Value $AppInstallLocation
$OutputObj | Add-Member -MemberType NoteProperty -Name AppPublisher -Value $AppPublisher
$OutputObj | Add-Member -MemberType NoteProperty -Name AppUninstallString -Value $AppUninstallString
$OutputObj | Add-Member -MemberType NoteProperty -Name AppVersion -Value $AppVersion
$Array += $OutputObj
$Array #| Where-Object {$_.AppDisplayName -ne $null -and $_.AppGUID -ne $null -and $_.AppPublisher -ne $null -and $_.AppUninstallString -ne $null -and $_.AppVersion -ne $null} | Select-Object -Property ComputerName, AppBitVersion, AppDisplayName, AppGUID, AppInstallDate, AppInstallLocation, AppPublisher, AppUninstallString, AppVersion -Unique
}
}
}
}
Else
{
$NewLine
Write-Output "$Computer is NOT online!"
$NewLine
}
}
}
system
December 22, 2014, 6:30am
2
You need to decide whether your intention is to build an array and output it all at once at the end of the function, or output the objects one at a time as they’re produced. Right now, you’re doing a combination of both (outputting the whole array each time through a loop):
$Array += $OutputObj
$Array
That essentially boils down to this:
$Array = @()
$Array += 'A'; $Array # Outputs 'A'
$Array += 'B'; $Array # Outputs 'A', 'B'
# etc
On a side note, your Test-Path to detect the Wow6432Node key is being done on the local computer, not on each remote machine. You won’t be able to use Test-Path for that; you’ll have to try to open the key with $HKLM.OpenSubKey() inside your loop, and check for $null.
system
December 22, 2014, 12:14pm
3
Well my preference is to have it all at once at the end, but I am not certain on how to go about doing this.
What would some suggestions be on how to get this desired output?
Yeah I noticed that about the Test-Path cmdlet, but I wanted to work on the looping issue first before working on that next.
I just started working on this script so I am still in the early stages.
Thanks for your help, Dave.
system
December 22, 2014, 5:49pm
4
Okay I finally got it to do what I wanted and I finally understood where you were coming from, Dave.
I decided I wanted to detect if the OS is a 32 or 64 bit version using the Get-CIMInstance cmdlet and use that to move forward with searching in the WOW6432Node Reg key rather using the .Net method.
Can you let me know how this code looks, please:
[blockquote]Function Get-InstalledApplications
{
[cmdletbinding()]
Param
(
[Parameter(
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullorEmpty()]
[string[]]
$ComputerName = $env:COMPUTERNAME
)
Begin
{
$NewLine = "`r`n"
$UninstallRegKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$UninstallRegKey6432 = "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
}
Process
{
$Array = @()
Foreach ($Computer in $ComputerName)
{
If ((Get-Service -Name 'RemoteRegistry' -ComputerName $Computer).Status -ne 'Running')
{
$NewLine
Write-Warning -Message "The RemoteRegistry service is not running on $Computer. Please wait while this script tries to start this service."
$NewLine
Try
{
(Get-Service -Name "RemoteRegistry" -ComputerName $Computer).Start()
Write-Output "The RemoteRegistry on $Computer was successfully started!"
}
Catch
{
$NewLine
Write-Warning "RemoteRegistry couldn't be started on $Computer"
$NewLine
Write-Output "This script will now exit"
$NewLine
Pause
Exit
}
}
Else
{
$NewLine
Write-Output "The RemoteRegistry service is running on $Computer"
$NewLine
}
$NewLine
Write-Output "+++++++++ $Computer ++++++++++"
If (Test-Connection -ComputerName $Computer -Count 1 -Quiet)
{
$OSBitVer = @(
If ((Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $Computer).OSArchitecture -eq "64-bit")
{
Write-Output "64-bit"
}
Else
{
Write-Output "32-bit"
})
If ($OSBitVer -eq "64-bit")
{
$NewLine
Write-Output "64-Bit OS Detected!"
Write-Output "-------------------"
$NewLine
Write-Output "-----------------------------"
Write-Output "64-Bit Applications Installed"
Write-Output "-----------------------------"
$NewLine
$HKLM = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine', $Computer)
$UninstallRef = $HKLM.OpenSubKey($UninstallRegKey)
$Applications = $UninstallRef.GetSubKeyNames()
Foreach ($AppSubKey in $Applications)
{
$AppRegistryKey = $UninstallRegKey + "\\" + $AppSubKey
$AppDetails = $HKLM.OpenSubKey($AppRegistryKey)
$AppBitVersion = "64-Bit"
$AppDisplayName = $($AppDetails.GetValue("DisplayName"))
$AppGUID = $AppSubKey
$AppInstallDate = $($AppDetails.GetValue("InstallDate"))
$AppInstallLocation = $($AppDetails.GetValue("InstallLocation"))
$AppPublisher = $($AppDetails.GetValue("Publisher"))
$AppUninstallString = $($AppDetails.GetValue("UninstallString"))
$AppVersion = $($AppDetails.GetValue("DisplayVersion"))
$OutputObj = New-Object -TypeName PSobject
$OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
$OutputObj | Add-Member -MemberType NoteProperty -Name AppBitVersion -Value $AppBitVersion
$OutputObj | Add-Member -MemberType NoteProperty -Name AppDisplayName -Value $AppDisplayName
$OutputObj | Add-Member -MemberType NoteProperty -Name AppGUID -Value $AppGUID
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallDate -Value $AppInstallDate
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallLocation -Value $AppInstallLocation
$OutputObj | Add-Member -MemberType NoteProperty -Name AppPublisher -Value $AppPublisher
$OutputObj | Add-Member -MemberType NoteProperty -Name AppUninstallString -Value $AppUninstallString
$OutputObj | Add-Member -MemberType NoteProperty -Name AppVersion -Value $AppVersion
$Array += $OutputObj
}
$Array
$NewLine
Write-Output "--------------------------------------------"
Write-Output " 32-Bit Applications Installed on 64-Bit OS "
Write-Output "--------------------------------------------"
$NewLine
$HKLM = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine', $Computer)
$UninstallRef = $HKLM.OpenSubKey($UninstallRegKey6432)
$Applications = $UninstallRef.GetSubKeyNames()
Foreach ($AppSubKey in $Applications)
{
$AppRegistryKey = $UninstallRegKey6432 + "\\" + $AppSubKey
$AppDetails = $HKLM.OpenSubKey($AppRegistryKey)
$AppBitVersion = "32-Bit"
$AppDisplayName = $($AppDetails.GetValue("DisplayName"))
$AppGUID = $AppSubKey
$AppInstallDate = $($AppDetails.GetValue("InstallDate"))
$AppInstallLocation = $($AppDetails.GetValue("InstallLocation"))
$AppPublisher = $($AppDetails.GetValue("Publisher"))
$AppUninstallString = $($AppDetails.GetValue("UninstallString"))
$AppVersion = $($AppDetails.GetValue("DisplayVersion"))
$OutputObj = New-Object -TypeName PSobject
$OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
$OutputObj | Add-Member -MemberType NoteProperty -Name AppBitVersion -Value $AppBitVersion
$OutputObj | Add-Member -MemberType NoteProperty -Name AppDisplayName -Value $AppDisplayName
$OutputObj | Add-Member -MemberType NoteProperty -Name AppGUID -Value $AppGUID
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallDate -Value $AppInstallDate
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallLocation -Value $AppInstallLocation
$OutputObj | Add-Member -MemberType NoteProperty -Name AppPublisher -Value $AppPublisher
$OutputObj | Add-Member -MemberType NoteProperty -Name AppUninstallString -Value $AppUninstallString
$OutputObj | Add-Member -MemberType NoteProperty -Name AppVersion -Value $AppVersion
$Array += $OutputObj
}
$Array
}
Else
{
$NewLine
Write-Output "64-Bit OS NOT Detected!"
Write-Output "-----------------------"
$NewLine
Write-Output "----------------------"
Write-Output "Applications Installed"
Write-Output "----------------------"
$NewLine
$HKLM = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine', $Computer)
$UninstallRef = $HKLM.OpenSubKey($UninstallRegKey)
$Applications = $UninstallRef.GetSubKeyNames()
Foreach ($AppSubKey in $Applications)
{
$AppRegistryKey = $UninstallRegKey + "\\" + $AppSubKey
$AppDetails = $HKLM.OpenSubKey($AppRegistryKey)
$AppBitVersion = "32-Bit"
$AppDisplayName = $($AppDetails.GetValue("DisplayName"))
$AppGUID = $AppSubKey
$AppInstallDate = $($AppDetails.GetValue("InstallDate"))
$AppInstallLocation = $($AppDetails.GetValue("InstallLocation"))
$AppPublisher = $($AppDetails.GetValue("Publisher"))
$AppUninstallString = $($AppDetails.GetValue("UninstallString"))
$AppVersion = $($AppDetails.GetValue("DisplayVersion"))
$OutputObj = New-Object -TypeName PSobject
$OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.ToUpper()
$OutputObj | Add-Member -MemberType NoteProperty -Name AppBitVersion -Value $AppBitVersion
$OutputObj | Add-Member -MemberType NoteProperty -Name AppDisplayName -Value $AppDisplayName
$OutputObj | Add-Member -MemberType NoteProperty -Name AppGUID -Value $AppGUID
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallDate -Value $AppInstallDate
$OutputObj | Add-Member -MemberType NoteProperty -Name AppInstallLocation -Value $AppInstallLocation
$OutputObj | Add-Member -MemberType NoteProperty -Name AppPublisher -Value $AppPublisher
$OutputObj | Add-Member -MemberType NoteProperty -Name AppUninstallString -Value $AppUninstallString
$OutputObj | Add-Member -MemberType NoteProperty -Name AppVersion -Value $AppVersion
$Array += $OutputObj
}
$Array
}
}
Else
{
$NewLine
Write-Output "$Computer is NOT online!"
$NewLine
}
}
}
}[/blockquote]
My observations:
If you pipe an array of computer names into this function, as soon as it encounters one where it cannot start the remote registry service, it will exit the function.
There’s 3 duplicate code blocks (where you get all the properties from the registry keys). The only thing that differs in these code blocks is the top level registry key. You could easily make this a foreach loop, passing just the top level registry keys depending on the architecture.
You’re not clearing the $Array variable at all after you output it. So every application from every machine simply gets added to the existing array. So for a single machine, you get the 64bit and 32bit applications output after the 32bit header. If you run the function with more than one machine, you get all the previous machines details output too, incrementing every time.
Here is a script I wrote that gets installed applictions in a way that mimics the output of Add/Remove Programs. It works with remote machines too, and outputs everything as objects. It might give you some additional ideas.
system
December 23, 2014, 2:03pm
6
Thanks Sean.
Wow, that script you wrote just made me dizzy - LOL
That’s quite a bit more code than I was hoping for, it looks great though.
Can you please expound a bit more on this in number 2: “You could easily make this a foreach loop, passing just the top level registry keys depending on the architecture.”
Thanks
Your code goes like this:
If [$OSBitVer -eq "64-bit"]
{
}
else
{
}
The only difference between those 3 blocks of code is that the 64bit block opens one registry key and the 32bit block opens a different registry key. You get the 32bit apps in both blocks.
So I would refine the code to look like this:
$RegistryKeys = @["32bit registry key"]
If [$OSBitVer -eq "64-bit"]
{
$RegistryKeys += "64bit registry key"
}
foreach [$Key in $RegistryKeys] {
}
You create an array with the 32bit registry key already in it (since you will always be getting that key no matter what the architecture). If the architecture is 64bit, then add the 64bit key to the array as well.
Then loop through the array and run the same block of code for each registry key.
The whole block of code would be the same, apart from this line:
$UninstallRef = $HKLM.OpenSubKey[$UninstallRegKey6432]
which would now change to
$UninstallRef = $HKLM.OpenSubKey[$Key]
Hope that makes sense.