internal/functions/Get-AllAgentInfo.ps1

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

    #ToDo: Clean unused SMO classes
    #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.Agent.Operator], $false)
    $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem], $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)

    # Job Server Initial fields
    $OperatorInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Operator])

    # Job Server Alert System Initial fields
    $FailsafeInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem])

    # JobServer Initial fields
    $AgentMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer])

    # Database Mail Profile Initial fields
    $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Mail.MailProfile])

    # JobOwner Initial fields
    $JobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job])

    # Invalid JobOwner Initial fields
    $InvalidJobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job])

    # Failed Job Initial fields
    $FailedJobInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job])

    # Agent Alerts Initial fields
    $AgentAlertsInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Alert])

    # Agent Job History Initial fields
    $AgentJobHistory = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer])

    # 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) {

        'DatabaseMailEnabled' {
            $configurations = $true
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DatabaseMailEnabled' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'policy.security.databasemailenabled' }).Value)
        }
        'AgentServiceAccount' {
            if (($Instance.VersionMajor -ge 14) -or $IsLinux -or $Instance.HostPlatform -eq 'Linux') {
                $Agent = @($Instance.Query("SELECT status_desc, startup_type_desc, servicename FROM sys.dm_server_services") | Where-Object servicename -Like '*Agent*').ForEach{
                    [PSCustomObject]@{
                        State     = $PSItem.status_desc
                        StartMode = $PSItem.startup_type_desc
                    }
                }
            } else {
                # Windows
                $Agent = @(Get-DbaService -ComputerName $Instance.ComputerName -Type Agent)
            }
        }
        'DbaOperator' {
            $OperatorInitFields.Add("Name") | Out-Null # so we can check operators
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Operator], $OperatorInitFields)
            $OperatorInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Operator])

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DbaOperatorName' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.dbaoperatorname' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DbaOperatorEmail' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.dbaoperatoremail' }).Value)

            $Operator = $ConfigValues.DbaOperatorName.ForEach{
                [PSCustomObject]@{
                    InstanceName          = $Instance.Name
                    ExpectedOperatorName  = $PSItem
                    ActualOperatorName    = $Instance.JobServer.Operators.Name
                    ExpectedOperatorEmail = 'null'
                    ActualOperatorEmail   = 'null'
                }
            }

            $Operator += $ConfigValues.DbaOperatorEmail.ForEach{
                [PSCustomObject]@{
                    InstanceName          = $Instance.Name
                    ExpectedOperatorName  = 'null'
                    ActualOperatorName    = 'null'
                    ExpectedOperatorEmail = $PSItem
                    ActualOperatorEmail   = $Instance.JobServer.Operators.EmailAddress
                }
            }
        }
        'FailsafeOperator' {
            $FailsafeInitFields.Add("FailSafeOperator") | Out-Null # so we can check failsafe operators
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem], $FailsafeInitFields)
            $FailsafeInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem])

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'FailsafeOperator' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.failsafeoperator' }).Value)

            $failsafeOperator = $ConfigValues.FailsafeOperator.ForEach{
                [PSCustomObject]@{
                    InstanceName             = $Instance.Name
                    ExpectedFailSafeOperator = $PSItem
                    ActualFailSafeOperator   = $Instance.JobServer.AlertSystem.FailSafeOperator
                }
            }
        }
        'DatabaseMailProfile' {
            $DatabaseMailProfileInitFields.Add("Name") | Out-Null # so we can check failsafe operators
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Mail.MailProfile], $DatabaseMailProfileInitFields)
            $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Mail.MailProfile])

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DatabaseMailProfile' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.databasemailprofile' }).Value)

            $databaseMailProfile = $ConfigValues.DatabaseMailProfile.ForEach{
                [PSCustomObject]@{
                    InstanceName                = $Instance.Name
                    ExpectedDatabaseMailProfile = $ConfigValues.DatabaseMailProfile
                    ActualDatabaseMailProfile   = $Instance.Mail.Profiles.Name
                }
            }
        }
        'AgentMailProfile' {
            $AgentMailProfileInitFields.Add("DatabaseMailProfile") | Out-Null # so we can check failsafe operators
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer], $AgentMailProfileInitFields)
            $AgentMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer])

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMailProfile' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.databasemailprofile' }).Value)

            $agentMailProfile = $ConfigValues.AgentMailProfile.ForEach{

                [PSCustomObject]@{
                    InstanceName             = $Instance.Name
                    ExpectedAgentMailProfile = $ConfigValues.AgentMailProfile
                    ActualAgentMailProfile   = $Instance.JobServer.DatabaseMailProfile
                }
            }
        }
        'FailedJob' {
            $FailedJobInitFields.Add("Name") | Out-Null # so we can check Job Name
            $FailedJobInitFields.Add("IsEnabled") | Out-Null # so we can check Job status
            $FailedJobInitFields.Add("LastRunDate") | Out-Null # so we can check Job LastRunDate
            $FailedJobInitFields.Add("LastRunOutcome") | Out-Null # so we can check Job LastRunOutcome

            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $FailedJobInitFields)
            $FailedJobInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job])

            $maxdays = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.failedjob.since' }).Value
            $startdate = (Get-Date).AddDays( - $maxdays)

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'FailedJob' -Value 'Succeeded'

            $JobsFailed = ($Instance.JobServer.Jobs | Where-Object { $_.IsEnabled -and ($_.LastRunDate -gt $startdate) }).ForEach{
                [PSCustomObject]@{
                    InstanceName    = $Instance.Name
                    JobName         = $PSItem.Name
                    ExpectedOutcome = $ConfigValues.FailedJob
                    LastRunOutcome  = $PSItem.LastRunOutcome
                }
            }
        }
        'ValidJobOwner' {
            $JobOwnerInitFields.Add("OwnerLoginName") | Out-Null # so we can check Job Owner
            $JobOwnerInitFields.Add("Name") | Out-Null # so we can check Job Name
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $JobOwnerInitFields)
            $JobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job])

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TargetJobOwner' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.validjobowner.name' }).Value)

            $JobOwner = $Instance.JobServer.Jobs.ForEach{
                [PSCustomObject]@{
                    InstanceName         = $Instance.Name
                    JobName              = $PSItem.Name
                    ExpectedJobOwnerName = $ConfigValues.TargetJobOwner #$PSItem
                    ActualJobOwnerName   = $PSItem.OwnerLoginName
                }
            }
        }
        'InvalidJobOwner' {
            $InvalidJobOwnerInitFields.Add("OwnerLoginName") | Out-Null # so we can check Job Owner
            $InvalidJobOwnerInitFields.Add("Name") | Out-Null # so we can check Job Name
            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $InvalidJobOwnerInitFields)
            $InvalidJobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job])

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'InvalidJobOwner' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.invalidjobowner.name' }).Value)

            $InvalidJobOwner = $Instance.JobServer.Jobs.ForEach{
                [PSCustomObject]@{
                    InstanceName         = $Instance.Name
                    JobName              = $PSItem.Name
                    ExpectedJobOwnerName = $ConfigValues.InvalidJobOwner
                    ActualJobOwnerName   = $PSItem.OwnerLoginName
                }
            }

        }
        'AgentAlert' {
            $AgentAlertsInitFields.Add("Severity") | Out-Null # so we can check Alert Severity
            $AgentAlertsInitFields.Add("IsEnabled") | Out-Null # so we can check Alert status
            $AgentAlertsInitFields.Add("JobName") | Out-Null # so we can check Alert job
            $AgentAlertsInitFields.Add("HasNotification") | Out-Null # so we can check Alert notification

            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Alert], $AgentAlertsInitFields)
            $AgentAlertsInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Alert])

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentAlertSeverity' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Severity' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentAlertMessageId' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.messageid' }).Value)

            $Severities = $ConfigValues.AgentAlertSeverity.ForEach{
                $Severity = [int]($PSItem)
                $sev = $Instance.JobServer.Alerts.Where{ $_.Severity -eq $Severity }
                [PSCustomObject]@{
                    InstanceName       = $Instance.Name
                    AlertName          = $sev.Name
                    Severity           = $sev.Severity
                    IsEnabled          = $sev.IsEnabled
                    JobName            = $sev.JobName
                    HasNotification    = $sev.HasNotification
                    AgentAlertSeverity = $Severity
                }
            }

            $MessageIDs = $ConfigValues.AgentAlertMessageId.ForEach{
                $MessageID = [int]($PSItem)
                $msgID = $Instance.JobServer.Alerts.Where{ $_.MessageID -eq $MessageID }
                [PSCustomObject]@{
                    InstanceName    = $Instance.Name
                    AlertName       = $msgID.Name
                    MessageID       = $msgID.MessageID
                    IsEnabled       = $msgID.IsEnabled
                    JobName         = $msgID.JobName
                    HasNotification = $msgID.HasNotification
                    AgentMessageID  = $MessageID
                }
            }

            $AgentAlerts = [PSCustomObject]@{
                Severities = $Severities
                MessageIDs = $MessageIDs
            }
        }
        'JobHistory' {
            $AgentJobHistory.Add("MaximumHistoryRows") | Out-Null # so we can check Alert Severity
            $AgentJobHistory.Add("MaximumJobHistoryRows") | Out-Null # so we can check Alert status

            $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer], $AgentJobHistory)
            $AgentJobHistory = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer])

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMaximumHistoryRows' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.history.maximumhistoryrows' }).Value)
            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMaximumJobHistoryRows' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.history.maximumjobhistoryrows' }).Value)

            $JobHistory = [PSCustomObject]@{
                InstanceName                  = $Instance.Name
                CurrentMaximumHistoryRows     = $Instance.JobServer.MaximumHistoryRows
                ExpectedMaximumHistoryRows    = $ConfigValues.AgentMaximumHistoryRows
                CurrentMaximumJobHistoryRows  = $Instance.JobServer.MaximumJobHistoryRows
                ExpectedMaximumJobHistoryRows = $ConfigValues.AgentMaximumJobHistoryRows
            }
        }
        'LongRunningJob' {
            $query = "SELECT
                JobName,
                AvgSec,
                start_execution_date as StartDate,
                RunningSeconds,
                RunningSeconds - AvgSec AS Diff
                FROM
                (
                SELECT
                j.name AS JobName,
                start_execution_date,
                AVG(DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000'
                + CONVERT(VARCHAR(6),jh.run_duration),6),5,0,':'),3,0,':'))) AS AvgSec,
                ja.start_execution_date as startdate,
                DATEDIFF(second, ja.start_execution_date, GetDate()) AS RunningSeconds
                FROM msdb.dbo.sysjobactivity ja
                JOIN msdb.dbo.sysjobs j
                ON ja.job_id = j.job_id
                JOIN msdb.dbo.sysjobhistory jh
                ON jh.job_id = j.job_id
                WHERE start_execution_date is not null
                AND stop_execution_date is null
                AND run_duration < 235959
                AND run_duration >= 0
                AND ja.start_execution_date > DATEADD(day,-1,GETDATE())
                GROUP BY j.name,j.job_id,start_execution_date,stop_execution_date,ja.job_id
                ) AS t
                ORDER BY JobName;"

            $runningjobs = Invoke-DbaQuery -SqlInstance $Instance -Database msdb -Query $query

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'LongRunningJob' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.longrunningjob.percentage' }).Value)

            $LongRunningJobs = $($runningjobs | Where-Object { $_.AvgSec -ne 0 }).ForEach{
                [PSCustomObject]@{
                    InstanceName                     = $Instance.Name
                    JobName                          = $PSItem.JobName
                    RunningSeconds                   = $PSItem.RunningSeconds
                    Average                          = $PSItem.AvgSec
                    Diff                             = $PSItem.Diff
                    ExpectedLongRunningJobPercentage = $ConfigValues.LongRunningJob
                    ActualLongRunningJobPercentage   = [math]::Round($PSItem.Diff / $PSItem.AvgSec * 100)
                }
            }
        }
        'LastJobRunTime' {
            $maxdays = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.failedjob.since' }).Value
            $query = "IF OBJECT_ID('tempdb..#dbachecksLastRunTime') IS NOT NULL DROP Table #dbachecksLastRunTime
                SELECT * INTO #dbachecksLastRunTime
                FROM
                (
                SELECT
                j.job_id,
                j.name AS JobName,
                DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6),jh.run_duration),6),5,0,':'),3,0,':')) AS Duration
                FROM msdb.dbo.sysjobs j
                INNER JOIN
                    (
                        SELECT job_id, instance_id = MAX(instance_id)
                            FROM msdb.dbo.sysjobhistory
                            GROUP BY job_id
                    ) AS h
                    ON j.job_id = h.job_id
                INNER JOIN
                    msdb.dbo.sysjobhistory AS jh
                    ON jh.job_id = h.job_id
                    AND jh.instance_id = h.instance_id
                    WHERE msdb.dbo.agent_datetime(jh.run_date, jh.run_time) > DATEADD(DAY,- {0},GETDATE())
                    AND jh.step_id = 0
                ) AS lrt
                            IF OBJECT_ID('tempdb..#dbachecksAverageRunTime') IS NOT NULL DROP Table #dbachecksAverageRunTime
                SELECT * INTO #dbachecksAverageRunTime
                FROM
                (
                SELECT
                job_id,
                AVG(DATEDIFF(SECOND, 0, STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(6),run_duration),6),5,0,':'),3,0,':'))) AS AvgSec
                FROM msdb.dbo.sysjobhistory hist
                WHERE msdb.dbo.agent_datetime(run_date, run_time) > DATEADD(DAY,- {0},GETDATE())
                AND Step_id = 0
                AND run_duration >= 0
                GROUP BY job_id
                ) as art
                            SELECT
                JobName,
                Duration,
                AvgSec,
                Duration - AvgSec AS Diff
                FROM #dbachecksLastRunTime lastrun
                JOIN #dbachecksAverageRunTime avgrun
                ON lastrun.job_id = avgrun.job_id
                            DROP Table #dbachecksLastRunTime
                DROP Table #dbachecksAverageRunTime"
 -f $maxdays
            $lastagentjobruns = Invoke-DbaQuery -SqlInstance $Instance -Database msdb -Query $query

            $ConfigValues | Add-Member -MemberType NoteProperty -Name 'LastJobRuns' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.lastjobruntime.percentage' }).Value)

            $LastJobRuns = $($lastagentjobruns | Where-Object { $_.AvgSec -ne 0 }).ForEach{
                [PSCustomObject]@{
                    InstanceName                 = $Instance.Name
                    JobName                      = $PSItem.JobName
                    Duration                     = $PSItem.Duration
                    Average                      = $PSItem.AvgSec
                    ExpectedRunningJobPercentage = $ConfigValues.LastJobRuns
                    ActualRunningJobPercentage   = [math]::Round($PSItem.Diff / $PSItem.AvgSec * 100)
                }
            }
        }
        Default { }
    }

    #build the object
    $testInstanceObject = [PSCustomObject]@{
        ComputerName        = $Instance.ComputerName
        InstanceName        = $Instance.DbaInstanceName
        Name                = $Instance.Name
        ConfigValues        = @($ConfigValues)
        HostPlatform        = $Instance.HostPlatform
        IsClustered         = $Instance.IsClustered
        DatabaseMailEnabled = $Instance.Configuration.DatabaseMailEnabled.ConfigValue
        Agent               = @($Agent)
        Operator            = @($Operator)
        FailSafeOperator    = @($failsafeOperator)
        DatabaseMailProfile = @($databaseMailProfile)
        AgentMailProfile    = @($agentMailProfile)
        JobOwner            = $JobOwner
        InvalidJobOwner     = $InvalidJobOwner
        JobsFailed          = $JobsFailed
        LastJobRuns         = $LastJobRuns
        LongRunningJobs     = $LongRunningJobs
        AgentAlerts         = $AgentAlerts
        JobHistory          = @($JobHistory)
    }
    return $testInstanceObject
}