Public/SEPPmailAPI-Customer.ps1

<#
.SYNOPSIS
    Lists all SEPPmail customers (tenants) and their details.
.DESCRIPTION
    Retrieves all customers from the SEPPmail appliance with a GET request to the
    'customer' API endpoint. The list output is requested automatically and every
    returned customer is normalized (ISO-8859-1 Umlaut and DateTime conversion)
    before being emitted. Depending on the number of customers this may take a while.
.PARAMETER limit
    Maximum number of customers to return. Defaults to 0, which returns all entries.
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.OUTPUTS
    System.Management.Automation.PSCustomObject
        Returns one object per customer including all customer details.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Aliases: Find-SMACust, Find-SMATen.
.LINK
    Get-SMACustomer
.LINK
    New-SMACustomer
.LINK
    Set-SMACustomer
.LINK
    Remove-SMAcustomer
.EXAMPLE
    PS C:\> Find-SMACustomer
    Emits all customers and their details - may take some time.
.EXAMPLE
    PS C:\> Find-SMACustomer -limit 50
    Returns at most 50 customers.
#>

function Find-SMACustomer
{
    [CmdletBinding()]
    param (
        #region REST-API params
        [Parameter(Mandatory = $false)]
        [Int]$limit = 0,
        #endregion

        #region SMA Config param block
        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion,

        [Parameter(
         Mandatory=$false
         )]
        [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,
        [Parameter(
            Mandatory=$false
            )]
        [switch]$SMASkipCertCheck=$Script:activeCfg.SMAskipCertCheck
        #endregion
    )

    begin {
        if (!(verifyVars -VarList $Script:requiredVarList))
        {
            Throw($missingVarsMessage)
        }
        Write-verbose "Build Parameter hashtable"
        $boundParam = @{list=$true} #hardcode list output
        if ($limit -gt 0) {
            $boundParam.limit = $limit
        } else {
            Write-Verbose "No limit set, retrieving all entries"
            $boundParam.limit = 0
        }
    }
    process {
        Write-Verbose "Creating URL Path"
        $uriPath = 'customer'

        Write-Verbose "Build QueryString"
        $smaParams=@{
            Host=$SMAHost;
            Port=$SMAPort;
            Version=$SMAVersion;
        }; # end smaParams
        $uri = New-SMAQueryString -uriPath $uriPath -qParam $boundParam @smaParams;

        Write-verbose "Crafting InvokeParam for Invoke-SMARestMethod"
        $invokeParam = @{
            Uri         = $uri 
            Method      = 'GET'
            Cred        =  $SMACred
            SkipCertCheck = $SMASkipCertCheck
        }

        Write-Verbose "Call Invoke-SMARestMethod $uri" 
        $CustomerRaw = Invoke-SMARestMethod @invokeParam

        if ($customerRaw) {
        Write-Verbose 'Converting Umlauts from ISO-8859-1 and DateTime correctly'
            $customer = foreach ($c in $CustomerRaw) {ConvertFrom-SMAPIFormat -inputobject $c}
            return $customer
        }
        else {
            Write-Information 'Nothing to return'
        }

    }
    end {

    }

}

<#
.SYNOPSIS
    Gets the properties of a single SEPPmail customer.
.DESCRIPTION
    Reads the detailed properties of one existing customer with a GET request to the
    'customer/<name>' API endpoint. The returned data is normalized (ISO-8859-1 Umlaut
    conversion) before being emitted. Customer names are case-sensitive.
.PARAMETER name
    Name of the customer to read. Case-sensitive. Accepts pipeline input and must match
    the pattern [a-zA-Z0-9\-_].
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.OUTPUTS
    System.Management.Automation.PSCustomObject
        Returns the properties of the requested customer.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Customer names are case-sensitive.
    - Aliases: Get-SMACust, Get-SMATen.
.LINK
    Find-SMACustomer
.LINK
    New-SMACustomer
.LINK
    Set-SMACustomer
.LINK
    Remove-SMAcustomer
.EXAMPLE
    PS C:\> Get-SMACustomer -name 'Fabrikam'
    Get information about the SEPPmail customer 'Fabrikam'.
.EXAMPLE
    PS C:\> 'Contoso','Fabrikam'|Get-SMACustomer
    Use the pipeline to query multiple customers.
#>

function Get-SMACustomer
{
    [CmdletBinding()]
    param (
        [Parameter(
            Mandatory                       = $true,
            ValueFromPipeline               = $true,
            HelpMessage                     = 'Customer name (Case sensitive!)'
            )]
        [ValidatePattern('[a-zA-Z0-9\-_]')]
        [string]$name,

        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion,

        [Parameter(
            Mandatory=$false
            )]
            [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,

            [Parameter(
                Mandatory=$false
                )]
            [switch]$SMASkipCertCheck=$Script:activeCfg.SMAskipCertCheck
    )

    begin {
        if (! (verifyVars -VarList $Script:requiredVarList))
            {
                Throw($missingVarsMessage);
            }
    }
    process {
        Write-Verbose "Creating URL Path"
        $uriPath = "{0}/{1}" -f 'customer', $name

        Write-Verbose "Build QueryString"
        $smaParams=@{
            Host=$SMAHost;
            Port=$SMAPort;
            Version=$SMAVersion;
        }; # end smaParams
        $uri = New-SMAQueryString -uriPath $uriPath @smaParams;

        Write-verbose "Crafting Invokeparam for Invoke-SMARestMethod"
        $invokeParam = @{
            Uri         = $uri 
            Method      = 'GET'
            Cred        =  $SMACred
            SkipCertCheck = $SMASkipCertCheck
        }
        Write-Verbose "Call Invoke-SMARestMethod $uri" 
        $customerRaw = Invoke-SMARestMethod @invokeParam

        Write-Verbose 'Filter data and return as PSObject'
        $GetCustomer = $customerRaw.Psobject.properties.value

        # CustomerObject
        if ($customerRaw) {
            Write-Verbose 'Converting Umlauts from ISO-8859-1'
            $customer = ConvertFrom-SMAPIFormat -inputObject $GetCustomer
            return $customer
        }
        else {
            Write-Information 'Nothing to return'
        }
    }
    end {
    }
}

<#
.SYNOPSIS
    Creates a new SEPPmail customer.
.DESCRIPTION
    Creates a new customer with a POST request to the 'customer' API endpoint. Only the
    customer name is mandatory; all other properties are optional and sent in the request
    body when provided. On success the name of the created customer is returned.
.PARAMETER name
    Unique customer name. Mandatory. Accepts pipeline input and must match the pattern
    '^[a-zA-Z0-9\-_]+$|^\[(default|none)\]$'.
.PARAMETER adminEmail
    Customer admin E-Mail address.
.PARAMETER admins
    Array of the customer administrators uids (E-Mail addresses).
.PARAMETER backupPassword
    Backup password as a SecureString. Converted to plain text only inside the request body.
.PARAMETER comment
    Additional free-text comment.
.PARAMETER defaultGINADomain
    GINA domain to use when none is selected.
.PARAMETER deleteOldMessagesGracePeriod
    Grace period in days after which old GINA message metadata are automatically removed.
    Defaults to 0 (disabled). Alias: delMessGrace.
.PARAMETER deleteUnregistered
    Grace period in days after which unregistered GINA accounts are automatically removed.
    Defaults to 0 (disabled). Alias: delUnreg.
.PARAMETER description
    Customer display name / description.
.PARAMETER maximumEncryptionLicenses
    Maximum number of encryption licenses the users of this customer may consume.
.PARAMETER maximumLFTLicenses
    Maximum number of large file transfer licenses the users of this customer may consume.
.PARAMETER sendBackupToAdmin
    If $true, automatically sends the backup to the customer admin E-Mail.
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.OUTPUTS
    System.String
        Returns the name of the newly created customer as reported by the API.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Supports -WhatIf and -Confirm.
.LINK
    Get-SMACustomer
.LINK
    Find-SMACustomer
.LINK
    Set-SMACustomer
.LINK
    Remove-SMAcustomer
.EXAMPLE
    PS C:\> New-SMACustomer -Name 'Fabrikam'
    Create the customer 'Fabrikam' with default values.
.EXAMPLE
    PS C:\> New-SMACustomer -Name 'Fabrikam' -adminEmail admin@fabrikam.com
    Create the customer 'Fabrikam' and set the admin E-Mail address.
.EXAMPLE
    PS C:\> New-SMACustomer -Name 'Fabrikam' -admins @('admin@fabrikam.com','admin2@fabrikam.com')
    Create a new customer and set 2 admins by defining their E-Mail addresses.
.EXAMPLE
    PS C:\> $customerInfo = @{
        Name = 'Contoso'
        adminEmail = 'admin@contoso.com'
        admins = @('admin@contoso.com','admin2@contoso.com')
        backupPassword = 'someReallydifficultPassword'
        comment = 'Contoso is one of our most important clients'
        defaultGINADomain = 'ContosoMain'
        deleteOldMessagesGracePeriod = 30
        deleteUnregistered = 60
        description = 'Contoso Holding AG'
        maximumEncryptionLicenses = 5
        maximumLFTLicenses = 3
        sendBackupToAdmin = $true
    }
    PS C:\> New-SMACustomer @customerInfo
    Example of all parameters possible to create a customer using PowerShell parameter splatting.
#>

function New-SMACustomer
{
    [CmdletBinding(SupportsShouldProcess)]
    param (
        #region API params
        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromPipeline               = $true,
            HelpMessage                     = 'The customers unique name'
            )]
        [ValidatePattern('^[a-zA-Z0-9\-_]+$|^\[(default|none)\]$')]
        [string]$name,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Customers admin E-Mail address'
            )]
        [string]$adminEmail,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'The customers administrators uid´s as array'
            )]
        [string[]]$admins,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Backup password'
            )]
        [secureString]$backupPassword,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Some additional text'
            )]
        [string]$comment,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'GINA domain to use of none is selected'
            )]
        [string]$defaultGINADomain,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Grace period (in days) after which old GINA message metadata are automatically removed. Mails can still be decrypted by recipient if metadata is missing. (set to 0 to disable)'
            )]
        [Alias('delMessGrace')]
        [int]$deleteOldMessagesGracePeriod = 0,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Grace period (in days) after which unregistered GINA accounts are automatically removed (set to 0 to disable)'
            )]
        [Alias('delUnreg')]
        [int]$deleteUnregistered = 0,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Customers display name'
            )]
        [string]$description,

        <#[Parameter(
            Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = 'Add customer specific mail routes'
            )]
        [string[]]$mailRoutes,#>


        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'How many licenses may users of this customers consume for encryption ?'
            )]
        [int]$maximumEncryptionLicenses,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'How many licenses may users of this customers consume for elarge file transfer ?'
            )]
        [int]$maximumLFTLicenses,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Automatically send backup to Customer Admin E-mail'
            )]
        [bool]$sendBackupToAdmin,
        #endregion

        #region SMAParams
        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion,

        [Parameter(
            Mandatory=$false
            )]
        [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,

        [Parameter(
            Mandatory=$false
            )]
        [switch]$SMASkipCertCheck=$Script:activeCfg.SMAskipCertCheck
        #endregion
    )

    begin {
        if (! (verifyVars -VarList $Script:requiredVarList)){
            Throw($missingVarsMessage);
        }
        Write-Verbose "Creating URL path"
        $uriPath = "{0}" -f 'customer'
    
        Write-verbose "Crafting Invokeparam for Invoke-SMARestMethod"
        $smaParams=@{
            Host=$SMAHost;
            Port=$SMAPort;
            Version=$SMAVersion;
        }
        $uri = New-SMAQueryString -uriPath $uriPath @smaParams;
    }
    process {

        Write-Verbose 'Crafting mandatory $body JSON'
        $bodyHt = @{
            name = $name
        }
        $apiParams = @(
                        'adminEmail',
                        'admins',
                        'backupPassword',
                        'comment',
                        'defaultGINADomain',
                        'deleteOldMessagesGracePeriod',
                        'deleteUnregistered',
                        'description',
                        #'mailRoutes', #FIXME: waitfor explanaition
                        'maximumEncryptionLicenses',
                        'maximumLFTLicenses',
                        'sendBackupToAdmin'
                    )
        foreach ($param in $apiParams) {
            if ($PSBoundParameters.ContainsKey(($param))) {
                $bodyHt[$param] = $PSBoundParameters[$param]
            }
            if ($bodyHt.backupPassword) {$bodyHt.backupPassword = ConvertFrom-SecureString -SecureString $bodyHt.backupPassword -AsPlainText}
        }

        $body = $bodyHt|ConvertTo-JSON

        $invokeParam = @{
            Uri           = $uri 
            Method        = 'POST'
            body          = $body
            Cred          =  $SMACred
            SkipCertCheck = $SMASkipCertCheck
        }
        if ($PSCmdLet.ShouldProcess($($bodyHt.Name),"Create customer")) {
            Write-Verbose "Call Invoke-SMARestMethod $uri"
            $customerRaw = Invoke-SMARestMethod @invokeParam
    
            Write-Verbose 'Returning name of customer'
            ($customerRaw.message -split '\s+')[3]
        }
    }
    end {

    }
}

