internal/functions/NewGet-AllInstanceInfo.ps1

function NewGet-AllInstanceInfo {
    # Using the unique tags gather the information required
    Param($Instance, $Tags)

    #clear out the default initialised fields
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Login], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Information], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile], $false)

    # set the default init fields for all the tags

    # Server Initial fields
    $ServerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server])
    $ServerInitFields.Add("VersionMajor") | Out-Null # so we can check versions
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $ServerInitFields)

    # Database Initial Fields
    $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database])

    # Stored Procedure Initial Fields
    $StoredProcedureInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure])

    # Information Initial Fields

    # Settings Initial Fields
    $SettingsInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings])

    # Login Initial Fields
    $LoginInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Login])

    # Log File Initial Fields
    $LogFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile])

    # Data File Initial Fields
    $DataFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile])

    # Configuration cannot have default init fields :-)
    $configurations = $false

    # Set up blank ConfigValues object for any config we need to use in the checks
    $ConfigValues = [PSCustomObject]@{}

    # Using there so that if the instance is not contactable, no point carrying on with gathering more information
    switch ($tags) {

        'DefaultTrace' {
            $configurations = $true
        }
        'OleAutomationProceduresDisabled' {
            $configurations = $true
        }
        'CrossDBOwnershipChaining' {
            $configurations = $true
        }
        'ScanForStartupProceduresDisabled' {
            # we have to check the spconfigure and we have to check that any stored procedurees in master have startup set to true
            $configurations = $true
            $ScanForStartupProceduresDisabled = $true
            $StoredProcedureInitFields.Add("Startup") | Out-Null # So we can check SPs start up for the CIS checks
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure], $StoredProcedureInitFields)
            $StoredProcedureInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.StoredProcedure]) # I think we need to re-initialise here
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'scanforstartupproceduresdisabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.scanforstartupproceduresdisabled' }).Value)
        }
        'RemoteAccessDisabled' {
            $configurations = $true
        }
        'SQLMailXPsDisabled' {
            $configurations = $true
        }
        'DAC' {
            $configurations = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'dacallowed' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.dacallowed' }).Value)
        }
        'OLEAutomation' {
            $configurations = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'OLEAutomation' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.oleautomation' }).Value)
        }
        'AdHocWorkload' {
            $configurations = $true
        }
        'AdHocDistributedQueriesEnabled' {
            $configurations = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AdHocDistributedQueriesEnabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.AdHocDistributedQueriesEnabled' }).Value)
        }
        'DefaultBackupCompression' {
            $configurations = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DefaultBackupCompression' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.backup.defaultbackupcompression' }).Value)
        }
        'DefaultFilePath' {
            $SettingsInitFields.Add("DefaultFile") | Out-Null # so we can check file paths
            $SettingsInitFields.Add("DefaultLog") | Out-Null # so we can check file paths
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $SettingsInitFields)
        }
        'SaRenamed' {
        }
        'SaDisabled' {
            $LoginInitFields.Add("IsDisabled") | Out-Null # so we can check if sa is disabled
            $LoginInitFields.Add("ID") | Out-Null # so we can check if sa is disabled even if it has been renamed
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Settings], $LoginInitFields)
        }
        'ModelDbGrowth' {
            $LogFileInitFields.Add("Growth") | Out-Null # So we can check the model file growth settings
            $LogFileInitFields.Add("GrowthType") | Out-Null # So we can check the model file growth settings
            $LogFileInitFields.Add("Name") | Out-Null # So we can check the model file growth settings
            $DataFileInitFields.Add("Growth") | Out-Null # So we can check the model file growth settings
            $DataFileInitFields.Add("GrowthType") | Out-Null # So we can check the model file growth settings
            $DataFileInitFields.Add("Name") | Out-Null # So we can check the model file growth settings
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile], $LogFileInitFields)
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile], $DataFileInitFields)
            $LogFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.LogFile]) # I think we need to re-initialise here
            $DataFileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.DataFile]) # I think we need to re-initialise here

        }
        'ErrorlogCount' {

            $ServerInitFields.Add("NumberOfLogFiles") | Out-Null # so we can check versions
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server], $ServerInitFields)
            $ServerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Server]) # I think we need to re-initialise here

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'errorLogCount' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.errorlog.logcount' }).Value)

        }
        'MaxDopInstance' {
            #Test-DbaMaxDop needs these because it checks every database as well
            $DatabaseInitFields.Add("IsAccessible") | Out-Null # so we can check if its accessible
            $DatabaseInitFields.Add("IsSystemObject ") | Out-Null # so we can check if its accessible
            $DatabaseInitFields.Add("MaxDop ") | Out-Null # so we can check if its accessible
            $DatabaseInitFields.Add("Name ") | Out-Null # so we can check if its accessible
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database], $DatabaseInitFields)
            $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) # I think we need to re-initialise here

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'UseRecommendedMaxDop' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.instancemaxdop.userecommended' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'InstanceMaxDop' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.instancemaxdop.maxdop' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'ExcludeInstanceMaxDop' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.instancemaxdop.excludeinstance' }).Value)
            if ($Instance.Name -notin $ConfigValues.ExcludeInstanceMaxDop) {
                $MaxDopSettings = (Test-DbaMaxDop -SqlInstance $Instance)[0] # because we dont care about the database maxdops here - potentially we could store it and use it for DatabaseMaxDop ?
            }
        }
        'TwoDigitYearCutoff' {
            $configurations = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TwoDigitYearCutoff' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.twodigityearcutoff' }).Value)

        }
        'TraceFlagsExpected' {
            $TraceFlagsExpected = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.traceflags.expected' }).Value
            $TraceFlagsActual = $Instance.EnumActiveGlobalTraceFlags()
            if (-not $ConfigValues.TraceFlagsExpected) {
                $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TraceFlagsExpected' -Value $TraceFlagsExpected -Force
            }
            $ExpectedTraceFlags = $TraceFlagsExpected.Foreach{
                [PSCustomObject]@{
                    InstanceName      = $Instance.Name
                    ExpectedTraceFlag = $PSItem
                    ActualTraceFlags  = $TraceFlagsActual
                }
            }
            $ExpectedTraceFlags += [PSCustomObject]@{
                InstanceName      = $Instance.Name
                ExpectedTraceFlag = 'null'
                ActualTraceFlags  = $TraceFlagsActual
            }
        }
        'TraceFlagsNotExpected' {
            $TraceFlagsNotExpected = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.traceflags.notexpected' }).Value
            $TraceFlagsExpected = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.traceflags.expected' }).Value
            if ($null -eq $TraceFlagsExpected) { $TraceFlagsExpected = 'none expected' }
            $TraceFlagsActual = $Instance.EnumActiveGlobalTraceFlags()
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TraceFlagsNotExpected' -Value $TraceFlagsNotExpected
            if (-not $ConfigValues.TraceFlagsExpected) {
                $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TraceFlagsExpected' -Value $TraceFlagsExpected -Force
            }
            $NotExpectedTraceFlags = $TraceFlagsNotExpected.Where{ $_ -notin $TraceFlagsExpected }.Foreach{
                [PSCustomObject]@{
                    InstanceName         = $Instance.Name
                    NotExpectedTraceFlag = $PSItem
                    TraceFlagsExpected   = $TraceFlagsExpected
                    ActualTraceFlags     = $TraceFlagsActual
                }
            }
            $NotExpectedTraceFlags += [PSCustomObject]@{
                InstanceName         = $Instance.Name
                TraceFlagsExpected   = $TraceFlagsExpected
                NotExpectedTraceFlag = 'null'
                ActualTraceFlags     = $TraceFlagsActual
            }
        }
        'CLREnabled' {
            $configurations = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'CLREnabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.clrenabled' }).Value)
        }
        'WhoIsActiveInstalled' {
            $configurations = $true
            $WhoIsActiveInstalled = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'whoisactivedatabase' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.whoisactive.database' }).Value)
        }
        'XpCmdShellDisabled' {
            $configurations = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'XpCmdShellDisabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.XpCmdShellDisabled' }).Value)

        }
        'XESessionStopped' {
            if (-not $xeSessions) {
                $xeSessions = Get-DbaXESession -SqlInstance $Instance
            }
            $RequiredStopped = (($__dbcconfig | Where-Object { $_.Name -eq 'policy.xevent.requiredstoppedsession' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'requiredstoppedsession' -Value $RequiredStopped
            if (-not $xeSessions) {
                $RunningSessions = $xeSessions.Where{ $_.Status -eq 'Running' }.Name
            }
            if (-not $Sessions) {
                $Sessions = $xeSessions.Name
            }
        }
        'XESessionExists' {
            if (-not $xeSessions) {
                $xeSessions = Get-DbaXESession -SqlInstance $Instance
            }
            $RequiredExists = (($__dbcconfig | Where-Object { $_.Name -eq 'policy.xevent.requiredexists' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'requiredexistssessions' -Value $RequiredExists
            if (-not $RunningSessions) {
                $RunningSessions = $xeSessions.Where{ $_.Status -eq 'Running' }.Name
            }
            if (-not $Sessions) {
                $Sessions = $xeSessions.Name
            }
        }
        'XESessionRunning' {
            if (-not $xeSessions) {
                $xeSessions = Get-DbaXESession -SqlInstance $Instance
            }
            $RequiredRunning = (($__dbcconfig | Where-Object { $_.Name -eq 'policy.xevent.requiredrunningsession' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'requiredrunningsession' -Value $RequiredRunning
            if (-not $RunningSessions) {
                $RunningSessions = $xeSessions.Where{ $_.Status -eq 'Running' }.Name
            }
            if (-not $Sessions) {
                $Sessions = $xeSessions.Name
            }
        }
        'XESessionRunningAllowed' {
            if (-not $xeSessions) {
                $xeSessions = Get-DbaXESession -SqlInstance $Instance
            }
            $RunningAllowed = (($__dbcconfig | Where-Object { $_.Name -eq 'policy.xevent.validrunningsession' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'validrunningsession' -Value $RunningAllowed
            if (-not $RunningSessions) {
                $RunningSessions = $xeSessions.Where{ $_.Status -eq 'Running' }.Name
            }
            if (-not $Sessions) {
                $Sessions = $xeSessions.Name
            }
        }
        'ErrorLog' {
            $logWindow = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.errorlog.warningwindow' }).Value
            # so that it can be mocked
            function Get-ErrorLogEntry {
                # get the number of the first error log that was created after the log window config
                $OldestErrorLogNumber = ($InstanceSMO.EnumErrorLogs() | Where-Object { $psitem.CreateDate -gt (Get-Date).AddDays( - $LogWindow) } | Sort-Object ArchiveNo -Descending | Select-Object -First 1).ArchiveNo + 1
                # Get the Error Log entries for each one
                    (0..$OldestErrorLogNumber).ForEach{
                    $InstanceSMO.ReadErrorLog($psitem).Where{ $_.Text -match "Severity: 1[7-9]|Severity: 2[0-4]" }
                }
            }
            # It is not enough to check the CreateDate on the log, you must check the LogDate on every error record as well.
            $ErrorLogCount = (Get-ErrorLogEntry | Where-Object { $psitem.LogDate -gt (Get-Date).AddDays( - $LogWindow) }).Count
        }
        'TempDbConfiguration' {
            $TempDBTest = Test-DbaTempDbConfig -SqlInstance $Instance
        }
        'InstanceConnection' {
            #local is always NTLM except when its a container ;-)
            if ($Instance.ComputerNamePhysicalNetBIOS -eq $ENV:COMPUTERNAME -and ($instance.Name -notlike '*,*')) {
                $authscheme = 'skipped-local'
            } else {
                if (-not(($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.auth' }).Value)) {
                    $authscheme = $instance.Query("Select auth_scheme as AuthScheme FROM sys.dm_exec_connections WHERE session_id = @@SPID").AuthScheme
                } else {
                    $authscheme = 'skipped'
                }
            }

            if (-not(($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.ping' }).Value)) {
                $pingu = New-Object System.Net.NetworkInformation.Ping
                $timeout = 1000 #milliseconds
                $ping = ($pingu.Send($instance.ComputerName, $timeout)).Status
            } else {
                $ping = 'skipped'
            }


            if (-not(($__dbcconfig | Where-Object { $_.Name -eq 'skip.connection.remote' }).Value)) {
                #simple remoting check
                try {
                    $null = Invoke-Command -ComputerName $instance.ComputerName -ScriptBlock { Get-ChildItem } -ErrorAction Stop
                    $remote = $true
                } catch {
                    $remote = $false
                }
            } else {
                $remote = 'skipped'
            }

            $InstanceConnection = @{
                Connect    = $true # because we wouldnt get here otherwise
                AuthScheme = $authscheme
                Ping       = $ping
                Remote     = $remote
            }
        }
        'BackUpPathAccess' {
            # get value from config or from default setting
            $BackupPath = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.storage.backuppath' }).Value
            if (-not $BackupPath) {
                $BackupPath = $Instance.BackupDirectory
            }
            $BackupPathAccess = Test-DbaPath -SqlInstance $Instance -Path $BackupPath
        }
        'LatestBuild' {
            $LatestBuild = Test-DbaBuild -SqlInstance $Instance -Latest
        }
        'NetworkLatency' {
            $NetworkThreshold = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.network.latencymaxms' }).Value
            $Latency = (Test-DbaNetworkLatency -SqlInstance $Instance).NetworkOnlyTotal.TotalMilliseconds
        }

        'LinkedServerConnection' {
            $LinkedServerResults = Test-DbaLinkedServerConnection -SqlInstance $Instance
        }

        'MaxMemory' {
            if ($isLinux -or $isMacOS) {
                $totalMemory = $Instance.PhysicalMemory
                # Some servers under-report by 1.
                if (($totalMemory % 1024) -ne 0) {
                    $totalMemory = $totalMemory + 1
                }
                $MaxMemory = [PSCustomObject]@{
                    MaxValue         = $totalMemory
                    RecommendedValue = $Instance.Configuration.MaxServerMemory.ConfigValue + 379
                    # because we added 379 before and I have zero idea why
                }
            } else {
                $MemoryValues = Test-DbaMaxMemory -SqlInstance $Instance
                $MaxMemory = [PSCustomObject]@{
                    MaxValue         = $MemoryValues.MaxValue
                    RecommendedValue = $MemoryValues.RecommendedValue
                }
            }
        }

        Default { }
    }

    #build the object

    $testInstanceObject = [PSCustomObject]@{
        ComputerName          = $Instance.ComputerName
        InstanceName          = $Instance.DbaInstanceName
        Name                  = $Instance.Name
        ConfigValues          = $ConfigValues
        VersionMajor          = $Instance.VersionMajor
        Configuration         = if ($configurations) { $Instance.Configuration } else { $null }
        Settings              = $Instance.Settings
        Logins                = $Instance.Logins
        Databases             = $Instance.Databases
        NumberOfLogFiles      = $Instance.NumberOfLogFiles
        MaxDopSettings        = $MaxDopSettings
        ExpectedTraceFlags    = $ExpectedTraceFlags
        NotExpectedTraceFlags = $NotExpectedTraceFlags
        XESessions            = [pscustomobject]@{
            RequiredStopped = $RequiredStopped.ForEach{
                [pscustomobject]@{
                    Name        = $Instance.Name
                    SessionName = $PSItem
                    Running     = $RunningSessions
                }
            }
            RequiredExists  = $RequiredExists.ForEach{
                [pscustomobject]@{
                    Name        = $Instance.Name
                    SessionName = $PSItem
                    Sessions    = $Sessions
                }
            }
            RequiredRunning = $RequiredRunning.ForEach{
                [pscustomobject]@{
                    Name        = $Instance.Name
                    SessionName = $PSItem
                    Sessions    = $Sessions
                    Running     = $RunningSessions
                }
            }
            RunningAllowed  = $RunningSessions.ForEach{
                [pscustomobject]@{
                    Name        = $Instance.Name
                    SessionName = $PSItem
                    Sessions    = $Sessions
                    Allowed     = $RunningAllowed
                }
            }
            Name            = $Instance.Name
            Sessions        = $Sessions
            Running         = $RunningSessions
        }
        ErrorLogEntries       = [pscustomobject]@{
            errorLogCount = $ErrorLogCount
            logWindow     = $logWindow
        }
        InstanceConnection    = $InstanceConnection
        BackupPathAccess      = [pscustomobject]@{
            Result     = $BackupPathAccess
            BackupPath = $BackupPath
        }
        LatestBuild           = [PSCustomObject]@{
            Compliant = $LatestBuild.Compliant
        }
        NetworkLatency        = [PSCustomObject]@{
            Latency   = $Latency
            Threshold = $NetworkThreshold
        }
        LinkedServerResults   = if ($LinkedServerResults) {
            $LinkedServerResults.ForEach{
                [pscustomobject]@{
                    InstanceName     = $Instance.Name
                    LinkedServerName = $PSItem.LinkedServerName
                    RemoteServer     = $PSItem.RemoteServer
                    Connectivity     = $PSItem.Connectivity
                    Result           = $PSItem.Result
                }
            }
        } else {
            [pscustomobject]@{
                InstanceName     = $Instance.Name
                LinkedServerName = 'None found'
                RemoteServer     = 'None'
                Connectivity     = $true
                Result           = 'None'
            }
        }
        MaxMemory             = $MaxMemory
        # TempDbConfig = [PSCustomObject]@{
        # TF118EnabledCurrent = $tempDBTest[0].CurrentSetting
        # TF118EnabledRecommended = $tempDBTest[0].Recommended
        # TempDBFilesCurrent = $tempDBTest[1].CurrentSetting
        # TempDBFilesRecommended = $tempDBTest[1].Recommended
        # }
    }
    if ($ScanForStartupProceduresDisabled) {
        $StartUpSPs = $Instance.Databases['master'].StoredProcedures.Where{ $_. Name -ne 'sp_MSrepl_startup' -and $_.StartUp -eq $true }.count
        if ($StartUpSPs -eq 0) {
            $testInstanceObject.Configuration.ScanForStartupProcedures.ConfigValue = 0
        }
    }
    if ($WhoIsActiveInstalled) {
        $whoisdatabase = ($__dbcconfig | Where-Object { $_.Name -eq 'policy.whoisactive.database' }).Value
        $WhoIsActiveInstalled = $Instance.Databases[$whoisdatabase].StoredProcedures.Where{ $_.Name -eq 'sp_WhoIsActive' }.count
        $testInstanceObject.ConfigValues | Add-Member -MemberType NoteProperty -Name 'WhoIsActiveInstalled' -Value $whoIsActiveInstalled
    }
    return $testInstanceObject
}