powershelldba.de

AlwaysOnSetup vs. Enable-SqlAlwaysOn and New-SqlAvailabilityGroup

PowerShell can create a SQL Server Availability Group. Microsoft ships the cmdlets for it. But "I ran the cmdlets" and "the AG is production-ready" are two different states, and the gap between them is where most manual AlwaysOn setups actually go wrong.

What the native cmdlets actually do

The SqlServer PowerShell module ships a real set of AlwaysOn cmdlets: Enable-SqlAlwaysOn, New-SqlAvailabilityGroup, New-SqlAvailabilityReplica, Join-SqlAvailabilityGroup, Add-SqlAvailabilityDatabase, and New-SqlAvailabilityGroupListener. Each one does exactly what its name says, and nothing more.

Enable-SqlAlwaysOn flips the feature on at the instance level and restarts the SQL Server service. It doesn't create an endpoint, doesn't check Windows Failover Clustering health, and doesn't touch Kerberos. That's still your job:

Enable-SqlAlwaysOn -ServerInstance "Node1" -Force

# The HADR endpoint is still T-SQL or SMO, not a single cmdlet:
Invoke-Sqlcmd -ServerInstance "Node1" -Query @"
CREATE ENDPOINT Hadr_endpoint
   STATE = STARTED
   AS TCP (LISTENER_PORT = 5022)
   FOR DATABASE_MIRRORING (ROLE = ALL, AUTHENTICATION = WINDOWS NEGOTIATE);
"@

New-SqlAvailabilityGroup -Name "ProdAG" -Path "SQLSERVER:\SQL\Node1\Default" `
    -AvailabilityReplica $replica1, $replica2 -Database "AppDB"

Each replica object in $replica1/$replica2 still has to be built first with New-SqlAvailabilityReplica, pointed at the right endpoint URL, and joined on every secondary with Join-SqlAvailabilityGroup. It works. It's also six or seven cmdlets deep before you've created a single listener, and none of them know about the failover cluster underneath the AG.

dbatools closes part of the gap

dbatools' New-DbaAvailabilityGroup is a genuine improvement: one call creates the endpoint, the AG, the replicas, and the database join in a single pipeline-friendly step. If you're scripting a new AG on a clean WSFC and want it in source control, this is usually the right tool, and it's what most PowerShell-based DBA automation is already built on.

What it still doesn't do: validate or register the SPNs the listener needs for Kerberos, detect and clean up leftover cluster resources from a previous failed attempt, or produce a run log you can hand to an auditor.

What AlwaysOnSetup adds on top

See it end to end The full nine-step sequence and what each error message actually means is in the AlwaysOnSetup documentation. For the raw T-SQL comparison rather than the cmdlet comparison, see AlwaysOn Setup: Traditional T-SQL vs. Automated PowerShell.

When the native cmdlets are the right call

If you already control SPN delegation, the WSFC is clean, and you're creating one AG as part of a scripted, version-controlled deployment, dbatools' New-DbaAvailabilityGroup is a fine choice and keeps the whole thing in a repo next to the rest of your infrastructure code. AlwaysOnSetup earns its keep in the messier, more common case: SPNs nobody delegated, a WSFC with history, and an audit trail somebody is actually going to ask for.

Questions people actually ask

Q: Does PowerShell have a built-in cmdlet that creates a complete AlwaysOn Availability Group in one call? Not from Microsoft's own SqlServer module. dbatools' New-DbaAvailabilityGroup comes closest, wrapping endpoint creation, AG creation, and replica join into one call. Neither one handles Kerberos SPNs or WSFC cleanup.
Q: Do I need to register SPNs manually before creating an AlwaysOn listener? Yes, unless something checks and registers them for you. Without the right SPNs on the listener's virtual computer object, clients connecting through the listener can fail with an ANONYMOUS LOGON error instead of Kerberos, even though the AG itself is healthy.
Q: Why does New-SqlAvailabilityGroup fail when I already ran it once and it errored out partway? Usually because the first attempt left cluster resources or a partially created endpoint behind. The native cmdlets don't detect or clean this up; you either clean the WSFC manually or use a tool that checks for it before retrying.