@@ -59,11 +59,13 @@ function Test-DbaAgPolicyState {
5959 - InstanceName: The SQL Server instance name (string)
6060 - SqlInstance: The full SQL Server instance name (string)
6161 - AvailabilityGroup: Name of the availability group (string)
62+ - Replica: Name of the availability replica for replica-level policies, $null for server/AG-level policies (string)
63+ - Database: Name of the availability database for database-level policies, $null for server/AG/replica-level policies (string)
6264 - PolicyName: The name of the Always On policy being evaluated (string)
6365 - Category: The severity of the policy - Critical or Warning (string)
6466 - Facet: The object type the policy applies to (string)
6567 - IsHealthy: Boolean indicating whether the policy check passed (bool)
66- - Issue: Description of the issue when the policy is not healthy (string)
68+ - Issue: Description of the issue when the policy is not healthy, $null when healthy (string)
6769 - Details: Additional detail about the current state (string)
6870
6971 . EXAMPLE
@@ -104,6 +106,7 @@ function Test-DbaAgPolicyState {
104106
105107 foreach ($ag in $InputObject ) {
106108 $server = $ag.Parent
109+ $ag.Refresh ()
107110
108111 <#
109112 WSFC cluster service is offline
@@ -124,11 +127,13 @@ function Test-DbaAgPolicyState {
124127 InstanceName = $ag.InstanceName
125128 SqlInstance = $ag.SqlInstance
126129 AvailabilityGroup = $ag.Name
130+ Replica = $null
131+ Database = $null
127132 PolicyName = " WSFC Cluster State"
128133 Category = " Critical"
129134 Facet = " Instance of SQL Server"
130135 IsHealthy = $isHealthy
131- Issue = " WSFC cluster service is offline."
136+ Issue = if ( $isHealthy ) { $null } else { " WSFC cluster service is offline." }
132137 Details = " ClusterQuorumState is $ ( $server.ClusterQuorumState ) "
133138 }
134139
@@ -152,11 +157,13 @@ function Test-DbaAgPolicyState {
152157 InstanceName = $ag.InstanceName
153158 SqlInstance = $ag.SqlInstance
154159 AvailabilityGroup = $ag.Name
160+ Replica = $null
161+ Database = $null
155162 PolicyName = " Availability Group Online State"
156163 Category = " Critical"
157164 Facet = " Availability group"
158165 IsHealthy = $agState.IsOnline
159- Issue = " Availability group is offline."
166+ Issue = if ( $agState .IsOnline ) { $null } else { " Availability group is offline." }
160167 Details = " IsOnline is $ ( $agState.IsOnline ) "
161168 }
162169
@@ -179,11 +186,13 @@ function Test-DbaAgPolicyState {
179186 InstanceName = $ag.InstanceName
180187 SqlInstance = $ag.SqlInstance
181188 AvailabilityGroup = $ag.Name
189+ Replica = $null
190+ Database = $null
182191 PolicyName = " Availability Group Automatic Failover Readiness"
183192 Category = " Critical"
184193 Facet = " Availability group"
185194 IsHealthy = $isHealthy
186- Issue = " Availability group is not ready for automatic failover."
195+ Issue = if ( $isHealthy ) { $null } else { " Availability group is not ready for automatic failover." }
187196 Details = " IsAutoFailover is $ ( $agState.IsAutoFailover ) , NumberOfSynchronizedSecondaryReplicas is $ ( $agState.NumberOfSynchronizedSecondaryReplicas ) "
188197 }
189198
@@ -206,11 +215,13 @@ function Test-DbaAgPolicyState {
206215 InstanceName = $ag.InstanceName
207216 SqlInstance = $ag.SqlInstance
208217 AvailabilityGroup = $ag.Name
218+ Replica = $null
219+ Database = $null
209220 PolicyName = " Availability Replicas Connection State"
210221 Category = " Warning"
211222 Facet = " Availability group"
212223 IsHealthy = $isHealthy
213- Issue = " Some availability replicas are disconnected."
224+ Issue = if ( $isHealthy ) { $null } else { " Some availability replicas are disconnected." }
214225 Details = " NumberOfDisconnectedReplicas is $ ( $agState.NumberOfDisconnectedReplicas ) "
215226 }
216227
@@ -233,11 +244,13 @@ function Test-DbaAgPolicyState {
233244 InstanceName = $ag.InstanceName
234245 SqlInstance = $ag.SqlInstance
235246 AvailabilityGroup = $ag.Name
247+ Replica = $null
248+ Database = $null
236249 PolicyName = " Availability Replicas Data Synchronization State"
237250 Category = " Warning"
238251 Facet = " Availability group"
239252 IsHealthy = $isHealthy
240- Issue = " Some availability replicas are not synchronizing data."
253+ Issue = if ( $isHealthy ) { $null } else { " Some availability replicas are not synchronizing data." }
241254 Details = " NumberOfNotSynchronizingReplicas is $ ( $agState.NumberOfNotSynchronizingReplicas ) "
242255 }
243256
@@ -260,11 +273,13 @@ function Test-DbaAgPolicyState {
260273 InstanceName = $ag.InstanceName
261274 SqlInstance = $ag.SqlInstance
262275 AvailabilityGroup = $ag.Name
276+ Replica = $null
277+ Database = $null
263278 PolicyName = " Availability Replicas Role State"
264279 Category = " Warning"
265280 Facet = " Availability group"
266281 IsHealthy = $isHealthy
267- Issue = " Some availability replicas do not have a healthy role."
282+ Issue = if ( $isHealthy ) { $null } else { " Some availability replicas do not have a healthy role." }
268283 Details = " NumberOfReplicasWithUnhealthyRole is $ ( $agState.NumberOfReplicasWithUnhealthyRole ) "
269284 }
270285
@@ -287,13 +302,193 @@ function Test-DbaAgPolicyState {
287302 InstanceName = $ag.InstanceName
288303 SqlInstance = $ag.SqlInstance
289304 AvailabilityGroup = $ag.Name
305+ Replica = $null
306+ Database = $null
290307 PolicyName = " Synchronous Replicas Data Synchronization State"
291308 Category = " Warning"
292309 Facet = " Availability group"
293310 IsHealthy = $isHealthy
294- Issue = " Some synchronous replicas are not synchronized."
311+ Issue = if ( $isHealthy ) { $null } else { " Some synchronous replicas are not synchronized." }
295312 Details = " NumberOfNotSynchronizedReplicas is $ ( $agState.NumberOfNotSynchronizedReplicas ) "
296313 }
314+
315+ foreach ($replica in $ag.AvailabilityReplicas ) {
316+ <#
317+ Availability replica does not have a healthy role
318+ Documentation: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/availability-replica-does-not-have-a-healthy-role
319+ Policy Name: Availability Replica Role State
320+ Issue: Availability replica does not have a healthy role.
321+ Category: Warning
322+ Facet: Availability replica
323+
324+ Name : AlwaysOnArReplicaRoleHealthCondition
325+ Facet : IAvailabilityReplicaState
326+ ExpressionNode : @Role = Enum('Microsoft.SqlServer.Management.Smo.AvailabilityReplicaRole', 'Primary') OR @Role = Enum('Microsoft.SqlServer.Management.Smo.AvailabilityReplicaRole', 'Secondary')
327+ #>
328+
329+ $isHealthy = $replica.Role -in " Primary" , " Secondary"
330+ [PSCustomObject ]@ {
331+ ComputerName = $ag.ComputerName
332+ InstanceName = $ag.InstanceName
333+ SqlInstance = $ag.SqlInstance
334+ AvailabilityGroup = $ag.Name
335+ Replica = $replica.Name
336+ Database = $null
337+ PolicyName = " Availability Replica Role State"
338+ Category = " Warning"
339+ Facet = " Availability replica"
340+ IsHealthy = $isHealthy
341+ Issue = if ($isHealthy ) { $null } else { " Availability replica does not have a healthy role." }
342+ Details = " Role is $ ( $replica.Role ) "
343+ }
344+
345+ <#
346+ Availability replica is disconnected
347+ Documentation: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/availability-replica-is-disconnected
348+ Policy Name: Availability Replica Connection State
349+ Issue: Availability replica is disconnected.
350+ Category: Warning
351+ Facet: Availability replica
352+
353+ Name : AlwaysOnArReplicaConnectionHealthCondition
354+ Facet : IAvailabilityReplicaState
355+ ExpressionNode : @ConnectionState = Enum('Microsoft.SqlServer.Management.Smo.AvailabilityReplicaConnectionState', 'Connected') OR @Role = Enum('Microsoft.SqlServer.Management.Smo.AvailabilityReplicaRole', 'Primary')
356+ #>
357+
358+ $isHealthy = $replica.ConnectionState -eq " Connected" -or $replica.Role -eq " Primary"
359+ [PSCustomObject ]@ {
360+ ComputerName = $ag.ComputerName
361+ InstanceName = $ag.InstanceName
362+ SqlInstance = $ag.SqlInstance
363+ AvailabilityGroup = $ag.Name
364+ Replica = $replica.Name
365+ Database = $null
366+ PolicyName = " Availability Replica Connection State"
367+ Category = " Warning"
368+ Facet = " Availability replica"
369+ IsHealthy = $isHealthy
370+ Issue = if ($isHealthy ) { $null } else { " Availability replica is disconnected." }
371+ Details = " ConnectionState is $ ( $replica.ConnectionState ) , Role is $ ( $replica.Role ) "
372+ }
373+
374+ <#
375+ Availability replica is not joined
376+ Documentation: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/availability-replica-is-not-joined
377+ Policy Name: Availability Replica Joined State
378+ Issue: Availability replica is not joined.
379+ Category: Warning
380+ Facet: Availability replica
381+
382+ Name : AlwaysOnArReplicaJoinedHealthCondition
383+ Facet : IAvailabilityReplicaState
384+ ExpressionNode : @JoinState = Enum('Microsoft.SqlServer.Management.Smo.AvailabilityReplicaJoinState', 'JoinedStandaloneInstance') OR @JoinState = Enum('Microsoft.SqlServer.Management.Smo.AvailabilityReplicaJoinState', 'JoinedWindowsServerFailoverCluster')
385+ #>
386+
387+ $isHealthy = $replica.JoinState -in " JoinedStandaloneInstance" , " JoinedWindowsServerFailoverCluster"
388+ [PSCustomObject ]@ {
389+ ComputerName = $ag.ComputerName
390+ InstanceName = $ag.InstanceName
391+ SqlInstance = $ag.SqlInstance
392+ AvailabilityGroup = $ag.Name
393+ Replica = $replica.Name
394+ Database = $null
395+ PolicyName = " Availability Replica Joined State"
396+ Category = " Warning"
397+ Facet = " Availability replica"
398+ IsHealthy = $isHealthy
399+ Issue = if ($isHealthy ) { $null } else { " Availability replica is not joined." }
400+ Details = " JoinState is $ ( $replica.JoinState ) "
401+ }
402+ }
403+
404+ foreach ($databaseReplicaState in $ag.DatabaseReplicaStates ) {
405+ <#
406+ Data synchronization state of availability database is not healthy
407+ Documentation: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/data-synchronization-state-of-availability-database-is-not-healthy
408+ Policy Name: Availability Database Synchronization State
409+ Issue: Data synchronization state of availability database is not healthy.
410+ Category: Critical
411+ Facet: Availability database
412+
413+ Name : AlwaysOnDbDataSynchronizationHealthCondition
414+ Facet : IAvailabilityDatabaseState
415+ ExpressionNode : @SynchronizationState = Enum('Microsoft.SqlServer.Management.Smo.AvailabilityDatabaseSynchronizationState', 'Synchronized') OR @SynchronizationState = Enum('Microsoft.SqlServer.Management.Smo.AvailabilityDatabaseSynchronizationState', 'Synchronizing')
416+ #>
417+
418+ $isHealthy = $databaseReplicaState.SynchronizationState -in " Synchronized" , " Synchronizing"
419+ [PSCustomObject ]@ {
420+ ComputerName = $ag.ComputerName
421+ InstanceName = $ag.InstanceName
422+ SqlInstance = $ag.SqlInstance
423+ AvailabilityGroup = $ag.Name
424+ Replica = $databaseReplicaState.AvailabilityReplicaServerName
425+ Database = $databaseReplicaState.AvailabilityDatabaseName
426+ PolicyName = " Availability Database Synchronization State"
427+ Category = " Critical"
428+ Facet = " Availability database"
429+ IsHealthy = $isHealthy
430+ Issue = if ($isHealthy ) { $null } else { " Data synchronization state of availability database is not healthy." }
431+ Details = " SynchronizationState is $ ( $databaseReplicaState.SynchronizationState ) "
432+ }
433+
434+ <#
435+ Availability database is suspended
436+ Documentation: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/availability-database-is-suspended
437+ Policy Name: Availability Database Suspension State
438+ Issue: Availability database is suspended.
439+ Category: Warning
440+ Facet: Availability database
441+
442+ Name : AlwaysOnDbSuspendedHealthCondition
443+ Facet : IAvailabilityDatabaseState
444+ ExpressionNode : @IsSuspended = False()
445+ #>
446+
447+ $isHealthy = -not $databaseReplicaState.IsSuspended
448+ [PSCustomObject ]@ {
449+ ComputerName = $ag.ComputerName
450+ InstanceName = $ag.InstanceName
451+ SqlInstance = $ag.SqlInstance
452+ AvailabilityGroup = $ag.Name
453+ Replica = $databaseReplicaState.AvailabilityReplicaServerName
454+ Database = $databaseReplicaState.AvailabilityDatabaseName
455+ PolicyName = " Availability Database Suspension State"
456+ Category = " Warning"
457+ Facet = " Availability database"
458+ IsHealthy = $isHealthy
459+ Issue = if ($isHealthy ) { $null } else { " Availability database is suspended." }
460+ Details = " IsSuspended is $ ( $databaseReplicaState.IsSuspended ) "
461+ }
462+
463+ <#
464+ Availability database is not joined to the availability group
465+ Documentation: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/availability-database-is-not-joined
466+ Policy Name: Availability Database Join State
467+ Issue: Availability database is not joined to the availability group.
468+ Category: Warning
469+ Facet: Availability database
470+
471+ Name : AlwaysOnDbJoinedHealthCondition
472+ Facet : IAvailabilityDatabaseState
473+ ExpressionNode : @IsJoined = True()
474+ #>
475+
476+ $isHealthy = $databaseReplicaState.IsJoined
477+ [PSCustomObject ]@ {
478+ ComputerName = $ag.ComputerName
479+ InstanceName = $ag.InstanceName
480+ SqlInstance = $ag.SqlInstance
481+ AvailabilityGroup = $ag.Name
482+ Replica = $databaseReplicaState.AvailabilityReplicaServerName
483+ Database = $databaseReplicaState.AvailabilityDatabaseName
484+ PolicyName = " Availability Database Join State"
485+ Category = " Warning"
486+ Facet = " Availability database"
487+ IsHealthy = $isHealthy
488+ Issue = if ($isHealthy ) { $null } else { " Availability database is not joined to the availability group." }
489+ Details = " IsJoined is $ ( $databaseReplicaState.IsJoined ) "
490+ }
491+ }
297492 }
298493 }
299494}
0 commit comments