DSCResources/MSFT_xExchActiveSyncVirtualDirectory/MSFT_xExchActiveSyncVirtualDirectory.psm1

function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $Identity,

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

        [Parameter()]
        [System.Boolean]
        $AllowServiceRestart = $false,

        [Parameter()]
        [System.Boolean]
        $AutoCertBasedAuth = $false,

        [Parameter()]
        [System.String]
        $AutoCertBasedAuthThumbprint,

        [Parameter()]
        [System.String[]]
        $AutoCertBasedAuthHttpsBindings = @('0.0.0.0:443', '127.0.0.1:443'),

        [Parameter()]
        [System.String]
        $ActiveSyncServer,

        [Parameter()]
        [System.Boolean]
        $BadItemReportingEnabled,

        [Parameter()]
        [System.Boolean]
        $BasicAuthEnabled,

        [Parameter()]
        [ValidateSet('Ignore', 'Accepted', 'Required')]
        [System.String]
        $ClientCertAuth,

        [Parameter()]
        [System.Boolean]
        $CompressionEnabled,

        [Parameter()]
        [System.String]
        $DomainController,

        [Parameter()]
        [ValidateSet('None', 'Proxy', 'NoServiceNameCheck', 'AllowDotlessSpn', 'ProxyCohosting')]
        [System.String[]]
        $ExtendedProtectionFlags,

        [Parameter()]
        [System.String[]]
        $ExtendedProtectionSPNList,

        [Parameter()]
        [ValidateSet('None', 'Allow', 'Require')]
        [System.String]
        $ExtendedProtectionTokenChecking,

        [Parameter()]
        [System.String[]]
        $ExternalAuthenticationMethods,

        [Parameter()]
        [System.String]
        $ExternalUrl,

        [Parameter()]
        [System.Boolean]
        $InstallIsapiFilter,

        [Parameter()]
        [System.String[]]
        $InternalAuthenticationMethods,

        [Parameter()]
        [System.String]
        $InternalUrl,

        [Parameter()]
        [System.String]
        $MobileClientCertificateAuthorityURL,

        [Parameter()]
        [System.Boolean]
        $MobileClientCertificateProvisioningEnabled,

        [Parameter()]
        [System.String]
        $MobileClientCertTemplateName,

        [Parameter()]
        [System.String]
        $Name,

        [Parameter()]
        [ValidateSet('Allow', 'Block')]
        [System.String]
        $RemoteDocumentsActionForUnknownServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsAllowedServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsBlockedServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsInternalDomainSuffixList,

        [Parameter()]
        [System.Boolean]
        $SendWatsonReport,

        [Parameter()]
        [System.Boolean]
        $WindowsAuthEnabled
    )

    Write-Verbose -Message 'Getting the Exchange ActiveSyncVirtualDirectory settings'

    Write-FunctionEntry -Parameters @{
        'Identity' = $Identity
    } -Verbose:$VerbosePreference

    # Establish remote PowerShell session
    Get-RemoteExchangeSession -Credential $Credential -CommandsToLoad 'Get-ActiveSyncVirtualDirectory' -Verbose:$VerbosePreference

    $easVdir = Get-ActiveSyncVirtualDirectoryInternal @PSBoundParameters

    if ($null -ne $easVdir)
    {
        $returnValue = @{
            Identity                                   = [System.String] $Identity
            ActiveSyncServer                           = [System.String] $easVdir.ActiveSyncServer
            BadItemReportingEnabled                    = [System.Boolean] $easVdir.BadItemReportingEnabled
            BasicAuthEnabled                           = [System.Boolean] $easVdir.BasicAuthEnabled
            ClientCertAuth                             = [System.String] $easVdir.ClientCertAuth
            CompressionEnabled                         = [System.Boolean] $easVdir.CompressionEnabled
            ExtendedProtectionFlags                    = [System.String[]] $easVdir.ExtendedProtectionFlags
            ExtendedProtectionSPNList                  = [System.String[]] $easVdir.ExtendedProtectionSPNList
            ExtendedProtectionTokenChecking            = [System.String] ($easVdir.ExtendedProtectionTokenChecking)
            ExternalAuthenticationMethods              = [System.String[]] $easVdir.ExternalAuthenticationMethods
            ExternalUrl                                = [System.String] $easVdir.ExternalUrl.AbsoluteUri
            InstallIsapiFilter                         = [System.Boolean] (Test-ISAPIFilter)
            InternalAuthenticationMethods              = [System.String[]] $easVdir.InternalAuthenticationMethods
            InternalUrl                                = [System.String] $easVdir.InternalUrl.AbsoluteUri
            MobileClientCertificateAuthorityURL        = [System.String] $easVdir.MobileClientCertificateAuthorityURL
            MobileClientCertificateProvisioningEnabled = [System.Boolean] $easVdir.MobileClientCertificateProvisioningEnabled
            MobileClientCertTemplateName               = [System.String] $easVdir.MobileClientCertTemplateName
            Name                                       = [System.String] $easVdir.Name
            RemoteDocumentsActionForUnknownServers     = [System.String] $easVdir.RemoteDocumentsActionForUnknownServers
            RemoteDocumentsAllowedServers              = [System.String[]] $easVdir.RemoteDocumentsAllowedServers
            RemoteDocumentsBlockedServers              = [System.String[]] $easVdir.RemoteDocumentsBlockedServers
            RemoteDocumentsInternalDomainSuffixList    = [System.String[]] $easVdir.RemoteDocumentsInternalDomainSuffixList
            SendWatsonReport                           = [System.Boolean] $easVdir.SendWatsonReport
            WindowsAuthEnabled                         = [System.Boolean] $easVdir.WindowsAuthEnabled
        }
    }

    $returnValue
}

