Script seems to keep looping

This topic contains 6 replies, has 3 voices, and was last updated by Profile photo of Sean Quinlan Sean Quinlan 1 year, 11 months ago.

  • Author
    Posts
  • #21357
    Profile photo of I Am Sir Ask Alot
    I Am Sir Ask Alot
    Participant

    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
    }
    }
    }

  • #21358
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    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.

  • #21364
    Profile photo of I Am Sir Ask Alot
    I Am Sir Ask Alot
    Participant

    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.

  • #21365
    Profile photo of I Am Sir Ask Alot
    I Am Sir Ask Alot
    Participant

    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]

  • #21368
    Profile photo of Sean Quinlan
    Sean Quinlan
    Participant

    My observations:

    1. 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.

    2. 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.

    3. 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.

    [url=https://bitbucket.org/SeanQuinlan/misc-powershell/src/89f25b5ed304f54af305f7029a1b60369be56d33/Get-Programs.ps1?at=master]Here is a script[/url] 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.

  • #21406
    Profile photo of I Am Sir Ask Alot
    I Am Sir Ask Alot
    Participant

    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:[i] "You could easily make this a foreach loop, passing just the top level registry keys depending on the architecture."[/i]

    Thanks

  • #21411
    Profile photo of Sean Quinlan
    Sean Quinlan
    Participant

    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.

You must be logged in to reply to this topic.