DSCResources/MSFT_xWaitForSqlHAGroup/MSFT_xWaitForSqlHAGroup.psm1
# # xWaitForSqlHAGroup: DSC resource to wait for existency of given name of Sql HA group, it checks the state of # the HA group with given interval until it exists or the number of retries is reached. # # # The Get-TargetResource cmdlet. # function Get-TargetResource { param ( [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Name, [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ClusterName, [UInt64] $RetryIntervalSec = 10, [UInt32] $RetryCount = 10, [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $InstanceName, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [PSCredential]$DomainCredential, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [PSCredential]$SqlAdministratorCredential ) $sa = $SqlAdministratorCredential.UserName $saPassword = $SqlAdministratorCredential.GetNetworkCredential().Password $bFound = Check-SQLHAGroup -InstanceName $InstanceName -Name $Name -sa $sa -saPassword $saPassword $returnValue = @{ Name = $Name InstanceName = $InstanceName RetryIntervalSec = $RetryIntervalSec RetryCount = $RetryCount HAGroupExist = $bFound } $returnValue } # # The Set-TargetResource cmdlet. # function Set-TargetResource { param ( [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Name, [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ClusterName, [UInt64] $RetryIntervalSec = 10, [UInt32] $RetryCount = 10, [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $InstanceName, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [PSCredential]$DomainCredential, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [PSCredential]$SqlAdministratorCredential ) $bFound = $false Write-Verbose -Message "Checking for SQL HA Group $Name on instance $InstanceName ..." $sa = $SqlAdministratorCredential.UserName $saPassword = $SqlAdministratorCredential.GetNetworkCredential().Password for ($count = 0; $count -lt $RetryCount; $count++) { $bFound = Check-SQLHAGroupExist -ClusterName $ClusterName -Name $Name -domainCred $DomainCredential -sa $sa -saPassword $saPassword if ($bFound) { Write-Verbose -Message "Found SQL HA Group $Name on instance $InstanceName" break; } else { Write-Verbose -Message "SQL HA Group $Name on instance $InstanceName not found. Will retry again after $RetryIntervalSec sec" Start-Sleep -Seconds $RetryIntervalSec } } if (!$bFound) { throw "SQL HA Group $Name on instance $InstanceName not found afater $count attempt with $RetryIntervalSec sec interval" } } # # The Test-TargetResource cmdlet. # function Test-TargetResource { param ( [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Name, [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ClusterName, [UInt64] $RetryIntervalSec = 10, [UInt32] $RetryCount = 10, [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $InstanceName, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [PSCredential]$DomainCredential, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [PSCredential]$SqlAdministratorCredential ) Write-Verbose -Message "Checking for SQL HA Group $Name on instance $InstanceName ..." $sa = $SqlAdministratorCredential.UserName $saPassword = $SqlAdministratorCredential.GetNetworkCredential().Password $bFound = Check-SQLHAGroup -InstanceName $InstanceName -Name $Name -sa $sa -saPassword $saPassword if ($bFound) { Write-Verbose -Message "Found SQL HA Group $Name on instance $InstanceName" $true } else { Write-Verbose -Message "SQL HA Group $Name on instance $InstanceName not found" $false } } function Check-SQLHAGroup($InstanceName, $Name, $sa, $saPassword) { $query = OSQL -S $InstanceName -U $sa -P $saPassword -Q "select count(name) from master.sys.availability_groups where name = '$Name'" -h-1 [bool] [int] $query[0].Trim() } function Check-SQLHAGroupExist($ClusterName, $Name, $sa, $saPassword, $domainCred) { $bHAGExist = $false try { ($oldToken, $context, $newToken) = ImpersonateAs -cred $domainCred $nodes = Get-ClusterNode -Cluster $ClusterName } finally { if ($context) { $context.Undo() $context.Dispose() CloseUserToken($newToken) } } foreach ($node in $nodes.Name) { $instance = Get-SQLInstanceName -node $node -InstanceName $InstanceName $bCheck = Check-SQLHAGroup -InstanceName $instance -Name $Name -sa $sa -saPassword $saPassword if ($bCheck) { $bHAGExist = $true break } } $bHAGExist } function Get-ImpersonatetLib { if ($script:ImpersonateLib) { return $script:ImpersonateLib } $sig = @' [DllImport("advapi32.dll", SetLastError = true)] public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("kernel32.dll")] public static extern Boolean CloseHandle(IntPtr hObject); '@ $script:ImpersonateLib = Add-Type -PassThru -Namespace 'Lib.Impersonation' -Name ImpersonationLib -MemberDefinition $sig return $script:ImpersonateLib } function ImpersonateAs([PSCredential] $cred) { [IntPtr] $userToken = [Security.Principal.WindowsIdentity]::GetCurrent().Token $userToken $ImpersonateLib = Get-ImpersonatetLib $bLogin = $ImpersonateLib::LogonUser($cred.GetNetworkCredential().UserName, $cred.GetNetworkCredential().Domain, $cred.GetNetworkCredential().Password, 9, 0, [ref]$userToken) if ($bLogin) { $Identity = New-Object Security.Principal.WindowsIdentity $userToken $context = $Identity.Impersonate() } else { throw "Can't Logon as User $cred.GetNetworkCredential().UserName." } $context, $userToken } function CloseUserToken([IntPtr] $token) { $ImpersonateLib = Get-ImpersonatetLib $bLogin = $ImpersonateLib::CloseHandle($token) if (!$bLogin) { throw "Can't close token" } } function Get-PureInstanceName ($InstanceName) { $list = $InstanceName.Split("\") if ($list.Count -gt 1) { $list[1] } else { "MSSQLSERVER" } } function Get-SQLInstanceName ($node, $InstanceName) { $pureInstanceName = Get-PureInstanceName -InstanceName $InstanceName if ("MSSQLSERVER" -eq $pureInstanceName) { $node } else { $node + "\" + $pureInstanceName } } Export-ModuleMember -Function *-TargetResource |