DSCResources/MSFT_xExchDatabaseAvailabilityGroup/MSFT_xExchDatabaseAvailabilityGroup.psm1

function Get-TargetResource
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "")]
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Name,

        [parameter(Mandatory = $true)]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential,

        [parameter(Mandatory = $true)]
        [System.Int32]
        $AutoDagTotalNumberOfServers,

        [System.String]
        $AlternateWitnessDirectory,

        [System.String]
        $AlternateWitnessServer,

        [System.Boolean]
        $AutoDagAutoReseedEnabled,

        [System.Int32]
        $AutoDagDatabaseCopiesPerDatabase,

        [System.Int32]
        $AutoDagDatabaseCopiesPerVolume,

        [System.String]
        $AutoDagDatabasesRootFolderPath,

        [System.Boolean]
        $AutoDagDiskReclaimerEnabled,

        [System.Int32]
        $AutoDagTotalNumberOfDatabases,

        [System.String]
        $AutoDagVolumesRootFolderPath,

        [System.String[]]
        $DatabaseAvailabilityGroupIpAddresses,

        [ValidateSet("Off","DagOnly")]
        [System.String]
        $DatacenterActivationMode,

        [System.String]
        $DomainController,

        [ValidateSet("NTFS","ReFS")]
        [System.String]
        $FileSystem,

        [System.Boolean]
        $ManualDagNetworkConfiguration,

        [ValidateSet("Disabled","Enabled","InterSubnetOnly","SeedOnly")]
        [System.String]
        $NetworkCompression,

        [ValidateSet("Disabled","Enabled","InterSubnetOnly","SeedOnly")]
        [System.String]
        $NetworkEncryption,

        [System.Boolean]
        $ReplayLagManagerEnabled,

        [System.UInt16]
        $ReplicationPort,

        [System.Boolean]
        $SkipDagValidation,

        [System.String]
        $WitnessDirectory,

        [System.String]
        $WitnessServer
    )

    #Load helper module
    Import-Module "$((Get-Item -LiteralPath "$($PSScriptRoot)").Parent.Parent.FullName)\Misc\xExchangeCommon.psm1" -Verbose:0

    LogFunctionEntry -Parameters @{"Name" = $Name} -VerbosePreference $VerbosePreference

    #Establish remote Powershell session
    GetRemoteExchangeSession -Credential $Credential -CommandsToLoad "Get-DatabaseAvailabilityGroup" -VerbosePreference $VerbosePreference

    $dag = GetDatabaseAvailabilityGroup @PSBoundParameters

    if ($null -ne $dag)
    {
        $returnValue = @{
            Name = $Name
            AlternateWitnessDirectory = $dag.AlternateWitnessDirectory
            AlternateWitnessServer = $dag.AlternateWitnessServer
            AutoDagAutoReseedEnabled = $dag.AutoDagAutoReseedEnabled
            AutoDagDatabaseCopiesPerDatabase = $dag.AutoDagDatabaseCopiesPerDatabase
            AutoDagDatabaseCopiesPerVolume = $dag.AutoDagDatabaseCopiesPerVolume
            AutoDagDatabasesRootFolderPath = $dag.AutoDagDatabasesRootFolderPath
            AutoDagDiskReclaimerEnabled = $dag.AutoDagDiskReclaimerEnabled
            AutoDagTotalNumberOfDatabases = $dag.AutoDagTotalNumberOfDatabases
            AutoDagTotalNumberOfServers = $dag.AutoDagTotalNumberOfServers
            AutoDagVolumesRootFolderPath = $dag.AutoDagVolumesRootFolderPath
            DatabaseAvailabilityGroupIpAddresses = $dag.DatabaseAvailabilityGroupIpAddresses
            DatacenterActivationMode = $dag.DatacenterActivationMode
            ManualDagNetworkConfiguration = $dag.ManualDagNetworkConfiguration
            NetworkCompression = $dag.NetworkCompression
            NetworkEncryption = $dag.NetworkEncryption
            ReplayLagManagerEnabled = $dag.ReplayLagManagerEnabled
            ReplicationPort = $dag.ReplicationPort
            WitnessDirectory = $dag.WitnessDirectory
            WitnessServer = $dag.WitnessServer
        }

        $serverVersion = GetExchangeVersion

        if ($serverVersion -eq "2016")
        {
            $returnValue.Add("FileSystem", $dag.FileSystem)
        }
    }

    $returnValue
}

