There are two ways to get AD Last Backup Time. The first one is based on a well-known repadmin /showbackup command, which is not a PowerShell way to do things, but it does work if you want to do things quick and dirty.
Some people try to parse output from repadmin command, but it's tricky as dates tend to be culture oriented. So what works for en-US, may not work in pl-PL scenarios. Fortunately, there's another way to do it. Below you can find two functions. First function Convert-TimeToDays is a simple support function for the primary function Get-WinADLastBackup.
function Convert-TimeToDays {
[CmdletBinding()]
param (
$StartTime,
$EndTime,
#[nullable[DateTime]] $StartTime, # can't use this just yet, some old code uses strings in StartTime/EndTime.
#[nullable[DateTime]] $EndTime, # After that's fixed will change this.
[string] $Ignore = '*1601*'
)
if ($null -ne $StartTime -and $null -ne $EndTime) {
try {
if ($StartTime -notlike $Ignore -and $EndTime -notlike $Ignore) {
$Days = (NEW-TIMESPAN -Start $StartTime -End $EndTime).Days
}
} catch {}
} elseif ($null -ne $EndTime) {
if ($StartTime -notlike $Ignore -and $EndTime -notlike $Ignore) {
$Days = (NEW-TIMESPAN -Start (Get-Date) -End ($EndTime)).Days
}
} elseif ($null -ne $StartTime) {
if ($StartTime -notlike $Ignore -and $EndTime -notlike $Ignore) {
$Days = (NEW-TIMESPAN -Start $StartTime -End (Get-Date)).Days
}
}
return $Days
}
function Get-WinADLastBackup {
<#
.SYNOPSIS
Gets Active directory forest or domain last backup time
.DESCRIPTION
Gets Active directory forest or domain last backup time
.PARAMETER Domain
Optionally you can pass Domains by hand
.EXAMPLE
$LastBackup = Get-WinADLastBackup
$LastBackup | Format-Table -AutoSize
.EXAMPLE
$LastBackup = Get-WinADLastBackup -Domain 'ad.evotec.pl'
$LastBackup | Format-Table -AutoSize
.NOTES
General notes
#>
[cmdletBinding()]
param(
[string[]] $Domains
)
$NameUsed = [System.Collections.Generic.List[string]]::new()
[DateTime] $CurrentDate = Get-Date
if (-not $Domains) {
try {
$Forest = Get-ADForest -ErrorAction Stop
$Domains = $Forest.Domains
} catch {
Write-Warning "Get-WinADLastBackup - Failed to gather Forest Domains $($_.Exception.Message)"
}
}
foreach ($Domain in $Domains) {
try {
[string[]]$Partitions = (Get-ADRootDSE -Server $Domain -ErrorAction Stop).namingContexts
[System.DirectoryServices.ActiveDirectory.DirectoryContextType] $contextType = [System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain
[System.DirectoryServices.ActiveDirectory.DirectoryContext] $context = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext($contextType, $Domain)
[System.DirectoryServices.ActiveDirectory.DomainController] $domainController = [System.DirectoryServices.ActiveDirectory.DomainController]::FindOne($context)
} catch {
Write-Warning "Get-WinADLastBackup - Failed to gather partitions information for $Domain with error $($_.Exception.Message)"
}
$Output = ForEach ($Name in $Partitions) {
if ($NameUsed -contains $Name) {
continue
} else {
$NameUsed.Add($Name)
}
$domainControllerMetadata = $domainController.GetReplicationMetadata($Name)
$dsaSignature = $domainControllerMetadata.Item("dsaSignature")
$LastBackup = [DateTime] $($dsaSignature.LastOriginatingChangeTime)
[PSCustomObject] @{
Domain = $Domain
NamingContext = $Name
LastBackup = $LastBackup
LastBackupDaysAgo = - (Convert-TimeToDays -StartTime ($CurrentDate) -EndTime ($LastBackup))
}
}
$Output
}
}
To run it, execute the following code.
Don't get too excited on my domains last backup time — I don't back them up.