Functions/Get-BcServerInstance.ps1

<#
.SYNOPSIS
    Gets service details for all or the specified Business Central Server instance.
.DESCRIPTION
    Use the Get-FpsBCServerInstance cmdlet to obtain service details for all or the specified Business Central Server instance.
     
    When not a service instance is provided all instances of all versions for the specific machine is returned.
    With VersionFilter, StateFilter and ExcludeServerInstance the returned list can be filtered.
.EXAMPLE
    Get-FpsBCServerInstance
.EXAMPLE
    Get-FpsBCServerInstance -Computer 'remote.domain.eu'
.EXAMPLE
    Get-FpsBCServerInstance -ServiceInstance 'BC150'
.EXAMPLE
    # Returns all BC 15 service instances with a running service state, excluding the BC150 service.
    Get-FpsBCServerInstance -VersionFilter '15' -StateFilter Running -ExcludeServerInstance 'BC150'
#>

function Get-BCServerInstance {
    [CmdletBinding(DefaultParameterSetName='All Instances')]
    Param (
        # Param1 help description
        [Parameter(ValueFromPipeline=$true, ParameterSetName='Specific Instance')]
        [string[]] $ServerInstance,

        [Parameter(ParameterSetName='All Instances')]
        [string] $VersionFilter,

        [Parameter(ParameterSetName='All Instances')]
        [ValidateSet("Running", "Stopped", "Starting", "Stopping", "All")]
        [string] $StateFilter = "All",

        [Parameter(ParameterSetName='All Instances')]
        [ValidateSet("Auto", "Manual", "Disabled", "All")]
        [string] $StartModeFilter = 'All',

        [Parameter(ParameterSetName='All Instances')]
        [string[]] $ExcludeServerInstance,

        [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName='Specific Instance')]
        [Parameter(ValueFromPipelineByPropertyName = $true, ParameterSetName='All Instances')]
        [string] $Computer = $env:COMPUTERNAME
    )
    
    begin {
        if([string]::IsNullOrEmpty($ServerInstance)){
            $AllServerInstances = $true
        }
        
        $Results = @()

        [scriptblock] $ScriptBlock = {
            param(
                $ServerInstance,
                $AllServerInstances,
                $VersionFilter,
                $StateFilter,
                $StartModeFilter,
                $ExcludeServerInstance
            )

            function Get-ServiceVersion {
                param(
                    [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
                    [System.Management.ManagementBaseObject] $Service
                )

                $Regex = '.*"(?<ServicePath>.*?.exe)".*'
                $Match = $Service.PathName | Select-String -Pattern $Regex
                $ExecutablePath = $Match.Matches[0].Groups['ServicePath'].Value
                [version] $ExecutableVersion = (Get-Item $ExecutablePath).VersionInfo.FileVersion

                return $ExecutableVersion
            }

            function Get-BcsAppSettings {
                param(
                    [string] $ServerInstance,
                    # The PathName of the Business Central Windows Service object.
                    [string] $ServicePathName
                )
                # Get the Business Central Service Tier config file path from the service.
                $Regex = 'config\s"(?<Config>.*?)"'
                $Match = $ServicePathName | Select-String -Pattern $Regex
                $BcsConfigPath = $Match.Matches[0].Groups['Config'].Value
                
                if($BcsConfigPath){
                    if(Test-Path $BcsConfigPath){
                        
                        # Get the ServiceTier appSettings config file path from the BCS config
                        [XML] $BcsConfig = Get-Content -Path $BcsConfigPath
                        $BcsAppSettingsConfigPath = $BcsConfig.configuration.appSettings.file

                        if($BcsAppSettingsConfigPath -eq 'CustomSettings.config'){
                            $BcsAppSettingsConfigPath = Join-Path ($BcsConfigPath | Split-Path -Parent) $BcsAppSettingsConfigPath
                        }
                    }
                }

                if($BcsAppSettingsConfigPath){
                    if(Test-Path $BcsAppSettingsConfigPath){
                        
                        # Read Business Central appSettings and convert the keys and values to hashtable
                        [XML] $BcsAppSettingsConfig = Get-Content -Path $BcsAppSettingsConfigPath

                        $BcsAppSettings = @{}
                        foreach($Key in $BcsAppSettingsConfig.appSettings.add){
                            $BcsAppSettings += @{($Key.key.ToString()) = $Key.value}
                        }
                    }
                }

                if(-not $BcsAppSettings){
                    'Could not find the AppSettings for ServerInstance {0}' -f $ServerInstance | Write-Warning
                    return
                }

                return $BcsAppSettings
            }
            
            $Results = @()

            # Get Business Central Service Instances
            $BcServices = @()

            if($ServerInstance){
                foreach ($Instance in $ServerInstance){
                    $BcServices += Get-WmiObject win32_service | Where-Object Name -like ('MicrosoftDynamicsNavServer`${0}' -f $Instance)
                }
            } 
            elseif($AllServerInstances){
                $BcServices = Get-WmiObject win32_service | Where-Object Name -like 'MicrosoftDynamicsNavServer*'
            }

            # Apply Exclude filter
            if($ExcludeServerInstance){
                $BcServices = $BcServices | ForEach-Object {
                    if($_.Name -notin $ExcludeServerInstance -and $_.Name.Split('$')[1] -notin $ExcludeServerInstance){
                        $_
                    }
                }
            }

            # Apply version filter
            if($VersionFilter){
                $BcServices = $BcServices | ForEach-Object {
                    $ServiceVersion = ($_ | Get-ServiceVersion).ToString()
                    if($ServiceVersion -like ('{0}*' -f $VersionFilter)){
                        $_
                    }
                }
            }

            # Apply start-up type filter
            if($StartModeFilter -and $StartModeFilter -ne 'All'){
                $BcServices = $BcServices | ForEach-Object {
                    if($_.StartMode -eq $StartModeFilter){
                        $_
                    }
                }
            }
            
            # Apply State filter
            if($StateFilter -and $StateFilter -ne 'All'){
                $BcServices = $BcServices | ForEach-Object {
                    if($_.State -eq $StateFilter){
                        $_
                    }
                }            
            }

            # Get desired properties
            foreach ($Service in $BcServices){
                            
                $AppSettings = Get-BcsAppSettings `
                                    -ServicePathName $Service.PathName `
                                    -ServerInstance $Service.Name.Split('$')[1]

                # Set SqlInstance (SqlServer\SqlInstanceName)
                if ([string]::IsNullOrEmpty($AppSettings.DatabaseInstance)){
                    $SqlInstance = $AppSettings.DatabaseServer
                } else {
                    $SqlInstance = Join-Path $AppSettings.DatabaseServer $AppSettings.DatabaseInstance
                }
                
                $Result = New-Object PSObject -Property @{
                            'ServerInstance'   = $Service.Name.Split('$')[1]
                            'ServiceName'      = $Service.Name
                            'Version'          = ($Service | Get-ServiceVersion).ToString()
                            'State'            = $Service.State
                            'StartMode'        = $Service.StartMode
                            'ServiceAccount'   = $Service.StartName
                            'Computer'         = $Service.SystemName
                            'PID'              = $Service.ProcessId
                            'DatabaseServer'   = $AppSettings.DatabaseServer
                            'DatabaseInstance' = $AppSettings.DatabaseInstance
                            'DatabaseName'     = $AppSettings.DatabaseName
                            'SqlInstance'      = $SqlInstance
                            'AppSettings'      = $AppSettings
                }
                
                # Sort result
                $Result = $Result | Select-Object -Property ServerInstance, ServiceName, Version, State, StartMode, ServiceAccount, Computer, PID, SqlInstance, DatabaseServer, DatabaseInstance, DatabaseName, AppSettings
                      
                # List of properties visible by default
                [string[]] $Visible = 'ServerInstance', 'Version', 'State', 'ServiceAccount', 'SqlInstance', 'DatabaseName'
                [Management.Automation.PSMemberInfo[]] $PSStandardMembers = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',$Visible)

                # Add the information about the visible properties to the return value
                $Result | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers

                $Results += $Result
            }

            return $Results
        }
    }
    
    process {
        
        $AdditionParams = @{}
        if ($Computer -ne 'localhost' -and $Computer -ne $env:COMPUTERNAME) {
            $AdditionParams = @{'ComputerName' = $Computer}
        }

        $Result = Invoke-Command @AdditionParams -ScriptBlock $ScriptBlock -ArgumentList `
            $ServerInstance,
            $AllServerInstances,
            $VersionFilter,
            $StateFilter,
            $StartModeFilter,
            $ExcludeServerInstance

        $Result | ForEach-Object {
            $Results += $_
        }

    }
    end {
        return $Results
    }
}

Export-ModuleMember -Function Get-BCServerInstance