function Set-TargetResource
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $Identity,

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

        [Parameter()]
        [System.Boolean]
        $AllowServiceRestart = $false,

        [Parameter()]
        [System.Boolean]
        $AutoCertBasedAuth = $false,

        [Parameter()]
        [System.String]
        $AutoCertBasedAuthThumbprint,

        [Parameter()]
        [System.String[]]
        $AutoCertBasedAuthHttpsBindings = @('0.0.0.0:443', '127.0.0.1:443'),

        [Parameter()]
        [System.String]
        $ActiveSyncServer,

        [Parameter()]
        [System.Boolean]
        $BadItemReportingEnabled,

        [Parameter()]
        [System.Boolean]
        $BasicAuthEnabled,

        [Parameter()]
        [ValidateSet('Ignore', 'Accepted', 'Required')]
        [System.String]
        $ClientCertAuth,

        [Parameter()]
        [System.Boolean]
        $CompressionEnabled,

        [Parameter()]
        [System.String]
        $DomainController,

        [Parameter()]
        [ValidateSet('None', 'Proxy', 'NoServiceNameCheck', 'AllowDotlessSpn', 'ProxyCohosting')]
        [System.String[]]
        $ExtendedProtectionFlags,

        [Parameter()]
        [System.String[]]
        $ExtendedProtectionSPNList,

        [Parameter()]
        [ValidateSet('None', 'Allow', 'Require')]
        [System.String]
        $ExtendedProtectionTokenChecking,

        [Parameter()]
        [System.String[]]
        $ExternalAuthenticationMethods,

        [Parameter()]
        [System.String]
        $ExternalUrl,

        [Parameter()]
        [System.Boolean]
        $InstallIsapiFilter,

        [Parameter()]
        [System.String[]]
        $InternalAuthenticationMethods,

        [Parameter()]
        [System.String]
        $InternalUrl,

        [Parameter()]
        [System.String]
        $MobileClientCertificateAuthorityURL,

        [Parameter()]
        [System.Boolean]
        $MobileClientCertificateProvisioningEnabled,

        [Parameter()]
        [System.String]
        $MobileClientCertTemplateName,

        [Parameter()]
        [System.String]
        $Name,

        [Parameter()]
        [ValidateSet('Allow', 'Block')]
        [System.String]
        $RemoteDocumentsActionForUnknownServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsAllowedServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsBlockedServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsInternalDomainSuffixList,

        [Parameter()]
        [System.Boolean]
        $SendWatsonReport,

        [Parameter()]
        [System.Boolean]
        $WindowsAuthEnabled
    )

    Write-Verbose -Message 'Setting the Exchange ActiveSyncVirtualDirectory settings'

    Write-FunctionEntry -Parameters @{
        'Identity' = $Identity
    } -Verbose:$VerbosePreference

    # Establish remote PowerShell session
    Get-RemoteExchangeSession -Credential $Credential -CommandsToLoad 'Set-ActiveSyncVirtualDirectory' -Verbose:$VerbosePreference

    # Ensure an empty string is $null and not a string
    Set-EmptyStringParamsToNull -PSBoundParametersIn $PSBoundParameters

    # Remove Credential and AllowServiceRestart because those parameters do not exist on Set-ActiveSyncVirtualDirectory
    Remove-FromPSBoundParametersUsingHashtable -PSBoundParametersIn $PSBoundParameters -ParamsToRemove 'Credential', 'AllowServiceRestart', 'AutoCertBasedAuth', 'AutoCertBasedAuthThumbprint', 'AutoCertBasedAuthHttpsBindings'

    # Verify SPNs depending on AllowDotlesSPN
    if ( -not (Test-ExtendedProtectionSPNList -SPNList $ExtendedProtectionSPNList -Flags $ExtendedProtectionFlags))
    {
        throw 'SPN list contains DotlesSPN, but AllowDotlessSPN is not added to ExtendedProtectionFlags or invalid combination was used!'
    }

    # Configure everything but CBA
    Set-ActiveSyncVirtualDirectory @PSBoundParameters

    if ($AutoCertBasedAuth)
    {
        # Need to configure CBA
        Test-PreReqsForCertBasedAuth

        if (-not ([System.String]::IsNullOrEmpty($AutoCertBasedAuthThumbprint)))
        {
            Enable-CertBasedAuth -AutoCertBasedAuthThumbprint $AutoCertBasedAuthThumbprint -AutoCertBasedAuthHttpsBindings $AutoCertBasedAuthHttpsBindings
        }
        else
        {
            throw 'AutoCertBasedAuthThumbprint must be specified when AutoCertBasedAuth is set to true'
        }

        if ($AllowServiceRestart)
        {
            # Need to restart all of IIS for auth settings to stick
            Write-Verbose -Message 'Restarting IIS'

            iisreset /noforce /timeout:300
        }
        else
        {
            Write-Warning -Message 'The configuration will not take effect until IISReset /noforce is run.'
        }
    }

    # Only bounce the app pool if we didn't already restart IIS for CBA
    if (-not $AutoCertBasedAuth)
    {
        if ($AllowServiceRestart)
        {
            Write-Verbose -Message 'Recycling MSExchangeSyncAppPool'

            Restart-ExistingAppPool -Name MSExchangeSyncAppPool
        }
        else
        {
            Write-Warning -Message 'The configuration will not take effect until MSExchangeSyncAppPool is manually recycled.'
        }
    }

    # Install IsapiFilter manually as workaround as Exchange Cmdlet doesn't do it
    if ($InstallIsapiFilter)
    {
        if (-not (Test-ISAPIFilter))
        {
            Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
                -Location 'Default Web Site' `
                -Filter 'system.webServer/isapiFilters' `
                -Name '.' `
                -value @{
                    name = 'Exchange ActiveSync ISAPI Filter'
                    path = "$env:ExchangeInstallPath\FrontEnd\HttpProxy\bin\AirFilter.dll"
                }
        }
    }
}

function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $Identity,

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

        [Parameter()]
        [System.Boolean]
        $AllowServiceRestart = $false,

        [Parameter()]
        [System.Boolean]
        $AutoCertBasedAuth = $false,

        [Parameter()]
        [System.String]
        $AutoCertBasedAuthThumbprint,

        [Parameter()]
        [System.String[]]
        $AutoCertBasedAuthHttpsBindings = @('0.0.0.0:443', '127.0.0.1:443'),

        [Parameter()]
        [System.String]
        $ActiveSyncServer,

        [Parameter()]
        [System.Boolean]
        $BadItemReportingEnabled,

        [Parameter()]
        [System.Boolean]
        $BasicAuthEnabled,

        [Parameter()]
        [ValidateSet('Ignore', 'Accepted', 'Required')]
        [System.String]
        $ClientCertAuth,

        [Parameter()]
        [System.Boolean]
        $CompressionEnabled,

        [Parameter()]
        [System.String]
        $DomainController,

        [Parameter()]
        [ValidateSet('None', 'Proxy', 'NoServiceNameCheck', 'AllowDotlessSpn', 'ProxyCohosting')]
        [System.String[]]
        $ExtendedProtectionFlags,

        [Parameter()]
        [System.String[]]
        $ExtendedProtectionSPNList,

        [Parameter()]
        [ValidateSet('None', 'Allow', 'Require')]
        [System.String]
        $ExtendedProtectionTokenChecking,

        [Parameter()]
        [System.String[]]
        $ExternalAuthenticationMethods,

        [Parameter()]
        [System.String]
        $ExternalUrl,

        [Parameter()]
        [System.Boolean]
        $InstallIsapiFilter,

        [Parameter()]
        [System.String[]]
        $InternalAuthenticationMethods,

        [Parameter()]
        [System.String]
        $InternalUrl,

        [Parameter()]
        [System.String]
        $MobileClientCertificateAuthorityURL,

        [Parameter()]
        [System.Boolean]
        $MobileClientCertificateProvisioningEnabled,

        [Parameter()]
        [System.String]
        $MobileClientCertTemplateName,

        [Parameter()]
        [System.String]
        $Name,

        [Parameter()]
        [ValidateSet('Allow', 'Block')]
        [System.String]
        $RemoteDocumentsActionForUnknownServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsAllowedServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsBlockedServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsInternalDomainSuffixList,

        [Parameter()]
        [System.Boolean]
        $SendWatsonReport,

        [Parameter()]
        [System.Boolean]
        $WindowsAuthEnabled
    )

    Write-Verbose -Message 'Testing the Exchange ActiveSyncVirtualDirectory settings'

    Write-FunctionEntry -Parameters @{
        'Identity' = $Identity
    } -Verbose:$VerbosePreference

    # Establish remote PowerShell session
    Get-RemoteExchangeSession -Credential $Credential -CommandsToLoad 'Get-ActiveSyncVirtualDirectory' -Verbose:$VerbosePreference

    # Ensure an empty string is $null and not a string
    Set-EmptyStringParamsToNull -PSBoundParametersIn $PSBoundParameters

    $easVdir = Get-ActiveSyncVirtualDirectoryInternal @PSBoundParameters

    $testResults = $true

    if ($null -eq $easVdir)
    {
        Write-Error -Message 'Unable to retrieve ActiveSync Virtual Directory for server'

        $testResults = $false
    }
    else
    {
        if (-not (Test-ExchangeSetting -Name 'ActiveSyncServer' -Type 'String' -ExpectedValue $ActiveSyncServer -ActualValue $easVdir.ActiveSyncServer -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'BadItemReportingEnabled' -Type 'Boolean' -ExpectedValue $BadItemReportingEnabled -ActualValue $easVdir.BadItemReportingEnabled -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'BasicAuthEnabled' -Type 'Boolean' -ExpectedValue $BasicAuthEnabled -ActualValue $easVdir.BasicAuthEnabled -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'ClientCertAuth' -Type 'String' -ExpectedValue $ClientCertAuth -ActualValue $easVdir.ClientCertAuth -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'CompressionEnabled' -Type 'Boolean' -ExpectedValue $CompressionEnabled -ActualValue $easVdir.CompressionEnabled -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'ExtendedProtectionFlags' -Type 'ExtendedProtection' -ExpectedValue $ExtendedProtectionFlags -ActualValue $easVdir.ExtendedProtectionFlags -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'ExtendedProtectionSPNList' -Type 'Array' -ExpectedValue $ExtendedProtectionSPNList -ActualValue $easVdir.ExtendedProtectionSPNList -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'ExtendedProtectionTokenChecking' -Type 'String' -ExpectedValue $ExtendedProtectionTokenChecking -ActualValue $easVdir.ExtendedProtectionTokenChecking -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'ExternalAuthenticationMethods' -Type 'Array' -ExpectedValue $ExternalAuthenticationMethods -ActualValue $easVdir.ExternalAuthenticationMethods -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'ExternalUrl' -Type 'String' -ExpectedValue $ExternalUrl -ActualValue $easVdir.ExternalUrl.AbsoluteUri -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'InternalAuthenticationMethods' -Type 'Array' -ExpectedValue $InternalAuthenticationMethods -ActualValue $easVdir.InternalAuthenticationMethods -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'InternalUrl' -Type 'String' -ExpectedValue $InternalUrl -ActualValue $easVdir.InternalUrl.AbsoluteUri -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'MobileClientCertificateAuthorityURL' -Type 'String' -ExpectedValue $MobileClientCertificateAuthorityURL -ActualValue $easVdir.MobileClientCertificateAuthorityURL -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'MobileClientCertificateProvisioningEnabled' -Type 'Boolean' -ExpectedValue $MobileClientCertificateProvisioningEnabled -ActualValue $easVdir.MobileClientCertificateProvisioningEnabled -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'MobileClientCertTemplateName' -Type 'String' -ExpectedValue $MobileClientCertTemplateName -ActualValue $easVdir.MobileClientCertTemplateName -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'Name' -Type 'String' -ExpectedValue $Name -ActualValue $easVdir.Name -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'RemoteDocumentsActionForUnknownServers' -Type 'String' -ExpectedValue $RemoteDocumentsActionForUnknownServers -ActualValue $easVdir.RemoteDocumentsActionForUnknownServers -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'RemoteDocumentsAllowedServers' -Type 'Array' -ExpectedValue $RemoteDocumentsAllowedServers -ActualValue $easVdir.RemoteDocumentsAllowedServers -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'RemoteDocumentsBlockedServers' -Type 'Array' -ExpectedValue $RemoteDocumentsBlockedServers -ActualValue $easVdir.RemoteDocumentsBlockedServers -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'RemoteDocumentsInternalDomainSuffixList' -Type 'Array' -ExpectedValue $RemoteDocumentsInternalDomainSuffixList -ActualValue $easVdir.RemoteDocumentsInternalDomainSuffixList -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'SendWatsonReport' -Type 'Boolean' -ExpectedValue $SendWatsonReport -ActualValue $easVdir.SendWatsonReport -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if (-not (Test-ExchangeSetting -Name 'WindowsAuthEnabled' -Type 'Boolean' -ExpectedValue $WindowsAuthEnabled -ActualValue $easVdir.WindowsAuthEnabled -PSBoundParametersIn $PSBoundParameters -Verbose:$VerbosePreference))
        {
            $testResults = $false
        }

        if ($AutoCertBasedAuth)
        {
            Test-PreReqsForCertBasedAuth

            if ([System.String]::IsNullOrEmpty($AutoCertBasedAuthThumbprint))
            {
                Write-InvalidSettingVerbose -SettingName 'AutoCertBasedAuthThumbprint' `
                    -ExpectedValue 'Not null or empty' `
                    -ActualValue '' `
                    -Verbose:$VerbosePreference
                $testResults = $false
            }
            elseif ($null -eq $AutoCertBasedAuthHttpsBindings -or $AutoCertBasedAuthHttpsBindings.Count -eq 0)
            {
                Write-InvalidSettingVerbose -SettingName 'AutoCertBasedAuthHttpsBindings' `
                    -ExpectedValue 'Not null or empty' `
                    -ActualValue '' `
                    -Verbose:$VerbosePreference
                $testResults = $false
            }
            elseif ((Test-CertBasedAuth -AutoCertBasedAuthThumbprint $AutoCertBasedAuthThumbprint -AutoCertBasedAuthHttpsBindings $AutoCertBasedAuthHttpsBindings) -eq $false)
            {
                Write-InvalidSettingVerbose -SettingName 'TestCertBasedAuth' `
                    -ExpectedValue $true `
                    -ActualValue $false `
                    -Verbose:$VerbosePreference
                $testResults = $false
            }
        }

        if ($InstallIsapiFilter)
        {
            if (-not (Test-ISAPIFilter))
            {
                Write-InvalidSettingVerbose -SettingName 'InstallIsapiFilter' -ExpectedValue $InstallIsapiFilter -ActualValue 'false' -Verbose:$VerbosePreference
                $testResults = $false
            }
        }
    }

    return $testResults
}

