Skip to content

Add check for pester v5 - LastFullBackup #1030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

- fixed typo in Invoke-PerfAndValidateCheck so we know which version we're looking at
- New database level check `LastFullBackup`
- Updated HADR checks to use dbatools new outputs

## [3.0.2] - 2025-03-10
Expand Down
7 changes: 7 additions & 0 deletions containers/JessAndBeard.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -2379,6 +2379,13 @@ The Tags are the same"
PassedChange = 0 # + or - the number of tests passed for v5
FailedChange = 0 # + or - the number of tests failed for v5
SkippedChange = -3 # + or - the number of tests skipped for v5
},
@{
Name = 'LastFullBackup'
RunChange = +1 # + or - the number of tests run for v5
PassedChange = 0 # + or - the number of tests passed for v5
FailedChange = 0 # + or - the number of tests failed for v5
SkippedChange = +1 # + or - the number of tests skipped for v5
}
)
$runchange = 0
Expand Down
37 changes: 36 additions & 1 deletion source/checks/Databasev5.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ Describe "Page Verify" -Tag PageVerify, Medium, Database -ForEach $InstancesToTe

Describe "Foreign keys and check constraints not trusted" -Tag FKCKTrusted, Low, Database -ForEach $InstancesToTest {
$Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.database.fkcktrusted').Value
Context "Testing Foreign Keys and Check Constraints are not trusted <_.Name>" {
Context "Testing Foreign Keys and Check Constraints are not trusted <_.Name>" {

It "Database <_.Database> Foreign Key <_.Name> on table <_.Parent> should be trusted on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{ if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.fkcktrustedexclude -notcontains $psitem.Name } }.ForeignKeys {
$psitem.IsChecked | Should -Be $true -Because "This can have a huge performance impact on queries. SQL Server won't use untrusted constraints to build better execution plans. It will also avoid data violation"
Expand All @@ -319,3 +319,38 @@ Describe "Foreign keys and check constraints not trusted" -Tag FKCKTrusted, Low
}
}

#TODO: test if database is offline or not `IsAccessible`
Describe "Last Full Backup Times" -Tag LastFullBackup, LastBackup, Backup, DISA, Varied -ForEach $InstancesToTest {
$Skip = ($__dbcconfig | Where-Object Name -EQ 'skip.database.lastfullbackup').Value
#TODO: also skip secondaries? and read only?
Context "Testing last full backups on <_.Name>" {
It "Database <_.Name> should have full backups less than <_.ConfigValues.fullmaxdays> on <_.SqlInstance>" -Skip:$skip -ForEach $psitem.Databases.Where{if ($Database) { $_.Name -in $Database } else { $psitem.ConfigValues.fullbackupexclude -notcontains $psitem.Name } }.Where{if ($psitem.ConfigValues.skipreadonly) { -not $psitem.readonly } else {$psitem} }.Where{if ($psitem.ConfigValues.skipsecondaries) { $psitem.AGReplicaRole -ne 'Secondary' } else {$psitem} } { #TODO: secondary? is that right
$psitem.LastFullBackup.ToUniversalTime() | Should -BeGreaterThan (Get-Date).ToUniversalTime().AddDays( - ($psitem.ConfigValues.fullmaxdays)) -Because "Taking regular backups is extraordinarily important"
}
}
}


#TODO: convert checks
# TestLastBackup
# TestLastBackupVerifyOnly
# LastGoodCheckDb
# IdentityUsage
# DuplicateIndex
# UnusedIndex
# DisabledIndex
# DatabaseGrowthEvent
# LastFullBackup
# LastDiffBackup
# LastLogBackup
# LogfilePercentUsed
# LogfileSize
# FutureFileGrowth
# FileGroupBalanced
# CertificateExpiration
# DatafileAutoGrowthType
# OrphanedUser
# MaxDopDatabase
# DatabaseExists
# CLRAssembliesSafe
# SymmetricKeyEncryptionLevel
8 changes: 6 additions & 2 deletions source/internal/configurations/configuration.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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', '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'
$__dbachecksNotv5 = 'ADUser', 'BuiltInAdmin', 'EngineServiceAdmin', 'FullTextServiceAdmin', 'LocalWindowsGroup', 'PublicPermission', 'SqlBrowserServiceAccount', 'TempDbConfiguration','CertificateExpiration', 'DatabaseExists', 'DatabaseGrowthEvent', 'DatafileAutoGrowthType', 'DisabledIndex', 'DuplicateIndex', 'FileGroupBalanced', 'FutureFileGrowth', 'IdentityUsage', 'LastDiffBackup', '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"

Expand Down Expand Up @@ -178,7 +178,9 @@ Set-PSFConfig -Module dbachecks -Name policy.database.clrassembliessafeexcludedb
Set-PSFConfig -Module dbachecks -Name policy.database.pseudosimpleexcludedb -Value @('tempdb', 'model') -Initialize -Description "A List of databases that we do not want to check for pseudosimple recovery modelasd a"
Set-PSFConfig -Module dbachecks -Name policy.database.contdbautocloseexclude -Value @('msdb') -Initialize -Description "A List of contained database that we we do not want to check for autoclose"
Set-PSFConfig -Module dbachecks -Name policy.database.contdbsqlauthexclude -Value @() -Initialize -Description "A list of databases that we do not want to check for contained databases with SQL authenticated users"
Set-PSFConfig -Module dbachecks -Name policy.database.logfilepercentused -Value 75 -Initialize -Description " The % log used we should stay below"
Set-PSFConfig -Module dbachecks -Name policy.database.logfilepercentused -Value 75 -Initialize -Description "The % log used we should stay below"
Set-PSFConfig -Module dbachecks -Name policy.database.fullbackupexclude -Value @('tempdb') -Initialize -Description "The list of databases that we do not want to check the date of the last full backup of."


# Policy for Ola Hallengren Maintenance Solution
Set-PSFConfig -Module dbachecks -Name policy.ola.installed -Validation bool -Value $true -Initialize -Description "Checks to see if Ola Hallengren solution is installed"
Expand Down Expand Up @@ -344,6 +346,8 @@ Set-PSFConfig -Module dbachecks -Name skip.database.recoverymodel -Validation bo
Set-PSFConfig -Module dbachecks -Name skip.database.pseudosimple -Validation bool -Value $false -Initialize -Description "Skip the database PseudoSimple recovery model test"
Set-PSFConfig -Module dbachecks -Name skip.database.pageverify -Validation bool -Value $false -Initialize -Description "Skip the database page verify test"
Set-PSFConfig -Module dbachecks -Name skip.database.fkcktrusted -Validation bool -Value $false -Initialize -Description "Skip the check for foreign keys and constraints being trusted"
Set-PSFConfig -Module dbachecks -Name skip.database.lastfullbackup -Validation bool -Value $false -Initialize -Description "Skip the check for last full backup"


Set-PSFConfig -Module dbachecks -Name skip.logshiptesting -Validation bool -Value $false -Initialize -Description "Skip the logshipping test"

Expand Down
14 changes: 12 additions & 2 deletions source/internal/functions/Get-AllDatabaseInfo.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,21 @@ function Get-AllDatabaseInfo {
}
'PageVerify' {
$pageverify = $true
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'pageverifyexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.contdbsqlauthexclude').Value
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'pageverifyexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.contdbsqlauthexclude').Value #TODO: fix that config name
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'pageverify' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.pageverify').Value
}
'FKCKTrusted' {
$trusted = $true
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'fkcktrustedexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.fkcktrustedexclude').Value
}
'LastFullBackup' {
$lastFullBackup = $true
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'fullbackupexclude' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.database.fullbackupexclude').Value
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'fullmaxdays' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.backup.fullmaxdays').Value
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'graceperiod' -Value ($__dbcconfig | Where-Object Name -EQ 'policy.backup.newdbgraceperiod').Value
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'skipreadonly' -Value ($__dbcconfig | Where-Object Name -EQ 'skip.backup.readonly').Value
$ConfigValues | Add-Member -MemberType NoteProperty -Name 'skipsecondaries' -Value ($__dbcconfig | Where-Object Name -EQ 'skip.backup.secondaries').Value
}
Default { }
}