function Set-TargetResource
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "")]
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Name,

        [parameter(Mandatory = $true)]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential,

        [parameter(Mandatory = $true)]
        [System.Int32]
        $AutoDagTotalNumberOfServers,

        [System.String]
        $AlternateWitnessDirectory,

        [System.String]
        $AlternateWitnessServer,

        [System.Boolean]
        $AutoDagAutoReseedEnabled,

        [System.Int32]
        $AutoDagDatabaseCopiesPerDatabase,

        [System.Int32]
        $AutoDagDatabaseCopiesPerVolume,

        [System.String]
        $AutoDagDatabasesRootFolderPath,

        [System.Boolean]
        $AutoDagDiskReclaimerEnabled,

        [System.Int32]
        $AutoDagTotalNumberOfDatabases,

        [System.String]
        $AutoDagVolumesRootFolderPath,

        [System.String[]]
        $DatabaseAvailabilityGroupIpAddresses,

        [ValidateSet("Off","DagOnly")]
        [System.String]
        $DatacenterActivationMode,

        [System.String]
        $DomainController,

        [ValidateSet("NTFS","ReFS")]
        [System.String]
        $FileSystem,

        [System.Boolean]
        $ManualDagNetworkConfiguration,

        [ValidateSet("Disabled","Enabled","InterSubnetOnly","SeedOnly")]
        [System.String]
        $NetworkCompression,

        [ValidateSet("Disabled","Enabled","InterSubnetOnly","SeedOnly")]
        [System.String]
        $NetworkEncryption,

        [System.Boolean]
        $ReplayLagManagerEnabled,

        [System.UInt16]
        $ReplicationPort,

        [System.Boolean]
        $SkipDagValidation,

        [System.String]
        $WitnessDirectory,

        [System.String]
        $WitnessServer
    )

    #Load helper module
    Import-Module "$((Get-Item -LiteralPath "$($PSScriptRoot)").Parent.Parent.FullName)\Misc\xExchangeCommon.psm1" -Verbose:0

    LogFunctionEntry -Parameters @{"Name" = $Name} -VerbosePreference $VerbosePreference

    #Establish remote Powershell session
    GetRemoteExchangeSession -Credential $Credential -CommandsToLoad "Get-DatabaseAvailabilityGroup","Set-DatabaseAvailabilityGroup","New-DatabaseAvailabilityGroup" -VerbosePreference $VerbosePreference
  
    #Check for non-existent parameters in Exchange 2013
    RemoveVersionSpecificParameters -PSBoundParametersIn $PSBoundParameters -ParamName "FileSystem" -ResourceName "xExchDatabaseAvailabilityGroup" -ParamExistsInVersion "2016"

    SetEmptyStringParamsToNull -PSBoundParametersIn $PSBoundParameters

    $dag = GetDatabaseAvailabilityGroup @PSBoundParameters

    #We need to create the DAG
    if ($null -eq $dag)
    {
        #Create a copy of the original parameters
        $originalPSBoundParameters = @{} + $PSBoundParameters

        #Remove parameters that don't exist in New-DatabaseAvailabilityGroup
        RemoveParameters -PSBoundParametersIn $PSBoundParameters -ParamsToKeep "Name","DatabaseAvailabilityGroupIpAddresses","WitnessDirectory","WitnessServer","DomainController"

        #Create the DAG
        $dag = New-DatabaseAvailabilityGroup @PSBoundParameters

        if ($null -ne $dag)
        {
            #Add original props back
            AddParameters -PSBoundParametersIn $PSBoundParameters -ParamsToAdd $originalPSBoundParameters
        }
        else
        {
            throw "Failed to create new DAG."
        }
    }

    #Modify existing DAG
    if ($null -ne $dag)
    {
        #convert Name to Identity, and Remove Credential
        AddParameters -PSBoundParametersIn $PSBoundParameters -ParamsToAdd @{"Identity" = $PSBoundParameters["Name"]}
        RemoveParameters -PSBoundParametersIn $PSBoundParameters -ParamsToRemove "Name","Credential"

        #If not all members are in DAG yet, remove params that require them to be
        if ($dag.Servers.Count -lt $AutoDagTotalNumberOfServers)
        {
            if ($PSBoundParameters.ContainsKey("DatacenterActivationMode") -and $DatacenterActivationMode -like "DagOnly")
            {
                RemoveParameters -PSBoundParametersIn $PSBoundParameters -ParamsToRemove "DatacenterActivationMode"                
            }
        }

        Set-DatabaseAvailabilityGroup @PSBoundParameters
    }
}