<#
.SYNOPSIS
    Modifies an existing SEPPmail customer.
.DESCRIPTION
    Updates an existing customer with a PUT request to the 'customer/<name>' API endpoint.
    The customer is identified by its name; only the provided properties are sent in the
    request body and changed. On success the name of the customer is returned.
.PARAMETER name
    Name of the customer to modify. Mandatory. Accepts pipeline input by property name and
    must match the pattern [a-zA-Z0-9\-_].
.PARAMETER adminEmail
    Customer admin E-Mail address(es).
.PARAMETER admins
    Array of the customer administrators uids (E-Mail addresses).
.PARAMETER backupPassword
    Backup password as a SecureString. Converted to plain text only inside the request body.
.PARAMETER comment
    Additional free-text comment.
.PARAMETER defaultGINADomain
    GINA domain to use when none is selected.
.PARAMETER deleteOldMessagesGracePeriod
    Grace period in days after which old GINA message metadata are automatically removed.
    Defaults to 0 (disabled). Alias: delMessGrace.
.PARAMETER deleteUnregistered
    Grace period in days after which unregistered GINA accounts are automatically removed.
    Defaults to 0 (disabled). Alias: delUnreg.
.PARAMETER description
    Customer's more detailed description.
.PARAMETER maximumEncryptionLicenses
    Maximum number of encryption licenses the users of this customer may consume.