function Get-ActiveSyncVirtualDirectoryInternal
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $Identity,

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

        [Parameter()]
        [System.Boolean]
        $AllowServiceRestart = $false,

        [Parameter()]
        [System.Boolean]
        $AutoCertBasedAuth = $false,

        [Parameter()]
        [System.String]
        $AutoCertBasedAuthThumbprint,

        [Parameter()]
        [System.String[]]
        $AutoCertBasedAuthHttpsBindings = @('0.0.0.0:443', '127.0.0.1:443'),

        [Parameter()]
        [System.String]
        $ActiveSyncServer,

        [Parameter()]
        [System.Boolean]
        $BadItemReportingEnabled,

        [Parameter()]
        [System.Boolean]
        $BasicAuthEnabled,

        [Parameter()]
        [ValidateSet('Ignore', 'Accepted', 'Required')]
        [System.String]
        $ClientCertAuth,

        [Parameter()]
        [System.Boolean]
        $CompressionEnabled,

        [Parameter()]
        [System.String]
        $DomainController,

        [Parameter()]
        [ValidateSet('None', 'Proxy', 'NoServiceNameCheck', 'AllowDotlessSpn', 'ProxyCohosting')]
        [System.String[]]
        $ExtendedProtectionFlags,

        [Parameter()]
        [System.String[]]
        $ExtendedProtectionSPNList,

        [Parameter()]
        [ValidateSet('None', 'Allow', 'Require')]
        [System.String]
        $ExtendedProtectionTokenChecking,

        [Parameter()]
        [System.String[]]
        $ExternalAuthenticationMethods,

        [Parameter()]
        [System.String]
        $ExternalUrl,

        [Parameter()]
        [System.Boolean]
        $InstallIsapiFilter,

        [Parameter()]
        [System.String[]]
        $InternalAuthenticationMethods,

        [Parameter()]
        [System.String]
        $InternalUrl,

        [Parameter()]
        [System.String]
        $MobileClientCertificateAuthorityURL,

        [Parameter()]
        [System.Boolean]
        $MobileClientCertificateProvisioningEnabled,

        [Parameter()]
        [System.String]
        $MobileClientCertTemplateName,

        [Parameter()]
        [System.String]
        $Name,

        [Parameter()]
        [ValidateSet('Allow', 'Block')]
        [System.String]
        $RemoteDocumentsActionForUnknownServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsAllowedServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsBlockedServers,

        [Parameter()]
        [System.String[]]
        $RemoteDocumentsInternalDomainSuffixList,

        [Parameter()]
        [System.Boolean]
        $SendWatsonReport,

        [Parameter()]
        [System.Boolean]
        $WindowsAuthEnabled
    )

    Remove-FromPSBoundParametersUsingHashtable -PSBoundParametersIn $PSBoundParameters -ParamsToKeep 'Identity', 'DomainController'

    return (Get-ActiveSyncVirtualDirectory @PSBoundParameters)
}

