· Uwe Janke
Commands / Invoke-sqmPreferredPrimaryCheck

Invoke-sqmPreferredPrimaryCheck

Always OnsqmSQLTool v1.9.130+ · Invoke🔓 VIEW SERVER STATE + ALTER AVAILABILITY GROUP
After a patch weekend the AG usually sits on whichever node happened to be rebooted last. Where a specific node has to be the primary - for licensing, hardware, backup or monitoring reasons - this function is the watchdog: it compares the current primary against -PreferredReplica and, if they differ, performs a controlled failover back, but only when every safety check passes. If any check fails, nothing happens and the result object says exactly why.

The gates: the preferred replica is a member of the AG and currently SECONDARY; it runs in SYNCHRONOUS_COMMIT (a manual failover to an async replica would lose data, so such a replica is never failed over to automatically); all AG databases are joined on it, SYNCHRONIZED, ONLINE and not suspended; its redo queue is at or below -MaxRedoQueueMB; SQL Server on it has been up for at least -MinTargetUptimeMinutes (a node fresh from a reboot may still be mid-patch); the current primary has held its role for at least -MinRoleAgeMinutes (anti-flapping, keeps the watchdog out of an ongoing failover sequence); and the current time is inside -AllowedDay and -AllowedTimeStart..-AllowedTimeEnd if given.

The failover itself is delegated to Invoke-sqmFailover, so pre- and post-checks and the plain ALTER AVAILABILITY GROUP ... FAILOVER (manual, never forced) behave exactly like a hand-triggered failover. Nothing changes when the preferred replica is already primary, which is the normal case for nearly every run. Deploy it as a recurring job with New-sqmPreferredPrimaryJob.

Parameters

ParameterTypeRequiredDefaultNotes
-SqlInstancestringOptional$env:COMPUTERNAMEAny replica of the AG, used to read the current state. The function resolves the current primary itself, so this instance may be primary or secondary.
-SqlCredentialPSCredentialOptional, SQL or Windows credential. Without it: Windows authentication.
-AvailabilityGroupstringRequired, Name of the availability group to watch.
-PreferredReplicastringRequired, Instance that should hold the PRIMARY role, as it appears in sys.availability_replicas.replica_server_name. A host name with a DNS suffix is matched against the catalog name as well.
-MaxRedoQueueMBintOptional50Maximum redo queue on the preferred replica in MB. Above that, no failover is performed.
-MinRoleAgeMinutesintOptional15Minimum time the current primary must already have held its role. 0 disables the check. Read from current_configuration_commit_start_time_utc, an approximation that can only delay a switch back, never trigger a wrong one.
-MinTargetUptimeMinutesintOptional15Minimum uptime of the SQL Server service on the preferred replica. 0 disables the check.
-AllowedDaystring[]Optionalall daysWeekdays on which a switch back is allowed, e.g. Monday..Friday.
-AllowedTimeStartstring HH:mmOptional, Start of the daily window in which a switch back is allowed. Only together with -AllowedTimeEnd. The window may cross midnight.
-AllowedTimeEndstring HH:mmOptional, End of the daily window. Only together with -AllowedTimeStart.
-WaitAfterFailoverSecondsint (5-300)Optional30Wait before the post-check. Passed to Invoke-sqmFailover.
-CheckOnlyswitchSwitch$falseOnly check and report, never fail over. Use it to watch the watchdog for a few weeks before letting it act.
-FailOnBlockedswitchSwitch$falseReturn an error (failed Agent job step) when a failover would be needed but a gate blocked it. By default that is a WARNING in the log and the result object only, so a patch weekend does not turn every run red.
-EnableExceptionswitchSwitch$falseThrow exceptions immediately instead of writing an error and returning a result object.
-WhatIf / -ConfirmswitchSwitchConfirmImpact = High-WhatIf shows whether a switch back would happen right now, without touching anything.

Execution Flow

START dbatools installed? NO throw: dbatools not found YES Resolve the current primary of -AvailabilityGroup Read from -SqlInstance, whichever role that replica currently holds Preferred replica already PRIMARY? YES Nothing to do The normal case for nearly every run NO SYNCHRONOUS_COMMIT and all databases SYNCHRONIZED? NO Blocked - no failover An async replica is never failed over to automatically: that would lose data YES Redo queue and uptime gates passed? NO Blocked - no failover -MaxRedoQueueMB: too much redo -MinTargetUptimeMinutes: still mid-patch? -MinRoleAgeMinutes: anti-flapping YES Inside -AllowedDay / -AllowedTimeStart..End? NO Outside the window - postponed e.g. not during the patch weekend YES -CheckOnly? YES Report only Full gate evaluation, never a failover NO Invoke-sqmFailover (manual, never forced) Plain ALTER AVAILABILITY GROUP ... FAILOVER with the usual pre-/post-checks Post-check after -WaitAfterFailoverSeconds Return [PSCustomObject] AvailabilityGroup · CurrentPrimary · PreferredReplica · Action Blocked reason · gate results · failover outcome DONE

Examples

Would a switch back happen right now?
Invoke-sqmPreferredPrimaryCheck -AvailabilityGroup 'AG_Prod' -PreferredReplica 'SQL01' -WhatIf
Full check including every safety gate, reported only
Invoke-sqmPreferredPrimaryCheck -AvailabilityGroup 'AG_Prod' -PreferredReplica 'SQL01' -CheckOnly
Switch back only during the week and inside working hours
Invoke-sqmPreferredPrimaryCheck -AvailabilityGroup 'AG_Prod' -PreferredReplica 'SQL01' -AllowedDay Monday,Tuesday,Wednesday,Thursday,Friday -AllowedTimeStart '06:00' -AllowedTimeEnd '20:00'
Tighter redo-queue limit, longer anti-flapping window
Invoke-sqmPreferredPrimaryCheck -AvailabilityGroup 'AG_Prod' -PreferredReplica 'SQL01' -MaxRedoQueueMB 10 -MinRoleAgeMinutes 60