.PARAMETER maximumLFTLicenses
    Maximum number of large file transfer licenses the users of this customer may consume.
.PARAMETER sendBackupToAdmin
    If $true, automatically sends the backup to the customer admin E-Mail.
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.OUTPUTS
    System.String
        Returns the name of the updated customer as reported by the API.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Aliases: Set-SMACust, Set-SMATen.
.LINK
    Get-SMACustomer
.LINK
    Find-SMACustomer
.LINK
    New-SMACustomer
.LINK
    Remove-SMAcustomer
.EXAMPLE
    PS C:\> Set-SMAcustomer -name 'Contoso' -description 'Contoso AG London'
    Change the description of Contoso.
.EXAMPLE
    PS C:\> $customerInfo = @{
        adminEmail = 'admin@contoso.com'
        admins = @('admin@contoso.com','admin2@contoso.com')
        backupPassword = 'someReallydifficultPassword'
        comment = 'Contoso is one of our most important clients'
        defaultGINADomain = 'ContosoMain'
        deleteOldMessagesGracePeriod = 30
        deleteUnregistered = 60
        description = 'Contoso Holding AG'
        maximumEncryptionLicenses = 10
        maximumLFTLicenses = 5
        sendBackupToAdmin = $true
    }
    PS C:\> Set-SMAcustomer -name 'Contoso' @customerInfo
    Change multiple values of a customer at once using PowerShell parameter splatting.
#>

function Set-SMACustomer
{
    [CmdletBinding()]
    param (
        #region API params
        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'The customers display name'
            )]
        [ValidatePattern('[a-zA-Z0-9\-_]')]
        [string]$name,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Customers admin E-Mail address(es)'
            )]
        [string]$adminEmail,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'The customers administrators uid´s as array'
            )]
        [string[]]$admins,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Backup password'
            )]
        [secureString]$backupPassword,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Some additional text'
            )]
        [string]$comment,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'GINA domain to use of none is selected'
            )]
        [string]$defaultGINADomain,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Grace period (in days) after which old GINA message metadata are automatically removed. Mails can still be decrypted by recipient if metadata is missing. (set to 0 to disable)'
            )]
        [Alias('delMessGrace')]
        [int]$deleteOldMessagesGracePeriod = 0,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Grace period (in days) after which unregistered GINA accounts are automatically removed (set to 0 to disable)'
            )]
        [Alias('delUnreg')]
        [int]$deleteUnregistered = 0,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Customers more detailed description'
            )]
        [string]$description,

        <#[Parameter(
            Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = '?????????????????'
            )]
        [string[]]$mailRoutes,#>


        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'How many licenses may users of this customers consume for encryption ?'
            )]
        [int]$maximumEncryptionLicenses,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'How many licenses may users of this customers consume for elarge file transfer ?'
            )]
        [int]$maximumLFTLicenses,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Automatically send backup to Customer Admin E-mail'
            )]
        [bool]$sendBackupToAdmin,
        #endregion

        #region SMAParams
        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion,

        [Parameter(
            Mandatory=$false
            )]
        [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,

        [Parameter(
            Mandatory=$false
            )]
        [switch]$SMASkipCertCheck=$Script:activeCfg.SMAskipCertCheck
        #endregion
    )

    begin {
        if (! (verifyVars -VarList $Script:requiredVarList))
        {
            Throw($missingVarsMessage);
        }
        $smaParams=@{
            Host=$SMAHost;
            Port=$SMAPort;
            Version=$SMAVersion;
        }
    }

    process {
        Write-Verbose "Creating URL path"
        $uriPath = "{0}/{1}" -f 'customer', $name

        Write-Verbose "Building full request uri"
        
        $uri = New-SMAQueryString -uriPath $uriPath @smaParams

        Write-Verbose 'Crafting empty $body JSON'
        $bodyht = @{}

        Write-Verbose 'Adding optional values to $body JSON'
        $apiParams = @(
                        'adminEmail',
                        'admins',
                        'backupPassword',
                        'comment',
                        'defaultGINADomain',
                        'deleteOldMessagesGracePeriod',
                        'deleteUnregistered',
                        'description',
                        #'mailRoutes', :FIXME:
                        'maximumEncryptionLicenses',
                        'maximumLFTLicenses',
                        'sendBackupToAdmin'
                    )
        foreach ($param in $apiParams) {
            if ($PSBoundParameters.ContainsKey($param)) {
                $bodyHt[$param] = $PSBoundParameters[$param]
            }
        }
        if ($bodyHt.backupPassword) {$bodyHt.backupPassword = ConvertFrom-SecureString -SecureString $bodyHt.backupPassword -AsPlainText}
        $body = $bodyHt|ConvertTo-JSON

        Write-verbose "Crafting Invokeparam for Invoke-SMARestMethod"
        $invokeParam = @{
            Uri         = $uri 
            Method      = 'PUT'
            body        = $body
            Cred        =  $SMACred
            SkipCertCheck = $SMASkipCertCheck
        }
        #debug $uri
        Write-Verbose "Call Invoke-SMARestMethod $uri"
        $customerRaw = Invoke-SMARestMethod @invokeParam

        #debug $customerraw
        if ($customerRaw) {
            $customer = ConvertFrom-SMAPIFormat -inputObject $customerRaw
            Write-Verbose 'Returning name of customer'    
            ($customer.message.split(' ')[3])
        }
    }

    end{

    }

}

