SharedResources/Src/ConfigSQLServer/xSQLServer/DSCResources/MSFT_xSQLAOGroupEnsure/MSFT_xSQLAOGroupEnsure.psm1 (290 lines of code) (raw):
$currentPath = Split-Path -Parent $MyInvocation.MyCommand.Path
Write-Verbose -Message "CurrentPath: $currentPath"
# Load Common Code
Import-Module $currentPath\..\..\xSQLServerHelper.psm1 -Verbose:$false -ErrorAction Stop
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([System.Collections.Hashtable])]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure,
[parameter(Mandatory = $true)]
[System.String]
$AvailabilityGroupName,
[System.String]
$SQLServer = $env:COMPUTERNAME,
[ValidateNotNull()]
[System.String]
$SQLInstanceName= "MSSQLSERVER",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential
)
if(!$SQL)
{
$SQL = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName
}
$vConfigured = Test-TargetResource -Ensure $Ensure -AvailabilityGroupName $AvailabilityGroupName -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName
$returnValue = @{
Ensure = $vConfigured
AvailabilityGroupName = $sql.AvailabilityGroups[$AvailabilityGroupName]
AvailabilityGroupNameListener = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityGroupListeners.name
AvailabilityGroupNameIP = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityGroupListeners.availabilitygrouplisteneripaddresses.IPAddress
AvailabilityGroupSubMask = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityGroupListeners.availabilitygrouplisteneripaddresses.SubnetMask
AvailabilityGroupPort = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityGroupListeners.portnumber
AvailabilityGroupNameDatabase = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityDatabases.name
BackupDirectory = ""
SQLServer = $SQLServer
SQLInstanceName = $SQLInstanceName
}
$returnValue
}
function Set-TargetResource
{
[CmdletBinding()]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure,
[parameter(Mandatory = $true)]
[System.String]
$AvailabilityGroupName,
[System.String]
$AvailabilityGroupNameListener = $AvailabilityGroupName,
[System.String[]]
$AvailabilityGroupNameIP,
[System.String[]]
$AvailabilityGroupSubMask,
[System.UInt32]
$AvailabilityGroupPort ="1433",
[ValidateSet("None","ReadOnly","ReadIntent")]
[System.String]
$ReadableSecondary="ReadOnly",
[ValidateSet("Primary","Secondary")]
[System.String]
$AutoBackupPrefernce ="Primary",
[System.String]
$SQLServer = $env:COMPUTERNAME,
[System.String]
$SQLInstanceName= "MSSQLSERVER",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential
)
$null = [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Smo')
$null = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended")
if(!$SQL)
{
$SQL = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName -SetupCredential $SetupCredential
}
if (($AvailabilityGroupNameIP -and !$AvailabilityGroupSubMask) -or (!$AvailabilityGroupNameIP -and $AvailabilityGroupSubMask))
{
Throw "AvailabilityGroupNameIP and AvailabilityGroupSubMask must both be passed for Static IP assignment."
Exit
}
Switch ($Ensure)
{
"Present"
{
Grant-ServerPerms -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName -AuthorizedUser "NT AUTHORITY\SYSTEM" -SetupCredential $SetupCredential
New-ListenerADObject -AvailabilityGroupNameListener $AvailabilityGroupNameListener -SetupCredential $SetupCredential
$FailoverCondition = 3
$HealthCheckTimeout = 30000
$ConnectionModeInPrimary ="AllowAllConnections"
$ConnectionModeInSecondaryRole = switch ($ReadableSecondary)
{
'None' {"AllowNoConnections"}
'ReadOnly' {"AllowAllConnections"}
'ReadIntent'{"AllowReadIntentConnectionsOnly"}
Default {"AllowAllConnections"}
}
#Get Servers participating in the cluster
#First two nodes will account for Syncronous Automatic Failover, Any additional will be Asyncronous
try
{
$nodes= Get-ClusterNode -cluster $sql.ClusterName -Verbose:$false | select -ExpandProperty name
$syncNodes = $nodes | Select-Object -First 2
$asyncNodes = $nodes | Select-Object -Skip 2
$availabilityGroup = New-Object -typename Microsoft.SqlServer.Management.Smo.AvailabilityGroup -ArgumentList $SQL, $AvailabilityGroupName
$availabilityGroup.AutomatedBackupPreference="Primary"
$availabilityGroup.FailureConditionLevel = $FailoverCondition
$availabilityGroup.HealthCheckTimeout =$HealthCheckTimeout
}
Catch
{
Throw "Failed to connect to Cluster Nodes from $sql.ClusterName"
Exit
}
#Loop through Sync nodes Create Replica Object Assign properties and add it to AvailabilityGroup
foreach ($node in $syncNodes)
{
Try
{
$Replica = New-Object -typename Microsoft.SqlServer.Management.Smo.AvailabilityReplica -ArgumentList $availabilityGroup, $node
$Replica.EndpointUrl = "TCP://$($node):5022"
$Replica.FailoverMode = [Microsoft.SqlServer.Management.Smo.AvailabilityReplicaFailoverMode]::Automatic
$Replica.AvailabilityMode = [Microsoft.SqlServer.Management.Smo.AvailabilityReplicaAvailabilityMode]::SynchronousCommit
#Backup Priority Gives the ability to set a priority of one secondany over another valid values are from 1 - 100
$Replica.BackupPriority = 50
$Replica.ConnectionModeInPrimaryRole = $ConnectionModeInPrimary
$replica.ConnectionModeInSecondaryRole = $ConnectionModeInSecondaryRole
$availabilityGroup.AvailabilityReplicas.Add($Replica)
}
Catch
{
Throw "Failed to add $Replica to the Availability Group $AvailabilityGroupName"
Exit
}
}
#Loop through ASync nodes Create Replica Object Assign properties and add it to AvailabilityGroup
foreach ($node in $AsyncNodes)
{
Try
{
$asyncReplica = New-Object -typename Microsoft.SqlServer.Management.Smo.AvailabilityReplica -ArgumentList $availabilityGroup, $node
$asyncReplica.EndpointUrl = "TCP://$($node):5022"
$asyncReplica.FailoverMode = [Microsoft.SqlServer.Management.Smo.AvailabilityReplicaFailoverMode]::Manual
$asyncReplica.AvailabilityMode = [Microsoft.SqlServer.Management.Smo.AvailabilityReplicaAvailabilityMode]::ASynchronousCommit
$asyncReplica.BackupPriority = 50
$asyncReplica.ConnectionModeInPrimaryRole = $ConnectionModeInPrimary
$asyncReplica.ConnectionModeInSecondaryRole = $ConnectionModeInSecondaryRole
$AvailabilityGroup.AvailabilityReplicas.Add($asyncReplica)
}
Catch
{
Write-Error "Failed to add $asyncReplica to the Availability Group $AvailabilityGroupName"
}
}
Try{
$AgListener = New-Object -typename Microsoft.SqlServer.Management.Smo.AvailabilityGroupListener -ArgumentList $AvailabilityGroup, $AvailabilityGroupNameListener
$AgListener.PortNumber =$AvailabilityGroupPort
}
Catch{
Write-Error -Message ((Get-Date -format yyyy-MM-dd_HH-mm-ss) + ": Failed to Create AG Listener Object");
}
If($AvailabilityGroupNameIP)
{
Foreach ($IP in $AvailabilityGroupNameIP)
{
$AgListenerIp = New-Object -typename Microsoft.SqlServer.Management.Smo.AvailabilityGroupListenerIPAddress -ArgumentList $AgListener
$AgListenerIp.IsDHCP = $false
$AgListenerIp.IPAddress = $IP
$AgListenerIp.SubnetMask = $AvailabilityGroupSubMask
$AgListener.AvailabilityGroupListenerIPAddresses.Add($AgListenerIp)
New-VerboseMessage -Message "Added Static IP $IP to $AvailabilityGroupNameListener..."
}
}
Else
{
#Utilize Dynamic IP since no Ip was passed
$AgListenerIp = New-Object -typename Microsoft.SqlServer.Management.Smo.AvailabilityGroupListenerIPAddress -ArgumentList $AgListener
$AgListenerIp.IsDHCP = $true
$AgListener.AvailabilityGroupListenerIPAddresses.Add($AgListenerIp)
New-VerboseMessage -Message "Added DynamicIP to $AvailabilityGroupNameListener..."
}
Try{
$AvailabilityGroup.AvailabilityGroupListeners.Add($AgListener);
}
Catch{
Throw "Failed to Add $AvailabilityGroupNameListener to $AvailabilityGroupName..."
Exit
}
#Add Availabilty Group to the SQL connection
Try{
$SQL.AvailabilityGroups.Add($availabilityGroup)
New-VerboseMessage -Message "Added $availabilityGroupName Availability Group to Connection"
}
Catch{
Throw "Unable to Add $AvailabilityGroup to $SQLServer\$SQLInstanceName"
Exit
}
#Create Availability Group
Try
{
$availabilityGroup.Create()
New-VerboseMessage -Message "Created Availability Group $availabilityGroupName"
}
Catch
{
Throw "Unable to Create $AvailabilityGroup on $SQLServer\$SQLInstanceName"
Exit
}
}
"Absent"
{
Try
{
$sql.AvailabilityGroups[$AvailabilityGroupName].Drop()
NNew-VerboseMessage -Message "Dropped $AvailabilityGroupName"
}
Catch{
Throw "Unable to Drop $AvailabilityGroup on $SQLServer\$SQLInstanceName"
}
}
}
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([System.Boolean])]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure,
[parameter(Mandatory = $true)]
[System.String]
$AvailabilityGroupName,
[System.String]
$AvailabilityGroupNameListener,
[System.String[]]
$AvailabilityGroupNameIP,
[System.String[]]
$AvailabilityGroupSubMask,
[System.UInt32]
$AvailabilityGroupPort,
[ValidateSet("None","ReadOnly","ReadIntent")]
[System.String]
$ReadableSecondary ="ReadOnly",
[ValidateSet("Primary","Secondary")]
[System.String]
$AutoBackupPrefernce="Primary",
[System.String]
$SQLServer = $env:COMPUTERNAME,
[System.String]
$SQLInstanceName= "MSSQLSERVER",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential
)
if(!$SQL)
{
$SQL = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName
}
Switch ($Ensure)
{
"Present"
{
$AGPresent=$sql.AvailabilityGroups.Contains($AvailabilityGroupName)
if ($AGPresent)
{$Return = $true}
else
{$Return = $false}
}
"Absent"
{
if(!$sql.AvailabilityGroups[$AvailabilityGroupName])
{$Return = $true}
else{$Return = $false}
}
}
$Return
}
Export-ModuleMember -Function *-TargetResource