function Test-TargetResource
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "")]
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Name,

        [parameter(Mandatory = $true)]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential,

        [parameter(Mandatory = $true)]
        [System.Int32]
        $AutoDagTotalNumberOfServers,

        [System.String]
        $AlternateWitnessDirectory,

        [System.String]
        $AlternateWitnessServer,

        [System.Boolean]
        $AutoDagAutoReseedEnabled,

        [System.Int32]
        $AutoDagDatabaseCopiesPerDatabase,

        [System.Int32]
        $AutoDagDatabaseCopiesPerVolume,

        [System.String]
        $AutoDagDatabasesRootFolderPath,

        [System.Boolean]
        $AutoDagDiskReclaimerEnabled,

        [System.Int32]
        $AutoDagTotalNumberOfDatabases,

        [System.String]
        $AutoDagVolumesRootFolderPath,

        [System.String[]]
        $DatabaseAvailabilityGroupIpAddresses,

        [ValidateSet("Off","DagOnly")]
        [System.String]
        $DatacenterActivationMode,

        [System.String]
        $DomainController,

        [ValidateSet("NTFS","ReFS")]
        [System.String]
        $FileSystem,

        [System.Boolean]
        $ManualDagNetworkConfiguration,

        [ValidateSet("Disabled","Enabled","InterSubnetOnly","SeedOnly")]
        [System.String]
        $NetworkCompression,

        [ValidateSet("Disabled","Enabled","InterSubnetOnly","SeedOnly")]
        [System.String]
        $NetworkEncryption,

        [System.Boolean]
        $ReplayLagManagerEnabled,

        [System.UInt16]
        $ReplicationPort,

        [System.Boolean]
        $SkipDagValidation,

        [System.String]
        $WitnessDirectory,

        [System.String]
        $WitnessServer
    )

    #Load helper module
    Import-Module "$((Get-Item -LiteralPath "$($PSScriptRoot)").Parent.Parent.FullName)\Misc\xExchangeCommon.psm1" -Verbose:0

    LogFunctionEntry -Parameters @{"Name" = $Name} -VerbosePreference $VerbosePreference

    #Establish remote Powershell session
    GetRemoteExchangeSession -Credential $Credential -CommandsToLoad "Get-DatabaseAvailabilityGroup" -VerbosePreference $VerbosePreference

    #Check for non-existent parameters in Exchange 2013
    RemoveVersionSpecificParameters -PSBoundParametersIn $PSBoundParameters -ParamName "FileSystem" -ResourceName "xExchDatabaseAvailabilityGroup" -ParamExistsInVersion "2016"

    $dag = GetDatabaseAvailabilityGroup @PSBoundParameters

    if ($null -eq $dag)
    {
        return $false
    }
    else
    {
        if (!(VerifySetting -Name "AlternateWitnessDirectory" -Type "String" -ExpectedValue $AlternateWitnessDirectory -ActualValue $dag.AlternateWitnessDirectory -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AlternateWitnessServer" -Type "String" -ExpectedValue $AlternateWitnessServer -ActualValue $dag.AlternateWitnessServer -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AutoDagAutoReseedEnabled" -Type "Boolean" -ExpectedValue $AutoDagAutoReseedEnabled -ActualValue $dag.AutoDagAutoReseedEnabled -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AutoDagDatabaseCopiesPerDatabase" -Type "Int" -ExpectedValue $AutoDagDatabaseCopiesPerDatabase -ActualValue $dag.AutoDagDatabaseCopiesPerDatabase -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AutoDagDatabaseCopiesPerVolume" -Type "Int" -ExpectedValue $AutoDagDatabaseCopiesPerVolume -ActualValue $dag.AutoDagDatabaseCopiesPerVolume -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AutoDagDatabasesRootFolderPath" -Type "String" -ExpectedValue $AutoDagDatabasesRootFolderPath -ActualValue $dag.AutoDagDatabasesRootFolderPath -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AutoDagDiskReclaimerEnabled" -Type "Boolean" -ExpectedValue $AutoDagDiskReclaimerEnabled -ActualValue $dag.AutoDagDiskReclaimerEnabled -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AutoDagTotalNumberOfDatabases" -Type "Int" -ExpectedValue $AutoDagTotalNumberOfDatabases -ActualValue $dag.AutoDagTotalNumberOfDatabases -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AutoDagTotalNumberOfServers" -Type "Int" -ExpectedValue $AutoDagTotalNumberOfServers -ActualValue $dag.AutoDagTotalNumberOfServers -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "AutoDagVolumesRootFolderPath" -Type "String" -ExpectedValue $AutoDagVolumesRootFolderPath -ActualValue $dag.AutoDagVolumesRootFolderPath -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "DatabaseAvailabilityGroupIpAddresses" -Type "Array" -ExpectedValue $DatabaseAvailabilityGroupIpAddresses -ActualValue $dag.DatabaseAvailabilityGroupIpAddresses -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "FileSystem" -Type "String" -ExpectedValue $FileSystem -ActualValue $dag.FileSystem -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "ManualDagNetworkConfiguration" -Type "Boolean" -ExpectedValue $ManualDagNetworkConfiguration -ActualValue $dag.ManualDagNetworkConfiguration -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "NetworkCompression" -Type "String" -ExpectedValue $NetworkCompression -ActualValue $dag.NetworkCompression -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "NetworkEncryption" -Type "String" -ExpectedValue $NetworkEncryption -ActualValue $dag.NetworkEncryption -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "ReplayLagManagerEnabled" -Type "Boolean" -ExpectedValue $ReplayLagManagerEnabled -ActualValue $dag.ReplayLagManagerEnabled -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        #Replication port only comes back correctly from Get-DatabaseAvailabilityGroup if it has been set when there is 1 or more servers in the DAG
        if ($dag.Servers.Count -gt 0)
        {
            if (!(VerifySetting -Name "ReplicationPort" -Type "Int" -ExpectedValue $ReplicationPort -ActualValue $dag.ReplicationPort -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
            {
                return $false
            }
        }
        
        if (!(VerifySetting -Name "WitnessDirectory" -Type "String" -ExpectedValue $WitnessDirectory -ActualValue $dag.WitnessDirectory -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        if (!(VerifySetting -Name "WitnessServer" -Type "String" -ExpectedValue $WitnessServer -ActualValue $dag.WitnessServer -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
        {
            return $false
        }

        #Verify these props only if all members are in the DAG
        if ($dag.Servers.Count -ge $AutoDagTotalNumberOfServers)
        {
            if (!(VerifySetting -Name "DatacenterActivationMode" -Type "String" -ExpectedValue $DatacenterActivationMode -ActualValue $dag.DatacenterActivationMode -PSBoundParametersIn $PSBoundParameters -VerbosePreference $VerbosePreference))
            {
                return $false
            }
        }
    }

    return $true
}

#Runs Get-DatabaseAvailabilityGroup, only specifying Identity, ErrorAction, and optionally DomainController
function GetDatabaseAvailabilityGroup
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [System.String]
        $Name,

        [parameter(Mandatory = $true)]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential,

        [parameter(Mandatory = $true)]
        [System.Int32]
        $AutoDagTotalNumberOfServers,

        [System.String]
        $AlternateWitnessDirectory,

        [System.String]
        $AlternateWitnessServer,

        [System.Boolean]
        $AutoDagAutoReseedEnabled,

        [System.Int32]
        $AutoDagDatabaseCopiesPerDatabase,

        [System.Int32]
        $AutoDagDatabaseCopiesPerVolume,

        [System.String]
        $AutoDagDatabasesRootFolderPath,

        [System.Boolean]
        $AutoDagDiskReclaimerEnabled,

        [System.Int32]
        $AutoDagTotalNumberOfDatabases,

        [System.String]
        $AutoDagVolumesRootFolderPath,

        [System.String[]]
        $DatabaseAvailabilityGroupIpAddresses,

        [ValidateSet("Off","DagOnly")]
        [System.String]
        $DatacenterActivationMode,

        [System.String]
        $DomainController,

        [ValidateSet("NTFS","ReFS")]
        [System.String]
        $FileSystem,

        [System.Boolean]
        $ManualDagNetworkConfiguration,

        [ValidateSet("Disabled","Enabled","InterSubnetOnly","SeedOnly")]
        [System.String]
        $NetworkCompression,

        [ValidateSet("Disabled","Enabled","InterSubnetOnly","SeedOnly")]
        [System.String]
        $NetworkEncryption,

        [System.Boolean]
        $ReplayLagManagerEnabled,

        [System.UInt16]
        $ReplicationPort,

        [System.Boolean]
        $SkipDagValidation,

        [System.String]
        $WitnessDirectory,

        [System.String]
        $WitnessServer
    )

    AddParameters -PSBoundParametersIn $PSBoundParameters -ParamsToAdd @{"Identity" = $PSBoundParameters["Name"]; "ErrorAction" = "SilentlyContinue"}
    RemoveParameters -PSBoundParametersIn $PSBoundParameters -ParamsToKeep "Identity","ErrorAction","DomainController"

    return (Get-DatabaseAvailabilityGroup @PSBoundParameters -Status)
}

Export-ModuleMember -Function *-TargetResource