<#
.SYNOPSIS
    Removes a SEPPmail customer.
.DESCRIPTION
    Deletes an existing customer with a DELETE request to the 'customer/<name>' API endpoint.
    The customer is identified by its name. Optional switches control which related objects
    (users, GINA users, admin users, managed domains, GINA domains, policies, smarthost
    credentials) are deleted along with the customer. On success the deletion details are
    returned.
.PARAMETER name
    Name of the customer to delete. Mandatory. Accepts pipeline input and must match the
    pattern [a-zA-Z0-9\-_]. (Parameter set 'Default')
.PARAMETER deleteUsers
    If set, deletes all related users of this customer. (Parameter set 'Default')
.PARAMETER deleteGINAUsers
    If set, deletes all related GINA users of this customer. (Parameter set 'Default')
.PARAMETER deleteAdminUsers
    If set, deletes all admin users of this customer. (Parameter set 'Default')
.PARAMETER deleteManagedDomains
    If set, deletes all managed domains related to this customer. (Parameter set 'Default')
.PARAMETER deleteGINADomains
    If set, deletes all GINA domains related to this customer. (Parameter set 'Default')
.PARAMETER deletePolicies
    If set, deletes all policies of this customer. (Parameter set 'Default')
.PARAMETER deleteSmarthostCredentials
    If set, deletes all smarthost credentials used EXCLUSIVELY by this customer.
    (Parameter set 'Default')
.PARAMETER deleteEverything
    If set, deletes everything related to this customer. (Parameter set 'DeleteAll')
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.OUTPUTS
    System.String
        Returns the deletion details reported by the API.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Supports -WhatIf and -Confirm.
    - Aliases: Remove-SMACust, Remove-SMATen.
.LINK
    Get-SMACustomer
.LINK
    Find-SMACustomer
.LINK
    New-SMACustomer
.LINK
    Set-SMACustomer
.EXAMPLE
    PS C:\> Remove-SMAcustomer -name 'Fabrikam'
    Delete a customer.
.EXAMPLE
    PS C:\> 'Contoso','Fabrikam'|Remove-SMAcustomer
    Delete customers by using the pipeline.
.EXAMPLE
    PS C:\> Remove-SMAcustomer -name 'Fabrikam' -WhatIf
    Simulate the customer deletion.
.EXAMPLE
    PS C:\> Remove-SMAcustomer -name 'Fabrikam' -deleteEverything
    Delete a customer together with all related objects.
#>

function Remove-SMAcustomer
{
    [CmdletBinding(DefaultParameterSetName = 'Default',SupportsShouldProcess)]
    param (
        #region API Params
        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromPipeline               = $true,
            ParameterSetName                = 'Default',
            Position                        = 0,
            HelpMessage                     = 'The customer´s name you want to delete'
            )]
        [ValidatePattern('[a-zA-Z0-9\-_]')]
        [string]$name,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Default',
            HelpMessage                     = 'If set, deletes all related users of this customer'
            )]
        [switch]$deleteUsers = $false,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Default',
            HelpMessage                     = 'If set, deletes all related GINA users of this customer'
            )]
        [switch]$deleteGINAUsers = $false,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Default',
            HelpMessage                     = 'If set, deletes all Admin Users of this customer'
            )]
        [switch]$deleteAdminUsers = $false,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Default',
            HelpMessage                     = 'If set, deletes all managed domains related to this customer'
            )]
        [switch]$deleteManagedDomains = $false,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Default',
            HelpMessage                     = 'If set, deletes all GINA domains related to this customer'
            )]
        [switch]$deleteGINADomains = $false,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Default',
            HelpMessage                     = 'If set, deletes all policies of this customer'
            )]
        [switch]$deletePolicies = $false,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Default',
            HelpMessage                     = 'If set, deletes all smarhost credentials used EXCLUSIVELY by this customer'
            )]
        [switch]$deleteSmarthostCredentials = $false,

        [Parameter(
            Mandatory                       = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'DeleteAll',
            HelpMessage                     = 'If set, deletes everything related to this customer'
            )]
        [switch]$deleteEverything = $false,
        #endregion

        #region SMAParams
        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion,

        [Parameter(
            Mandatory=$false
            )]
            [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,

            [Parameter(
                Mandatory=$false
                )]
            [switch]$SMASkipCertCheck=$Script:activeCfg.SMAskipCertCheck

    )

    begin {
        if (! (verifyVars -VarList $Script:requiredVarList))
        {
            Throw($missingVarsMessage);
        }
        $smaParams=@{
            Host=$SMAHost;
            Port=$SMAPort;
            Version=$SMAVersion;
        }

    }
    process {

        Write-Verbose "Creating URL path"
        $uriPath = "{0}/{1}" -f 'customer', $name

        Write-Verbose "Building param query"
        $boundParam = $psCmdLet.MyInvocation.BoundParameters
        $boundParam.Remove('name')|out-null
        $boundParam.Remove('whatif')|out-null
        
        Write-Verbose "Building full request uri"
        $uri = New-SMAQueryString -uriPath $uriPath -qParam $boundParam @smaParams;

        Write-verbose "Crafting Invokeparam for Invoke-SMARestMethod"
        $invokeParam = @{
            Uri         = $uri 
            Method      = 'DELETE'
            Cred        =  $SMACred
            SkipCertCheck = $SMASkipCertCheck
        }
        if ($PSCmdLet.ShouldProcess($name, "Remove customer")){
            Write-Verbose "Call Invoke-SMARestMethod $uri"
            # Wait-Debugger
            $customerRaw = Invoke-SMARestMethod @invokeParam
            $customer = ConvertFrom-SMAPIFormat -inputObject $customerRaw
            Write-Verbose 'Returning Delete details'
            return $customer.message.Split(' ')[3]
        }
    }
    end {

    }

}

<#
.SYNOPSIS
    Exports a SEPPmail customer and all its details to an encrypted ZIP file.
.DESCRIPTION
    Exports an existing customer with a POST request to the 'customer/<name>/export' API
    endpoint. The appliance returns the export as Base64 encoded ZIP data which is decoded
    and written to the local file system. The ZIP is encrypted with the supplied password.
    Customer names are case-sensitive. On success the full path of the written file is returned.
