Functions/PlatformManagement/Get-BcComponent.ps1

<#
.Synopsis
    Scans host system on installed NAV components, installation location and installation details
 
.DESCRIPTION
    Scans host system on installed NAV components, installation location and installation details
 
.PARAMETER BcVersion
    The Bc Version, example: 'bc21', 'nav2017', 'bc17', 'nav2013 R2'
 
.EXAMPLE
    $NavComponents = Get-NavComponents -BcVersion "nav2017"
 
.EXAMPLE
    $NavComponents = Get-NavComponents -BcVersion "nav2013 R2"
#>

function Get-BcComponent
{
    [CmdletBinding()]
    [OutputType([array])]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0)]
        $BcVersion,
        $Computer = $env:COMPUTERNAME
    )

    # Validate BC Version and get BC version folder
    $BcVersion = Get-BcVersion -BcVersion $BcVersion

    $scriptBlock = [scriptblock] {
        param
        (
            $BcVersion
        )

        # Helper functions
        function Get-NavComponentsFromWinReg
        {   
            param(
                $NavComponents
            )

            # Create an instance of the Registry Object and open the HKLM base key
            $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$($env:computername))

            $Architectures = @("32", "64")

            foreach ($Architecture in $Architectures) {

                if ($Architecture -eq "32") {
                    # Reg locations of currently Installed 32bit or 32/64bit programs
                    $UninstallKey = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
                }
                if ($Architecture -eq "64") {
                    # Reg locations of currently Installed 64bit programs
                    $UninstallKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
                }

                # Drill down into the Uninstall key for the corresponding architecture using the OpenSubKey Method
                $Regkey = $Reg.OpenSubKey($UninstallKey)

                Write-Verbose "Reg path for $Architecture bit: $UninstallKey"

                # Retrieve an array of string that contain all the subkey names from the Uninstall registery tree
                $subkeys = $Regkey.GetSubKeyNames()

                # Open each Subkey to check if it's a NAV component
                foreach ($key in $subkeys) {

                    $thisKey = $UninstallKey + "\\" + $key

                    # Open the subkey
                    $thisSubKey = $Reg.OpenSubKey($thisKey)

                    # If the regkey doesn't contain a NAV component: continue
                    if (-not $thisSubKey.GetValue("DisplayName") -or 
                        $thisSubKey.GetValue("DisplayName") -notin $NavComponents.Displayname) {
                        continue
                    }

                    # Match the regkey with the correct NAV components and add the information from the regkey to the nav component array
                    foreach ($Component in $NavComponents) {
                        if ($Component.Displayname -ne $thisSubKey.GetValue("DisplayName")) {
                            continue
                        }

                        # If the display name matches, check if the major version of the product correspond.
                        # Unlike NAV the Business Central releases do not have an unique identifiers in the displayname.
                        if ($thisSubKey.GetValue("DisplayVersion") -notlike ('{0}*' -f $BcVersion.VersionFolder.Substring(0,2))) {
                            continue
                        }

                        $Component.DisplayVersion = $($thisSubKey.GetValue("DisplayVersion"))
                        $Component.InstallLocation = $($thisSubKey.GetValue("InstallLocation"))
                        $Component.InstallSource = $($thisSubKey.GetValue("InstallSource"))
                        $Component.RegKey = $thisKey
                        $Component.Bit = $Architecture

                        # Validate the found component path
                        if ($Component.InstallLocation) {
                                    
                            if (Test-Path -Path $Component.InstallLocation) {
                                $Component.IsInstalled = $True

                                Write-Verbose ""
                                Write-Verbose "$($Component.Displayname) found"
                                Write-Verbose "File location: $($Component.InstallLocation)" 
                                Write-Verbose "Register location: $($Component.RegKey)"
                                continue

                            } # End if

                        } # End if

                        Write-Verbose ""
                        Write-Verbose "$($Component.Displayname) found"
                        Write-Verbose "Register location: $($Component.RegKey)"

                    } # End foreach component

                } # End foreach subkey

            } # End foreach architecture

            $Reg.Close()

            return $NavComponents

        } # End function Get-NavComponentsFromWinReg

        function Get-NavComponentPaths {    
            param(
                $NavComponents,
                $BCVersion
            ) 

            foreach ($Component in $NavComponents) {
                        
                if ($Component.Component -eq "ADCS") {
                    $RegPath = 'SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft Dynamics NAV\\{0}\\Automated Data Capture System' -f $BCVersion.VersionFolder
                }

                if ($Component.Component -eq "HelpServer") {
                    $RegPath = 'SOFTWARE\\Microsoft\\Microsoft Dynamics NAV\\{0}\\DynamicsNAV{0}Help' -f $BCVersion.VersionFolder
                }

                if ($Component.Component -eq "NST") {
                    $RegPath = 'SOFTWARE\\Microsoft\\Microsoft Dynamics NAV\\{0}\\Service' -f $BCVersion.VersionFolder
                }

                if ($Component.Component -eq "OUTLOOK") {
                    $RegPath = 'SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft Dynamics NAV\\{0}\\OutlookAddin' -f $BCVersion.VersionFolder
                }

                if ($Component.Component -eq "RTC") {
                    $RegPath = 'SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft Dynamics NAV\\{0}\\RoleTailored Client' -f $BCVersion.VersionFolder
                }

                if ($Component.Component -eq "WEB CLIENT") {
                    $RegPath = 'SOFTWARE\\Microsoft\\Microsoft Dynamics NAV\\{0}\\Web Client' -f $BCVersion.VersionFolder
                }

                $ComponentPath = Get-NavComponentPath ($RegPath)

                if ($ComponentPath) {
                    $Component.IsInstalled = $True
                    $Component.InstallLocation = $ComponentPath
                }

                if($RegPath){
                    Clear-Variable RegPath
                }
                Clear-Variable ComponentPath
            }

            return $NavComponents

        } # End function GetNavComponentPaths

        function Get-NavComponentPath ($RegPath) {
                    
            # Create an instance of the Registry Object and open the HKLM base key
            $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$($env:computername))

            $RegKey = $Reg.OpenSubKey($RegPath)
                    
            if ($RegKey) {
                        
                if ($RegKey.GetValue("Path")) {
                            
                    if (Test-Path -Path ($RegKey.GetValue("Path"))) {
                                
                        $ComponentPath = $RegKey.GetValue("Path")
                        return $ComponentPath
                    }
                }
            }
                    
            $ComponentPath = $False
            $Reg.Close()
            return $ComponentPath

        } # End function GetNavComponentPath
        # End Helper functions

        # Excluded: BPA, TestToolKit, UpgradeToolKit, WindowsPowerShellScripts
        $properties = @{
            'Component'       = ''
            'DisplayName'     = ''
            'IsInstalled'     = $false
            'InstallLocation' = ''
            'DisplayVersion'  = ''
            'InstallSource'   = ''
            'Bit'             = ''
            'RegKey'          = ''
        }

        $components = [ordered] @{
            'ADCS'       = 'Microsoft Dynamics NAV Automated Data Capture System'
            'HelpServer' = 'Microsoft Dynamics NAV {0} Help'                -f $BcVersion.VersionNumber
            'NST'        = 'Microsoft Dynamics NAV {0} Server'              -f $BcVersion.VersionNumber
            'OUTLOOK'    = 'Microsoft Dynamics NAV {0} Outlook Add-in'      -f $BcVersion.VersionNumber
            'RTC'        = 'Microsoft Dynamics NAV {0} RoleTailored Client' -f $BcVersion.VersionNumber
            'WEB CLIENT' = 'Microsoft Dynamics NAV {0} Web Client'          -f $BcVersion.VersionNumber
        }

        if($BcVersion.ProductAbb -eq 'BC'){
            $components = [ordered] @{
                'ADCS'       = 'Microsoft Dynamics NAV Automated Data Capture System'
                'HelpServer' = 'Microsoft Dynamics 365 Business Central Help'
                'NST'        = 'Microsoft Dynamics 365 Business Central Server'
                'OUTLOOK'    = 'Microsoft Dynamics 365 Business Central Outlook Add-in'
                'RTC'        = 'Microsoft Dynamics NAV RoleTailored Client'
                'WEB CLIENT' = 'Microsoft Dynamics 365 Business Central Web Client'
            }
        }

        $NavComponents = @()
        foreach($key in $components.Keys){
            $component = New-Object psobject -Property $properties
            $component.Component = $key
            $component.DisplayName = $components.$key
            $NavComponents += $component
        }

        $NavComponents = Get-NavComponentsFromWinReg -NavComponents $NavComponents -BcVersion $BcVersion
        $NavComponents = Get-NavComponentPaths -NavComponents $NavComponents -BcVersion $BcVersion

        return $NavComponents
    } # End Scriptblock

    # Do not add the computerName parameter if the host and target machine are the same.
    # This removes the requirement to have remote PowerShell enabled.
    $additionParams = @{}
    if ($Computer -ne 'localhost' -and $Computer -ne $env:COMPUTERNAME) {
        $additionParams = @{'ComputerName' = $Computer}
    }
    
    $result = Invoke-Command @additionParams -ScriptBlock $scriptBlock -ArgumentList $BcVersion
    
    return $result
}

Export-ModuleMember -Function Get-BcComponent