DSCResources/MSFT_xWebConfigKeyValue/MSFT_xWebConfigKeyValue.psm1

# Load the Helper Module
Import-Module -Name "$PSScriptRoot\..\Helper.psm1"

# Localized messages
data LocalizedData
{
    # culture="en-US"
    ConvertFrom-StringData -StringData @'
        VerboseGetTargetPresent = MIMEType is present
        VerboseGetTargetAbsent = MIMEType is absent
'@

}

function Get-TargetResource
{
    <#
    .SYNOPSIS
        This will return a hashtable of results
    #>


    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [Parameter(Mandatory = $true)]
        [String] $WebsitePath,

        [Parameter(Mandatory = $true)]
        [ValidateSet('AppSettings')]
        [String] $ConfigSection,

        [Parameter(Mandatory = $true)]
        [String] $Key
    )

    $existingValue = Get-ItemValue -Key $Key `
                                   -IsAttribute $false `
                                   -WebsitePath $WebsitePath `
                                   -ConfigSection $ConfigSection
    if($null -eq $existingValue)
    {
        $existingValue = Get-ItemValue -Key $Key `
                                       -IsAttribute $true `
                                       -WebsitePath $WebsitePath `
                                       -ConfigSection $ConfigSection
    }

    if($existingValue.Length -eq 0)
    {
        Write-Verbose -Message $LocalizedData.VerboseGetTargetAbsent
         return @{
             Ensure = 'Absent'
             Key = $Key
             Value = $existingValue
        }
    }

    Write-Verbose -Message $LocalizedData.VerboseGetTargetPresent
    
    return @{
        Ensure = 'Present'
        Key = $Key
        Value = $existingValue

    }

}


function Set-TargetResource
{
    <#
    .SYNOPSIS
        This will set the desired state
    #>


    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [String] $WebsitePath,

        [Parameter(Mandatory = $true)]
        [ValidateSet('AppSettings')]
        [String] $ConfigSection,

        [ValidateSet('Present','Absent')]
        [String] $Ensure = 'Present',

        [Parameter(Mandatory = $true)]
        [String] $Key,

        [String] $Value,

        [Boolean] $IsAttribute
    )

    if($Ensure -eq 'Present')
    {
        $existingValue = Get-ItemValue -Key $Key `
                                       -IsAttribute $IsAttribute `
                                       -WebsitePath $WebsitePath `
                                       -ConfigSection $ConfigSection

        if((-not($IsAttribute -and `
                ($null -eq $existingValue)) -or `
                ($IsAttribute -and `
            ($existingValue.Length -eq 0))))
        {
            Add-Item -Key $Key `
                     -Value $Value `
                     -IsAttribute $IsAttribute `
                     -WebsitePath $WebsitePath `
                     -ConfigSection $ConfigSection
        }
        else
        {
            $propertyName ='Value'
            if($IsAttribute)
            {
                $propertyName = $Key
            }
            Edit-Item -PropertyName $propertyName `
                      -OldValue $existingValue `
                      -NewValue $Value `
                      -IsAttribute $IsAttribute `
                      -WebsitePath $WebsitePath `
                      -ConfigSection $ConfigSection
        }
    }
    else
    {
        Remove-Item -Key $Key `
                    -IsAttribute $IsAttribute `
                    -WebsitePath $WebsitePath `
                    -ConfigSection $ConfigSection
    }
}