.PARAMETER name
    Name of the customer to export. Case-sensitive. Mandatory. Must match the pattern
    [a-zA-Z0-9\-_].
.PARAMETER encryptionPassword
    SecureString password used to encrypt the exported ZIP file. Mandatory.
.PARAMETER path
    Relative path for the ZIP file, e.g. .\contoso.zip. Mandatory in parameter set 'Path'.
.PARAMETER literalPath
    Literal path for the ZIP file, e.g. c:\temp\contoso.zip. Mandatory in parameter set
    'LiteralPath'.
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.OUTPUTS
    System.String
        Returns the full path of the written ZIP file.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Customer names are case-sensitive.
    - Aliases: Export-SMACust, Export-SMATen.
.LINK
    Import-SMACustomer
.LINK
    Get-SMACustomer
.LINK
    Find-SMACustomer
.EXAMPLE
    PS C:\> $backuppassword = ConvertTo-SecureString -String 'secretbackup' -AsPlainText -Force
    PS C:\> Export-SMACustomer -name 'Fabrikam' -encryptionpassword $backuppassword -path ..\Fabrikam.zip
    Export the customer Fabrikam to a local ZIP file in the parent folder using a relative path.
.EXAMPLE
    PS C:\> $backuppassword = ConvertTo-SecureString -String 'secretbackup' -AsPlainText -Force
    PS C:\> Export-SMACustomer -name 'Fabrikam' -encryptionpassword $backuppassword -literalpath c:\temp\Fabrikam.zip
    Export the customer Fabrikam to a local ZIP file using a literal path.
#>

function Export-SMACustomer
{
    [CmdletBinding(DefaultParameterSetName = 'Path')]
    param (
        #region API Params
        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Customer name (Case sensitive!)'
            )]
        [ValidatePattern('[a-zA-Z0-9\-_]')]
        [string]$name,

        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Password for encrypted ZIP'
            )]
        [SecureString]$encryptionPassword,

        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Path',
            HelpMessage                     = 'Relative Path for ZIP-File, i.e. .\contoso.zip'
            )]
        [string]$path,

        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'LiteralPath',
            HelpMessage                     = 'Literal path for ZIP-File, i.e. c:\temp\contoso.zip'
            )]
        [string]$literalPath,
        #endregion

        #region SMAParams
        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion,

        [Parameter(
            Mandatory=$false
            )]
        [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,

        [Parameter(
            Mandatory=$false
            )]
        [switch]$SMASkipCertCheck=$Script:activeCfg.SMAskipCertCheck
        #endregion

    )

    begin {
        if (! (verifyVars -VarList $Script:requiredVarList))
        {
            Throw($missingVarsMessage);
        }; # end if
            $smaParams=@{
                Host=$SMAHost;
                Port=$SMAPort;
                Version=$SMAVersion;
            }; # end smaParams
    }
    process {
        Write-Verbose "Creating URL path"
        $uriPath = "{0}/{1}/{2}" -f 'customer', $name, 'export'

        Write-Verbose "Building full request uri"
        $uri = New-SMAQueryString -uriPath $uriPath @smaParams;

        Write-verbose "Packing password into body JSON"
        $encryptionPasswordPlain = ConvertFrom-SMASecureString -securePassword $encryptionPassword

        $bodyHt = @{
            encryptionpassword = $encryptionPasswordPlain
        }
        $body = ConvertTo-Json $bodyHt

        Write-verbose "Crafting Invokeparam for Invoke-SMARestMethod"
        $invokeParam = @{
            Uri         = $uri 
            Method      = 'POST'
            body        = $body
            Cred        =  $SMACred
            SkipCertCheck = $SMASkipCertCheck
        }

        Write-Verbose "Call Invoke-SMARestMethod $uri" 
        $ExportRaw = Invoke-SMARestMethod @invokeParam


        Write-Verbose "Converting JSON Zip data to ZipFile"
        $bytes = [System.Convert]::FromBase64String($ExportRaw.zippedData)
        if ($pscmdlet.ParameterSetName -eq 'Path') {
            Write-Verbose "Will create a file according to $path definition"
            $ZipfileRoot = (Split-Path $path -Parent|resolve-path).Path
            $ZipfileName = Split-Path $path -leaf
            $ZipfilePath = Join-Path -Path $ZipFileRoot -ChildPath $ZipFileName
            [IO.File]::WriteAllBytes($ZipFilePath, $bytes)
            Write-Verbose "Written file to $ZipFilePath"
            return $ZipfilePath
        }
        if ($pscmdlet.ParameterSetName -eq 'literalPath') {
            $fileParent = Split-Path $literalPath -Parent
            if (!(test-path $fileparent)) {
                Write-Verbose "Directory of $literalpath didnt exist, trying to create it"
                New-Item -ItemType Directory -Path $fileParent
            }
            Write-Verbose "Will create a file according to $literalpath definition"
            [IO.File]::WriteAllBytes($literalpath, $bytes)
            Write-Verbose "Written file to $literalPath"
            return $literalPath
        }
    }
}
#>

<#
.SYNOPSIS
    Imports a SEPPmail customer from an encrypted ZIP file.
.DESCRIPTION
    Imports a customer with a POST request to the 'customer/import' API endpoint. The local
    ZIP file is read, Base64 encoded and sent together with the customer name and the
    decryption password in the request body. The ZIP must have been encrypted with the same
    password. On success the name of the imported customer is returned.
.PARAMETER name
    Name of the customer to import. Case-sensitive. Mandatory. Must match the pattern
    [a-zA-Z0-9\-_].
.PARAMETER encryptionPassword
    SecureString password used to decrypt the ZIP file. Mandatory.
.PARAMETER path
    Relative path of the ZIP file to import, e.g. .\contoso.zip. Mandatory in parameter
    set 'Path'.
.PARAMETER literalPath
    Literal path of the ZIP file to import, e.g. c:\temp\contoso.zip. Mandatory in
    parameter set 'LiteralPath'.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.OUTPUTS
    System.String
        Returns the name of the imported customer as reported by the API.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Supports -WhatIf and -Confirm.
    - Aliases: Import-SMACust, Import-SMATen.
.LINK
    Export-SMACustomer
.LINK
    New-SMACustomer
.LINK
    Get-SMACustomer
.EXAMPLE
    PS C:\> $backuppassword = ConvertTo-SecureString -String 'secretbackup' -AsPlainText -Force
    PS C:\> Import-SMACustomer -name 'Fabrikam' -encryptionpassword $backuppassword -path .\Fabrikam.zip
    Import the customer Fabrikam from a local ZIP file using a relative path.