function Enable-CertBasedAuth
{
    param
    (
        [Parameter()]
        [System.String]
        $AutoCertBasedAuthThumbprint,

        [Parameter()]
        [System.String[]]
        $AutoCertBasedAuthHttpsBindings = @('0.0.0.0:443', '127.0.0.1:443')
    )

    $appCmdExe = "$($env:SystemRoot)\System32\inetsrv\appcmd.exe"

    # Enable cert auth in IIS, and require SSL on the AS vdir
    $output = &$appCmdExe set config -section:system.webServer/security/authentication/clientCertificateMappingAuthentication /enabled:'True' /commit:apphost
    Write-Verbose -Message "$output"

    $output = &$appCmdExe set config 'Default Web Site' -section:system.webServer/security/authentication/clientCertificateMappingAuthentication /enabled:'True' /commit:apphost
    Write-Verbose -Message "$output"

    $output = &$appCmdExe set config 'Default Web Site/Microsoft-Server-ActiveSync' /section:access /sslFlags:'Ssl, SslNegotiateCert, SslRequireCert, Ssl128' /commit:apphost
    Write-Verbose -Message "$output"

    $output = &$appCmdExe set config 'Default Web Site/Microsoft-Server-ActiveSync' -section:system.webServer/security/authentication/clientCertificateMappingAuthentication /enabled:'True' /commit:apphost
    Write-Verbose -Message "$output"

    # Set DSMapperUsage to enabled on all the required SSL bindings
    $appId = '{4dc3e181-e14b-4a21-b022-59fc669b0914}' # The appId of all IIS applications

    foreach ($binding in $AutoCertBasedAuthHttpsBindings)
    {
        Enable-DSMapperUsage -IpPortCombo $binding -CertThumbprint $AutoCertBasedAuthThumbprint -AppId $appId
    }
}