function Test-TargetResource
{
    <#
    .SYNOPSIS
        This tests the desired state. If the state is not correct it will return $false.
        If the state is correct it will return $true
    #>

    
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [Parameter(Mandatory = $true)]
        [String] $WebsitePath,

        [Parameter(Mandatory = $true)]
        [ValidateSet('AppSettings')]
        [String] $ConfigSection,

        [ValidateSet('Present','Absent')]
        [String] $Ensure = 'Present',

        [Parameter(Mandatory = $true)]
        [String] $Key,

        [String] $Value,

        [Boolean] $IsAttribute
    )

    if(-not($PSBoundParameters.ContainsKey('IsAttribute')))
    {
        $IsAttribute = $false
    }

    $existingValue = Get-ItemValue -Key $Key `
                                   -IsAttribute $IsAttribute `
                                   -WebsitePath $WebsitePath `
                                   -ConfigSection $ConfigSection
    
    if($Ensure -eq 'Present')
    {
        if(-not($IsAttribute))
        {
            if(($null -eq $existingValue) -or ($existingValue -ne $Value))
            {
                return $false
            }
            else
            {
                return $true
            }
        }
        else
        {
            if(($existingValue.Length -eq 0) -or ($existingValue -ne $Value))
            {
                return $false
            }
            else
            {
                return $true
            }
        }
    }
    
    else
    {
        if(-not($IsAttribute))
        {
            if(($null -eq $existingValue))
            {
                return $true
            }
            else
            {
                return $false
            }
        }
        else
        {
            if(($existingValue.Length -eq 0))
            {
                return $true
            }
            else
            {
                return $false
            }
        }
    }
}

#region HelperFunctions

function Add-Item
{
    [CmdletBinding()]
    param
    
    (
        [String] $Key, 
    
        [String] $Value, 
    
        [Boolean] $IsAttribute, 
    
        [String] $WebsitePath, 
    
        [String] $ConfigSection
    )

    $defaultFilter = $ConfigSection

    $itemCollection = @{key=$Key;Value=$Value}

    if(-not($isAttribute))
    {
        Add-WebConfigurationProperty -Filter $DefaultFilter `
                                     -Name '.' `
                                     -Value $ItemCollection `
                                     -PSPath $WebsitePath
    }
    else
    {
        Set-WebConfigurationProperty -Filter $DefaultFilter `
                                     -PSPath $WebsitePath `
                                     -Name $Key `
                                     -Value $Value `
                                     -WarningAction Stop 
    }
}

function Edit-Item
{
    [CmdletBinding()]
    param
    (
        [String] $PropertyName, 
        
        [String] $OldValue, 
        
        [String] $NewValue, 
        
        [Boolean] $IsAttribute, 
        
        [String] $WebsitePath, 
        
        [String] $ConfigSection
    )

    $defaultFilter = $ConfigSection

    if(-not($IsAttribute))
    {
        $Filter= "$defaultFilter/add[@$propertyName=`'$oldValue`']"

        Set-WebConfigurationProperty -Filter $Filter `
                                     -PSPath $WebsitePath `
                                     -Name $PropertyName `
                                     -Value $NewValue `
                                     -WarningAction Stop
    }

    else
    {
        Set-WebConfigurationProperty -Filter $DefaultFilter `
                                     -PSPath $WebsitePath `
                                     -Name $PropertyName `
                                     -Value $NewValue `
                                     -WarningAction Stop
    }
}

function Remove-Item
{
    <#
    .NOTES
        This is a workaround to ensure if appSettings has no collection and we try to delete
        the only attribute, the entire node is not deleted.
        If we try removing the only attribute even if there is one collection item, the node
        is preserved. I am not able to find a way to do this using clear-webconfiguration alone.
    #>

    [CmdletBinding()]
    param
    (
        [String] $Key, 
    
        [Boolean] $IsAttribute, 
    
        [String] $WebsitePath, 
    
        [String] $ConfigSection
    )
    $defaultFilter = $ConfigSection

    if(-not($IsAttribute))
    {
        $Filter = "$defaultFilter/add[@key=`'$Key`']"

        Clear-WebConfiguration -Filter $Filter `
                               -PSPath $WebsitePath `
                               -WarningAction Stop
    }
    else
    {
        $Filter = "$defaultFilter/@$Key"


        Add-Item -Key 'dummyKey' `
                 -Value 'dummyValue' `
                 -IsAttribute $false `
                 -WebsitePath $WebsitePath `
                 -ConfigSection $ConfigSection

        clear-WebConfiguration -Filter $Filter `
                               -PSPath $WebsitePath `
                               -WarningAction Stop

        Remove-Item -Key 'dummyKey' `
                    -IsAttribute $false `
                    -WebsitePath $WebsitePath `
                    -ConfigSection $ConfigSection
    }
}

function Get-ItemValue
{
    [CmdletBinding()]
    param
    (
        [String] $Key, 
    
        [Boolean] $IsAttribute, 
    
        [String] $WebsitePath, 
    
        [String] $ConfigSection
    )
    
    # if not present, $Value.Value will be null
    $defaultFilter = $ConfigSection

    if(-not($IsAttribute))
    {
        $Filter = "$defaultFilter/add[@key=`'$Key`']"

        $Value = Get-WebConfigurationProperty -Filter $Filter `
                                              -Name 'Value' `
                                              -PSPath $WebsitePath
 
    }
    else
    {
        $Value = Get-WebConfigurationProperty -Filter $DefaultFilter `
                                              -Name "$Key" `
                                              -PSPath $WebsitePath
    }
  
    return $Value.Value
}

#endregion

Export-ModuleMember -Function *-TargetResource