.EXAMPLE
    PS C:\> $backuppassword = ConvertTo-SecureString -String 'secretbackup' -AsPlainText -Force
    PS C:\> Import-SMACustomer -name 'Fabrikam' -encryptionpassword $backuppassword -literalpath c:\temp\Fabrikam.zip
    Import the customer Fabrikam from a local ZIP file using a literal path.
#>

function Import-SMACustomer
{
    [CmdletBinding(DefaultParameterSetName = 'Path',SupportsShouldProcess)]
    param (
        #region API Params
        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Customer name (Case sensitive!)'
            )]
        [ValidatePattern('[a-zA-Z0-9\-_]')]
        [string]$name,

        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Secure password for encrypted ZIP'
            )]
        [SecureString]$encryptionPassword,

        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'Path',
            HelpMessage                     = 'Relative Path for ZIP-File, i.e. .\contoso.zip'
            )]
        [string]$path,

        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName                = 'LiteralPath',
            HelpMessage                     = 'Literal path for ZIP-File, i.e. c:\temp\contoso.zip'
            )]
        [string]$literalPath,
        #endregion

        #region SMA Params
        [Parameter(
            Mandatory=$false
            )]
        [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,

        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(
            Mandatory=$false
            )]
        [switch]$SMASkipCertCheck=$Script:activeCfg.SMAskipCertCheck,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion
        #endregion
    )

    begin { 
        if (! (verifyVars -VarList $Script:requiredVarList))  # no version needed
        {
            Throw($missingVarsMessage);
        }
        $smaParams = @{
            Host    = $SMAHost
            Port    = $SMAPort
            Version = $SMAVersion
        }
    }

    process {
        Write-Verbose "Creating URI path"
        $uripath = "{0}/{1}" -f 'customer', 'import'
    
        Write-verbose "Creating SMA Query String"
        $uri = New-SMAQueryString -uriPath $uriPath @smaParams

        Write-verbose "Packing password into body JSON"
        $encryptionPasswordPlain = ConvertFrom-SMASecureString -securePassword $encryptionPassword

        $jsonZIP = $null
        Write-Verbose "Convert ZIPFile to JSON Zip Data"
        if ($psCmdLet.ParameterSetName -eq 'Path')
        {
            if (!(Test-Path $path))
            {
                Write-Error "$Path does not exist - please enter a valid path"
                break
            }
            else
            {
                  $truePath = Resolve-Path $path
                $zipContent = [IO.File]::ReadAllBytes($truePath)
                   $jsonZip = [System.Convert]::ToBase64String($zipContent)
            }
        }

        if ($psCmdLet.ParameterSetName -eq 'LiteralPath') {
            if (!(Test-path $literalPath)) {
                Write-Error "$literalPath does not exist - please enter a valid path"
                break
            } else {
                $truePath = Resolve-Path $literalPath
                $zipContent = [IO.File]::ReadAllBytes($truePath)
                $jsonZip = [System.Convert]::ToBase64String($zipContent)
            }
        }

        $bodyHt = @{
            zippedData = $jsonZip
            encryptionpassword = $encryptionPasswordPlain
            name = $name
        }
        $body = ConvertTo-Json $bodyHt

        Write-verbose "Crafting Invokeparam for Invoke-SMARestMethod"
        $invokeParam = @{
            Uri           = $uri 
            Method        = 'POST'
            body          = $body
            Cred          = $SMACred
            SkipCertCheck = $SMASkipCertCheck
        }

        if ($PSCmdLet.ShouldProcess($name,"Import customer")) {
            Write-Verbose "Call Invoke-SMARestMethod $uri" 
            #Wait-Debugger
            $customerRaw =Invoke-SMARestMethod @invokeParam

            if ($customerRaw) {
                $customer = ConvertFrom-SMAPIFormat -inputObject $customerRaw
                Write-Verbose 'Returning name of customer'    
                ($customer.message.split(' ')[3])
            }
        }
    }
    end {}
}   


<#
.SYNOPSIS
    Adds admins to a SEPPmail customer.
.DESCRIPTION
    Adds one or more administrators to an existing customer with a POST request to the
    'customer/<customer>/adminuser' API endpoint. The admins are supplied as an array of
    E-Mail addresses. On success the change details are returned.
.PARAMETER admins
    Array of admin E-Mail addresses to add, e.g.
    @('john.doe@contoso.com','jane.black@fabrikam.com'). Mandatory. Accepts pipeline input.
.PARAMETER customer
    Name of the customer to add the admins to. Mandatory.
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.OUTPUTS
    System.String
        Returns the change details reported by the API.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Supports -WhatIf and -Confirm.
.LINK
    Remove-SMAcustomerAdmin
.LINK
    Set-SMACustomer
.LINK
    Get-SMACustomer
.EXAMPLE
    PS C:\> Add-SMAcustomerAdmin -customer 'Contoso' -admins 'john.doe@contoso.com'
    Add a single admin to the customer Contoso.
.EXAMPLE
    PS C:\> Add-SMAcustomerAdmin -customer 'Contoso' -admins @('john.doe@contoso.com','jane.black@contoso.com')
    Add multiple admins to the customer Contoso.
#>

function Add-SMAcustomerAdmin
{
    [CmdletBinding(SupportsShouldProcess)]
    param (
        #region API Params
        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromPipeline               = $true,
            HelpMessage                     = "Admin E-Mail addresses in an array @('john.doe@contoso.com','jane.black@fabrikam.com')"
            )]
        [string[]]$admins,

        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Customer name'
            )]
        [string]$customer,
        #endregion

        #region SMAParams
        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion,

        [Parameter(
            Mandatory=$false
            )]
        [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,

        [Parameter(
            Mandatory=$false
            )]
        [switch]$SMASkipCertCheck=$Script:activeCfg.SMAskipCertCheck 
        #endregion
    )

    begin {
        if (! (verifyVars -VarList $Script:requiredVarList))
        {
            Throw($missingVarsMessage);
        }
        $smaParams=@{
            Host=$SMAHost;
            Port=$SMAPort;
            Version=$SMAVersion;
        }

        Write-Verbose "Creating URL path"
        $uriPath = "{0}/{1}/{2}" -f 'customer', $customer, 'adminuser'
    }
    process {
        #TODO: Prüfen ob es den admin schon gibt.
        Write-Verbose "Building full request uri"
        $uri = New-SMAQueryString -uriPath $uriPath -qParam $boundParam @smaParams;
        Write-verbose "Crafting body ht for list of admins"
        $bodyht = @{
            admins = $admins
        }
        $body = $bodyht|ConvertTo-JSON
        Write-verbose "Crafting Invokeparam for Invoke-SMARestMethod"
        $invokeParam = @{
            Uri         = $uri 
            Method      = 'POST'
            body        = $body
            Cred        =  $SMACred
            SkipCertCheck = $SMASkipCertCheck
            }
        
        if ($PSCmdLet.ShouldProcess($customer,"Adding admin users")) {
            Write-Verbose "Call Invoke-SMARestMethod $uri"
            $adminUsersRaw = Invoke-SMARestMethod @invokeParam
            if ($adminUsersRaw) {
                $adminusers = ConvertFrom-SMAPIFormat -inputObject $adminUsersRaw
                Write-Verbose 'Returning changes'
                return $adminusers.message.Split(' ')[3]
            }
        }
    }
}

