From c1d29838933dd6b059c2145d19237f44faebc93c Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Thu, 13 Apr 2023 15:02:09 +0000 Subject: [PATCH 01/24] add FailsafeOperator (but not working) --- source/checks/Agentv5.Tests.ps1 | 51 ++++++++++++------- .../internal/configurations/configuration.ps1 | 3 +- .../internal/functions/Get-AllAgentInfo.ps1 | 51 ++++++++++++++----- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 63b10584..262260d3 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -14,8 +14,7 @@ BeforeDiscovery { $Instance = $psitem try { $InstanceSMO = Connect-DbaInstance -SqlInstance $Instance -ErrorAction SilentlyContinue -ErrorVariable errorvar - } - catch { + } catch { $NotContactable += $Instance } if ($NotContactable -notcontains $psitem) { @@ -49,38 +48,56 @@ Describe "SQL Agent Account" -Tag AgentServiceAccount, ServiceAccount -ForEach $ $skipServiceState = Get-DbcConfigValue skip.agent.servicestate $skipServiceStartMode = Get-DbcConfigValue skip.agent.servicestartmode - Context "Testing SQL Agent is running on <_.Name>" { - It "SQL Agent should be running for <_.InstanceName> on <_.Name>" -Skip:$skipServiceState { - $PSItem.Agent.State | Should -Be "Running" -Because 'The agent service is required to run SQL Agent jobs' + # cant check agent on container - hmm does this actually work with instance need to check + if (-not $IsLinux -and ($InstanceSMO.HostPlatform -ne 'Linux')) { + Context "Testing SQL Agent is running on <_.Name>" { + It "SQL Agent should be running for <_.InstanceName> on <_.Name>" -Skip:$skipServiceState { + $PSItem.Agent.State | Should -Be "Running" -Because 'The agent service is required to run SQL Agent jobs' + } } - } - if ($PSItem.IsClustered) { - It "SQL Agent service should have a start mode of Manual for FailOver Clustered Instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { - $PSItem.Agent.StartMode | Should -Be "Manual" -Because 'Clustered Instances required that the Agent service is set to manual' + if ($PSItem.IsClustered) { + It "SQL Agent service should have a start mode of Manual for FailOver Clustered Instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { + $PSItem.Agent.StartMode | Should -Be "Manual" -Because 'Clustered Instances required that the Agent service is set to manual' + } + } else { + It "SQL Agent service should have a start mode of Automatic for standalone instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { + $PSItem.Agent.StartMode | Should -Be "Automatic" -Because 'Otherwise the Agent Jobs wont run if the server is restarted' + } } - } - else { - It "SQL Agent service should have a start mode of Automatic for standalone instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { - $PSItem.Agent.StartMode | Should -Be "Automatic" -Because 'Otherwise the Agent Jobs wont run if the server is restarted' + } else { + Context "Testing SQL Agent is running on $psitem" { + It "Running on Linux or connecting to container so can't check Services on $Psitem" -Skip { + } } } } -Describe "DBA Operators" -Tag DbaOperator, Operator -ForEach $InstancesToTest { +Describe "DBA Operator" -Tag DbaOperator, Operator -ForEach $InstancesToTest { $skipOperatorName = Get-DbcConfigValue skip.agent.operatorname - $skipOperatorEamil = Get-DbcConfigValue skip.agent.operatoremail + $skipOperatorEmail = Get-DbcConfigValue skip.agent.operatoremail Context "Testing DBA Operators exists on <_.Name>" { - It "The Operator <_.ExpectedOperatorName> exists on <_.Name>" -Skip:$skipOperatorName -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorName -ne 'null') { + It "The Operator <_.ExpectedOperatorName> exists on <_.Name>" -Skip:$skipOperatorName -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorName -NE 'null') { $PSItem.ExpectedOperatorName | Should -BeIn $PSItem.ActualOperatorName -Because 'This Operator is expected to exist' } - It "The Operator email <_.ExpectedOperatorEmail> is correct on <_.Name>" -Skip:$skipOperatorEamil -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorEmail -ne 'null') { + It "The Operator email <_.ExpectedOperatorEmail> is correct on <_.Name>" -Skip:$skipOperatorEmail -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorEmail -NE 'null') { $PSItem.ExpectedOperatorEmail | Should -BeIn $PSItem.ActualOperatorEmail -Because 'This operator email is expected to exist' } } } +Describe "Failsafe Operator" -Tag FailsafeOperator, Operator -ForEach $InstancesToTest { + $skipFailsafeoperator = Get-DbcConfigValue skip.agent.failsafeoperator + $failsafeoperator = Get-DbcConfigValue agent.failsafeoperator + + Context "Testing failsafe Operators exists on <_.Name>" { + It "The Failsafe operator <_.FailSafeOperator> exists on <_.Name>" -Skip:$skipFailsafeoperator -ForEach ($PSItem.JobServer.AlertSystem | Where-Object FailSafeOperator -NE $null) { + $PSItem.ExpectedFailSafeOperator | Should -Be $failsafeoperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' + } + } +} + # Describe "Failsafe Operator" -Tags FailsafeOperator, Operator, $filename { # if ($NotContactable -contains $psitem) { # Context "Testing failsafe operator exists on $psitem" { diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index f9f16b56..f9cf723a 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -334,6 +334,7 @@ Set-PSFConfig -Module dbachecks -Name skip.agent.servicestartmode -Validation bo Set-PSFConfig -Module dbachecks -Name skip.agent.servicestate -Validation bool -Value $false -Initialize -Description "Skip the Agent Service Start Mode check" Set-PSFConfig -Module dbachecks -Name skip.agent.operatorname -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Name check" Set-PSFConfig -Module dbachecks -Name skip.agent.operatoremail -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Email check" +Set-PSFConfig -Module dbachecks -Name skip.agent.failsafeoperator -Validation bool -Value $false -Initialize -Description "Skip the Agent Failsafe Operator check" Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation bool -Value $false -Initialize -Description "Skip the long running agent jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" @@ -367,7 +368,7 @@ Set-PSFConfig -Module dbachecks -Name skip.security.serverprotocol -Validation b #agent Set-PSFConfig -Module dbachecks -Name agent.dbaoperatorname -Value $null -Initialize -Description "Name of the DBA Operator in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.dbaoperatoremail -Value $null -Initialize -Description "Email address of the DBA Operator in SQL Agent" -Set-PSFConfig -Module dbachecks -Name agent.failsafeoperator -Value $null -Initialize -Description "Email address of the DBA Operator in SQL Agent" +Set-PSFConfig -Module dbachecks -Name agent.failsafeoperator -Value $null -Initialize -Description "Email address of the Failsafe Operator in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.databasemailprofile -Value $null -Initialize -Description "Name of the Database Mail Profile in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.validjobowner.name -Value "sa" -Initialize -Description "Agent job owner account should be this user" Set-PSFConfig -Module dbachecks -Name agent.invalidjobowner.name -Value $null -Initialize -Description "Agent job owner account should not be this user" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 3c82897b..912f7a61 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -24,6 +24,9 @@ function Get-AllAgentInfo { # 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]) + # Database Initial Fields $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) @@ -59,13 +62,14 @@ function Get-AllAgentInfo { } 'AgentServiceAccount' { if (($Instance.VersionMajor -ge 14) -or $IsLinux -or $Instance.HostPlatform -eq 'Linux') { - $Agent = @($Instance.Query("SELECT status_desc, startup_type_desc FROM sys.dm_server_services") | Where-Object servicename -like '*Agent*').ForEach{ + $Agent = @($Instance.Query("SELECT status_desc, startup_type_desc FROM sys.dm_server_services") | Where-Object servicename -Like '*Agent*').ForEach{ [PSCustomObject]@{ - State = $PSItem.status_desc + State = $PSItem.status_desc StartMode = $PSItem.startup_type_desc } } - } else { # Windows + } else { + # Windows $Agent = @(Get-DbaService -ComputerName $Instance.ComputerName -Type Agent) } } @@ -79,25 +83,46 @@ function Get-AllAgentInfo { $Operator = $ConfigValues.DbaOperatorName.ForEach{ [PSCustomObject]@{ - InstanceName = $Instance.Name - ExpectedOperatorName = $PSItem - ActualOperatorName = $Instance.JobServer.Operators.Name - ExpectedOperatorEmail = 'null' - ActualOperatorEmail = 'null' + 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 + InstanceName = $Instance.Name + ExpectedOperatorName = 'null' + ActualOperatorName = 'null' + ExpectedOperatorEmail = $PSItem + ActualOperatorEmail = $Instance.JobServer.Operators.EmailAddress } } } 'FailsafeOperator' { + $FailsafeInitFields.Add("Name") | 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 (Get-DbcConfigValue agent.failsafeoperator) + + $Operator = $ConfigValues.FailsafeOperator.ForEach{ + [PSCustomObject]@{ + InstanceName = $Instance.Name + ExpectedFailSafeOperator = $PSItem + ActualOperatorName = $Instance.JobServer.AlertSystem.Name + } + } + + $Operator += $ConfigValues.FailsafeOperator.ForEach{ + [PSCustomObject]@{ + InstanceName = $Instance.Name + ExpectedFailSafeOperator = 'null' + ActualOperatorName = 'null' + } + } } 'DatabaseMailProfile' { From 9eb5111d1706554fe64bab7295ef26edacc8a1ba Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Thu, 13 Apr 2023 15:02:09 +0000 Subject: [PATCH 02/24] add FailsafeOperator (but not working) --- source/checks/Agentv5.Tests.ps1 | 51 ++++++++++++------- .../internal/configurations/configuration.ps1 | 3 +- .../internal/functions/Get-AllAgentInfo.ps1 | 51 ++++++++++++++----- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 63b10584..262260d3 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -14,8 +14,7 @@ BeforeDiscovery { $Instance = $psitem try { $InstanceSMO = Connect-DbaInstance -SqlInstance $Instance -ErrorAction SilentlyContinue -ErrorVariable errorvar - } - catch { + } catch { $NotContactable += $Instance } if ($NotContactable -notcontains $psitem) { @@ -49,38 +48,56 @@ Describe "SQL Agent Account" -Tag AgentServiceAccount, ServiceAccount -ForEach $ $skipServiceState = Get-DbcConfigValue skip.agent.servicestate $skipServiceStartMode = Get-DbcConfigValue skip.agent.servicestartmode - Context "Testing SQL Agent is running on <_.Name>" { - It "SQL Agent should be running for <_.InstanceName> on <_.Name>" -Skip:$skipServiceState { - $PSItem.Agent.State | Should -Be "Running" -Because 'The agent service is required to run SQL Agent jobs' + # cant check agent on container - hmm does this actually work with instance need to check + if (-not $IsLinux -and ($InstanceSMO.HostPlatform -ne 'Linux')) { + Context "Testing SQL Agent is running on <_.Name>" { + It "SQL Agent should be running for <_.InstanceName> on <_.Name>" -Skip:$skipServiceState { + $PSItem.Agent.State | Should -Be "Running" -Because 'The agent service is required to run SQL Agent jobs' + } } - } - if ($PSItem.IsClustered) { - It "SQL Agent service should have a start mode of Manual for FailOver Clustered Instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { - $PSItem.Agent.StartMode | Should -Be "Manual" -Because 'Clustered Instances required that the Agent service is set to manual' + if ($PSItem.IsClustered) { + It "SQL Agent service should have a start mode of Manual for FailOver Clustered Instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { + $PSItem.Agent.StartMode | Should -Be "Manual" -Because 'Clustered Instances required that the Agent service is set to manual' + } + } else { + It "SQL Agent service should have a start mode of Automatic for standalone instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { + $PSItem.Agent.StartMode | Should -Be "Automatic" -Because 'Otherwise the Agent Jobs wont run if the server is restarted' + } } - } - else { - It "SQL Agent service should have a start mode of Automatic for standalone instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { - $PSItem.Agent.StartMode | Should -Be "Automatic" -Because 'Otherwise the Agent Jobs wont run if the server is restarted' + } else { + Context "Testing SQL Agent is running on $psitem" { + It "Running on Linux or connecting to container so can't check Services on $Psitem" -Skip { + } } } } -Describe "DBA Operators" -Tag DbaOperator, Operator -ForEach $InstancesToTest { +Describe "DBA Operator" -Tag DbaOperator, Operator -ForEach $InstancesToTest { $skipOperatorName = Get-DbcConfigValue skip.agent.operatorname - $skipOperatorEamil = Get-DbcConfigValue skip.agent.operatoremail + $skipOperatorEmail = Get-DbcConfigValue skip.agent.operatoremail Context "Testing DBA Operators exists on <_.Name>" { - It "The Operator <_.ExpectedOperatorName> exists on <_.Name>" -Skip:$skipOperatorName -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorName -ne 'null') { + It "The Operator <_.ExpectedOperatorName> exists on <_.Name>" -Skip:$skipOperatorName -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorName -NE 'null') { $PSItem.ExpectedOperatorName | Should -BeIn $PSItem.ActualOperatorName -Because 'This Operator is expected to exist' } - It "The Operator email <_.ExpectedOperatorEmail> is correct on <_.Name>" -Skip:$skipOperatorEamil -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorEmail -ne 'null') { + It "The Operator email <_.ExpectedOperatorEmail> is correct on <_.Name>" -Skip:$skipOperatorEmail -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorEmail -NE 'null') { $PSItem.ExpectedOperatorEmail | Should -BeIn $PSItem.ActualOperatorEmail -Because 'This operator email is expected to exist' } } } +Describe "Failsafe Operator" -Tag FailsafeOperator, Operator -ForEach $InstancesToTest { + $skipFailsafeoperator = Get-DbcConfigValue skip.agent.failsafeoperator + $failsafeoperator = Get-DbcConfigValue agent.failsafeoperator + + Context "Testing failsafe Operators exists on <_.Name>" { + It "The Failsafe operator <_.FailSafeOperator> exists on <_.Name>" -Skip:$skipFailsafeoperator -ForEach ($PSItem.JobServer.AlertSystem | Where-Object FailSafeOperator -NE $null) { + $PSItem.ExpectedFailSafeOperator | Should -Be $failsafeoperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' + } + } +} + # Describe "Failsafe Operator" -Tags FailsafeOperator, Operator, $filename { # if ($NotContactable -contains $psitem) { # Context "Testing failsafe operator exists on $psitem" { diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index 746240d6..b4f5ba2c 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -340,6 +340,7 @@ Set-PSFConfig -Module dbachecks -Name skip.agent.servicestartmode -Validation bo Set-PSFConfig -Module dbachecks -Name skip.agent.servicestate -Validation bool -Value $false -Initialize -Description "Skip the Agent Service Start Mode check" Set-PSFConfig -Module dbachecks -Name skip.agent.operatorname -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Name check" Set-PSFConfig -Module dbachecks -Name skip.agent.operatoremail -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Email check" +Set-PSFConfig -Module dbachecks -Name skip.agent.failsafeoperator -Validation bool -Value $false -Initialize -Description "Skip the Agent Failsafe Operator check" Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation bool -Value $false -Initialize -Description "Skip the long running agent jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" @@ -373,7 +374,7 @@ Set-PSFConfig -Module dbachecks -Name skip.security.serverprotocol -Validation b #agent Set-PSFConfig -Module dbachecks -Name agent.dbaoperatorname -Value $null -Initialize -Description "Name of the DBA Operator in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.dbaoperatoremail -Value $null -Initialize -Description "Email address of the DBA Operator in SQL Agent" -Set-PSFConfig -Module dbachecks -Name agent.failsafeoperator -Value $null -Initialize -Description "Email address of the DBA Operator in SQL Agent" +Set-PSFConfig -Module dbachecks -Name agent.failsafeoperator -Value $null -Initialize -Description "Email address of the Failsafe Operator in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.databasemailprofile -Value $null -Initialize -Description "Name of the Database Mail Profile in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.validjobowner.name -Value "sa" -Initialize -Description "Agent job owner account should be this user" Set-PSFConfig -Module dbachecks -Name agent.invalidjobowner.name -Value $null -Initialize -Description "Agent job owner account should not be this user" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 3c82897b..912f7a61 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -24,6 +24,9 @@ function Get-AllAgentInfo { # 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]) + # Database Initial Fields $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) @@ -59,13 +62,14 @@ function Get-AllAgentInfo { } 'AgentServiceAccount' { if (($Instance.VersionMajor -ge 14) -or $IsLinux -or $Instance.HostPlatform -eq 'Linux') { - $Agent = @($Instance.Query("SELECT status_desc, startup_type_desc FROM sys.dm_server_services") | Where-Object servicename -like '*Agent*').ForEach{ + $Agent = @($Instance.Query("SELECT status_desc, startup_type_desc FROM sys.dm_server_services") | Where-Object servicename -Like '*Agent*').ForEach{ [PSCustomObject]@{ - State = $PSItem.status_desc + State = $PSItem.status_desc StartMode = $PSItem.startup_type_desc } } - } else { # Windows + } else { + # Windows $Agent = @(Get-DbaService -ComputerName $Instance.ComputerName -Type Agent) } } @@ -79,25 +83,46 @@ function Get-AllAgentInfo { $Operator = $ConfigValues.DbaOperatorName.ForEach{ [PSCustomObject]@{ - InstanceName = $Instance.Name - ExpectedOperatorName = $PSItem - ActualOperatorName = $Instance.JobServer.Operators.Name - ExpectedOperatorEmail = 'null' - ActualOperatorEmail = 'null' + 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 + InstanceName = $Instance.Name + ExpectedOperatorName = 'null' + ActualOperatorName = 'null' + ExpectedOperatorEmail = $PSItem + ActualOperatorEmail = $Instance.JobServer.Operators.EmailAddress } } } 'FailsafeOperator' { + $FailsafeInitFields.Add("Name") | 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 (Get-DbcConfigValue agent.failsafeoperator) + + $Operator = $ConfigValues.FailsafeOperator.ForEach{ + [PSCustomObject]@{ + InstanceName = $Instance.Name + ExpectedFailSafeOperator = $PSItem + ActualOperatorName = $Instance.JobServer.AlertSystem.Name + } + } + + $Operator += $ConfigValues.FailsafeOperator.ForEach{ + [PSCustomObject]@{ + InstanceName = $Instance.Name + ExpectedFailSafeOperator = 'null' + ActualOperatorName = 'null' + } + } } 'DatabaseMailProfile' { From db487be49e951c606be79ffded2bf6d987888da1 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Sun, 9 Jul 2023 22:31:18 +0100 Subject: [PATCH 03/24] failsafe Operators --- source/checks/Agentv5.Tests.ps1 | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 262260d3..3701479e 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -48,26 +48,18 @@ Describe "SQL Agent Account" -Tag AgentServiceAccount, ServiceAccount -ForEach $ $skipServiceState = Get-DbcConfigValue skip.agent.servicestate $skipServiceStartMode = Get-DbcConfigValue skip.agent.servicestartmode - # cant check agent on container - hmm does this actually work with instance need to check - if (-not $IsLinux -and ($InstanceSMO.HostPlatform -ne 'Linux')) { - Context "Testing SQL Agent is running on <_.Name>" { - It "SQL Agent should be running for <_.InstanceName> on <_.Name>" -Skip:$skipServiceState { - $PSItem.Agent.State | Should -Be "Running" -Because 'The agent service is required to run SQL Agent jobs' - } + Context "Testing SQL Agent is running on <_.Name>" { + It "SQL Agent should be running for <_.InstanceName> on <_.Name>" -Skip:$skipServiceState { + $PSItem.Agent.State | Should -Be "Running" -Because 'The agent service is required to run SQL Agent jobs' } - if ($PSItem.IsClustered) { - It "SQL Agent service should have a start mode of Manual for FailOver Clustered Instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { - $PSItem.Agent.StartMode | Should -Be "Manual" -Because 'Clustered Instances required that the Agent service is set to manual' - } - } else { - It "SQL Agent service should have a start mode of Automatic for standalone instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { - $PSItem.Agent.StartMode | Should -Be "Automatic" -Because 'Otherwise the Agent Jobs wont run if the server is restarted' - } + } + if ($PSItem.IsClustered) { + It "SQL Agent service should have a start mode of Manual for FailOver Clustered Instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { + $PSItem.Agent.StartMode | Should -Be "Manual" -Because 'Clustered Instances required that the Agent service is set to manual' } } else { - Context "Testing SQL Agent is running on $psitem" { - It "Running on Linux or connecting to container so can't check Services on $Psitem" -Skip { - } + It "SQL Agent service should have a start mode of Automatic for standalone instance <_.InstanceName> on <_.Name>" -Skip:$skipServiceStartMode { + $PSItem.Agent.StartMode | Should -Be "Automatic" -Because 'Otherwise the Agent Jobs wont run if the server is restarted' } } } @@ -92,7 +84,7 @@ Describe "Failsafe Operator" -Tag FailsafeOperator, Operator -ForEach $Instances $failsafeoperator = Get-DbcConfigValue agent.failsafeoperator Context "Testing failsafe Operators exists on <_.Name>" { - It "The Failsafe operator <_.FailSafeOperator> exists on <_.Name>" -Skip:$skipFailsafeoperator -ForEach ($PSItem.JobServer.AlertSystem | Where-Object FailSafeOperator -NE $null) { + It "The Failsafe operator <_.FailSafeOperator> exists on <_.Name>" -Skip:$skipFailsafeoperator -ForEach ($PSItem.JobServer.AlertSystem | Where-Object FailSafeOperator -EQ 'null') { $PSItem.ExpectedFailSafeOperator | Should -Be $failsafeoperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' } } From a8d4d3aa05a82818028070ff8b14b16c3f899f09 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Wed, 12 Jul 2023 15:55:07 +0100 Subject: [PATCH 04/24] add filesafeoperator + small improves + configs --- source/checks/Agentv5.Tests.ps1 | 62 +++++++++++-------- .../internal/configurations/configuration.ps1 | 4 +- .../internal/functions/Get-AllAgentInfo.ps1 | 17 ++--- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 69341648..60f86dce 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -31,23 +31,26 @@ BeforeDiscovery { } } } + Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable -} + # Get-DbcConfig is expensive so we call it once + $__dbcconfig = Get-DbcConfig +} -Describe "Database Mail XPs" -Tag DatabaseMailEnabled, CIS, security -ForEach $InstancesToTest { - $skip = Get-DbcConfigValue skip.agent.databasemailenabled +Describe "Database Mail XPs" -Tag DatabaseMailEnabled, CIS, security, Agent -ForEach $InstancesToTest { + $skip = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.databasemailenabled' }).Value Context "Testing Database Mail XPs on <_.Name>" { - It "Testing Database Mail XPs is set to <_.DatabaseMailEnabled> on <_.Name>" -Skip:$skip { + It "Testing Database Mail XPs is set to <_.ConfigValues.DatabaseMailEnabled> on <_.Name>" -Skip:$skip { $PSItem.DatabaseMailEnabled | Should -Be $PSItem.ConfigValues.DatabaseMailEnabled -Because 'The Database Mail XPs setting should be set correctly' } } } -Describe "SQL Agent Account" -Tag AgentServiceAccount, ServiceAccount -ForEach $InstancesToTest { - $skipServiceState = Get-DbcConfigValue skip.agent.servicestate - $skipServiceStartMode = Get-DbcConfigValue skip.agent.servicestartmode +Describe "SQL Agent Account" -Tag AgentServiceAccount, ServiceAccount, Agent -ForEach $InstancesToTest { + $skipServiceState = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.servicestate' }).Value + $skipServiceStartMode = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.servicestartmode' }).Value Context "Testing SQL Agent is running on <_.Name>" { It "SQL Agent should be running for <_.InstanceName> on <_.Name>" -Skip:$skipServiceState { @@ -66,9 +69,9 @@ Describe "SQL Agent Account" -Tag AgentServiceAccount, ServiceAccount -ForEach $ } } -Describe "DBA Operator" -Tag DbaOperator, Operator -ForEach $InstancesToTest { - $skipOperatorName = Get-DbcConfigValue skip.agent.operatorname - $skipOperatorEmail = Get-DbcConfigValue skip.agent.operatoremail +Describe "DBA Operator" -Tag DbaOperator, Operator, Agent -ForEach $InstancesToTest { + $skipOperatorName = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.dbaoperatorname' }).Value + $skipOperatorEmail = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.dbaoperatoremail' }).Value Context "Testing DBA Operators exists on <_.Name>" { It "The Operator <_.ExpectedOperatorName> exists on <_.Name>" -Skip:$skipOperatorName -ForEach ($PSItem.Operator | Where-Object ExpectedOperatorName -NE 'null') { @@ -81,23 +84,28 @@ Describe "DBA Operator" -Tag DbaOperator, Operator -ForEach $InstancesToTest { } } -# Describe "Failsafe Operator" -Tags FailsafeOperator, Operator, $filename { -# if ($NotContactable -contains $psitem) { -# Context "Testing failsafe operator exists on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# Context "Testing failsafe operator exists on $psitem" { -# $failsafeoperator = Get-DbcConfigValue agent.failsafeoperator -# It "The Failsafe Operator exists on $psitem" { -# (Connect-DbaInstance -SqlInstance $psitem).JobServer.AlertSystem.FailSafeOperator | Should -Be $failsafeoperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' -# } -# } -# } -# } +Describe "Failsafe operator" -Tag FailsafeOperator, CIS, security, Agent -ForEach $InstancesToTest { + $skipFailsafeOperator = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.failsafeoperator' }).Value + + Context "Testing failsafe operator exists on <_.Name>" { + It "The failsafe operator <_.FailSafeOperator.ExpectedFailSafeOperator> exists on <_.Name>" -Skip:$skipFailsafeOperator { + $PSItem.FailSafeOperator.ActualFailSafeOperator | Should -Be $PSItem.FailSafeOperator.ExpectedFailSafeOperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' + } + } +} + +# +## Write-PSFMessage -Message "Tags = $Tags" -Level Verbose +# +#Describe "Failsafe Operator" -Tag FailsafeOperator, Operator, Agent -ForEach $InstancesToTest { +# $skipFailsafeOperator = Get-DbcConfigValue skip.agent.failsafeoperator +# +# Context "Testing failsafe operator exists on <_.Name>" { +# It "The Failsafe Operator <_.ExpectedFailSafeOperator> exists on <_.Name>" -Skip:$skipFailsafeOperator -ForEach ($PSItem.AlertSystem | Where-Object ExpectedFailSafeOperator -NE 'null') { +# $PSItem.ExpectedFailSafeOperator | Should -Be $PSItem.ActualFailSafeOperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' +# } +# } +#} # Describe "Database Mail Profile" -Tags DatabaseMailProfile, $filename { # if ($NotContactable -contains $psitem) { diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index b4f5ba2c..68ec5a61 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -338,8 +338,8 @@ Set-PSFConfig -Module dbachecks -Name skip.hadr.listener.pingcheck -Validation b Set-PSFConfig -Module dbachecks -Name skip.agent.databasemailenabled -Validation bool -Value $false -Initialize -Description "Skip the Database Mail Enabled agent check" Set-PSFConfig -Module dbachecks -Name skip.agent.servicestartmode -Validation bool -Value $false -Initialize -Description "Skip the Agent Service State check" Set-PSFConfig -Module dbachecks -Name skip.agent.servicestate -Validation bool -Value $false -Initialize -Description "Skip the Agent Service Start Mode check" -Set-PSFConfig -Module dbachecks -Name skip.agent.operatorname -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Name check" -Set-PSFConfig -Module dbachecks -Name skip.agent.operatoremail -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Email check" +Set-PSFConfig -Module dbachecks -Name skip.agent.dbaoperatorname -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Name check" +Set-PSFConfig -Module dbachecks -Name skip.agent.dbaoperatoremail -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Email check" Set-PSFConfig -Module dbachecks -Name skip.agent.failsafeoperator -Validation bool -Value $false -Initialize -Description "Skip the Agent Failsafe Operator check" Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation bool -Value $false -Initialize -Description "Skip the long running agent jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 912f7a61..16e57c92 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -8,6 +8,7 @@ function Get-AllAgentInfo { $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) @@ -102,28 +103,19 @@ function Get-AllAgentInfo { } } 'FailsafeOperator' { - $FailsafeInitFields.Add("Name") | Out-Null # so we can check failsafe operators + $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 (Get-DbcConfigValue agent.failsafeoperator) - $Operator = $ConfigValues.FailsafeOperator.ForEach{ + $failsafeOperator = $ConfigValues.FailsafeOperator.ForEach{ [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedFailSafeOperator = $PSItem - ActualOperatorName = $Instance.JobServer.AlertSystem.Name + ActualFailSafeOperator = $Instance.JobServer.AlertSystem.FailSafeOperator } } - - $Operator += $ConfigValues.FailsafeOperator.ForEach{ - [PSCustomObject]@{ - InstanceName = $Instance.Name - ExpectedFailSafeOperator = 'null' - ActualOperatorName = 'null' - } - } - } 'DatabaseMailProfile' { @@ -166,6 +158,7 @@ function Get-AllAgentInfo { DatabaseMailEnabled = $Instance.Configuration.DatabaseMailEnabled.ConfigValue Agent = @($Agent) Operator = @($Operator) + FailSafeOperator = @($failsafeOperator) } return $testInstanceObject } \ No newline at end of file From 00b489510a3254b89f804848691c7e89ce39e854 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Wed, 12 Jul 2023 17:13:21 +0100 Subject: [PATCH 05/24] DatabaseMailProfile --- source/checks/Agentv5.Tests.ps1 | 24 +++++++------- .../internal/configurations/configuration.ps1 | 2 ++ .../internal/functions/Get-AllAgentInfo.ps1 | 31 +++++++++++++++++++ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 60f86dce..2f54b41b 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -84,7 +84,7 @@ Describe "DBA Operator" -Tag DbaOperator, Operator, Agent -ForEach $InstancesToT } } -Describe "Failsafe operator" -Tag FailsafeOperator, CIS, security, Agent -ForEach $InstancesToTest { +Describe "Failsafe operator" -Tag FailsafeOperator, Operator, Agent -ForEach $InstancesToTest { $skipFailsafeOperator = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.failsafeoperator' }).Value Context "Testing failsafe operator exists on <_.Name>" { @@ -94,18 +94,16 @@ Describe "Failsafe operator" -Tag FailsafeOperator, CIS, security, Agent -ForEac } } -# -## Write-PSFMessage -Message "Tags = $Tags" -Level Verbose -# -#Describe "Failsafe Operator" -Tag FailsafeOperator, Operator, Agent -ForEach $InstancesToTest { -# $skipFailsafeOperator = Get-DbcConfigValue skip.agent.failsafeoperator -# -# Context "Testing failsafe operator exists on <_.Name>" { -# It "The Failsafe Operator <_.ExpectedFailSafeOperator> exists on <_.Name>" -Skip:$skipFailsafeOperator -ForEach ($PSItem.AlertSystem | Where-Object ExpectedFailSafeOperator -NE 'null') { -# $PSItem.ExpectedFailSafeOperator | Should -Be $PSItem.ActualFailSafeOperator -Because 'The failsafe operator will ensure that any job failures will be notified to someone if not set explicitly' -# } -# } -#} +Describe "Database Mail Profile" -Tag DatabaseMailProfile, Agent -ForEach $InstancesToTest { + $skipDatabaseMailProfile = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.databasemailprofile' }).Value + + Context "Testing Database Mail Profile exists on <_.Name>" { + It "The Database Mail profile <_.DatabaseMailProfile.ExpectedDatabaseMailProfile> exists on <_.Name>" -Skip:$skipDatabaseMailProfile { #-ForEach ($PSItem.DatabaseMailProfile | Where-Object ExpectedDatabaseMailProfile -NE 'null') { + $PSItem.DatabaseMailProfile.ActualDatabaseMailProfile | Should -Be $PSItem.DatabaseMailProfile.ExpectedDatabaseMailProfile -Because 'The database mail profile is required to send emails' + } + } +} + # Describe "Database Mail Profile" -Tags DatabaseMailProfile, $filename { # if ($NotContactable -contains $psitem) { diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index 68ec5a61..13c58bac 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -341,10 +341,12 @@ Set-PSFConfig -Module dbachecks -Name skip.agent.servicestate -Validation bool - Set-PSFConfig -Module dbachecks -Name skip.agent.dbaoperatorname -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Name check" Set-PSFConfig -Module dbachecks -Name skip.agent.dbaoperatoremail -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Email check" Set-PSFConfig -Module dbachecks -Name skip.agent.failsafeoperator -Validation bool -Value $false -Initialize -Description "Skip the Agent Failsafe Operator check" +Set-PSFConfig -Module dbachecks -Name skip.agent.databasemailprofile -Validation bool -Value $false -Initialize -Description "Skip the Database Mail Profile check" Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation bool -Value $false -Initialize -Description "Skip the long running agent jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" + Set-PSFConfig -Module dbachecks -Name skip.security.containedbautoclose -Validation bool -Value $true -Initialize -Description "Skips the scan for contained databases should have auto close enabled" Set-PSFConfig -Module dbachecks -Name skip.security.sqlagentproxiesnopublicrole -Validation bool -Value $true -Initialize -Description "Skips the scan for if the public role has access to SQL Agent proxies" Set-PSFConfig -Module dbachecks -Name skip.security.symmetrickeyencryptionlevel -Validation bool -Value $true -Initialize -Description "Skips the test for if the Symmetric Encryption is at least AES_128 or higher in non-system databases" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 16e57c92..6d0048c4 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -2,6 +2,7 @@ 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) @@ -28,6 +29,9 @@ function Get-AllAgentInfo { # Job Server Alert System Initial fields $FailsafeInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem]) + # JobServer Initial fields + $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) + # Database Initial Fields $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) @@ -118,7 +122,33 @@ function Get-AllAgentInfo { } } 'DatabaseMailProfile' { + $DatabaseMailProfileInitFields.Add("DatabaseMailProfile") | Out-Null # so we can check failsafe operators + $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer], $DatabaseMailProfileInitFields) + $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) + + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DatabaseMailProfile' -Value (Get-DbcConfigValue agent.databasemailprofile) + + $databaseMailProfile = $ConfigValues.DatabaseMailProfile.ForEach{ + [PSCustomObject]@{ + InstanceName = $Instance.Name + ExpectedDatabaseMailProfile = $ConfigValues.DatabaseMailProfile + ActualDatabaseMailProfile = $Instance.JobServer.DatabaseMailProfile + } + } + #TODO: Clean up + #$databaseMailProfile = $ConfigValues.DatabaseMailProfile.ForEach{ + # [PSCustomObject]@{ + # InstanceName = $Instance.Name + # ExpectedDatabaseMailProfile = 'null' + # ActualDatabaseMailProfile = 'null' + # } + #} +# + #Write-PSFMessage -Message "InstanceName : $($databaseMailProfile.InstanceName)" -Level Verbose + #Write-PSFMessage -Message "ExpectedDatabaseMailProfile : $($databaseMailProfile.ExpectedDatabaseMailProfile)" -Level Verbose + #Write-PSFMessage -Message "ActualDatabaseMailProfile : $($databaseMailProfile.ActualDatabaseMailProfile)" -Level Verbose + #Write-PSFMessage -Message "ActualDatabaseMailProfile instance : $($Instance.JobServer.DatabaseMailProfile)" -Level Verbose } 'AgentMailProfile' { @@ -159,6 +189,7 @@ function Get-AllAgentInfo { Agent = @($Agent) Operator = @($Operator) FailSafeOperator = @($failsafeOperator) + DatabaseMailProfile = @($databaseMailProfile) } return $testInstanceObject } \ No newline at end of file From a30f96991c61c6f71a7552751d7f5bda39017ab3 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Thu, 13 Jul 2023 08:59:01 +0100 Subject: [PATCH 06/24] added Agent Mail Profile --- source/checks/Agentv5.Tests.ps1 | 45 +++++-------------- .../internal/configurations/configuration.ps1 | 3 ++ .../internal/functions/Get-AllAgentInfo.ps1 | 45 +++++++++++++++---- 3 files changed, 50 insertions(+), 43 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 2f54b41b..4666c3ef 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -99,47 +99,22 @@ Describe "Database Mail Profile" -Tag DatabaseMailProfile, Agent -ForEach $Insta Context "Testing Database Mail Profile exists on <_.Name>" { It "The Database Mail profile <_.DatabaseMailProfile.ExpectedDatabaseMailProfile> exists on <_.Name>" -Skip:$skipDatabaseMailProfile { #-ForEach ($PSItem.DatabaseMailProfile | Where-Object ExpectedDatabaseMailProfile -NE 'null') { - $PSItem.DatabaseMailProfile.ActualDatabaseMailProfile | Should -Be $PSItem.DatabaseMailProfile.ExpectedDatabaseMailProfile -Because 'The database mail profile is required to send emails' + $PSItem.DatabaseMailProfile.ActualDatabaseMailProfile | Should -BeIn $PSItem.DatabaseMailProfile.ExpectedDatabaseMailProfile -Because 'The database mail profile is required to send emails' } } } +Describe "Agent Mail Profile" -Tag AgentMailProfile, Agent -ForEach $InstancesToTest { + $skipAgentMailProfile = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.agentmailprofile' }).Value + + Context "esting SQL Agent Alert System database mail profile is set on <_.Name>" { + It "The SQL Server Agent Alert System has the mail profile <_.AgentMailProfile.ExpectedAgentMailProfile> enabled as profile on <_.Name>." -Skip:$skipAgentMailProfile { #-ForEach ($PSItem.DatabaseMailProfile | Where-Object ExpectedDatabaseMailProfile -NE 'null') { + $PSItem.AgentMailProfile.ActualAgentMailProfile | Should -Be $PSItem.AgentMailProfile.ExpectedAgentMailProfile -Because 'The SQL Agent Alert System needs an enabled database mail profile to send alert emails' + } + } +} -# Describe "Database Mail Profile" -Tags DatabaseMailProfile, $filename { -# if ($NotContactable -contains $psitem) { -# Context "Testing database mail profile is set on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# Context "Testing database mail profile is set on $psitem" { -# $databasemailprofile = Get-DbcConfigValue agent.databasemailprofile -# It "The Database Mail profile $databasemailprofile exists on $psitem" { -# ((Get-DbaDbMailProfile -SqlInstance $InstanceSMO).Name -contains $databasemailprofile) | Should -Be $true -Because 'The database mail profile is required to send emails' -# } -# } -# } -# } -# Describe "Agent Mail Profile" -Tags AgentMailProfile, $filename { -# if ($NotContactable -contains $psitem) { -# Context "Testing SQL Agent Alert System database mail profile is set on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# Context "Testing SQL Agent Alert System database mail profile is set on $psitem" { -# $agentmailprofile = Get-DbcConfigValue agent.databasemailprofile -# It "The SQL Server Agent Alert System should have an enabled database mail profile on $psitem" { -# (Get-DbaAgentServer -SqlInstance $InstanceSMO).DatabaseMailProfile | Should -Be $agentmailprofile -Because 'The SQL Agent Alert System needs an enabled database mail profile to send alert emails' -# } -# } -# } -# } # Describe "Failed Jobs" -Tags FailedJob, $filename { diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index 13c58bac..a9962b69 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -342,6 +342,7 @@ Set-PSFConfig -Module dbachecks -Name skip.agent.dbaoperatorname -Validation boo Set-PSFConfig -Module dbachecks -Name skip.agent.dbaoperatoremail -Validation bool -Value $false -Initialize -Description "Skip the Agent Operator Email check" Set-PSFConfig -Module dbachecks -Name skip.agent.failsafeoperator -Validation bool -Value $false -Initialize -Description "Skip the Agent Failsafe Operator check" Set-PSFConfig -Module dbachecks -Name skip.agent.databasemailprofile -Validation bool -Value $false -Initialize -Description "Skip the Database Mail Profile check" +Set-PSFConfig -Module dbachecks -Name skip.agent.mailprofile -Validation bool -Value $false -Initialize -Description "Skip the SQL Server Agent Mail Profile check" Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation bool -Value $false -Initialize -Description "Skip the long running agent jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" @@ -377,7 +378,9 @@ Set-PSFConfig -Module dbachecks -Name skip.security.serverprotocol -Validation b Set-PSFConfig -Module dbachecks -Name agent.dbaoperatorname -Value $null -Initialize -Description "Name of the DBA Operator in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.dbaoperatoremail -Value $null -Initialize -Description "Email address of the DBA Operator in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.failsafeoperator -Value $null -Initialize -Description "Email address of the Failsafe Operator in SQL Agent" +# TODO: Should this be instance instead of agent? Set-PSFConfig -Module dbachecks -Name agent.databasemailprofile -Value $null -Initialize -Description "Name of the Database Mail Profile in SQL Agent" +Set-PSFConfig -Module dbachecks -Name agent.mailprofile -Value $null -Initialize -Description "Name of the SQL Server Agent Mail Profile in SQL Agent" Set-PSFConfig -Module dbachecks -Name agent.validjobowner.name -Value "sa" -Initialize -Description "Agent job owner account should be this user" Set-PSFConfig -Module dbachecks -Name agent.invalidjobowner.name -Value $null -Initialize -Description "Agent job owner account should not be this user" Set-PSFConfig -Module dbachecks -Name agent.alert.messageid -Value @('823', '824', '825') -Initialize -Description "Agent alert messageid to validate; https://www.brentozar.com/blitz/configure-sql-server-alerts/" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 6d0048c4..957ed210 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -30,7 +30,10 @@ function Get-AllAgentInfo { $FailsafeInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.AlertSystem]) # JobServer Initial fields - $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) + $AgentMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) + + + $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Mail.MailProfile]) # Database Initial Fields $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) @@ -122,9 +125,9 @@ function Get-AllAgentInfo { } } 'DatabaseMailProfile' { - $DatabaseMailProfileInitFields.Add("DatabaseMailProfile") | Out-Null # so we can check failsafe operators - $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer], $DatabaseMailProfileInitFields) - $DatabaseMailProfileInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) + $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 (Get-DbcConfigValue agent.databasemailprofile) @@ -132,7 +135,35 @@ function Get-AllAgentInfo { [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedDatabaseMailProfile = $ConfigValues.DatabaseMailProfile - ActualDatabaseMailProfile = $Instance.JobServer.DatabaseMailProfile + ActualDatabaseMailProfile = $Instance.Mail.Profiles.Name + } + } + + ##TODO: Clean up + #$databaseMailProfile += [PSCustomObject]@{ + # InstanceName = $Instance.Name + # ExpectedDatabaseMailProfile = 'null' + # ActualDatabaseMailProfile = 'null' + #} +# + #Write-PSFMessage -Message "InstanceName : $($databaseMailProfile.InstanceName)" -Level Verbose + #Write-PSFMessage -Message "ExpectedDatabaseMailProfile : $($databaseMailProfile.ExpectedDatabaseMailProfile)" -Level Verbose + #Write-PSFMessage -Message "ActualDatabaseMailProfile : $($databaseMailProfile.ActualDatabaseMailProfile)" -Level Verbose + #Write-PSFMessage -Message "ActualDatabaseMailProfile instance : $($Instance.Mail.Profiles.Name)" -Level Verbose + + } + '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 (Get-DbcConfigValue agent.databasemailprofile) + + $agentMailProfile = $ConfigValues.AgentMailProfile.ForEach{ + [PSCustomObject]@{ + InstanceName = $Instance.Name + ExpectedAgentMailProfile = $ConfigValues.AgentMailProfile + ActualAgentMailProfile = $Instance.JobServer.DatabaseMailProfile } } @@ -149,9 +180,6 @@ function Get-AllAgentInfo { #Write-PSFMessage -Message "ExpectedDatabaseMailProfile : $($databaseMailProfile.ExpectedDatabaseMailProfile)" -Level Verbose #Write-PSFMessage -Message "ActualDatabaseMailProfile : $($databaseMailProfile.ActualDatabaseMailProfile)" -Level Verbose #Write-PSFMessage -Message "ActualDatabaseMailProfile instance : $($Instance.JobServer.DatabaseMailProfile)" -Level Verbose - } - 'AgentMailProfile' { - } 'FailedJob' { @@ -190,6 +218,7 @@ function Get-AllAgentInfo { Operator = @($Operator) FailSafeOperator = @($failsafeOperator) DatabaseMailProfile = @($databaseMailProfile) + AgentMailProfile = @($agentMailProfile) } return $testInstanceObject } \ No newline at end of file From 7fee4ba3d5ccf6aa9e35a9af299810c9d45c5434 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Mon, 21 Aug 2023 16:01:52 +0100 Subject: [PATCH 07/24] ValidJobOwner --- source/checks/Agentv5.Tests.ps1 | 40 +++++++++---------- .../internal/configurations/configuration.ps1 | 1 + .../internal/functions/Get-AllAgentInfo.ps1 | 21 +++++++++- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 4666c3ef..278f1713 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -32,7 +32,12 @@ BeforeDiscovery { } } + #TODO : Clean this up Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose + + Write-PSFMessage -Message "JobOwner = $($InstancesToTest.JobOwner)" -Level Verbose + Write-PSFMessage -Message "JobOwner = $($InstancesToTest.JobOwner.JobName)" -Level Verbose + Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable # Get-DbcConfig is expensive so we call it once @@ -105,15 +110,26 @@ Describe "Database Mail Profile" -Tag DatabaseMailProfile, Agent -ForEach $Insta } Describe "Agent Mail Profile" -Tag AgentMailProfile, Agent -ForEach $InstancesToTest { - $skipAgentMailProfile = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.agentmailprofile' }).Value + $skipAgentMailProfile = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.mailprofile' }).Value - Context "esting SQL Agent Alert System database mail profile is set on <_.Name>" { + Context "Testing SQL Agent Alert System database mail profile is set on <_.Name>" { It "The SQL Server Agent Alert System has the mail profile <_.AgentMailProfile.ExpectedAgentMailProfile> enabled as profile on <_.Name>." -Skip:$skipAgentMailProfile { #-ForEach ($PSItem.DatabaseMailProfile | Where-Object ExpectedDatabaseMailProfile -NE 'null') { $PSItem.AgentMailProfile.ActualAgentMailProfile | Should -Be $PSItem.AgentMailProfile.ExpectedAgentMailProfile -Because 'The SQL Agent Alert System needs an enabled database mail profile to send alert emails' } } } +Describe "Valid Job Owner" -Tag ValidJobOwner, Agent -ForEach $InstancesToTest { + $skipAgentJobTargetOwner = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.jobowner' }).Value + + Context "Testing SQL Agent Job Owner on <_.Name>" { + It "The Job <_.JobName> has the Job Owner <_.ActualJobOwnerName> that should exist in this list ($([String]::Join(', ', "<_.ExpectedJobOwnerName>"))) on <_.InstanceName>" -Skip:$skipAgentJobTargetOwner -ForEach ($PSItem.JobOwner) { + $PSItem.ActualJobOwnerName | Should -BeIn $PSItem.ExpectedJobOwnerName -Because 'The account that is the job owner is not what was expected' + } + } +} + + # Describe "Failed Jobs" -Tags FailedJob, $filename { @@ -151,26 +167,6 @@ Describe "Agent Mail Profile" -Tag AgentMailProfile, Agent -ForEach $InstancesTo # } # } -# Describe "Valid Job Owner" -Tags ValidJobOwner, $filename { -# [string[]]$targetowner = Get-DbcConfigValue agent.validjobowner.name - -# if ($NotContactable -contains $psitem) { -# Context "Testing job owners on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# Context "Testing job owners on $psitem" { -# @(Get-DbaAgentJob -SqlInstance $psitem -EnableException:$false).ForEach{ -# It "Job $($psitem.Name) - owner $($psitem.OwnerLoginName) should be in this list ( $( [String]::Join(", ", $targetowner) ) ) on $($psitem.SqlInstance)" { -# $psitem.OwnerLoginName | Should -BeIn $TargetOwner -Because "The account that is the job owner is not what was expected" -# } -# } -# } -# } -# } # Describe "Invalid Job Owner" -Tags InValidJobOwner, $filename { # [string[]]$targetowner = Get-DbcConfigValue agent.invalidjobowner.name diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index a9962b69..3a6796ab 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -345,6 +345,7 @@ Set-PSFConfig -Module dbachecks -Name skip.agent.databasemailprofile -Validation Set-PSFConfig -Module dbachecks -Name skip.agent.mailprofile -Validation bool -Value $false -Initialize -Description "Skip the SQL Server Agent Mail Profile check" Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation bool -Value $false -Initialize -Description "Skip the long running agent jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" +Set-PSFConfig -Module dbachecks -Name skip.agent.jobowner -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Owner check" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 957ed210..56c21e46 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -32,9 +32,12 @@ function Get-AllAgentInfo { # 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]) + # Database Initial Fields $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) @@ -160,6 +163,7 @@ function Get-AllAgentInfo { $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMailProfile' -Value (Get-DbcConfigValue agent.databasemailprofile) $agentMailProfile = $ConfigValues.AgentMailProfile.ForEach{ + [PSCustomObject]@{ InstanceName = $Instance.Name ExpectedAgentMailProfile = $ConfigValues.AgentMailProfile @@ -185,7 +189,21 @@ function Get-AllAgentInfo { } '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 (Get-DbcConfigValue agent.validjobowner.name) + $JobOwner = $Instance.JobServer.Jobs.ForEach{ + [PSCustomObject]@{ + InstanceName = $Instance.Name + JobName = $PSItem.Name + ExpectedJobOwnerName = $ConfigValues.TargetJobOwner #$PSItem + ActualJobOwnerName = $PSItem.OwnerLoginName + } + } } 'InValidJobOwner' { @@ -219,6 +237,7 @@ function Get-AllAgentInfo { FailSafeOperator = @($failsafeOperator) DatabaseMailProfile = @($databaseMailProfile) AgentMailProfile = @($agentMailProfile) + JobOwner = $JobOwner } return $testInstanceObject } \ No newline at end of file From 35c41523378697e3c25a6fd05fe3bb0d88d29db6 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Tue, 22 Aug 2023 08:43:17 +0100 Subject: [PATCH 08/24] InvalidJobOwner --- source/checks/Agentv5.Tests.ps1 | 37 +++++++++---------- .../internal/configurations/configuration.ps1 | 1 + .../internal/functions/Get-AllAgentInfo.ps1 | 21 ++++++++++- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 278f1713..afb49c43 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -130,6 +130,23 @@ Describe "Valid Job Owner" -Tag ValidJobOwner, Agent -ForEach $InstancesToTest { } +Describe "Invalid Job Owner" -Tag InvalidJobOwner, Agent -ForEach $InstancesToTest { + $skipAgentJobTargetInvalidOwner = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.invalidjobowner.name' }).Value + + Context "Testing Invalid SQL Agent Job Owner on <_.Name>" { + It "The Job <_.JobName> has the Job Owner <_.ActualJobOwnerName> that shouldn't exist in this list ($([String]::Join(', ', "<_.InvalidJobOwnerName>"))) on <_.InstanceName>" -Skip:$skipAgentJobTargetOwner -ForEach ($PSItem.InvalidJobOwner) { + $PSItem.ActualJobOwnerName | Should -Not -BeIn $PSItem.InvalidJobOwnerName -Because 'The account that is the job owner has been defined as not valid' + } + } +} + + + + + + + + # Describe "Failed Jobs" -Tags FailedJob, $filename { @@ -167,26 +184,6 @@ Describe "Valid Job Owner" -Tag ValidJobOwner, Agent -ForEach $InstancesToTest { # } # } -# Describe "Invalid Job Owner" -Tags InValidJobOwner, $filename { -# [string[]]$targetowner = Get-DbcConfigValue agent.invalidjobowner.name - -# if ($NotContactable -contains $psitem) { -# Context "Testing job owners on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# Context "Testing job owners on $psitem" { -# @(Get-DbaAgentJob -SqlInstance $psitem -EnableException:$false).ForEach{ -# It "Job $($psitem.Name) - owner $($psitem.OwnerLoginName) should not be in this list ( $( [String]::Join(", ", $targetowner) ) ) on $($psitem.SqlInstance)" { -# $psitem.OwnerLoginName | Should -Not -BeIn $TargetOwner -Because "The account that is the job owner has been defined as not valid" -# } -# } -# } -# } -# } # Describe "Agent Alerts" -Tags AgentAlert, $filename { # $severity = Get-DbcConfigValue agent.alert.Severity diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index 3a6796ab..467a5872 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -346,6 +346,7 @@ Set-PSFConfig -Module dbachecks -Name skip.agent.mailprofile -Validation bool -V Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation bool -Value $false -Initialize -Description "Skip the long running agent jobs check" Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" Set-PSFConfig -Module dbachecks -Name skip.agent.jobowner -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Owner check" +Set-PSFConfig -Module dbachecks -Name skip.agent.invalidjobowner.name -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Invalid Owner check" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 56c21e46..00de560b 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -38,6 +38,9 @@ function Get-AllAgentInfo { # 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]) + # Database Initial Fields $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) @@ -205,7 +208,22 @@ function Get-AllAgentInfo { } } } - 'InValidJobOwner' { + '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 (Get-DbcConfigValue agent.invalidjobowner.name) + + $InvalidJobOwner = $Instance.JobServer.Jobs.ForEach{ + [PSCustomObject]@{ + InstanceName = $Instance.Name + JobName = $PSItem.Name + ExpectedJobOwnerName = $ConfigValues.InvalidJobOwner + ActualJobOwnerName = $PSItem.OwnerLoginName + } + } } 'AgentAlert' { @@ -238,6 +256,7 @@ function Get-AllAgentInfo { DatabaseMailProfile = @($databaseMailProfile) AgentMailProfile = @($agentMailProfile) JobOwner = $JobOwner + InvalidJobOwner = $InvalidJobOwner } return $testInstanceObject } \ No newline at end of file From 351fa7062843bd626c6e5ff536163d14343c83d4 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Tue, 22 Aug 2023 09:51:20 +0100 Subject: [PATCH 09/24] Last Agent Job Run --- source/checks/Agentv5.Tests.ps1 | 95 ++++--------------- .../internal/functions/Get-AllAgentInfo.ps1 | 63 +++++++++++- 2 files changed, 81 insertions(+), 77 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index afb49c43..66613133 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -34,10 +34,7 @@ BeforeDiscovery { #TODO : Clean this up Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose - - Write-PSFMessage -Message "JobOwner = $($InstancesToTest.JobOwner)" -Level Verbose - Write-PSFMessage -Message "JobOwner = $($InstancesToTest.JobOwner.JobName)" -Level Verbose - + Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable # Get-DbcConfig is expensive so we call it once @@ -134,7 +131,7 @@ Describe "Invalid Job Owner" -Tag InvalidJobOwner, Agent -ForEach $InstancesToTe $skipAgentJobTargetInvalidOwner = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.invalidjobowner.name' }).Value Context "Testing Invalid SQL Agent Job Owner on <_.Name>" { - It "The Job <_.JobName> has the Job Owner <_.ActualJobOwnerName> that shouldn't exist in this list ($([String]::Join(', ', "<_.InvalidJobOwnerName>"))) on <_.InstanceName>" -Skip:$skipAgentJobTargetOwner -ForEach ($PSItem.InvalidJobOwner) { + It "The Job <_.JobName> has the Job Owner <_.ActualJobOwnerName> that shouldn't exist in this list ($([String]::Join(', ', "<_.InvalidJobOwnerName>"))) on <_.InstanceName>" -Skip:$skipAgentJobTargetInvalidOwner -ForEach ($PSItem.InvalidJobOwner) { $PSItem.ActualJobOwnerName | Should -Not -BeIn $PSItem.InvalidJobOwnerName -Because 'The account that is the job owner has been defined as not valid' } } @@ -142,6 +139,22 @@ Describe "Invalid Job Owner" -Tag InvalidJobOwner, Agent -ForEach $InstancesToTe +Describe "Last Agent Job Run" -Tag LastJobRunTime, Agent -ForEach $InstancesToTest { + $skipAgentJobLastRun = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.lastjobruntime' }).Value + + Context "Testing last job run time on <_.Name>" { + It "Job <_.JobName> last run duration (<_.Duration> seconds) should not be greater than <_.ExpectedRunningJobPercentage>% extra of the average run time (<_.Average> seconds) on <_.InstanceName>" -Skip:$skipAgentJobLastRun -ForEach ($PSItem.LastJobRuns) { + $PSItem.ActualRunningJobPercentage | Should -BeLessThan $PSItem.ExpectedRunningJobPercentage -Because "The last run of job $($PSItem.JobName) was $($PSItem.Duration) seconds. This is more than the $($PSItem.ExpectedRunningJobPercentage)% specified as the maximum variance" + } + } +} + + + + + + + @@ -337,77 +350,7 @@ Describe "Invalid Job Owner" -Tag InvalidJobOwner, Agent -ForEach $InstancesToTe # } # } # } -# Describe "Last Agent Job Run" -Tags LastJobRunTime, $filename { -# $skip = Get-DbcConfigValue skip.agent.lastjobruntime -# $runningjobpercentage = Get-DbcConfigValue agent.lastjobruntime.percentage -# $maxdays = Get-DbcConfigValue agent.failedjob.since -# if (-not $skip) { -# $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,- $maxdays,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,- $maxdays,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" -# $lastagentjobruns = Invoke-DbaQuery -SqlInstance $PSItem -Database msdb -Query $query -# Context "Testing last job run time on $psitem" { -# foreach ($lastagentjobrun in $lastagentjobruns | Where-Object { $_.AvgSec -ne 0 }) { -# It "Job $($lastagentjobrun.JobName) last run duration should be not be greater than $runningjobpercentage % extra of the average run time on $psitem" -Skip:$skip { -# Assert-LastJobRun -lastagentjobrun $lastagentjobrun -runningjobpercentage $runningjobpercentage -# } -# } -# } -# } -# else { -# Context "Testing last job run time on $psitem" { -# It "Job average run time on $psitem" -Skip { -# Assert-LastJobRun -lastagentjobrun $lastagentjobrun -runningjobpercentage $runningjobpercentage -# } -# } -# } -# } + diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 00de560b..2151e5ab 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -236,7 +236,67 @@ function Get-AllAgentInfo { } 'LastJobRunTime' { - + $maxdays = Get-DbcConfigValue agent.failedjob.since + $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,- $maxdays,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,- $maxdays,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" + $lastagentjobruns = Invoke-DbaQuery -SqlInstance $Instance -Database msdb -Query $query + + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'LastJobRuns' -Value (Get-DbcConfigValue agent.lastjobruntime.percentage) + + $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 { } } @@ -257,6 +317,7 @@ function Get-AllAgentInfo { AgentMailProfile = @($agentMailProfile) JobOwner = $JobOwner InvalidJobOwner = $InvalidJobOwner + LastJobRuns = $LastJobRuns } return $testInstanceObject } \ No newline at end of file From a2ac79a1df4e239b5788b21166c9bd292dd5be1c Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Tue, 22 Aug 2023 09:51:26 +0100 Subject: [PATCH 10/24] Last Agent Job Run --- source/checks/Agentv5.Tests.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 66613133..2419c9e0 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -138,7 +138,6 @@ Describe "Invalid Job Owner" -Tag InvalidJobOwner, Agent -ForEach $InstancesToTe } - Describe "Last Agent Job Run" -Tag LastJobRunTime, Agent -ForEach $InstancesToTest { $skipAgentJobLastRun = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.lastjobruntime' }).Value From 4a0d92b97473a8ce8c7be9b86948f56fe315b6cd Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Tue, 22 Aug 2023 10:25:55 +0100 Subject: [PATCH 11/24] Long Running Agent Jobs --- source/checks/Agentv5.Tests.ps1 | 93 +++++++------------ .../internal/functions/Get-AllAgentInfo.ps1 | 43 +++++++++ 2 files changed, 78 insertions(+), 58 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 2419c9e0..9fd6bc0e 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -149,9 +149,43 @@ Describe "Last Agent Job Run" -Tag LastJobRunTime, Agent -ForEach $InstancesToTe } +Describe "Long Running Agent Jobs" -Tag LongRunningJob, Agent -ForEach $InstancesToTest { + $skipAgentLongRunningJobs = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.longrunningjobs' }).Value + Context "Testing long running jobs on <_.Name>" { + It "Running job <_.JobName> duration should not be more than <_.ExpectedLongRunningJobPercentage>% extra of the average run time (<_.Average> seconds) on <_.InstanceName>" -Skip:$skipAgentLongRunningJobs -ForEach ($PSItem.LongRunningJobs) { + $PSItem.ActualLongRunningJobPercentage | Should -BeLessThan $PSItem.ExpectedLongRunningJobPercentage -Because "The current running job $($PSItem.JobName) has been running for $($PSItem.Diff) seconds longer than the average run time. This is more than the $($PSItem.ExpectedLongRunningJobPercentage)% specified as the maximum" + } + } +} +# Describe "Long Running Agent Jobs" -Tags LongRunningJob, $filename { +# } +# if ($NotContactable -contains $psitem) { +# Context "Testing long running jobs on $psitem" { +# It "Can't Connect to $Psitem" { +# $false | Should -BeTrue -Because "The instance should be available to be connected to!" +# } +# } +# } +# else { +# Context "Testing long running jobs on $psitem" { +# if ($runningjobs) { +# foreach ($runningjob in $runningjobs | Where-Object { $_.AvgSec -ne 0 }) { +# It "Running job $($runningjob.JobName) duration should not be more than $runningjobpercentage % extra of the average run time on $psitem" -Skip:$skip { +# Assert-LongRunningJobs -runningjob $runningjob -runningjobpercentage $runningjobpercentage +# } +# } +# } +# else { +# It "There are no running jobs currently on $psitem" -Skip:$skip { +# $True | SHould -BeTrue +# } +# } +# } +# } +# } @@ -291,64 +325,7 @@ Describe "Last Agent Job Run" -Tag LastJobRunTime, Agent -ForEach $InstancesToTe # } # } # } -# Describe "Long Running Agent Jobs" -Tags LongRunningJob, $filename { -# $skip = Get-DbcConfigValue skip.agent.longrunningjobs -# $runningjobpercentage = Get-DbcConfigValue agent.longrunningjob.percentage -# if (-not $skip) { -# $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 $PSItem -Database msdb -Query $query -# } -# if ($NotContactable -contains $psitem) { -# Context "Testing long running jobs on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# Context "Testing long running jobs on $psitem" { -# if ($runningjobs) { -# foreach ($runningjob in $runningjobs | Where-Object { $_.AvgSec -ne 0 }) { -# It "Running job $($runningjob.JobName) duration should not be more than $runningjobpercentage % extra of the average run time on $psitem" -Skip:$skip { -# Assert-LongRunningJobs -runningjob $runningjob -runningjobpercentage $runningjobpercentage -# } -# } -# } -# else { -# It "There are no running jobs currently on $psitem" -Skip:$skip { -# $True | SHould -BeTrue -# } -# } -# } -# } -# } + diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 2151e5ab..17f1e6cf 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -233,7 +233,49 @@ function Get-AllAgentInfo { } '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 (Get-DbcConfigValue agent.longrunningjob.percentage) + $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 = Get-DbcConfigValue agent.failedjob.since @@ -318,6 +360,7 @@ function Get-AllAgentInfo { JobOwner = $JobOwner InvalidJobOwner = $InvalidJobOwner LastJobRuns = $LastJobRuns + LongRunningJobs = $LongRunningJobs } return $testInstanceObject } \ No newline at end of file From 24401bb322549cebdc14b12d3f353e0b1fa88b67 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Tue, 22 Aug 2023 15:01:53 +0100 Subject: [PATCH 12/24] SQL Agent Failed Jobs --- source/checks/Agentv5.Tests.ps1 | 89 ++++++------------- .../internal/configurations/configuration.ps1 | 1 + .../internal/functions/Get-AllAgentInfo.ps1 | 63 +++++++++---- 3 files changed, 70 insertions(+), 83 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 9fd6bc0e..c0600a76 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -34,7 +34,7 @@ BeforeDiscovery { #TODO : Clean this up Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose - + Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable # Get-DbcConfig is expensive so we call it once @@ -159,76 +159,37 @@ Describe "Long Running Agent Jobs" -Tag LongRunningJob, Agent -ForEach $Instance } } -# Describe "Long Running Agent Jobs" -Tags LongRunningJob, $filename { - -# } -# if ($NotContactable -contains $psitem) { -# Context "Testing long running jobs on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# Context "Testing long running jobs on $psitem" { -# if ($runningjobs) { -# foreach ($runningjob in $runningjobs | Where-Object { $_.AvgSec -ne 0 }) { -# It "Running job $($runningjob.JobName) duration should not be more than $runningjobpercentage % extra of the average run time on $psitem" -Skip:$skip { -# Assert-LongRunningJobs -runningjob $runningjob -runningjobpercentage $runningjobpercentage -# } -# } -# } -# else { -# It "There are no running jobs currently on $psitem" -Skip:$skip { -# $True | SHould -BeTrue -# } -# } -# } -# } -# } - - - +Describe "SQL Agent Failed Jobs" -Tag FailedJob, Agent -ForEach $InstancesToTest { + $skipAgentFailedJobs = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.failedjobs' }).Value + $excludecancelled = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.failedjob.excludecancelled' }).Value + Context "Checking for failed enabled jobs since $startdate on <_.Name>" { + ($PSItem.JobsFailed).ForEach{ + Write-PSFMessage -Message "LastRunOutcome = $($PSItem)" -Level Verbose + if ($PSItem.LastRunOutcome -eq "Unknown") { + It "We chose to skip this as $($PSItem.JobName)'s last run outcome is unknown on $($PSItem.InstanceName)" -Skip { + $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because 'All Agent Jobs should have succeed this one is unknown - you need to investigate the failed jobs' + } + } + elseif (($PSItem.LastRunOutcome -eq "Cancelled") -and ($excludecancelled -eq $true)) { + It "You chose to skip this as $($PSItem.JobName)'s last run outcome is cancelled on $($PSItem.InstanceName)" -Skip { + $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because 'All Agent Jobs should have succeed this one is Cancelled - you need to investigate the failed jobs' + } + } + else { + It "Job $($PSItem.JobName) last run outcome is $($PSItem.LastRunOutcome) on $($PSItem.InstanceName)" -Skip:$skipAgentFailedJobs { + $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because "All Agent Jobs should have succeed - you need to investigate the failed jobs" + } + } + } + } +} -# Describe "Failed Jobs" -Tags FailedJob, $filename { -# if ($NotContactable -contains $psitem) { -# Context "Checking for failed enabled jobs on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# $maxdays = Get-DbcConfigValue agent.failedjob.since -# $startdate = (Get-Date).AddDays( - $maxdays) -# Context "Checking for failed enabled jobs since $startdate on $psitem" { -# $excludecancelled = Get-DbcConfigValue agent.failedjob.excludecancelled -# @(Get-DbaAgentJob -SqlInstance $psitem | Where-Object { $Psitem.IsEnabled -and ($psitem.LastRunDate -gt $startdate) }).ForEach{ -# if ($psitem.LastRunOutcome -eq "Unknown") { -# It -Skip "We chose to skip this as $psitem's last run outcome is unknown on $($psitem.SqlInstance)" { -# $psitem.LastRunOutcome | Should -Be "Succeeded" -Because 'All Agent Jobs should have succeed this one is unknown - you need to investigate the failed jobs' -# } -# } -# elseif (($psitem.LastRunOutcome -eq "Cancelled") -and ($excludecancelled -eq $true)) { -# It -Skip "We chose to skip this as $psitem's last run outcome is cancelled on $($psitem.SqlInstance)" { -# $psitem.LastRunOutcome | Should -Be "Succeeded" -Because 'All Agent Jobs should have succeed this one is unknown - you need to investigate the failed jobs' -# } -# } -# else { -# It "$psitem's last run outcome is $($psitem.LastRunOutcome) on $($psitem.SqlInstance)" { -# $psitem.LastRunOutcome | Should -Be "Succeeded" -Because 'All Agent Jobs should have succeed - you need to investigate the failed jobs' -# } -# } -# } -# } -# } -# } # Describe "Agent Alerts" -Tags AgentAlert, $filename { diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index 467a5872..9ecfb761 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -347,6 +347,7 @@ Set-PSFConfig -Module dbachecks -Name skip.agent.longrunningjobs -Validation boo Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool -Value $false -Initialize -Description "Skip the last agent job time check" Set-PSFConfig -Module dbachecks -Name skip.agent.jobowner -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Owner check" Set-PSFConfig -Module dbachecks -Name skip.agent.invalidjobowner.name -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Invalid Owner check" +Set-PSFConfig -Module dbachecks -Name skip.agent.failedjobs -Validation bool -Value $false -Initialize -Description "Skip the Agent Failed Jobs check" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 17f1e6cf..dd0cb0a8 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -41,28 +41,32 @@ function Get-AllAgentInfo { # Invalid JobOwner Initial fields $InvalidJobOwnerInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) - # Database Initial Fields - $DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) + # Failed Job Initial fields + $FailedJobInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) - # 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]) + #TODO: Clean up? + ## 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 + #$configurations = $false # Set up blank ConfigValues object for any config we need to use in the checks $ConfigValues = [PSCustomObject]@{} @@ -189,7 +193,27 @@ function Get-AllAgentInfo { #Write-PSFMessage -Message "ActualDatabaseMailProfile instance : $($Instance.JobServer.DatabaseMailProfile)" -Level Verbose } '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 = Get-DbcConfigValue agent.failedjob.since + $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 @@ -359,6 +383,7 @@ function Get-AllAgentInfo { AgentMailProfile = @($agentMailProfile) JobOwner = $JobOwner InvalidJobOwner = $InvalidJobOwner + JobsFailed = $JobsFailed LastJobRuns = $LastJobRuns LongRunningJobs = $LongRunningJobs } From b558063dc8d153492e64643af919a242e2092384 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Tue, 22 Aug 2023 15:18:14 +0100 Subject: [PATCH 13/24] SQL Agent Failed Jobs "improve?" --- source/checks/Agentv5.Tests.ps1 | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index c0600a76..25e95db8 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -164,25 +164,18 @@ Describe "SQL Agent Failed Jobs" -Tag FailedJob, Agent -ForEach $InstancesToTest $skipAgentFailedJobs = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.failedjobs' }).Value $excludecancelled = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.failedjob.excludecancelled' }).Value - Context "Checking for failed enabled jobs since $startdate on <_.Name>" { - ($PSItem.JobsFailed).ForEach{ - Write-PSFMessage -Message "LastRunOutcome = $($PSItem)" -Level Verbose - if ($PSItem.LastRunOutcome -eq "Unknown") { - It "We chose to skip this as $($PSItem.JobName)'s last run outcome is unknown on $($PSItem.InstanceName)" -Skip { - $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because 'All Agent Jobs should have succeed this one is unknown - you need to investigate the failed jobs' - } + Context "Checking for failed enabled jobs since on <_.Name>" { + if (-not $skipAgentFailedJobs) { + It "We chose to skip this as <_.JobName>'s last run outcome is unknown on <_.InstanceName>" -Skip -ForEach ($PSItem.JobsFailed | Where-Object { $_.LastRunOutcome -eq "Unknown" }) { + $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because 'All Agent Jobs should have succeed this one is unknown - you need to investigate the failed jobs' } - elseif (($PSItem.LastRunOutcome -eq "Cancelled") -and ($excludecancelled -eq $true)) { - It "You chose to skip this as $($PSItem.JobName)'s last run outcome is cancelled on $($PSItem.InstanceName)" -Skip { - $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because 'All Agent Jobs should have succeed this one is Cancelled - you need to investigate the failed jobs' - } - } - else { - It "Job $($PSItem.JobName) last run outcome is $($PSItem.LastRunOutcome) on $($PSItem.InstanceName)" -Skip:$skipAgentFailedJobs { - $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because "All Agent Jobs should have succeed - you need to investigate the failed jobs" - } + It "You chose to skip this as <_.JobName>'s last run outcome is cancelled on <_.InstanceName>" -Skip -ForEach ($PSItem.JobsFailed | Where-Object { $_.LastRunOutcome -eq "Cancelled" -and ($excludecancelled -eq $true) }) { + $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because 'All Agent Jobs should have succeed this one is Cancelled - you need to investigate the failed jobs' } } + It "Job <_.JobName> last run outcome is <_.LastRunOutcome> on <_.InstanceName>" -Skip:$skipAgentFailedJobs -ForEach ($PSItem.JobsFailed | Where-Object { $_.LastRunOutcome -notin ("Cancelled", "Unknown") }) { + $PSItem.LastRunOutcome | Should -Be $PSItem.ExpectedOutcome -Because "All Agent Jobs should have succeed - you need to investigate the failed jobs" + } } } From 43e94b38574af7b9e8020738b9bdc5b7d34b76d9 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Wed, 23 Aug 2023 10:30:52 +0100 Subject: [PATCH 14/24] AgentAlert --- source/checks/Agentv5.Tests.ps1 | 107 ++++++++---------- .../internal/functions/Get-AllAgentInfo.ps1 | 46 ++++++++ 2 files changed, 91 insertions(+), 62 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 25e95db8..13d7ffe5 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -181,72 +181,55 @@ Describe "SQL Agent Failed Jobs" -Tag FailedJob, Agent -ForEach $InstancesToTest +Describe "Agent Alerts" -Tag AgentAlert, Agent -ForEach $InstancesToTest { + $skipAgentAlerts = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.alert' }).Value + $AgentAlertJob = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Job' }).Value + $AgentAlertNotification = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Notification' }).Value + Write-PSFMessage -Message "Instances = $($PSItem.Severity)" -Level Verbose + Context "Testing Agent Alerts Severity exists on <_.Name>" { + It "Severity <_.AgentAlertSeverity> Alert should exist on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { #| Where-Object { $_.Severity -NE $null }) { + $PSItem.Severity | Should -Be $PSItem.AgentAlertSeverity -Because "Recommended Agent Alerts to exists http://blog.extreme-advice.com/2013/01/29/list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages/" + } + + It "Severity <_.AgentAlertSeverity> Alert should be enabled on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { + $PSItem.IsEnabled | Should -Be $true -Because "Configured alerts should be enabled" + } + if ($AgentAlertJob) { + It "A job name for Severity <_.AgentAlertSeverity> Alert on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { + $PSItem.JobName -ne $null | Should -Be $true -Because "Should notify by SQL Agent Job" + } + } + if ($AgentAlertNotification) { + It "Severity <_.AgentAlertSeverity> Alert should have a notification on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { + $PSItem.HasNotification -in 1, 2, 3, 4, 5, 6, 7 | Should -Be $true -Because "Should notify by Agent notifications" + } + } + + } + + Context "Testing Agent Alerts MessageID exists on <_.Name>" { + It "MessageID <_.AgentMessageID> Alert should exist on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.MessageIDs) { + $PSItem.MessageID | Should -Be $PSItem.AgentMessageID -Because "Recommended Agent Alerts to exists http://blog.extreme-advice.com/2013/01/29/list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages/" + } + It "MessageID <_.AgentMessageID> Alert should be enabled on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.MessageIDs) { + $PSItem.IsEnabled | Should -Be $true -Because "Configured alerts should be enabled" + } + if ($AgentAlertJob) { + It "A job name for MessageID <_.AgentMessageID> on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.MessageIDs) { + $PSItem.JobName -ne $null | Should -Be $true -Because "Should notify by SQL Agent Job" + } + } + if ($AgentAlertNotification) { + It "MessageID <_.AgentMessageID> Alert should have a notification on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.MessageIDs) { + $PSItem.HasNotification -in 1, 2, 3, 4, 5, 6, 7 | Should -Be $true -Because "Should notify by Agent notifications" + } + } + } +} -# Describe "Agent Alerts" -Tags AgentAlert, $filename { -# $severity = Get-DbcConfigValue agent.alert.Severity -# $messageid = Get-DbcConfigValue agent.alert.messageid -# $AgentAlertJob = Get-DbcConfigValue agent.alert.Job -# $AgentAlertNotification = Get-DbcConfigValue agent.alert.Notification -# $skip = Get-DbcConfigValue skip.agent.alert -# if ($NotContactable -contains $psitem) { -# Context "Testing Agent Alerts Severity exists on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# Context "Testing Agent Alerts MessageID exists on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# $alerts = Get-DbaAgentAlert -SqlInstance $psitem -# Context "Testing Agent Alerts Severity exists on $psitem" { -# ForEach ($sev in $severity) { -# It "Severity $sev Alert should exist on $psitem" -Skip:$skip { -# ($alerts.Where{ $psitem.Severity -eq $sev }) | Should -be $true -Because "Recommended Agent Alerts to exists http://blog.extreme-advice.com/2013/01/29/list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages/" -# } -# It "Severity $sev Alert should be enabled on $psitem" -Skip:$skip { -# ($alerts.Where{ $psitem.Severity -eq $sev }).IsEnabled | Should -be $true -Because "Configured alerts should be enabled" -# } -# if ($AgentAlertJob) { -# It "A job name for Severity $sev Alert on $psitem" -Skip:$skip { -# ($alerts.Where{ $psitem.Severity -eq $sev }).jobname -ne $null | Should -be $true -Because "Should notify by SQL Agent Job" -# } -# } -# if ($AgentAlertNotification) { -# It "Severity $sev Alert should have a notification on $psitem" -Skip:$skip { -# ($alerts.Where{ $psitem.Severity -eq $sev }).HasNotification -in 1, 2, 3, 4, 5, 6, 7 | Should -be $true -Because "Should notify by Agent notifications" -# } -# } -# } -# } -# Context "Testing Agent Alerts MessageID exists on $psitem" { -# ForEach ($mid in $messageid) { -# It "Message_ID $mid Alert should exist on $psitem" -Skip:$skip { -# ($alerts.Where{ $psitem.messageid -eq $mid }) | Should -be $true -Because "Recommended Agent Alerts to exists http://blog.extreme-advice.com/2013/01/29/list-of-errors-and-severity-level-in-sql-server-with-catalog-view-sysmessages/" -# } -# It "Message_ID $mid Alert should be enabled on $psitem" -Skip:$skip { -# ($alerts.Where{ $psitem.messageid -eq $mid }) | Should -be $true -Because "Configured alerts should be enabled" -# } -# if ($AgentAlertJob) { -# It "A Job name for Message_ID $mid Alert should be on $psitem" -Skip:$skip { -# ($alerts.Where{ $psitem.messageid -eq $mid }).jobname -ne $null | Should -be $true -Because "Should notify by SQL Agent Job" -# } -# } -# if ($AgentAlertNotification) { -# It "Message_ID $mid Alert should have a notification on $psitem" -Skip:$skip { -# ($alerts.Where{ $psitem.messageid -eq $mid }).HasNotification -in 1, 2, 3, 4, 5, 6, 7 | Should -be $true -Because "Should notify by Agent notifications" -# } -# } -# } -# } -# } -# } # Describe "Job History Configuration" -Tags JobHistory, $filename { # if ($NotContactable -contains $psitem) { diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index dd0cb0a8..02b349a0 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -44,6 +44,9 @@ function Get-AllAgentInfo { # 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]) + #TODO: Clean up? ## Database Initial Fields #$DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) @@ -251,7 +254,49 @@ function Get-AllAgentInfo { } '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 (Get-DbcConfigValue agent.alert.Severity) + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentAlertMessageId' -Value (Get-DbcConfigValue agent.alert.messageid) + + $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' { @@ -386,6 +431,7 @@ function Get-AllAgentInfo { JobsFailed = $JobsFailed LastJobRuns = $LastJobRuns LongRunningJobs = $LongRunningJobs + AgentAlerts = $AgentAlerts } return $testInstanceObject } \ No newline at end of file From 55f30ce0bfb1ca7846998123027aa78bee3415ef Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Wed, 23 Aug 2023 10:59:53 +0100 Subject: [PATCH 15/24] Job History Configuration --- source/checks/Agentv5.Tests.ps1 | 58 ++++++------------- .../internal/configurations/configuration.ps1 | 1 + .../internal/functions/Get-AllAgentInfo.ps1 | 19 ++++++ 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 13d7ffe5..41ac57a0 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -34,6 +34,7 @@ BeforeDiscovery { #TODO : Clean this up Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose + Write-PSFMessage -Message "Instances = $($InstancesToTest.JobHistory)" -Level Verbose Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable @@ -184,9 +185,7 @@ Describe "SQL Agent Failed Jobs" -Tag FailedJob, Agent -ForEach $InstancesToTest Describe "Agent Alerts" -Tag AgentAlert, Agent -ForEach $InstancesToTest { $skipAgentAlerts = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.alert' }).Value $AgentAlertJob = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Job' }).Value - $AgentAlertNotification = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Notification' }).Value - - Write-PSFMessage -Message "Instances = $($PSItem.Severity)" -Level Verbose + $AgentAlertNotification = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.alert.Notification' }).Value Context "Testing Agent Alerts Severity exists on <_.Name>" { It "Severity <_.AgentAlertSeverity> Alert should exist on <_.InstanceName>" -Skip:$skipAgentAlerts -ForEach ($PSItem.AgentAlerts.Severities) { #| Where-Object { $_.Severity -NE $null }) { @@ -229,41 +228,20 @@ Describe "Agent Alerts" -Tag AgentAlert, Agent -ForEach $InstancesToTest { } } +Describe "Job History Configuration" -Tag JobHistory, Agent -ForEach $InstancesToTest { + $skipAgetJobHistory = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.JobHistory' }).Value + [int]$minimumJobHistoryRows = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.history.maximumhistoryrows' }).Value - -# Describe "Job History Configuration" -Tags JobHistory, $filename { -# if ($NotContactable -contains $psitem) { -# Context "Testing job history configuration on $psitem" { -# It "Can't Connect to $Psitem" { -# $false | Should -BeTrue -Because "The instance should be available to be connected to!" -# } -# } -# } -# else { -# Context "Testing job history configuration on $psitem" { -# [int]$minimumJobHistoryRows = Get-DbcConfigValue agent.history.maximumhistoryrows -# [int]$minimumJobHistoryRowsPerJob = Get-DbcConfigValue agent.history.maximumjobhistoryrows - -# $AgentServer = Get-DbaAgentServer -SqlInstance $psitem -EnableException:$false - -# if ($minimumJobHistoryRows -eq -1) { -# It "The maximum job history configuration should be set to disabled on $psitem" { -# Assert-JobHistoryRowsDisabled -AgentServer $AgentServer -minimumJobHistoryRows $minimumJobHistoryRows -# } -# } -# else { -# It "The maximum job history number of rows configuration should be greater or equal to $minimumJobHistoryRows on $psitem" { -# Assert-JobHistoryRows -AgentServer $AgentServer -minimumJobHistoryRows $minimumJobHistoryRows -# } -# It "The maximum job history rows per job configuration should be greater or equal to $minimumJobHistoryRowsPerJob on $psitem" { -# Assert-JobHistoryRowsPerJob -AgentServer $AgentServer -minimumJobHistoryRowsPerJob $minimumJobHistoryRowsPerJob -# } -# } -# } -# } -# } - - - - - + if ($minimumJobHistoryRows -eq -1) { + It "The maximum job history configuration should be set to disabled on <_.InstanceName>" -Skip:$skipAgetJobHistory -ForEach ($PSItem.JobHistory) { + $PSItem.CurrentMaximumHistoryRows | Should -Be $PSItem.ExpectedMaximumHistoryRows -Because "Maximum job history configuration should be disabled" + } + } else { + It "The maximum job history number of rows configuration should be greater or equal to <_.ExpectedMaximumHistoryRows> on <_.InstanceName>" -Skip:$skipAgetJobHistory -ForEach ($PSItem.JobHistory) { + $PSItem.CurrentMaximumHistoryRows | Should -BeGreaterOrEqual $PSItem.ExpectedMaximumHistoryRows -Because "We expect the maximum job history row configuration to be greater than the configured setting <_.ExpectedMaximumHistoryRows>" + } + It "The maximum job history rows per job configuration should be greater or equal to <_.ExpectedMaximumJobHistoryRows> on <_.InstanceName>" -Skip:$skipAgetJobHistory -ForEach ($PSItem.JobHistory) { + $PSItem.CurrentMaximumJobHistoryRows | Should -BeGreaterOrEqual $PSItem.ExpectedMaximumJobHistoryRows -Because "We expect the maximum job history row configuration per agent job to be greater than the configured setting <_.ExpectedMaximumJobHistoryRows>" + } + } +} \ No newline at end of file diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index 9ecfb761..47ab2605 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -348,6 +348,7 @@ Set-PSFConfig -Module dbachecks -Name skip.agent.lastjobruntime -Validation bool Set-PSFConfig -Module dbachecks -Name skip.agent.jobowner -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Owner check" Set-PSFConfig -Module dbachecks -Name skip.agent.invalidjobowner.name -Validation bool -Value $false -Initialize -Description "Skip the Agent Job Invalid Owner check" Set-PSFConfig -Module dbachecks -Name skip.agent.failedjobs -Validation bool -Value $false -Initialize -Description "Skip the Agent Failed Jobs check" +Set-PSFConfig -Module dbachecks -Name skip.agent.JobHistory -Validation bool -Value $false -Initialize -Description "Skip the Agent Job History check" diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 02b349a0..d7f080ff 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -47,6 +47,9 @@ function Get-AllAgentInfo { # 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]) + #TODO: Clean up? ## Database Initial Fields #$DatabaseInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Database]) @@ -299,7 +302,22 @@ function Get-AllAgentInfo { } } '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 (Get-DbcConfigValue agent.history.maximumhistoryrows) + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMaximumJobHistoryRows' -Value (Get-DbcConfigValue agent.history.maximumjobhistoryrows) + + $JobHistory = [PSCustomObject]@{ + InstanceName = $Instance.Name + CurrentMaximumHistoryRows = $Instance.JobServer.MaximumHistoryRows + ExpectedMaximumHistoryRows = $ConfigValues.AgentMaximumHistoryRows + CurrentMaximumJobHistoryRows = $Instance.JobServer.MaximumJobHistoryRows + ExpectedMaximumJobHistoryRows = $ConfigValues.AgentMaximumJobHistoryRows + } } 'LongRunningJob' { $query = "SELECT @@ -432,6 +450,7 @@ function Get-AllAgentInfo { LastJobRuns = $LastJobRuns LongRunningJobs = $LongRunningJobs AgentAlerts = $AgentAlerts + JobHistory = @($JobHistory) } return $testInstanceObject } \ No newline at end of file From e614b28f5a09415bc0aa4eab5e05ab4b2f1eb3f2 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Wed, 23 Aug 2023 15:21:21 +0100 Subject: [PATCH 16/24] some cleaning --- source/checks/Agentv5.Tests.ps1 | 1 - .../internal/functions/Get-AllAgentInfo.ps1 | 51 ------------------- 2 files changed, 52 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 41ac57a0..945f5fe9 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -34,7 +34,6 @@ BeforeDiscovery { #TODO : Clean this up Write-PSFMessage -Message "Instances = $($InstancesToTest.Name)" -Level Verbose - Write-PSFMessage -Message "Instances = $($InstancesToTest.JobHistory)" -Level Verbose Set-PSFConfig -Module dbachecks -Name global.notcontactable -Value $NotContactable diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index d7f080ff..e4facd76 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -50,30 +50,6 @@ function Get-AllAgentInfo { # Agent Job History Initial fields $AgentJobHistory = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.JobServer]) - #TODO: Clean up? - ## 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]@{} @@ -154,19 +130,6 @@ function Get-AllAgentInfo { ActualDatabaseMailProfile = $Instance.Mail.Profiles.Name } } - - ##TODO: Clean up - #$databaseMailProfile += [PSCustomObject]@{ - # InstanceName = $Instance.Name - # ExpectedDatabaseMailProfile = 'null' - # ActualDatabaseMailProfile = 'null' - #} -# - #Write-PSFMessage -Message "InstanceName : $($databaseMailProfile.InstanceName)" -Level Verbose - #Write-PSFMessage -Message "ExpectedDatabaseMailProfile : $($databaseMailProfile.ExpectedDatabaseMailProfile)" -Level Verbose - #Write-PSFMessage -Message "ActualDatabaseMailProfile : $($databaseMailProfile.ActualDatabaseMailProfile)" -Level Verbose - #Write-PSFMessage -Message "ActualDatabaseMailProfile instance : $($Instance.Mail.Profiles.Name)" -Level Verbose - } 'AgentMailProfile' { $AgentMailProfileInitFields.Add("DatabaseMailProfile") | Out-Null # so we can check failsafe operators @@ -183,20 +146,6 @@ function Get-AllAgentInfo { ActualAgentMailProfile = $Instance.JobServer.DatabaseMailProfile } } - - #TODO: Clean up - #$databaseMailProfile = $ConfigValues.DatabaseMailProfile.ForEach{ - # [PSCustomObject]@{ - # InstanceName = $Instance.Name - # ExpectedDatabaseMailProfile = 'null' - # ActualDatabaseMailProfile = 'null' - # } - #} -# - #Write-PSFMessage -Message "InstanceName : $($databaseMailProfile.InstanceName)" -Level Verbose - #Write-PSFMessage -Message "ExpectedDatabaseMailProfile : $($databaseMailProfile.ExpectedDatabaseMailProfile)" -Level Verbose - #Write-PSFMessage -Message "ActualDatabaseMailProfile : $($databaseMailProfile.ActualDatabaseMailProfile)" -Level Verbose - #Write-PSFMessage -Message "ActualDatabaseMailProfile instance : $($Instance.JobServer.DatabaseMailProfile)" -Level Verbose } 'FailedJob' { $FailedJobInitFields.Add("Name") | Out-Null # so we can check Job Name From 2f25a0f9de7eb445863dfede477f4c4ab34281cc Mon Sep 17 00:00:00 2001 From: Rob Sewell Date: Wed, 23 Aug 2023 15:12:39 +0000 Subject: [PATCH 17/24] so that we might know which way round to do this --- containers/JessAndBeard.psm1 | 65 ++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/containers/JessAndBeard.psm1 b/containers/JessAndBeard.psm1 index 853c79ab..12f381f4 100644 --- a/containers/JessAndBeard.psm1 +++ b/containers/JessAndBeard.psm1 @@ -2311,7 +2311,7 @@ Uh-Oh - The Tag filters between v4 and v5 are not the same somehow. For v4 We returned {0} and -For v5 we returned +for v4 we returned {1} " -f ($v4code.TagFilter | Out-String), ($v5code.Configuration.Filter.Tag.Value | Out-String) Write-PSFMessage -Message $Message -Level Warning @@ -2324,46 +2324,53 @@ The Tags are the same" $changedTags = @( @{ Name = 'TraceFlagsExpected' - RunChange = 3 # + or - the number of tests run for v5 - PassedChange = 3 # + or - the number of tests passed for v5 - FailedChange = 0 # + or - the number of tests failed for v5 - SkippedChange = 0 # + or - the number of tests skipped for v5 + RunChange = 3 # + or - the number of tests run for v4 + PassedChange = 3 # + or - the number of tests passed for v4 + FailedChange = 0 # + or - the number of tests failed for v4 + SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'TraceFlagsNotExpected' - RunChange = 3 # + or - the number of tests for v5 - PassedChange = 3 # + or - the number of tests passed for v5 - FailedChange = 0 # + or - the number of tests failed for v5 - SkippedChange = 0 # + or - the number of tests skipped for v5 + RunChange = 3 # + or - the number of tests for v4 + PassedChange = 3 # + or - the number of tests passed for v4 + FailedChange = 0 # + or - the number of tests failed for v4 + SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'XESessionRunningAllowed' - RunChange = -12 # + or - the number of tests for v5 - PassedChange = 0 # + or - the number of tests passed for v5 - FailedChange = -12 # + or - the number of tests failed for v5 - SkippedChange = 0 # + or - the number of tests skipped for v5 + RunChange = -12 # + or - the number of tests for v4 + PassedChange = 0 # + or - the number of tests passed for v4 + FailedChange = -12 # + or - the number of tests failed for v4 + SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'LinkedServerConnection' - RunChange = -3 # + or - the number of tests for v5 - PassedChange = -3 # + or - the number of tests passed for v5 - FailedChange = 0 # + or - the number of tests failed for v5 - SkippedChange = 0 # + or - the number of tests skipped for v5 + RunChange = -3 # + or - the number of tests for v4 + PassedChange = -3 # + or - the number of tests passed for v4 + FailedChange = 0 # + or - the number of tests failed for v4 + SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'SupportedBuild' - RunChange = -3 # + or - the number of tests run for v5 - PassedChange = -3 # + or - the number of tests passed for v5 - FailedChange = 0 # + or - the number of tests failed for v5 - SkippedChange = 0 # + or - the number of tests skipped for v5 + RunChange = -3 # + or - the number of tests run for v4 + PassedChange = -3 # + or - the number of tests passed for v4 + FailedChange = 0 # + or - the number of tests failed for v4 + SkippedChange = 0 # + or - the number of tests skipped for v4 }, @{ Name = 'GuestUserConnect' - RunChange = 0 # + or - the number of tests run for v5 - PassedChange = +2 # + or - the number of tests passed for v5 - FailedChange = -2 # + or - the number of tests failed for v5 - SkippedChange = 0 # + or - the number of tests skipped for v5 + RunChange = 0 # + or - the number of tests run for v4 + PassedChange = +2 # + or - the number of tests passed for v4 + FailedChange = -2 # + or - the number of tests failed for v4 + SkippedChange = 0 # + or - the number of tests skipped for v4 + }, + @{ + Name = 'AgentServiceAccount' + RunChange = -3 # + or - the number of tests run for v4 + PassedChange = -5 # + or - the number of tests passed for v4 + FailedChange = -1 # + or - the number of tests failed for v4 + SkippedChange = +3 # + or - the number of tests skipped for v4 } ) $runchange = 0 @@ -2399,7 +2406,7 @@ Uh-Oh - The total tests run between v4 and v5 are not the same somehow. For v4 We ran {0} tests and -For v5 we ran +for v4 we ran {1} tests The MOST COMMON REASON IS you have used Tags instead of Tag in your Describe block {2} " -f $v4code.TotalCount, $v5run, $messageAppend @@ -2418,7 +2425,7 @@ Uh-Oh - The total tests Passed between v4 and v5 are not the same somehow. For v4 We Passed {0} tests and -For v5 we Passed +for v4 we Passed {1} tests {2}" -f $v4code.PassedCount, $v5Passed, $messageAppend Write-PSFMessage -Message $Message -Level Warning @@ -2435,7 +2442,7 @@ Uh-Oh - The total tests Failed between v4 and v5 are not the same somehow. For v4 We Failed {0} tests and -For v5 we Failed +for v4 we Failed {1} tests " -f $v4code.FailedCount, $v5failed Write-PSFMessage -Message $Message -Level Warning @@ -2452,7 +2459,7 @@ Uh-Oh - The total tests Skipped between v4 and v5 are not the same somehow. For v4 We Skipped {0} tests and -For v5 we Skipped +for v4 we Skipped {1} tests {2}" -f $v4code.SkippedCount, $v5skipped, $messageAppend Write-PSFMessage -Message $Message -Level Warning From 069750e2a89fcf5eb6e8e01f02381b8889a6af2d Mon Sep 17 00:00:00 2001 From: Rob Sewell Date: Wed, 23 Aug 2023 15:14:41 +0000 Subject: [PATCH 18/24] so that #887 has some checks done --- .../internal/functions/Get-AllAgentInfo.ps1 | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index e4facd76..dec1449b 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -62,7 +62,7 @@ function Get-AllAgentInfo { } 'AgentServiceAccount' { if (($Instance.VersionMajor -ge 14) -or $IsLinux -or $Instance.HostPlatform -eq 'Linux') { - $Agent = @($Instance.Query("SELECT status_desc, startup_type_desc FROM sys.dm_server_services") | Where-Object servicename -Like '*Agent*').ForEach{ + $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 @@ -163,10 +163,10 @@ function Get-AllAgentInfo { $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 + InstanceName = $Instance.Name + JobName = $PSItem.Name + ExpectedOutcome = $ConfigValues.FailedJob + LastRunOutcome = $PSItem.LastRunOutcome } } } @@ -180,10 +180,10 @@ function Get-AllAgentInfo { $JobOwner = $Instance.JobServer.Jobs.ForEach{ [PSCustomObject]@{ - InstanceName = $Instance.Name - JobName = $PSItem.Name - ExpectedJobOwnerName = $ConfigValues.TargetJobOwner #$PSItem - ActualJobOwnerName = $PSItem.OwnerLoginName + InstanceName = $Instance.Name + JobName = $PSItem.Name + ExpectedJobOwnerName = $ConfigValues.TargetJobOwner #$PSItem + ActualJobOwnerName = $PSItem.OwnerLoginName } } } @@ -197,10 +197,10 @@ function Get-AllAgentInfo { $InvalidJobOwner = $Instance.JobServer.Jobs.ForEach{ [PSCustomObject]@{ - InstanceName = $Instance.Name - JobName = $PSItem.Name - ExpectedJobOwnerName = $ConfigValues.InvalidJobOwner - ActualJobOwnerName = $PSItem.OwnerLoginName + InstanceName = $Instance.Name + JobName = $PSItem.Name + ExpectedJobOwnerName = $ConfigValues.InvalidJobOwner + ActualJobOwnerName = $PSItem.OwnerLoginName } } @@ -303,13 +303,13 @@ function Get-AllAgentInfo { $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) + 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) } } } @@ -367,12 +367,12 @@ function Get-AllAgentInfo { $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) + InstanceName = $Instance.Name + JobName = $PSItem.JobName + Duration = $PSItem.Duration + Average = $PSItem.AvgSec + ExpectedRunningJobPercentage = $ConfigValues.LastJobRuns + ActualRunningJobPercentage = [math]::Round($PSItem.Diff / $PSItem.AvgSec * 100) } } } From 2ad34b2fd6db5e6209515a1b200553a8299122a2 Mon Sep 17 00:00:00 2001 From: Rob Sewell Date: Wed, 23 Aug 2023 15:28:06 +0000 Subject: [PATCH 19/24] sdo that it formats adn that the configvalue is more performant #887 --- source/internal/functions/Get-AllAgentInfo.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index dec1449b..68b1cd09 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -314,7 +314,7 @@ function Get-AllAgentInfo { } } 'LastJobRunTime' { - $maxdays = Get-DbcConfigValue agent.failedjob.since + $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 @@ -335,7 +335,7 @@ function Get-AllAgentInfo { 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,- $maxdays,GETDATE()) + 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 @@ -346,7 +346,7 @@ function Get-AllAgentInfo { 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,- $maxdays,GETDATE()) + 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 @@ -360,7 +360,7 @@ function Get-AllAgentInfo { JOIN #dbachecksAverageRunTime avgrun ON lastrun.job_id = avgrun.job_id DROP Table #dbachecksLastRunTime - DROP Table #dbachecksAverageRunTime" + DROP Table #dbachecksAverageRunTime" -f $maxdays $lastagentjobruns = Invoke-DbaQuery -SqlInstance $Instance -Database msdb -Query $query $ConfigValues | Add-Member -MemberType NoteProperty -Name 'LastJobRuns' -Value (Get-DbcConfigValue agent.lastjobruntime.percentage) From 24049948a3027ba60ca7cc64b652a82d7fdb9832 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Wed, 23 Aug 2023 16:39:10 +0100 Subject: [PATCH 20/24] using $__dbcconfig - we want PERFORMANNNNCE!!! --- .../internal/functions/Get-AllAgentInfo.ps1 | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/source/internal/functions/Get-AllAgentInfo.ps1 b/source/internal/functions/Get-AllAgentInfo.ps1 index 68b1cd09..f9221e27 100644 --- a/source/internal/functions/Get-AllAgentInfo.ps1 +++ b/source/internal/functions/Get-AllAgentInfo.ps1 @@ -58,7 +58,7 @@ function Get-AllAgentInfo { 'DatabaseMailEnabled' { $configurations = $true - $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DatabaseMailEnabled' -Value (Get-DbcConfigValue policy.security.databasemailenabled) + $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') { @@ -78,8 +78,8 @@ function Get-AllAgentInfo { $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 (Get-DbcConfigValue agent.dbaoperatorname) - $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DbaOperatorEmail' -Value (Get-DbcConfigValue agent.dbaoperatoremail) + $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]@{ @@ -106,7 +106,7 @@ function Get-AllAgentInfo { $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 (Get-DbcConfigValue agent.failsafeoperator) + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'FailsafeOperator' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.failsafeoperator' }).Value) $failsafeOperator = $ConfigValues.FailsafeOperator.ForEach{ [PSCustomObject]@{ @@ -121,7 +121,7 @@ function Get-AllAgentInfo { $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 (Get-DbcConfigValue agent.databasemailprofile) + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'DatabaseMailProfile' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.databasemailprofile' }).Value) $databaseMailProfile = $ConfigValues.DatabaseMailProfile.ForEach{ [PSCustomObject]@{ @@ -136,7 +136,7 @@ function Get-AllAgentInfo { $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 (Get-DbcConfigValue agent.databasemailprofile) + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMailProfile' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.databasemailprofile' }).Value) $agentMailProfile = $ConfigValues.AgentMailProfile.ForEach{ @@ -156,7 +156,7 @@ function Get-AllAgentInfo { $Instance.SetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job], $FailedJobInitFields) $FailedJobInitFields = $Instance.GetDefaultInitFields([Microsoft.SqlServer.Management.Smo.Agent.Job]) - $maxdays = Get-DbcConfigValue agent.failedjob.since + $maxdays = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.failedjob.since' }).Value $startdate = (Get-Date).AddDays( - $maxdays) $ConfigValues | Add-Member -MemberType NoteProperty -Name 'FailedJob' -Value 'Succeeded' @@ -176,7 +176,7 @@ function Get-AllAgentInfo { $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 (Get-DbcConfigValue agent.validjobowner.name) + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'TargetJobOwner' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.validjobowner.name' }).Value) $JobOwner = $Instance.JobServer.Jobs.ForEach{ [PSCustomObject]@{ @@ -193,7 +193,7 @@ function Get-AllAgentInfo { $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 (Get-DbcConfigValue agent.invalidjobowner.name) + $ConfigValues | Add-Member -MemberType NoteProperty -Name 'InvalidJobOwner' -Value (($__dbcconfig | Where-Object { $_.Name -eq 'agent.invalidjobowner.name' }).Value) $InvalidJobOwner = $Instance.JobServer.Jobs.ForEach{ [PSCustomObject]@{ @@ -214,8 +214,8 @@ function Get-AllAgentInfo { $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 (Get-DbcConfigValue agent.alert.Severity) - $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentAlertMessageId' -Value (Get-DbcConfigValue agent.alert.messageid) + $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) @@ -257,8 +257,8 @@ function Get-AllAgentInfo { $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 (Get-DbcConfigValue agent.history.maximumhistoryrows) - $ConfigValues | Add-Member -MemberType NoteProperty -Name 'AgentMaximumJobHistoryRows' -Value (Get-DbcConfigValue agent.history.maximumjobhistoryrows) + $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 @@ -299,7 +299,7 @@ function Get-AllAgentInfo { ORDER BY JobName;" $runningjobs = Invoke-DbaQuery -SqlInstance $Instance -Database msdb -Query $query - $ConfigValues | Add-Member -MemberType NoteProperty -Name 'LongRunningJob' -Value (Get-DbcConfigValue agent.longrunningjob.percentage) + $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]@{ @@ -363,7 +363,7 @@ function Get-AllAgentInfo { DROP Table #dbachecksAverageRunTime" -f $maxdays $lastagentjobruns = Invoke-DbaQuery -SqlInstance $Instance -Database msdb -Query $query - $ConfigValues | Add-Member -MemberType NoteProperty -Name 'LastJobRuns' -Value (Get-DbcConfigValue agent.lastjobruntime.percentage) + $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]@{ From d7f4434af34bb5c407b27d7c7d61f11e3a487f4d Mon Sep 17 00:00:00 2001 From: jpomfret Date: Sun, 27 Aug 2023 17:32:51 +0000 Subject: [PATCH 21/24] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4b895bb..01786913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- For new features. +- Pester v5 support for agent checks. ### Changed From 143ec3bb053599c41d8dd8fd8e563cb0156fb182 Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Mon, 28 Aug 2023 17:08:54 +0100 Subject: [PATCH 22/24] Fix typo --- source/checks/Agentv5.Tests.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/checks/Agentv5.Tests.ps1 b/source/checks/Agentv5.Tests.ps1 index 945f5fe9..9be16609 100644 --- a/source/checks/Agentv5.Tests.ps1 +++ b/source/checks/Agentv5.Tests.ps1 @@ -228,18 +228,18 @@ Describe "Agent Alerts" -Tag AgentAlert, Agent -ForEach $InstancesToTest { } Describe "Job History Configuration" -Tag JobHistory, Agent -ForEach $InstancesToTest { - $skipAgetJobHistory = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.JobHistory' }).Value + $skipAgentJobHistory = ($__dbcconfig | Where-Object { $_.Name -eq 'skip.agent.JobHistory' }).Value [int]$minimumJobHistoryRows = ($__dbcconfig | Where-Object { $_.Name -eq 'agent.history.maximumhistoryrows' }).Value if ($minimumJobHistoryRows -eq -1) { - It "The maximum job history configuration should be set to disabled on <_.InstanceName>" -Skip:$skipAgetJobHistory -ForEach ($PSItem.JobHistory) { + It "The maximum job history configuration should be set to disabled on <_.InstanceName>" -Skip:$skipAgentJobHistory -ForEach ($PSItem.JobHistory) { $PSItem.CurrentMaximumHistoryRows | Should -Be $PSItem.ExpectedMaximumHistoryRows -Because "Maximum job history configuration should be disabled" } } else { - It "The maximum job history number of rows configuration should be greater or equal to <_.ExpectedMaximumHistoryRows> on <_.InstanceName>" -Skip:$skipAgetJobHistory -ForEach ($PSItem.JobHistory) { + It "The maximum job history number of rows configuration should be greater or equal to <_.ExpectedMaximumHistoryRows> on <_.InstanceName>" -Skip:$skipAgentJobHistory -ForEach ($PSItem.JobHistory) { $PSItem.CurrentMaximumHistoryRows | Should -BeGreaterOrEqual $PSItem.ExpectedMaximumHistoryRows -Because "We expect the maximum job history row configuration to be greater than the configured setting <_.ExpectedMaximumHistoryRows>" } - It "The maximum job history rows per job configuration should be greater or equal to <_.ExpectedMaximumJobHistoryRows> on <_.InstanceName>" -Skip:$skipAgetJobHistory -ForEach ($PSItem.JobHistory) { + It "The maximum job history rows per job configuration should be greater or equal to <_.ExpectedMaximumJobHistoryRows> on <_.InstanceName>" -Skip:$skipAgentJobHistory -ForEach ($PSItem.JobHistory) { $PSItem.CurrentMaximumJobHistoryRows | Should -BeGreaterOrEqual $PSItem.ExpectedMaximumJobHistoryRows -Because "We expect the maximum job history row configuration per agent job to be greater than the configured setting <_.ExpectedMaximumJobHistoryRows>" } } From e4985056cb270ac96e2ff262af4e9f1af0fcee9b Mon Sep 17 00:00:00 2001 From: ClaudioESSilva Date: Mon, 28 Aug 2023 17:12:50 +0100 Subject: [PATCH 23/24] Removed entries from not converted tests --- source/internal/configurations/configuration.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index 64b7fb5a..a93db405 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -18,7 +18,7 @@ $EmailValidationSb = { } Register-PSFConfigValidation -Name validation.EmailValidation -ScriptBlock $EmailValidationSb -$__dbachecksNotv5 = 'ADUser', 'BuiltInAdmin', 'EngineServiceAdmin', 'FullTextServiceAdmin', 'LocalWindowsGroup', 'PublicPermission', 'SqlBrowserServiceAccount', 'TempDbConfiguration'',CertificateExpiration', 'DatabaseExists', 'DatabaseGrowthEvent', 'DatabaseMailEnabled', 'DatabaseMailProfile', 'DatafileAutoGrowthType', 'DisabledIndex', 'DuplicateIndex', 'FileGroupBalanced', 'FKCKTrusted', 'FutureFileGrowth', 'IdentityUsage', 'LastDiffBackup', 'LastFullBackup', 'LastGoodCheckDb', 'LastLogBackup', 'LogfilePercentUsed', 'LogfileSize', 'MaxDopDatabase', 'OrphanedUser', 'PageVerify', 'SymmetricKeyEncryptionLevel', 'TestLastBackup', 'TestLastBackupVerifyOnly', 'UnusedIndex', 'DatabaseMailEnabled', 'AgentServiceAccount', 'DbaOperator', 'FailsafeOperator', 'DatabaseMailProfile', 'AgentMailProfile', 'FailedJob', 'ValidJobOwner', 'InValidJobOwner', 'AgentAlert', 'JobHistory', 'LongRunningJob', 'LastJobRunTime', 'PowerPlan', 'SPN', 'DiskCapacity', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit', 'NonStandardPort', 'ServerProtocol', 'OlaInstalled', 'SystemFull', 'UserFull', 'UserDiff', 'UserLog', 'CommandLog', 'SystemIntegrityCheck', 'UserIntegrityCheck', 'UserIndexOptimize', 'OutputFileCleanup', 'DeleteBackupHistory', 'PurgeJobHistory', 'DomainName', 'OrganizationalUnit', 'ClusterHealth', 'LogShippingPrimary', 'LogShippingSecondary' +$__dbachecksNotv5 = 'ADUser', 'BuiltInAdmin', 'EngineServiceAdmin', 'FullTextServiceAdmin', 'LocalWindowsGroup', 'PublicPermission', 'SqlBrowserServiceAccount', 'TempDbConfiguration'',CertificateExpiration', 'DatabaseExists', 'DatabaseGrowthEvent', 'DatafileAutoGrowthType', 'DisabledIndex', 'DuplicateIndex', 'FileGroupBalanced', 'FKCKTrusted', 'FutureFileGrowth', 'IdentityUsage', 'LastDiffBackup', 'LastFullBackup', 'LastGoodCheckDb', 'LastLogBackup', 'LogfilePercentUsed', 'LogfileSize', 'MaxDopDatabase', 'OrphanedUser', 'PageVerify', 'SymmetricKeyEncryptionLevel', 'TestLastBackup', 'TestLastBackupVerifyOnly', 'UnusedIndex', 'PowerPlan', 'SPN', 'DiskCapacity', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit', 'NonStandardPort', 'ServerProtocol', 'OlaInstalled', 'SystemFull', 'UserFull', 'UserDiff', 'UserLog', 'CommandLog', 'SystemIntegrityCheck', 'UserIntegrityCheck', 'UserIndexOptimize', 'OutputFileCleanup', 'DeleteBackupHistory', 'PurgeJobHistory', 'DomainName', 'OrganizationalUnit', 'ClusterHealth', 'LogShippingPrimary', 'LogShippingSecondary' Set-PSFConfig -Module dbachecks -Name checks.notv5ready -Value @($__dbachecksNotv5) -Initialize -Description "Checks that have not been converted to v5 yet" From 6d39640c0e41b516f1f74b82cc5540d4a3288416 Mon Sep 17 00:00:00 2001 From: jpomfret Date: Mon, 28 Aug 2023 16:21:45 +0000 Subject: [PATCH 24/24] remove page verify --- source/internal/configurations/configuration.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/internal/configurations/configuration.ps1 b/source/internal/configurations/configuration.ps1 index a93db405..13e68259 100644 --- a/source/internal/configurations/configuration.ps1 +++ b/source/internal/configurations/configuration.ps1 @@ -18,7 +18,7 @@ $EmailValidationSb = { } Register-PSFConfigValidation -Name validation.EmailValidation -ScriptBlock $EmailValidationSb -$__dbachecksNotv5 = 'ADUser', 'BuiltInAdmin', 'EngineServiceAdmin', 'FullTextServiceAdmin', 'LocalWindowsGroup', 'PublicPermission', 'SqlBrowserServiceAccount', 'TempDbConfiguration'',CertificateExpiration', 'DatabaseExists', 'DatabaseGrowthEvent', 'DatafileAutoGrowthType', 'DisabledIndex', 'DuplicateIndex', 'FileGroupBalanced', 'FKCKTrusted', 'FutureFileGrowth', 'IdentityUsage', 'LastDiffBackup', 'LastFullBackup', 'LastGoodCheckDb', 'LastLogBackup', 'LogfilePercentUsed', 'LogfileSize', 'MaxDopDatabase', 'OrphanedUser', 'PageVerify', 'SymmetricKeyEncryptionLevel', 'TestLastBackup', 'TestLastBackupVerifyOnly', 'UnusedIndex', 'PowerPlan', 'SPN', 'DiskCapacity', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit', 'NonStandardPort', 'ServerProtocol', 'OlaInstalled', 'SystemFull', 'UserFull', 'UserDiff', 'UserLog', 'CommandLog', 'SystemIntegrityCheck', 'UserIntegrityCheck', 'UserIndexOptimize', 'OutputFileCleanup', 'DeleteBackupHistory', 'PurgeJobHistory', 'DomainName', 'OrganizationalUnit', 'ClusterHealth', 'LogShippingPrimary', 'LogShippingSecondary' +$__dbachecksNotv5 = 'ADUser', 'BuiltInAdmin', 'EngineServiceAdmin', 'FullTextServiceAdmin', 'LocalWindowsGroup', 'PublicPermission', 'SqlBrowserServiceAccount', 'TempDbConfiguration'',CertificateExpiration', 'DatabaseExists', 'DatabaseGrowthEvent', 'DatafileAutoGrowthType', 'DisabledIndex', 'DuplicateIndex', 'FileGroupBalanced', 'FKCKTrusted', 'FutureFileGrowth', 'IdentityUsage', 'LastDiffBackup', 'LastFullBackup', 'LastGoodCheckDb', 'LastLogBackup', 'LogfilePercentUsed', 'LogfileSize', 'MaxDopDatabase', 'OrphanedUser', 'SymmetricKeyEncryptionLevel', 'TestLastBackup', 'TestLastBackupVerifyOnly', 'UnusedIndex', 'PowerPlan', 'SPN', 'DiskCapacity', 'PingComputer', 'CPUPrioritisation', 'DiskAllocationUnit', 'NonStandardPort', 'ServerProtocol', 'OlaInstalled', 'SystemFull', 'UserFull', 'UserDiff', 'UserLog', 'CommandLog', 'SystemIntegrityCheck', 'UserIntegrityCheck', 'UserIndexOptimize', 'OutputFileCleanup', 'DeleteBackupHistory', 'PurgeJobHistory', 'DomainName', 'OrganizationalUnit', 'ClusterHealth', 'LogShippingPrimary', 'LogShippingSecondary' Set-PSFConfig -Module dbachecks -Name checks.notv5ready -Value @($__dbachecksNotv5) -Initialize -Description "Checks that have not been converted to v5 yet"