Expand Down Expand Up @@ -195,7 +203,7 @@ function Get-AllDatabaseInfo {
Trustworthy = @(if ($trustworthy) { $psitem.Trustworthy })
Status = @(if ($status) { $psitem.Status })
IsDatabaseSnapshot = @(if ($status) { $psitem.IsDatabaseSnapshot }) # needed for status test
Readonly = @(if ($status) { $psitem.Readonly }) # needed for status test
Readonly = @(if ($status -or $lastFullBackup) { $psitem.Readonly }) # needed for status test & lastfullbackup
QueryStore = @(if ($qs) { $psitem.QueryStoreOptions.ActualState })
CompatibilityLevel = @(if ($compatibilitylevel) { $psitem.CompatibilityLevel })
ServerLevel = @(if ($compatibilitylevel) { [Enum]::GetNames('Microsoft.SqlServer.Management.Smo.CompatibilityLevel').Where{ $psitem -match $Instance.VersionMajor } })
Expand All @@ -208,6 +216,8 @@ function Get-AllDatabaseInfo {
PageVerify = @(if ($pageverify) { $psitem.PageVerify })
ForeignKeys = @(if ($trusted) {$psitem.Tables.ForeignKeys | Where-Object {-not $_.NotForReplication} | Select-Object Name, Parent, @{l='Database';e={$_.Parent.Parent.Name}}, IsChecked } )
Constraints = @(if ($trusted) {$psitem.Tables.Checks | Where-Object {(-not $_.NotForReplication) -and $_.IsEnabled} | Select-Object Name, Parent, @{l='Database';e={$_.Parent.Parent.Name}}, IsChecked } )
LastFullBackup = @(if ($lastFullBackup) {$psitem.LastBackupDate})
AGReplicaRole = @(if ($lastFullBackup) { if ($psitem.AvailabilityGroupName) {$psitem.parent.AvailabilityGroups[$psitem.AvailabilityGroupName].LocalReplicaRole} else { 'N\A' }}) # TODO: this needs testing!
}
}
}
Expand Down