<#
.SYNOPSIS
    Removes admins from a SEPPmail customer.
.DESCRIPTION
    Removes one or more administrators from an existing customer with a PUT request to the
    'customer/<customer>/adminuser' API endpoint. The admins are supplied as an array of
    E-Mail addresses. On success the change details are returned.
.PARAMETER admins
    Array of admin E-Mail addresses to remove, e.g.
    @('john.doe@contoso.com','jane.black@fabrikam.com'). Mandatory. Accepts pipeline input.
.PARAMETER customer
    Name of the customer to remove the admins from. Mandatory.
.PARAMETER SMAHost
    SEPPmail API hostname. Defaults to the configured value.
.PARAMETER SMAPort
    SEPPmail API port. Defaults to the configured value.
.PARAMETER SMAVersion
    SEPPmail API version. Defaults to the configured value.
.PARAMETER SMACred
    API credentials (PSCredential). Defaults to the configured value.
.PARAMETER SMASkipCertCheck
    Skip SSL certificate validation. Use only in test environments.
.OUTPUTS
    System.String
        Returns the change details reported by the API.
.NOTES
    - Requires an active SEPPmail API session (New-SMAConfiguration).
    - Supports -WhatIf and -Confirm.
.LINK
    Add-SMAcustomerAdmin
.LINK
    Set-SMACustomer
.LINK
    Get-SMACustomer
.EXAMPLE
    PS C:\> Remove-SMAcustomerAdmin -customer 'Contoso' -admins 'john.doe@contoso.com'
    Remove a single admin from the customer Contoso.
.EXAMPLE
    PS C:\> Remove-SMAcustomerAdmin -customer 'Contoso' -admins @('john.doe@contoso.com','jane.black@contoso.com')
    Remove multiple admins from the customer Contoso.
#>

function Remove-SMAcustomerAdmin
{
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromPipeline               = $true,
            HelpMessage                     = "Admin E-Mail addresses in an array @('john.doe@contoso.com','jane.black@fabrikam.com')"
            )]
        [string[]]$admins,

        [Parameter(
            Mandatory                       = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage                     = 'Customer name'
            )]
        [string]$customer,

        [Parameter(Mandatory = $false)]
        [String]$SMAHost = $Script:activeCfg.SMAHost,

        [Parameter(Mandatory = $false)]
        [int]$SMAPort = $Script:activeCfg.SMAPort,

        [Parameter(Mandatory = $false)]
        [String]$SMAVersion = $Script:activeCfg.SMAPIVersion,

        [Parameter(
            Mandatory=$false
        )]
        [System.Management.Automation.PSCredential]$SMACred=$Script:activeCfg.SMACred,

        [Parameter(
                Mandatory=$false
           )]
        [switch]$SMASkipCertCheck=$Script:activeCfg.SMASkipCertCheck 
    )

    begin {
        if (! (verifyVars -VarList $Script:requiredVarList))
        {
            Throw($missingVarsMessage);
        }
        $smaParams=@{
            Host=$SMAHost;
            Port=$SMAPort;
            Version=$SMAVersion;
        }

        Write-Verbose "Creating URL path"
        $uriPath = "{0}/{1}/{2}" -f 'customer', $customer, 'adminuser'
    }
    process {
        #TODO: Add verification that at least one admin remains
        #TODO: Add verification that the admins to remove are really there.
        Write-Verbose "Building full request uri"
        $uri = New-SMAQueryString -uriPath $uriPath -qParam $boundParam @smaParams;
        Write-verbose "Crafting body ht for list of admins"
        $bodyht = @{
            admins = $admins
        }
        $body = $bodyht|ConvertTo-JSON
        Write-verbose "Crafting Invokeparam for Invoke-SMARestMethod"
        $invokeParam = @{
            Uri             = $uri 
            Method          = 'PUT'
            body            = $body
            Cred            =  $SMACred
            SkipCertCheck   = $SMASkipCertCheck
        }
        
        if ($PSCmdLet.ShouldProcess($customer,"Removing admin users")) {
            Write-Verbose "Call Invoke-SMARestMethod $uri"
            $adminUsersRaw = Invoke-SMARestMethod @invokeParam
            if ($adminUsersRaw) {
                $adminUsers = ConvertFrom-SMAPIFormat -inputObject $adminUsersRaw
                Write-Verbose 'Returning changes'
                return $adminUsers.message.Split(' ')[3]
            }        
        }
    }
    end {

    }
}

Write-Verbose 'Create CmdLet Alias for Customers' 
$custVerbs = ('Add','Remove','Get','Import','Export','Find','Set')

Foreach ($custverb in $custVerbs) {
    $aliasname1 = $custverb + '-SMACust'
    $aliasname2 = $custverb + '-SMATen'
    $cmdName = $custverb + '-SMACustomer'
    New-Alias -Name $aliasName1 -Value $cmdName
    New-Alias -Name $aliasName2 -Value $cmdName
}