function Test-CertBasedAuth
{
    param
    (
        [Parameter()]
        [System.String]
        $AutoCertBasedAuthThumbprint,

        [Parameter()]
        [System.String[]]
        $AutoCertBasedAuthHttpsBindings = @('0.0.0.0:443', '127.0.0.1:443')
    )

    $appCmdExe = "$($env:SystemRoot)\System32\inetsrv\appcmd.exe"

    $serverWideClientCertMappingAuth = &$appCmdExe list config -section:system.webServer/security/authentication/clientCertificateMappingAuthentication

    if (-not (Test-AppCmdOutputContainsString -AppCmdOutput $serverWideClientCertMappingAuth -SearchString "clientCertificateMappingAuthentication enabled=`"true`""))
    {
        return $false
    }

    $clientCertMappingAuth = &$appCmdExe list config 'Default Web Site' -section:system.webServer/security/authentication/clientCertificateMappingAuthentication

    if (-not (Test-AppCmdOutputContainsString -AppCmdOutput $clientCertMappingAuth -SearchString "clientCertificateMappingAuthentication enabled=`"true`""))
    {
        return $false
    }

    $asClientCertMappingAuth = &$appCmdExe list config 'Default Web Site/Microsoft-Server-ActiveSync' -section:system.webServer/security/authentication/clientCertificateMappingAuthentication

    if (-not (Test-AppCmdOutputContainsString -appCmdOutput $asClientCertMappingAuth -searchString "clientCertificateMappingAuthentication enabled=`"true`""))
    {
        return $false
    }

    $sslFlags = &$appCmdExe list config 'Default Web Site/Microsoft-Server-ActiveSync' /section:access

    if (-not (Test-AppCmdOutputContainsString -appCmdOutput $sslFlags -searchString "access sslFlags=`"Ssl, SslNegotiateCert, SslRequireCert, Ssl128`""))
    {
        return $false
    }

    $netshOutput = netsh.exe http show sslcert

    foreach ($binding in $AutoCertBasedAuthHttpsBindings)
    {
        if (-not (Test-NetshSslCertSetting -IpPort $binding -NetshSslCertOutput $netshOutput -SettingName 'DS Mapper Usage' -SettingValue 'Enabled'))
        {
            return $false
        }

        if (-not (Test-NetshSslCertSetting -IpPort $binding -NetshSslCertOutput $netshOutput -SettingName 'Certificate Hash' -SettingValue $AutoCertBasedAuthThumbprint))
        {
            return $false
        }

        if (-not (Test-NetshSslCertSetting -IpPort $binding -NetshSslCertOutput $netshOutput -SettingName 'Certificate Store Name' -SettingValue 'MY'))
        {
            return $false
        }
    }

    return $true
}

function Test-IsSslBinding
{
    param
    (
        [Parameter()]
        $NetshOutput
    )

    if ($null -ne $NetshOutput -and $NetshOutput.GetType().Name -eq 'Object[]')
    {
        for ($i = 0; $i -lt $NetshOutput.Count; $i++)
        {
            if ($NetshOutput[$i].Contains('IP:port'))
            {
                return $true
            }
        }
    }

    return $false
}

function Enable-DSMapperUsage
{
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $IpPortCombo,

        [Parameter(Mandatory = $true)]
        [System.String]
        $CertThumbprint,

        [Parameter(Mandatory = $true)]
        [System.String]
        $AppId
    )
    # See if a binding already exists, and if so, delete it
    $bindingOutput = netsh.exe http show sslcert ipport=$($IpPortCombo)

    if (Test-IsSslBinding $bindingOutput)
    {
        $output = netsh.exe http delete sslcert ipport=$($IpPortCombo)
        Write-Verbose -Message "$output"
    }

    # Add the binding back with new settings
    $output = netsh.exe http add sslcert ipport=$($IpPortCombo) certhash=$($CertThumbprint) appid=$($AppId) dsmapperusage=enable certstorename=MY
    Write-Verbose -Message "$output"
}

function Test-AppCmdOutputContainsString
{
    param
    (
        [Parameter()]
        $AppCmdOutput,

        [Parameter(Mandatory = $true)]
        [System.String]
        $SearchString
    )

    if ($null -ne $AppCmdOutput -and $AppCmdOutput.GetType().Name -eq 'Object[]')
    {
        foreach ($line in $AppCmdOutput)
        {
            if ($line.ToLower().Contains($SearchString.ToLower()))
            {
                return $true
            }
        }
    }

    return $false
}

function Test-NetshSslCertSetting
{
    param
    (
        [Parameter()]
        $NetshSslCertOutput,

        [Parameter(Mandatory = $true)]
        [System.String]
        $IpPort,

        [Parameter(Mandatory = $true)]
        [System.String]
        $SettingName,

        [Parameter(Mandatory = $true)]
        [System.String]
        $SettingValue
    )

    $SettingName = $SettingName.ToLower()
    $SettingValue = $SettingValue.ToLower()

    if ($null -ne $NetshSslCertOutput -and $NetshSslCertOutput.GetType().Name -eq 'Object[]')
    {
        $foundSetting = $false
        for ($i = 0; $i -lt $NetshSslCertOutput.Count -and -not $foundSetting; $i++)
        {
            if ($NetshSslCertOutput[$i].ToLower().Contains('ip:port') -and $NetshSslCertOutput[$i].Contains($IpPort))
            {
                $i++

                while ( -not $NetshSslCertOutput[$i].ToLower().Contains('ip:port') -and -not $foundSetting )
                {
                    if ($NetshSslCertOutput[$i].ToLower().Contains($SettingName))
                    {
                        $foundSetting = $true

                        if ($NetshSslCertOutput[$i].ToLower().Contains($SettingValue))
                        {
                            return $true
                        }
                    }

                    $i++
                }
            }
        }
    }

    return $false
}

# Ensures that required Certification Based Authentication prereqs are installed
function Test-PreReqsForCertBasedAuth
{
    $hasAllPreReqs = $true

    $webClientAuth = Get-WindowsFeature -Name Web-Client-Auth
    $webCertAuth = Get-WindowsFeature -Name Web-Cert-Auth

    if ($webClientAuth.InstallState -ne 'Installed')
    {
        $hasAllPreReqs = $false

        Write-Error -Message 'The Web-Client-Auth feature needs to be installed before the Auto Certification Based Authentication feature can be used'
    }

    if ($webCertAuth.InstallState -ne 'Installed')
    {
        $hasAllPreReqs = $false

        Write-Error -Message 'The Web-Cert-Auth feature needs to be installed before the Auto Certification Based Authentication feature can be used'
    }

    if ($hasAllPreReqs -eq $false)
    {
        throw 'Required Windows features need to be installed before the Auto Certification Based Authentication feature can be used'
    }
}

function Test-ISAPIFilter
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [Parameter()]
        [System.String]
        $WebSite = 'Default Web Site',

        [Parameter()]
        [System.String]
        $ISAPIFilterName = 'Exchange ActiveSync ISAPI Filter'
    )

    begin
    {
        $ReturnValue = $false

        $ISAPIFilters = Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
            -Location $WebSite `
            -Filter 'system.webServer/isapiFilters' `
            -Name '.'
    }
    process
    {
        if ($ISAPIFilters.Collection.Count -gt 0)
        {
            if ($ISAPIFilters.Collection.Name.Contains($ISAPIFilterName))
            {
                Write-Verbose -Message "Filter $($ISAPIFilterName) was found"
                $ReturnValue = $true
            }
        }
    }
    end
    {
        return $ReturnValue
    }
}

Export-ModuleMember -Function *-TargetResource