PSMimecast.psm1

function Get-HeldMessage {
    [cmdletbinding()]
    Param(
        [ValidateSet("all","internal","outbound","inbound","external")]
        [string]$route,
        [ValidateSet("administrator","moderator","user","cluster")]
        [string]$heldGroup,
        [bool]$attachments,
        [string]$reasonCode,
        [string]$subject,
        [Alias("Sender")]
        [string]$sender1,
        [string]$recipient,
        [string]$all,
        [bool]$admin = $true,
        [ArgumentCompleter({
            param ($commandName,$parameterName,$wordToComplete,$commandAst,$fakeBoundParameters)
            Get-MimecastDateTime
        })]
        [string]$start,
        [ArgumentCompleter({
            param ($commandName,$parameterName,$wordToComplete,$commandAst,$fakeBoundParameters)
            Get-MimecastDateTime
        })]
        [string]$end
    )

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/gateway/get-hold-message-list"
        $url = $baseUrl + $uri

        $searchBy = @{}
        $filterBy = @{}
        $data = @{}

        $CommonParameters = [System.Management.Automation.Internal.CommonParameters].DeclaredProperties.Name
        $Parameters = $MyInvocation.MyCommand.Parameters.Keys | where {$_ -notin $CommonParameters}

        $filterParam = @("route","heldGroup","attachments")
        $SearchParam = @("all","subject","sender1","recipient","reason_code")
        $dataParam = @("admin","start","end")
        foreach ($param in $Parameters){
            $value = (Get-Variable -Name $param).Value
            if (![String]::IsNullOrEmpty($value)){
                if ($param -in $filterParam){
                    $filterBy["fieldName"] = $param
                    $filterBy["value"] = $value.ToString()
                }
                elseif ($param -in $SearchParam){
                    $searchBy["fieldName"] = $param.TrimEnd('1')
                    $searchBy["value"] = $value.ToString()
                }
                elseif ($param -in $dataParam){
                    $data[$param] = $value.ToString()
                }
            }
        }
        
        if ($filterBy.Keys -ne $null){
            $data["filterBy"] = $filterBy
        }
        if ($searchBy.Keys -ne $null){
            $data["searchBy"] = $searchBy
        }
        $dataJson = $data | ConvertTo-Json
    } #Begin

    Process{
        $headers = New-MimecastHeader -Uri $Uri

        #Create post body
        $postBody = "{
                            ""data"": [
                                $dataJson
                            ]
                        }"


        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url
        #Print the response
        if ($response.fail){
            Write-Error $response.fail.errors.message
        }
        else{
            $message = $response.data
            $message | Add-Member -Name ReleaseMessage -MemberType ScriptMethod -Value {New-HeldMessageReleaseAction -Id $this.Id}
            $message | Add-Member -TypeName "Mimecast.HeldMessage"
            $message
        }
    } #Process
}
function Get-HeldMessageSummary {

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/gateway/get-hold-summary-list"
        $url = $baseUrl + $uri
    }
    
    Process{
        $headers = New-MimecastHeader -Uri $Uri

        #Create post body
        $postBody = "{
                            ""data"": []
                        }"


        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url

        #Print the response
        $response.data
    }
}
function Get-MimecastAccount{
    param(
        [Parameter(Mandatory)]
        $EmailAddress
    )

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/user/update-user"
        $url = $baseUrl + $uri
    }

    Process{
        $headers = New-MimecastHeader -Uri $Uri

        $postBody = "{
            ""data"": [
                {
                    ""emailAddress"": ""$EmailAddress""
                }
            ]
        }"


        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url
        
        #Print the respons
        if ($response.data){
            $response.data
        }
        else{
            Write-Error "$($response.fail.errors.message)"
        }
    }
}
function Get-MimecastAppInfo {
    $Path = "$ENV:APPDATA\PSMimecast\AppInfo.xml"
    if (Test-Path -Path $Path){
        $AppInfo = Import-Clixml -Path $Path
        [PSCustomObject]@{
            AppId = $Appinfo.AppId
            AppKey = [pscredential]::new("API",(ConvertTo-SecureString -String $Appinfo.AppKey)).GetNetworkCredential().Password
        }
    }
    else{
        Write-Error "No App Info has been set, use Set-MimecastAppInfo function to set this data" -ErrorAction Stop
    }
}
function Get-MimecastDateTime{
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing

    $form = New-Object Windows.Forms.Form -Property @{
        StartPosition = [Windows.Forms.FormStartPosition]::CenterScreen
        Size          = [drawing.size]::new(225,275)
        Text          = 'Select a Date'
        Topmost       = $true
    }

    $calendar = New-Object Windows.Forms.MonthCalendar -Property @{
        Location = [drawing.size]::new(15,15)
        ShowTodayCircle   = $false
        MaxSelectionCount = 1
    }
    $form.Controls.Add($calendar)

    $TimePicker = New-Object System.Windows.Forms.DateTimePicker
    $TimePicker.Size = [Drawing.Size]::new(125,25)
    $TimePicker.Location = [Drawing.Size]::new(40,175)
    $TimePicker.ShowUpDown = $true
    $TimePicker.Format = [System.Windows.Forms.DateTimePickerFormat]::Time
    $form.Controls.Add($TimePicker)

    $okButton = New-Object Windows.Forms.Button -Property @{
        Location     = [drawing.size]::new(30,200)
        Size         = [drawing.size]::new(75,23)
        Text         = 'OK'
        DialogResult = [Windows.Forms.DialogResult]::OK
    }
    $form.AcceptButton = $okButton
    $form.Controls.Add($okButton)

    $cancelButton = New-Object Windows.Forms.Button -Property @{
        Location     = [drawing.size]::new(105,200)
        Size         = New-Object Drawing.Size 75, 23
        Text         = 'Cancel'
        DialogResult = [Windows.Forms.DialogResult]::Cancel
    }
    $form.CancelButton = $cancelButton
    $form.Controls.Add($cancelButton)

    $result = $form.ShowDialog()

    if ($result -eq [Windows.Forms.DialogResult]::OK) {
        $date = $calendar.SelectionStart
        $time = $TimePicker.Value
        $SelectionDate = ([DateTime]::new($date.Year,$date.Month,$date.Day,$time.Hour,$time.Minute,0)).ToUniversalTime()
        $SelectionDate.ToString("yyyy-MM-ddTHH:mm:ss+0000")
    }
}
function Get-MimecastDirectoryConnection{
    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/directory/get-connection"
        $url = $baseUrl + $uri
    }

    Process{
        $headers = New-MimecastHeader -Uri $Uri

        #Create post body
        $postBody = "{
            ""data"": [
            ]
        }"


        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url

        #Print the response
        if ($response.data){
            $response.data
        }
        else{
            Write-Error "$($response.fail.errors.message)"
        }
    }
}
function Get-MimecastProfile {
    [cmdletbinding()]
    Param(
        [string]$EmailAddress
    )

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/user/get-profile"
        $url = $baseUrl + $uri
    }
    
    Process{
        $headers = New-MimecastHeader -Uri $Uri

        #Create post body
        $postBody = "{
                            ""data"": [
                                {
                                    ""emailAddress"": $EmailAddress,
                                    ""showAvatar"": False
                                }
                            ]
                        }"

        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url
        #Print the response
        if ($response.data){
            $response.data
        }
        else{
            Write-Error "$($response.fail.errors.message)"
        }
    }
}
function Lock-MimecastAccount{
    param(
        [Parameter(Mandatory)]
        $EmailAddress
    )

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/user/update-user"
        $url = $baseUrl + $uri
    }

    Process{
        $headers = New-MimecastHeader -Uri $Uri

        $postBody = "{
            ""data"": [
                {
                    ""accountLocked"": True,
                    ""emailAddress"": ""$EmailAddress""
                }
            ]
        }"


        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url
        #Print the respons
        if ($response.data){
            $response.data
        }
        else{
            Write-Error "$($response.fail.errors.message)"
        }
    }
}
function New-HeldMessageRejectAction{
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory)]
        [Alias("Id")]
        [string[]]$MessageId,
        [string]$message,
        [string]$reasonType,
        [bool]$nofify

    )

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/gateway/hold-reject"
        $url = $baseUrl + $uri

        $SkipParamerters = @("MessageId")
        $data = @{ids = $MessageId}
        $PSBoundParameters.Keys | where {$_ -notin $SkipParamerters} | foreach{
            $data[$_] = $PSBoundParameters[$_]
        }
        $dataJson = $data | ConvertTo-Json
    }

    Process{
        $headers = New-MimecastHeader -Uri $Uri

        $postBody = "{
            ""data"": [
                $dataJson
            ]
        }"


        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url

        #Print the response
        if ($response.fail){
            Write-Error $response.fail.errors.message
        }
        else{
            $response.data
        }
    } #Process
}
function New-HeldMessageReleaseAction{
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [Alias("Id")]
        [string]$MessageId
    )

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/gateway/hold-release"
        $url = $baseUrl + $uri
    }

    Process{
        $headers = New-MimecastHeader -Uri $uri

        #Create post body
        $postBody = "{
            ""data"": [
                {
                    ""id"": ""$MessageId""
                }
            ]
        }"

        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url

        #Print the response
        if ($response.fail){
            Write-Error $response.fail.errors.message
        }
        else{
            $message = $response.data
            $message | Add-Member -TypeName "Mimecast.ReleaseMessage"
            $message
        }
    }
}
function New-MimecastAPIKeys {
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory)]
        $AppId,
        [Parameter(Mandatory)]
        [pscredential]$Credentials,
        [ValidateSet("Basic-Cloud","Basic-Ad")]
        $AuthType = "Basic-Ad"
    )

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/login/login"
        $url = $baseUrl + $uri

        #Generate request header values
        $hdrDate = (Get-Date).ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss UTC") 
        $requestId = [guid]::NewGuid().guid
    }

    Process{    
        $EmailAddress = $Credentials.UserName
        $password = $Credentials.GetNetworkCredential().Password
        $headers = @{"Authorization" = $authType + " " + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($emailAddress + ":" + $password));
                "x-mc-date" = $hdrDate;
                "x-mc-app-id" = $AppId;
                "x-mc-req-id" = $requestId;
                "Content-Type" = "application/json"}
        #Create post body
        $postBody = "{
                        ""data"": [
                            {
                                ""userName"": "
 + $emailAddress + "
                            }
                        ]
                        }"

        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url
        #Print the response
        if ($response.data.accesskey){
            Set-MimecastAPIKeys -AccessKey $response.data.accesskey -SecretKey $response.data.secretKey -Email $EmailAddress
        }
        else{
            Write-Error "Unable to create keys" -ErrorAction Stop
        }
    }
}
function Set-MimecastAppInfo {
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory)]
        [string]$AppId,
        [Parameter(Mandatory)]
        [string]$AppKey
    )

    $Path = "$ENV:APPDATA\PSMimecast\AppInfo.xml"
        if (!(Test-Path -Path $Path)){
            $AppInfo = [PSCustomObject]@{
                AppId = $AppId
                AppKey = (ConvertTo-SecureString $AppKey -AsPlainText -Force | ConvertFrom-SecureString)
            }
            $AppInfo | Export-Clixml -Path $Path
        }
}
function Start-MimecastDirectorySync{
    Begin{       
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/directory/execute-sync"
        $url = $baseUrl + $uri
    }

    Process{
        $headers = New-MimecastHeader -Uri $Uri
        #Create post body
        $postBody = "{
            ""data"": [
            ]
        }"

        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url

        #Print the respons
        if ($response.data){
            $response.data
        }
        else{
            Write-Error "$($response.fail.errors.message)"
        }
    }
}
function Unlock-MimecastAccount{
    param(
        [Parameter(Mandatory)]
        $EmailAddress
    )

    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/user/update-user"
        $url = $baseUrl + $uri
    }

    Process{
        $headers = New-MimecastHeader -Uri $Uri

        $postBody = "{
            ""data"": [
                {
                    ""accountLocked"": False,
                    ""emailAddress"": ""$EmailAddress""
                }
            ]
        }"


        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url
        #Print the response
        if ($response.data){
            $response.data
        }
        else{
            Write-Error "$($response.fail.errors.message)"
        }
    }
}
function Update-MimecastExpiredAccessKey {
    param(
        [Parameter(Mandatory)]
        [SecureString]$Password,
        [ValidateSet("Basic-Cloud","Basic-Ad")]
        $AuthType = "Basic-Ad"
    )
    Begin{
        $baseUrl = "https://us-api.mimecast.com"
        $uri = "/api/login/login"
        $url = $baseUrl + $uri

        $Keys = Get-MimecastAPIKeys
        $Appinfo = Get-MimecastAppInfo
        $accessKey = $Keys.AccessKey
        $appId = $Appinfo.AppId
        $emailAddress = $keys.EmailAddress
    }

    Process{     
        $hdrDate = (Get-Date).ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss UTC")
        $requestId = [guid]::NewGuid().guid
        $cred = [pscredential]::new("Test",$Password)
        $pass = $cred.GetNetworkCredential().Password
        $headers = @{"Authorization" = $authType + " " + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($emailAddress + ":" + $pass));
        "x-mc-date" = $hdrDate;
        "x-mc-app-id" = $appId;
        "x-mc-req-id" = $requestId;
        "Content-Type" = "application/json"}

        #Create post body
        $postBody = "{
        ""data"": [
            {
                ""userName"": "
 + $emailAddress + ",
                ""accessKey"": "
 + $accessKey + "
            }
        ]
        }"


        #Send Request
        $response = Invoke-MimecastAPI -Method Post -Headers $headers -Body $postBody -Uri $url
        
        #Print the response
        if ($response.data){
            $response.data
        }
        else{
            Write-Error "$($response.fail.errors.message)"
        }
    }
}
function Get-MimecastAPIKeys {
    $Path = "$ENV:APPDATA\PSMimecast\Keys.xml"
    if (Test-Path -Path $Path){
        $SecretObject = Import-Clixml -Path $Path
        [PSCustomObject]@{
            AccessKey = [pscredential]::new("API",(ConvertTo-SecureString -String $SecretObject.AccessKey)).GetNetworkCredential().Password
            SecretKey = [pscredential]::new("API",(ConvertTo-SecureString -String $SecretObject.SecretKey)).GetNetworkCredential().Password
            EmailAddress = $SecretObject.EmailAddress
        }
    }
    else{
        Write-Error "Keys have not been set, use New-MimecastAPIKeys to set the keys" -ErrorAction Stop
    }
}
function Get-MimecastBaseURL {
    [cmdletbinding()]
    Param(
        $UserPrincipalName,
        $AppId
    )

    Begin{
        $baseUrl = "https://api.mimecast.com"
        $uri = "/api/login/discover-authentication"
        $url = $baseUrl + $uri
    }

    Process{    
        #Generate request header values
        $hdrDate = (Get-Date).ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss UTC")
        $requestId = [guid]::NewGuid().guid

        #Create Headers
        $headers = @{"x-mc-date" = $hdrDate; 
        "x-mc-app-id" = $Appid;
        "x-mc-req-id" = $requestId;
        "Content-Type" = "application/json"}

        #Create post body
        $postBody = "{
        ""data"": [
            {
                ""emailAddress"": $UserPrincipalName
            }
        ]
        }"

        #Send Request
        $response = Invoke-RestMethod -Method Post -Headers $headers -Body $postBody -Uri $url
        #Print the response
        $response
    }
}
function Invoke-MimecastAPI{
    [cmdletbinding()]
    param(
        $Method,
        $Uri,
        $headers,
        $Body
    )

    try{
        Write-Information "Sending API Request to $uri"
        $response = Invoke-RestMethod @PSBoundParameters
    }
    catch [System.Net.WebException]{
        Write-Information "A System.Net.WebException has occurred"
        if ($_.Exception.Message -like "*418*"){
            Write-Warning "Your API Access has expired. Use Update-MimecastExpiredAccessKey to update your expired AccessKey"
            if ((Read-Host "Would you like to Update your API Access key (Y/N)?") -like "Y*"){
                Update-MimecastExpiredAccessKey | Out-Null
                if ($?){
                    $response = Invoke-RestMethod @PSBoundParameters
                }
            }
        }
        elseif ($_.Exception.Message -like "*401*"){
            $errorresponse = $_.ErrorDetails.message | ConvertFrom-Json
            $email = $errorresponse.fail.key.username
            $message = $errorresponse.fail.errors.message
            $ErrorRecord = [System.Management.Automation.ErrorRecord]::new(
                        [System.Security.Authentication.InvalidCredentialException]::new($message),
                        'InvalidCredentialException',
                        [System.Management.Automation.ErrorCategory]::AuthenticationError,
                        $email
                    )
            throw $ErrorRecord
        }
    }
    catch{
        Write-Information "An unknown error has occurred"
        $PSCmdlet.WriteError($_)
    }

    return $response
}
function New-MimecastHeader{
    param(
        [string]$Uri
    )
    $Keys = Get-MimecastAPIKeys
    $Appinfo = Get-MimecastAppInfo
    $accessKey = $Keys.AccessKey
    $secretKey = $Keys.SecretKey
    $appId = $Appinfo.AppId
    $appKey = $Appinfo.AppKey

    #Generate request header values
    $hdrDate = (Get-Date).ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss UTC")
    $requestId = [guid]::NewGuid().guid

    #Create the HMAC SHA1 of the Base64 decoded secret key for the Authorization header
    $sha = New-Object System.Security.Cryptography.HMACSHA1
    $sha.key = [Convert]::FromBase64String($secretKey)
    $sig = $sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($hdrDate + ":" + $requestId + ":" + $Uri + ":" + $appKey))
    $sig = [Convert]::ToBase64String($sig)
        
    #Create Headers
    $headers = @{"Authorization" = "MC " + $accessKey + ":" + $sig;
                    "x-mc-date" = $hdrDate;
                    "x-mc-app-id" = $appId;
                    "x-mc-req-id" = $requestId;
                    "Content-Type" = "application/json"}
    
    $headers
}
function Set-MimecastAPIKeys{
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory)]
        $AccessKey,
        [Parameter(Mandatory)]
        $SecretKey,
        $EmailAddress
    )

    Begin{
        $Path = "$ENV:APPDATA\PSMimecast"
        if (!(Test-Path -Path $Path)){
            New-Item -Path $Path -ItemType Directory -Force | Out-Null
        }
    } #Begin

    Process{
        $SecureAccessKey = ConvertTo-SecureString $AccessKey -AsPlainText -Force
        $SecureSecretKey = ConvertTo-SecureString $SecretKey -AsPlainText -Force

        $EncryptedAccessKey = ConvertFrom-SecureString -SecureString $SecureAccessKey
        $EncryptedSecureKey = ConvertFrom-SecureString -SecureString $SecureSecretKey

        $SecretObject = [PSCustomObject]@{
            AccessKey = $EncryptedAccessKey
            SecretKey = $EncryptedSecureKey
            EmailAddress = $EmailAddress
        }

        $SecretObject | Export-Clixml -Path $Path\Keys.xml -Force
    } #Process
}
Export-ModuleMember -function Get-HeldMessage, Get-HeldMessageSummary, Get-MimecastAccount, Get-MimecastAppInfo, Get-MimecastDateTime, Get-MimecastDirectoryConnection, Get-MimecastProfile, Lock-MimecastAccount, New-HeldMessageRejectAction, New-HeldMessageReleaseAction, New-MimecastAPIKeys, Set-MimecastAppInfo, Start-MimecastDirectorySync, Unlock-MimecastAccount, Update-MimecastExpiredAccessKey