# SIG # Begin signature block
# MIIVyAYJKoZIhvcNAQcCoIIVuTCCFbUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD9gTQ8fpn7hw4/
# QihW7eHTwN862uEVitrXcExeAXMj4KCCEgQwggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M
# UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv
# ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5
# NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp
# BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G
# CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI
# ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV
# DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3
# 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw
# mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm
# +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe
# dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4
# 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM
# dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY
# MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU
# pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV
# HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG
# A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1
# YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG
# AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl
# U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0
# aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh
# w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd
# OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj
# cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc
# WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO
# hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs
# zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7
# 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J
# KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH
# j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2
# Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/
# L9Uo2bC5a4CH2RwwggZvMIIE16ADAgECAhBIqMP3CCLHOHtOKuaWNyeFMA0GCSqG
# SIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0
# ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYw
# HhcNMjYwNDE1MDAwMDAwWhcNMjcwNzE0MjM1OTU5WjBmMQswCQYDVQQGEwJERTEP
# MA0GA1UECAwGQmF5ZXJuMSIwIAYDVQQKDBlTRVBQbWFpbCBEZXV0c2NobGFuZCBH
# bWJIMSIwIAYDVQQDDBlTRVBQbWFpbCBEZXV0c2NobGFuZCBHbWJIMIICIjANBgkq
# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvAFzE8MbJpvQt+IdIh1M+bKYsJBFDk4b
# 9ySe25IrCi00B9o5XmQtIw42MqyIKbUq1tDARtp9KTQedEP9W+rflAF2l+0Z046J
# kiqumU9/enbqWLDyln1aS/p7HOgwZFMhnsR9zH0MfFckiklUmkzJO+vmzYAK7ZmD
# xajNLJs0gkGRU2/BecAx/TSvLXMaKONsKZCyMKQCnwo1mCY/tFl5EgUz7YQFrPOR
# BQGfQke/hkdBfQDqNRsi/J6+KhJWc6LvgQihdRg/INQbQsTxlow18NWvyFsjjueH
# 7kG6HR4YKfbv07xgrsIh8xvq9ZJ1SBhLXmkg4SdoQGASjqR6o3keAX+bDRFf+hml
# WWJp/FqVHR5QomF3vbK2/bbz4jAclYSPx/sPasNJ0YnKFkgmowZ7Ysa0KA0/egBg
# tI4gJ+8V7zrqIVEG3rMQh9KCdMnJqP2aM9o4gUzQvE1M4x606liX9EWwdLLS+fe7
# 9o+Fzo5oH4wBE/En6hQQkzseHHu+TXCDd6zUUZ/PlTK0gTaDIRXt6UzPNqJ4RiRC
# W2pNFcPt078qqVTuwKUXoE4ufxGgXKFrZlCYST/9eG1TnW2oq19nz8A333GCsL3g
# poNIKvfmDyGMMNzvx2aeqn2v6e75z8kH19iGSNZ51xT+WgS9F1aIvjz08/T7XAv7
# iDPF1/gPIp8CAwEAAaOCAakwggGlMB8GA1UdIwQYMBaAFA8qyyCHKLjsb0iuK1Sm
# KaoXpM0MMB0GA1UdDgQWBBS30/Tq+alF3j2BY5up8n5zpAU23DAOBgNVHQ8BAf8E
# BAMCB4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzBKBgNVHSAE
# QzBBMDUGDCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3Rp
# Z28uY29tL0NQUzAIBgZngQwBBAEwSQYDVR0fBEIwQDA+oDygOoY4aHR0cDovL2Ny
# bC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIzNi5jcmww
# eQYIKwYBBQUHAQEEbTBrMEQGCCsGAQUFBzAChjhodHRwOi8vY3J0LnNlY3RpZ28u
# Y29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NBUjM2LmNydDAjBggrBgEFBQcw
# AYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wHgYDVR0RBBcwFYETc3VwcG9ydEBz
# ZXBwbWFpbC5jaDANBgkqhkiG9w0BAQwFAAOCAYEAi7fmb5UYoemWG3CC4K2UZWVr
# R6GOfi8gbJKgjPbKO4zrCrU/x6cOdyp6scKZfUEGFDf8KH6pP4pAQv1Hsbi49gU2
# kxoUWLlCiipn05qJY663DHx9hlStej/ZdEatou0wyCDiG5xD7kmG+1t6iLyyCBgE
# B88tJpzTjI61qXmBTS/FGEOAsB4SDEW1ngA7bc5FOv4IUKA43hp8M+N3GeYFzDqw
# JELYEfVVYheBW3o7q4VrCdfFEuaQihOtvfDfYpP6ANgekNn8HdsMT8rx9D1I50Rl
# i/qQFo2BOuPyb2SIQPzJvCs5wgi5qgp1nHiN6igumu2Cz7BmGjOazGUgCSUY5Qwy
# E8+F+R2tVM+2O15rfX01+e56ZfojBEiEjMwfPHs3fa3V3gokWWNwUMkton/v0R/n
# l2zjmOr2okohOINZEDh9frg21zUCN5ZD8Y4zQWuiJLCvvvBZs0JR4c9xl2k2wtw/
# QLPhGU69zM3smGpRoLE8M6zvUvSU7jXjvefazUniMYIDGjCCAxYCAQEwaDBUMQsw
# CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJT
# ZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0EgUjM2AhBIqMP3CCLHOHtOKuaW
# NyeFMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAw
# GQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisG
# AQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIHT+4681tqQgA+yR1XursuPC+aJjqdP1
# fMmXgm/oIsecMA0GCSqGSIb3DQEBAQUABIICAGDYwGWeWI5dfTazjxI+F18+BfkG
# 8bvbcgQe6YXpVXXDEfYE66Bu9EsdlS1Us/xoEw7WJqxEIBv+8vb01eHMH84NC3dZ
# CZH/c7E2GXw1VB+xoFvDdK5Pa2ERoP4WNnGd28vkq65CNeVrRihfYrLYDqJDar3h
# eEll0uZbqHafOLUHa/b4N4sRAs2BlivMDjeXm0/bknJ143IDIkTf0/LnHEMypmvM
# H50KWQI5jqUq49vnPZkDAo+WPBaV9sFLDLOSOVkv3w9NcKMNl5IWvzoEoZZsKULy
# 2578JfsRgQZbzSlGfou48L+nikQ7QyJ2ZfpwCeTtCh1lw0BHmq3LGaW53lKVjBCS
# ND0IPYEUTRjSqpfLmriC21edjbf1ijmlcLAeM8n8DmwYUsRoGvjzL/AINRiw4m6a
# 50qfkQ8iy2nOehupgXZxy/MqiLhC2IC8lx10qWiTq9IPp7cqYfECwuu5CkhskYA2
# mZz3tL9F/YQrTy1xc/I/j0eKjYhpTo9J8d1wOucD9IWQqsoiFBxiM14IZsb/QHjw
# IGqJPtfK4CJBNGOHviiKmaatx45YqswqjrA67HNEiWxA2SwKYDmBKUMPuT+SYDr6
# XkF/4BW1U77rAFLGD0T66iKqz2pHACdxeObUKcLz1swjxbEnnyHXKuLdjf2fBIxc
# lYb8qh1ph5knGOWN
# SIG # End signature block