ExoGraphGUI.psm1

$script:ModuleRoot = $PSScriptRoot
$script:ModuleVersion = (Import-PowerShellDataFile -Path "$($script:ModuleRoot)\ExoGraphGUI.psd1").ModuleVersion

# Detect whether at some level dotsourcing was enforced
$script:doDotSource = Get-PSFConfigValue -FullName ExoGraphGUI.Import.DoDotSource -Fallback $false
if ($ExoGraphGUI_dotsourcemodule) { $script:doDotSource = $true }

<#
Note on Resolve-Path:
All paths are sent through Resolve-Path/Resolve-PSFPath in order to convert them to the correct path separator.
This allows ignoring path separators throughout the import sequence, which could otherwise cause trouble depending on OS.
Resolve-Path can only be used for paths that already exist, Resolve-PSFPath can accept that the last leaf my not exist.
This is important when testing for paths.
#>


# Detect whether at some level loading individual module files, rather than the compiled module was enforced
$importIndividualFiles = Get-PSFConfigValue -FullName ExoGraphGUI.Import.IndividualFiles -Fallback $false
if ($ExoGraphGUI_importIndividualFiles) { $importIndividualFiles = $true }
if (Test-Path (Resolve-PSFPath -Path "$($script:ModuleRoot)\..\.git" -SingleItem -NewChild)) { $importIndividualFiles = $true }
if ("<was compiled>" -eq '<was not compiled>') { $importIndividualFiles = $true }
    
function Import-ModuleFile
{
    <#
        .SYNOPSIS
            Loads files into the module on module import.
         
        .DESCRIPTION
            This helper function is used during module initialization.
            It should always be dotsourced itself, in order to proper function.
             
            This provides a central location to react to files being imported, if later desired
         
        .PARAMETER Path
            The path to the file to load
         
        .EXAMPLE
            PS C:\> . Import-ModuleFile -File $function.FullName
     
            Imports the file stored in $function according to import policy
    #>

    [CmdletBinding()]
    Param (
        [string]
        $Path
    )
    
    $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath
    if ($doDotSource) { . $resolvedPath }
    else { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($resolvedPath))), $null, $null) }
}

#region Load individual files
if ($importIndividualFiles)
{
    # Execute Preimport actions
    foreach ($path in (& "$ModuleRoot\internal\scripts\preimport.ps1")) {
        . Import-ModuleFile -Path $path
    }
    
    # Import all internal functions
    foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore))
    {
        . Import-ModuleFile -Path $function.FullName
    }
    
    # Import all public functions
    foreach ($function in (Get-ChildItem "$ModuleRoot\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore))
    {
        . Import-ModuleFile -Path $function.FullName
    }
    
    # Execute Postimport actions
    foreach ($path in (& "$ModuleRoot\internal\scripts\postimport.ps1")) {
        . Import-ModuleFile -Path $path
    }
    
    # End it here, do not load compiled code below
    return
}
#endregion Load individual files

#region Load compiled code
<#
This file loads the strings documents from the respective language folders.
This allows localizing messages and errors.
Load psd1 language files for each language you wish to support.
Partial translations are acceptable - when missing a current language message,
it will fallback to English or another available language.
#>

Import-PSFLocalizedString -Path "$($script:ModuleRoot)\en-us\*.psd1" -Module 'ExoGraphGUI' -Language 'en-US'

Function Connect-ExoGraphGuiService {
    <#
    .SYNOPSIS
    Function to authenticate the user or App.
     
    .DESCRIPTION
    Function to authenticate the user or App.
     
    .PARAMETER ClientID
    String parameter with the ClientID (or AppId) of your AzureAD Registered App.
 
    .PARAMETER TenantID
    String parameter with the TenantID of your AzureAD tenant.
     
    .PARAMETER CertificateThumbprint
    String parameter with the certificate thumbprint which is configured in the AzureAD App.
 
    .EXAMPLE
    PS C:\> Connect-ExoGraphGuiService
    Authenticates the user or Azure App.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")]
    [Cmdletbinding()]
    param(
        [String] $ClientID,

        [String] $TenantID,

        [String] $CertificateThumbprint
    )

    DynamicParam {
        $modules = Get-Module Microsoft.Graph.Authentication
        $latest = $modules | Sort-Object version -Descending
        if ($latest[0].Version -ge [version]"2.0.0") {
            $Attribute = New-Object System.Management.Automation.ParameterAttribute
            $Attribute.Mandatory = $false
            $Attribute.HelpMessage = "String parameter with the Client Secret which is configured in the AzureAD App."

            #create an attributecollection object for the attribute we just created.
            $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute]

            #add our custom attribute
            $attributeCollection.Add($Attribute)

            #add our paramater specifying the attribute collection
            $secretParam = New-Object System.Management.Automation.RuntimeDefinedParameter('ClientSecret', [String], $attributeCollection)

            #expose the name of our parameter
            $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
            $paramDictionary.Add('ClientSecret', $secretParam)
            return $paramDictionary
        }
    }

    Process {
        # Connect to Graph if there is no current context
        $conn = Get-MgContext
        $requiredScopes = "Mail.ReadWrite", "Mail.Send", "MailboxSettings.Read"
        if ( $conn ) {
            $compare = Compare-Object -ReferenceObject $conn.scopes -DifferenceObject $requiredScopes -IncludeEqual
        }
        if ( $null -eq $conn -or $compare.sideindicator -contains "=>" ) {
            Write-PSFMessage -Level Host -Message "There is currently no active connection to MgGraph or current connection is missing required scopes: $($requiredScopes -join ", ")"
            if ( $clientID -ne '' -and $TenantID -ne '' -and ($CertificateThumbprint -ne '' -or $ClientSecret -ne '')) {
                # Connecting to graph using Azure App Application flow with passed parameters
                Write-PSFMessage -Level Host -Message "Connecting to graph with Azure AppId: $ClientID with passed parameters"
                if ($PSBoundParameters.ContainsKey('CertificateThumbprint') ) {
                    Connect-MgGraph -ClientId $ClientID -TenantId $TenantID -CertificateThumbprint $CertificateThumbprint
                }
                elseif ($PSBoundParameters.ContainsKey('ClientSecret') ) {
                    $clientCredential = New-Object System.Net.NetworkCredential($ClientID, $ClientSecret)
                    Connect-MgGraph -TenantId $TenantID -ClientSecretCredential $clientCredential
                }
            }
            elseif (
                $null -ne (Get-PSFConfig -Module ExoGraphGUI -Name ClientID).value -and `
                $null -ne (Get-PSFConfig -Module ExoGraphGUI -Name TenantID).value -and `
                ($null -ne (Get-PSFConfig -Module ExoGraphGUI -Name ClientSecret).value -or $null -ne (Get-PSFConfig -Module ExoGraphGUI -Name CertificateThumbprint).value)
            ) {
                # Connecting to graph using Azure App Application flow saved values in the module
                Write-PSFMessage -Level Host -Message "Connecting to graph with Azure AppId: $((Get-PSFConfig -Module ExoGraphGUI -Name ClientID).value) with saved credentials in the module"
                $cid = (Get-PSFConfig -Module ExoGraphGUI -Name ClientID).value
                $tid = (Get-PSFConfig -Module ExoGraphGUI -Name TenantID).value
                $cs = ConvertTo-SecureString -String (Get-PSFConfig -Module ExoGraphGUI -Name ClientSecret).value -AsPlainText -Force
                $ct = (Get-PSFConfig -Module ExoGraphGUI -Name CertificateThumbprint).value
                if ( $ct ) {
                    Write-PSFMessage -Level Verbose -Message "Connecting to graph with Azure AppId: $cid with saved CertificateThumbprint"
                    Connect-MgGraph -ClientId $cid -TenantId $tid -CertificateThumbprint $ct
                }
                else {
                    Write-PSFMessage -Level Verbose -Message "Connecting to graph with Azure AppId: $cid with saved ClientSecret"
                    $clientCredential = New-Object System.Net.NetworkCredential($cid, $cs)
                    Connect-MgGraph -TenantId $tid -ClientSecretCredential $clientCredential
                }
            }
            else {
                # Connecting to graph with the user account
                Write-PSFMessage -Level Host -Message "Connecting to graph with the user account"
                Connect-MgGraph -Scopes $requiredScopes
            }
            $conn = Get-MgContext
        }
        if ( $null -eq $conn.Account ) {
            Write-PSFMessage -Level Host -Message "Currently connected with App Account: $($conn.AppName)"
        }
        else {
            Write-PSFMessage -Level Host -Message "Currently connected with User Account: $($conn.Account)"
        }
        return $conn
    }
}

Function Method1 {
    <#
    .SYNOPSIS
    Method to list folders in the user mailbox.
     
    .DESCRIPTION
    Method to list folders in the user mailbox, showing Folder name, FolderId, Number of items, and number of subfolders.
    Module required: Microsoft.Graph.Mail
    Scope needed:
    Delegated: Mail.ReadBasic
    Application: Mail.ReadBasic.All
     
    .PARAMETER Account
    User's UPN to get mail folders from.
 
    .EXAMPLE
    PS C:\> Method1
    lists folders in the user mailbox.
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
    [CmdletBinding()]
    param(
        $Account
    )
    $statusBarLabel.Text = "Running..."

    Function Find-Subfolders {
        Param (
            $Account,

            $array,

            $ParentFolderId,

            $ParentDisplayname
        )
        foreach ($folder in (Get-MgUserMailFolderChildFolder -UserId $Account -MailFolderId $ParentFolderId -All -Property *)) {
            $folderpath = $ParentDisplayname + $folder.DisplayName
            $line = $folder | Select-Object @{N="FolderPath";E={$folderpath}},ChildFolderCount,TotalItemCount,UnreadItemCount,Id
            $null = $array.add($line)
            if ( $folder.ChildFolderCount -gt 0 ) {
                Find-Subfolders -Account $Account -ParentFolderId $folder.id -Array $array -ParentDisplayname "$folderpath\"
            }
        }
    }

    #listing all available folders in the mailbox
    $array = New-Object System.Collections.ArrayList
    if ($radiobutton1.Checked) {
        $parentFolders = (Get-MgUserMailFolder -UserId $Account -MailFolderId "msgfolderRoot").Id
    }
    elseif ($radiobutton2.Checked) {
        $deletions = Get-MgUserMailFolder -UserId $Account -MailFolderId "recoverableitemsdeletions"
        $parentFolders = $deletions.ParentFolderId
    }
    Find-Subfolders -Account $Account -ParentFolderId $parentFolders -Array $array -ParentDisplayname "\"
    
    $dgResults.datasource = $array
    $dgResults.AutoResizeColumns()
    $dgResults.Visible = $True
    $txtBoxResults.Visible = $False
    $PremiseForm.refresh()
    $statusBarLabel.Text = "Ready. Folders found: $($array.Count)"
    Write-PSFMessage -Level Output -Message "Task finished succesfully" -FunctionName "Method 1 & 2" -Target $Account
}

Function Method10 {
    <#
    .SYNOPSIS
    Get user's Delegates information
     
    .DESCRIPTION
    Get user's Delegates information
    Module required: Microsoft.Graph.Authentication
    Scope needed:
    Delegated: MailboxSettings.Read
    Application: MailboxSettings.Read
 
    .PARAMETER Account
    User's UPN to get delegate settings from.
     
    .EXAMPLE
    PS C:\> Method10
    Get user's Delegates information
 
    #>

    [CmdletBinding()]
    param(
        $Account
    )
    $statusBarLabel.Text = "Running..."
    $txtBoxResults.Text = "This function is still under construction."
    
    #TODO
    $response = Invoke-MgGraphRequest -Method get -Uri https://graph.microsoft.com/v1.0/users/$Account/mailboxSettings
    $response["delegateMeetingMessageDeliveryOptions"]

    $dgResults.Visible = $False
    $txtBoxResults.Visible = $True
    $PremiseForm.refresh()
    $statusBarLabel.text = "Ready."
    Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 10" -Target $Account
}

Function Method11 {
    <#
    .SYNOPSIS
    Function to send email messages through MS Graph.
     
    .DESCRIPTION
    Function to send email messages through MS Graph.
    Module required: Microsoft.Graph.Users.Actions
    Scope needed:
    Delegated: Mail.Send
    Application: Mail.Send
 
    .PARAMETER Account
    User's UPN to send the email message from.
 
    .PARAMETER ToRecipients
    List of recipients in the "To" list. This is a Mandatory parameter.
     
    .PARAMETER CCRecipients
    List of recipients in the "CC" list. This is an optional parameter.
 
    .PARAMETER BccRecipients
    List of recipients in the "Bcc" list. This is an optional parameter.
 
    .PARAMETER Subject
    Use this parameter to set the subject's text. By default will have: "Test message sent via Graph".
 
    .PARAMETER Body
    Use this parameter to set the body's text. By default will have: "Test message sent via Graph using Powershell".
     
    .EXAMPLE
    PS C:\> Method11 -ToRecipients "john@contoso.com"
    Then will send the email message to "john@contoso.com" from the user previously authenticated.
 
    .EXAMPLE
    PS C:\> Method11 -ToRecipients "julia@contoso.com","carlos@contoso.com" -BccRecipients "mark@contoso.com" -Subject "Lets meet!"
    Then will send the email message to "julia@contoso.com" and "carlos@contoso.com" and bcc to "mark@contoso.com", from the user previously authenticated.
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")]
    [Cmdletbinding()]
    Param (
        [String] $Account,

        [parameter(Mandatory = $true)]
        [String[]] $ToRecipients,

        [String[]] $CCRecipients,

        [String[]] $BccRecipients,

        [String] $Subject,

        [String] $Body
    )
    $statusBarLabel.Text = "Running..."

    if ( $subject -eq "" ) { $Subject = "Test message sent via Graph" }
    if ( $Body -eq "" ) { $Body = "Test message sent via Graph using ExoGraphGUI tool" }

    # Base mail body Hashtable
    $global:MailBody = @{
        Message         = @{
            Subject = $Subject
            Body    = @{
                Content     = $Body
                ContentType = "HTML"
            }
        }
        savetoSentItems = "true"
    }

    # looping through each recipient in the list, and adding it in the hash table
    $recipientsList = New-Object System.Collections.ArrayList
    foreach ( $recipient in ($ToRecipients.split(",").Trim()) ) {
        $recipientsList.add(
            @{
                EmailAddress = @{
                    Address = $recipient
                }
            }
        )
    }
    $global:MailBody.Message.Add("ToRecipients", $recipientsList)

    # looping through each recipient in the CC list, and adding it in the hash table
    if ( $CCRecipients -ne "" ) {
        $ccRecipientsList = New-Object System.Collections.ArrayList
        foreach ( $cc in $CCRecipients.split(",").Trim()) {
            $null = $ccRecipientsList.add(
                @{
                    EmailAddress = @{
                        Address = $cc
                    }
                }
            )
        }
        $MailBody.Message.Add("CcRecipients", $ccRecipientsList)
    }

    # looping through each recipient in the Bcc list, and adding it in the hash table
    if ( $BccRecipients -ne "" ) {
        $BccRecipientsList = New-Object System.Collections.ArrayList
        foreach ( $bcc in $BccRecipients.split(",").Trim()) {
            $null = $BccRecipientsList.add(
                @{
                    EmailAddress = @{
                        Address = $bcc
                    }
                }
            )
        }
        $MailBody.Message.Add("BccRecipients", $BccRecipientsList)
    }

    # Making Graph call to send email message
    try {
        Send-MgUserMail -UserId $Account -BodyParameter $MailBody -ErrorAction Stop
        $statusBarLabel.text = "Ready. Mail sent."
        Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 11" -Target $Account
    }
    catch {
        $statusBarLabel.text = "Something failed to send the email message using graph. Ready."
        Write-PSFMessage -Level Error -Message "Something failed to send the email message using graph. Error message: $_" -FunctionName "Method 11" -Target $Account
    }
}

Function Method12 {
    <#
    .SYNOPSIS
    Function to inject an email messages through MS Graph.
     
    .DESCRIPTION
    Function to inject an email messages through MS Graph.
    Module required: Microsoft.Graph.Mail
    Scope needed:
    Delegated: Mail.ReadWrite
    Application: Mail.ReadWrite
 
    .PARAMETER Account
    User's UPN to inject the email message from.
 
    .PARAMETER ToRecipients
    List of recipients in the "To" list. If ommitted, it will be used the same as the logged on user.
 
    .PARAMETER NumberOfMessages
    Number of messages to be injected into the Inbox folder. By default is 1.
 
    .PARAMETER Subject
    Use this parameter to set the subject's text. By default will have: "Test message sent via Graph".
 
    .PARAMETER Body
    Use this parameter to set the body's text. By default will have: "Test message sent via Graph using Powershell".
     
    .PARAMETER UseAttachment
    Use this switch parameter to add an attachment to sample messages.
 
    .EXAMPLE
    PS C:\> Method12 -ToRecipients "john@contoso.com"
    Then will send the email message to "john@contoso.com" from the user previously authenticated.
 
    .EXAMPLE
    PS C:\> Method12 -ToRecipients "julia@contoso.com","carlos@contoso.com" -Subject "Lets meet!"
    Then will send the email message to "julia@contoso.com" and "carlos@contoso.com" and bcc to "mark@contoso.com", from the user previously authenticated.
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")]
    [Cmdletbinding()]
    Param (
        [String] $Account,

        [String[]] $ToRecipients,

        [int] $NumberOfMessages = 1,

        [String] $Subject,

        [String] $Body,

        [Switch] $UseAttachment
    )
    $statusBarLabel.Text = "Running..."

    if ( $ToRecipients -eq "" ) { $ToRecipients = $Account }
    if ( $subject -eq "" ) { $Subject = "Test message injected via Graph" }
    if ( $Body -eq "" ) { $Body = "Test message injected via Graph using ExoGraphGUI tool" }

    # Base mail body Hashtable
    $global:MailBody = @{
        Importance = "Low"
        Sender = @{
            EmailAddress = @{
                Address = $Account
            }
        }
        Subject = $Subject
        Body    = @{
            Content     = $Body
            ContentType = "HTML"
        }
        parentFolderId = (Get-MgUserMailFolder -UserId $Account -MailFolderId "inbox").Id
    }
    
    $attachParams = $null
    if ( $UseAttachment ) {
        # create sample attachment file
        if ( -not(test-path "$env:Temp\SampleFileName.txt") ) {
            $progresBar = New-BTProgressBar -Indeterminate -Status "working"
            New-burntToastNotification -ProgressBar $progresBar -UniqueIdentifier "bar001" -Text "Creating sample file"

            [int]$i = 0
            1..5000 | ForEach-Object {
                $i++
                Write-Progress -activity "Creating sample file. Please wait..." -status "Percent scanned: " -PercentComplete ($i * 100 / 5000) -ErrorAction SilentlyContinue
                "test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. " | Add-Content -Path "$env:Temp\SampleFileName.txt" -Force
            }
        }
        $fileContentInBytes = [System.Text.Encoding]::UTF8.GetBytes((Get-Content -path "$env:Temp\SampleFileName.txt"))
        $attachParams = @{
            "@odata.type" = "#microsoft.graph.fileAttachment"
            Name          = "SampleFileName.txt"
            ContentBytes  = [System.Convert]::ToBase64String($fileContentInBytes)
        }
    }
    # looping through each recipient in the list, and adding it in the hash table
    $recipientsList = New-Object System.Collections.ArrayList
    foreach ( $recipient in ($ToRecipients.split(",").Trim()) ) {
        $recipientsList.add(
            @{
                EmailAddress = @{
                    Address = $recipient
                }
            }
        )
    }
    $global:MailBody.Add("ToRecipients", $recipientsList)

    # Making Graph call to inject email message
    try {
        [int]$i = 0
        $progresBar = New-BTProgressBar -Indeterminate -Status "working"
        New-burntToastNotification -ProgressBar $progresBar -UniqueIdentifier "bar001" -Text "Creating sample messages"

        1..$NumberOfMessages | ForEach-Object {
            $i++
            Write-Progress -activity "Creating sample message. $i / $NumberOfMessages" -status "Percent scanned: " -PercentComplete ($i * 100 / $NumberOfMessages) -ErrorAction SilentlyContinue
            $msg = New-MgUserMessage -UserId $Account -BodyParameter $MailBody
            if ( $UseAttachment ) {
                New-MgUserMessageAttachment -UserId $Account -MessageId $msg.Id -BodyParameter $attachParams
            }
            Move-MgUserMessage -UserId $Account -MessageId $msg.id -DestinationId "inbox"
        }
        $statusBarLabel.text = "Ready. Mail injected."
        Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 12" -Target $Account
    }
    catch {
        $statusBarLabel.text = "Something failed to inject the email message using graph. Ready."
        Write-PSFMessage -Level Error -Message "Something failed to inject the email message using graph. Error message: $_" -FunctionName "Method 11" -Target $Account
    }
}

Function Method13 {
    <#
    .SYNOPSIS
    Method to switch to another mailbox.
     
    .DESCRIPTION
    Method to switch to another mailbox.
     
    .PARAMETER Account
    User's UPN to switch to.
     
    .EXAMPLE
    PS C:\> Method13
    Method to switch to another mailbox.
 
    #>

    [OutputType([String])]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")]
    [CmdletBinding()]
    param(
        [String] $Account
    )
    $statusBarLabel.Text = "Running..."

     if ( $Account -ne "" ) {
        $labImpersonation.Location = New-Object System.Drawing.Point(440,135)
        $labImpersonation.Size = New-Object System.Drawing.Size(300,20)
        $labImpersonation.Name = "labImpersonation"
        $labImpersonation.ForeColor = "Blue"
        $PremiseForm.Controls.Add($labImpersonation)
        $labImpersonation.Text = $Account
        $PremiseForm.Text = "Managing user: " + $Account + ". Choose your Option"

        Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 13" -Target $Account
        $statusBarLabel.text = "Ready..."
        $PremiseForm.Refresh()
        return $Account
    }
    else {
        [Microsoft.VisualBasic.Interaction]::MsgBox("Email Address textbox is empty. Check and try again",[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message")
        $statusBarLabel.text = "Process finished with warnings/errors"
    }
}

Function Method3 {
    <#
    .SYNOPSIS
    Method to list items in a specific folders in the user mailbox.
     
    .DESCRIPTION
    Method to list items in a specific folders in the user mailbox.
    Module required: Microsoft.Graph.Mail
    Scope needed:
    Delegated: Mail.ReadBasic
    Application: Mail.ReadBasic.All
 
    .PARAMETER Account
    User's UPN to get mail messages from.
     
    .PARAMETER folderID
    FolderID value to get mail messages from.
     
    .PARAMETER StartDate
    StartDate to search for items.
     
    .PARAMETER EndDate
    EndDate to search for items.
 
    .PARAMETER MsgSubject
    Optional parameter to search based on a subject text.
     
    .EXAMPLE
    PS C:\> Method3
     
    Method to list items in a specific folders in the user mailbox.
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")]
    [CmdletBinding()]
    Param(
        [String] $Account,
        [String] $folderID,
        [string] $StartDate,
        [string] $EndDate,
        [String] $MsgSubject
    )
    $statusBarLabel.Text = "Running..."
    
    if ( $folderID -ne "" ) {
        # Creating Filter variables
        $filter = $null
        if ($MsgSubject -ne "") {
            $filter = "Subject eq '$MsgSubject'"
        }
        
        $array = New-Object System.Collections.ArrayList
        $msgs = Get-MgUserMailFolderMessage -UserId $Account -MailFolderId $folderID -Filter $filter -All | Where-Object {$_.ReceivedDateTime -ge $StartDate -and $_.ReceivedDateTime -lt $EndDate} | Select-Object subject, @{N = "Sender"; E = { $_.Sender.EmailAddress.Address } }, ReceivedDateTime, isRead
        $null = $msgs | ForEach-Object { $array.Add($_) }
        
        $dgResults.datasource = $array
        $dgResults.AutoResizeColumns()
        $dgResults.Visible = $True
        $txtBoxResults.Visible = $False
        $PremiseForm.refresh()
        $statusBarLabel.text = "Ready. Items found: $($array.Count)"
        Write-PSFMessage -Level Output -Message "Task finished succesfully" -FunctionName "Method 3" -Target $Account
    }
    else {
        [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox is empty. Check and try again", [Microsoft.VisualBasic.MsgBoxStyle]::Okonly, "Information Message")
        $statusBarLabel.text = "Method 6 finished with warnings/errors"
    }
}

Function Method4 {
    <#
    .SYNOPSIS
    Method to create a custom folder in mailbox's Root.
     
    .DESCRIPTION
    Method to create a custom folder in mailbox's Root.
    Module required: Microsoft.Graph.Mail
    Scope needed:
    Delegated: Mail.ReadWrite
    Application: Mail.ReadWrite
     
    .PARAMETER Account
    User's UPN to create mail folder to.
 
    .PARAMETER DisplayName
    DisplayName of the folder to be created.
 
    .EXAMPLE
    PS C:\> Method4
    Method to create a custom folder in mailbox's Root.
 
    #>

    [CmdletBinding()]
    param(
        [String] $Account,
        [String] $DisplayName
    )
    
    if ( $DisplayName -ne "" )
    {
        $statusBarLabel.text = "Running..."
 
        $params = @{
            DisplayName = $DisplayName
            IsHidden = $false
        }
        New-MgUserMailFolder -UserId $Account -BodyParameter $params

        Write-PSFMessage -Level Host -Message "Task finished succesfully. Folder Created: $DisplayName" -FunctionName "Method 4" -Target $Account
        $statusBarLabel.text = "Ready..."
        $PremiseForm.Refresh()
    }
    else
    {
        [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox is empty. Check and try again",[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message")
        $statusBarLabel.text = "Method 7 finished with warnings/errors"
    }
}

Function Method5 {
    <#
    .SYNOPSIS
    Method to delete a specific folder in the user mailbox.
     
    .DESCRIPTION
    Method to delete a specific folder in the user mailbox with 3 different deletion methods.
    Module required: Microsoft.Graph.Mail
    Scope needed:
    Delegated: Mail.ReadWrite
    Application: Mail.ReadWrite
 
    .PARAMETER Account
    User's UPN to delete mail folder from.
 
    .PARAMETER FolderId
    FolderId of the folder to be deleted.
 
    .EXAMPLE
    PS C:\> Method5
    Method to delete a specific folder in the user mailbox.
 
    #>

    [CmdletBinding()]
    param(
        [String] $Account,

        [String] $FolderId
    )
    $statusBarLabel.Text = "Running..."

    if ( $FolderId -ne "" )
    {
        Remove-MgUserMailFolder -UserId $Account -MailFolderId $FolderId

        Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 5" -Target $Account
        $statusBarLabel.text = "Ready..."
        $PremiseForm.Refresh()
    }
    else
    {
        [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox is empty. Check and try again",[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message")
        $statusBarLabel.text = "Process finished with warnings/errors"
    }
}

Function Method6 {
    <#
    .SYNOPSIS
    Method to get user's Inbox Rules.
    Module required: Microsoft.Graph.Mail
    Scope needed:
    Delegated: MailboxSettings.Read
    Application: MailboxSettings.Read
     
    .DESCRIPTION
    Method to get user's Inbox Rules.
     
    .PARAMETER Account
    User's UPN to get mail folders from.
     
    .EXAMPLE
    PS C:\> Method6
    Method to get user's Inbox Rules.
 
    #>

    [CmdletBinding()]
    param(
        [String] $Account
    )
    $statusBarLabel.Text = "Running..."

    $array = New-Object System.Collections.ArrayList
    $rules = Get-MgUserMailFolderMessageRule -UserId $Account -MailFolderId "Inbox"
    foreach ( $rule in $rules ) {
        $output = $rule | Select-Object DisplayName, HasError, IsEnabled, IsReadOnly, Sequence
        $array.Add($output)
    }
    $dgResults.datasource = $array
    $dgResults.AutoResizeColumns()
    $dgResults.Visible = $True
    $txtBoxResults.Visible = $False
    $PremiseForm.refresh()
    $statusBarLabel.text = "Ready..."
    Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 6" -Target $Account
}

Function Method7 {
    <#
    .SYNOPSIS
    Method to get user's OOF Settings.
    Module required: Microsoft.Graph.Authentication
    Scope needed:
    Delegated: MailboxSettings.Read
    Application: MailboxSettings.Read
 
    .DESCRIPTION
    Method to get user's OOF Settings.
     
    .PARAMETER Account
    User's UPN to get OOF settings from.
 
    .EXAMPLE
    PS C:\> Method7
    Method to get user's OOF Settings.
 
    #>

    [CmdletBinding()]
    param(
        [String] $Account
    )
    $statusBarLabel.Text = "Running..."

    $response = Invoke-MgGraphRequest -Method Get -Uri "https://graph.microsoft.com/v1.0/users/$Account/mailboxSettings/automaticRepliesSetting"

    $array = New-Object System.Collections.ArrayList
    $output = $response | Select-Object `
        @{ Name = "Status" ; Expression = { $response["Status"] } }, `
        @{ Name = "ExternalAudience" ; Expression = { $response["externalAudience"] } }, `
        @{ Name = "StartTime" ; Expression = { $response["scheduledStartDateTime"].DateTime.ToString("yyyy/MM/dd HH:mm:ss") } }, `
        @{ Name = "EndTime"   ; Expression = { $response["scheduledEndDateTime"].DateTime.ToString("yyyy/MM/dd HH:mm:ss") } }, `
        @{ Name = "InternalReplyMessage" ; Expression = { $response["InternalReplyMessage"] } }, `
        @{ Name = "ExternalReplyMessage" ; Expression = { $response["ExternalReplyMessage"] } }
    $array.Add($output)

    $dgResults.datasource = $array
    $dgResults.AutoResizeColumns()
    $dgResults.Visible = $True
    $txtBoxResults.Visible = $False
    $PremiseForm.refresh()
    $statusBarLabel.text = "Ready..."
    Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 7" -Target $Account
}

Function Method8 {
    <#
    .SYNOPSIS
    Method to move items between folders.
     
    .DESCRIPTION
    Method to move items between folders by using FolderID values.
    Module required: Microsoft.Graph.Users.Actions
    Scope needed:
    Delegated: Mail.ReadWrite
    Application: Mail.ReadWrite
 
    .PARAMETER Account
    User's UPN to get move messages from.
     
    .PARAMETER FolderID
    FolderID value to get mail messages from.
 
    .PARAMETER TargetFolderID
    FolderID value to move mail messages to.
     
    .PARAMETER StartDate
    StartDate to search for items.
     
    .PARAMETER EndDate
    EndDate to search for items.
 
    .PARAMETER MsgSubject
    Optional parameter to search based on a subject text.
     
    .EXAMPLE
    PS C:\> Method8
 
    Moves items from source folder to target folder based on dates and/or subject filters.
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")]
    [CmdletBinding()]
    Param(
        [String] $Account,
        [String] $FolderID,
        [String] $TargetFolderID,
        [string] $StartDate,
        [string] $EndDate,
        [String] $MsgSubject
    )
    $statusBarLabel.Text = "Running..."

    if ( $FolderID -ne "" -and $TargetFolderID -ne "") {
        # Creating Filter variables
        $filter = $null
        if ($MsgSubject -ne "") {
            $filter = "Subject eq '$MsgSubject'"
        }
        
        $array = New-Object System.Collections.ArrayList
        $params = @{
            DestinationId = $TargetFolderID
        }
        $msgs = Get-MgUserMailFolderMessage -UserId $Account -MailFolderId $folderID -Filter $filter -All | Where-Object { $_.ReceivedDateTime -ge $StartDate -and $_.ReceivedDateTime -lt $EndDate } | Select-Object id, subject, @{N = "Sender"; E = { $_.Sender.EmailAddress.Address } }, ReceivedDateTime, isRead
        
        [int]$i = 0
        foreach ( $msg in $msgs ) {
            $i++
            $output = $msg | Select-Object @{Name = "Action"; Expression = { "Moving Item" } }, ReceivedDateTime, Subject
            Move-MgUserMessage -UserId $Account -MessageId $msg.Id -BodyParameter $params
            $array.Add($output)
        }
        $dgResults.datasource = $array
        $dgResults.AutoResizeColumns()
        $dgResults.Visible = $True
        $txtBoxResults.Visible = $False
        $PremiseForm.refresh()
        $statusBarLabel.text = "Ready. Moved Items: $i"
        Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 8" -Target $Account
    }
    else {
        [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox or TargetFolderID is empty. Check and try again", [Microsoft.VisualBasic.MsgBoxStyle]::Okonly, "Information Message")
        $statusBarLabel.text = "Process finished with warnings/errors"
    }
}

Function Method9 {
    <#
    .SYNOPSIS
    Method to Delete a subset of items in a folder.
     
    .DESCRIPTION
    Method to Delete a subset of items in a folder using Date Filters and/or subject.
    Module required: Microsoft.Graph.Mail
    Scope needed:
    Delegated: Mail.ReadWrite
    Application: Mail.ReadWrite
 
    .PARAMETER Account
    User's UPN to get delete messages from.
     
    .PARAMETER FolderID
    FolderID value to get mail messages from.
     
    .PARAMETER StartDate
    StartDate to search for items.
     
    .PARAMETER EndDate
    EndDate to search for items.
 
    .PARAMETER MsgSubject
    Optional parameter to search based on a subject text.
 
    .EXAMPLE
    PS C:\> Method9
    Method to Delete a subset of items in a folder.
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")]
    [CmdletBinding()]
    param(
        [String] $Account,
        [String] $FolderID,
        [string] $StartDate,
        [string] $EndDate,
        [String] $MsgSubject
    )
    $statusBarLabel.Text = "Running..."

    if ( $FolderID -ne "" )
    {
        # Creating Filter variables
        $filter = $null
        if ($MsgSubject -ne "") {
            $filter = "Subject eq '$MsgSubject'"
        }
        
        $array = New-Object System.Collections.ArrayList
        [int]$i = 0

        $msgs = Get-MgUserMailFolderMessage -UserId $Account -MailFolderId $folderID -Filter $filter -All | Where-Object { $_.ReceivedDateTime -ge $StartDate -and $_.ReceivedDateTime -lt $EndDate } | Select-Object id, subject, ReceivedDateTime
        foreach ( $msg in $msgs ) {
            $i++
            Remove-MgUserMessage -UserId $Account -MessageId $msg.Id
            $output = $msg | Select-Object @{Name="Action";Expression={"Deleting Item"}}, ReceivedDateTime, Subject
            $array.Add($output)
        }

        $dgResults.datasource = $array
        $dgResults.AutoResizeColumns()
        $dgResults.Visible = $True
        $txtBoxResults.Visible = $False
        $PremiseForm.refresh()
        $statusBarLabel.text = "Ready. Deleted items: $i"
        Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 9" -Target $Account
    }
    else
    {
        [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox is empty. Check and try again",[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message")
        $statusBarLabel.text = "Process finished with warnings/errors"
    }
}

Function Start-ModuleUpdate {
    <#
    .SYNOPSIS
    Function to start checking for updates on this module.
     
    .DESCRIPTION
    Function to start checking for updates on this module.
     
    .PARAMETER ModuleRoot
    Modules root path.
 
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
     
    .EXAMPLE
    PS C:\> Start-ModuleUpdate -ModuleRoot "C:\Temp"
    Runs the function to start checking for update for current module in "C:\Temp"
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param (
        [String]$ModuleRoot
    )

    $ScriptBlock = {
        Param (
            [String]$ModuleRoot
        )
        $moduleManifest = (Import-PowerShellDataFile -Path "$((Get-ChildItem -Path $ModuleRoot -Filter *.psd1).Fullname)")
        $moduleFileName = $moduleManifest.RootModule
        $moduleName = $ModuleFileName.Substring(0, $ModuleFileName.IndexOf("."))
        $script:ModuleVersion = $moduleManifest.ModuleVersion -as [version]

        $GalleryModule = Find-Module -Name $ModuleName -Repository PSGallery
        if ( $script:ModuleVersion -lt $GalleryModule.version ) {
            # if newer version is found in PSGallery, we will show a toast notification
            $bt = New-BTButton -Content "Get Update" -Arguments "$($moduleManifest.PrivateData.PSData.ProjectUri)#installation"
            New-BurntToastNotification -Text "$ModuleName Update found", "There is a new version $($GalleryModule.version) of this module available." -Button $bt
        }
    }

    # Create Runspace, set maximum threads
    $pool = [RunspaceFactory]::CreateRunspacePool(1, 1)
    $pool.ApartmentState = "MTA"
    $pool.Open()

    $runspace = [PowerShell]::Create()
    $runspace.Runspace.Name = "$ModuleName.Update"
    $null = $runspace.AddScript( $ScriptBlock )
    $null = $runspace.AddArgument( $ModuleRoot )
    $runspace.RunspacePool = $pool

    [PSCustomObject]@{
        Pipe   = $runspace
        Status = $runspace.BeginInvoke()
        Pool   = $pool
    }
}

Function Stop-ModuleUpdate {
    <#
    .SYNOPSIS
    Function to stop checking for updates on this module and clear runspaces.
     
    .DESCRIPTION
    Function to stop checking for updates on this module and clear runspaces.
     
    .PARAMETER RunspaceData
    Runspace data retrieved from intial Start-ModuleUpdate function.
 
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
     
    .EXAMPLE
    PS C:\> Stop-ModuleUpdate -RunspaceData $data
    Runs the function to stop checking for update on this module and clear runspaces.
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    Param(
        $RunspaceData
    )
    # Receive Results and cleanup
    $null = $RunspaceData.Pipe.EndInvoke($RunspaceData.Status)
    $RunspaceData.Pipe.Dispose()

    # Cleanup Runspace Pool
    $RunspaceData.pool.Close()
    $RunspaceData.pool.Dispose()
}

function Export-ExoGraphGuiLog {
    <#
    .SYNOPSIS
    This function will export current PSFramework logs.
     
    .DESCRIPTION
    This function will export current PSFramework logs based on the amount of days old define in the 'DaysOld' parameter.
    It will allow to export to CSV file and/or display in powershell GridView.
    Output will have the following header: "ComputerName","Username","Timestamp","Level","Message","Type","FunctionName","ModuleName","File","Line","Tags","TargetObject","Runspace","Callstack"
     
    .PARAMETER FilePath
    Defines the path file to export the CSV file.
    Default value is the user's Desktop with a file name like "yyyy-MM-dd HH_mm_ss" - EWSGui logs.csv"
     
    .PARAMETER OutputType
    Defines the output types available. Can be a single output or combined.
    Current available options are CSV, GridView.
 
    .PARAMETER DaysOld
    Defines how old we will go to fetch the logs. Valid range is between 1 through 7 days old. Default Value is 1
     
    .EXAMPLE
    PS C:\> Export-ExoGraphGuiLog -OutputType CSV
    In this example, the script will fetch all logs within the last 24 hrs (by default), and export to CSV to default location at the Desktop.
     
    .EXAMPLE
    PS C:\> Export-ExoGraphGuiLog -OutputType GridView -DaysOld 3
    In this example, the script will fetch all logs within the last 3 days, and displays them in powershell's GridView.
 
    .EXAMPLE
    PS C:\> Export-ExoGraphGuiLog -OutputType CSV,GridView -DaysOld 5
    In this example, the script will fetch all logs within the last 5 days, export to CSV to default location at the Desktop and also displays in powershell's GridView.
 
    .EXAMPLE
    PS C:\> Export-ExoGraphGuiLog -OutputType CSV,GridView -DaysOld 7 -FilePath "C:\Temp\newLog.csv"
    In this example, the script will fetch all logs within the last 7 days, export to CSV to path "C:\Temp\newLog.csv" and also displays them in powershell's GridView.
    #>

    [CmdletBinding()]
    Param (
        [ValidateScript({
                if ($_ -notmatch "(\.csv)") {
                    throw "The file specified in the path argument must be of type CSV"
                }
                return $true
            })]
        [String]$FilePath = "$([Environment]::GetFolderPath("Desktop"))\$(get-date -Format "yyyy-MM-dd HH_mm_ss") - ExoGraphGui logs.csv",
        
        [ValidateSet('CSV', 'GridView')]
        [string[]]$OutputType = "GridView",

        [ValidateRange(1, 7)]
        [int]$DaysOld = 1
    )
    # creating folder path if it doesn't exists
    $folderPath = ([System.IO.FileInfo]$FilePath).DirectoryName
    if ( -not (Test-Path $folderPath) ) {
        Write-PSFMessage -Level Warning -Message "Folder '$folderPath' does not exists. Creating folder."
        $null = New-Item -Path $folderPath -ItemType Directory -Force
    }
    
    Import-module PSFramework
    $loggingpath = (Get-PSFConfig PSFramework.Logging.FileSystem.LogPath).Value
    $logFiles = Get-ChildItem -Path $loggingpath | Where-Object LastwriteTime -gt (Get-Date).adddays(-1 * $DaysOld)
    $csv = Import-Csv -Path $logFiles.FullName
    $output = $csv | Where-Object ModuleName -eq "ExoGraphGui" | Select-Object @{N = "Date"; E = { ($_.timestamp -split " ")[0] } }, @{N = "Time"; E = { Get-Date ($_.timestamp.Substring($_.timestamp.IndexOf(" ")).trim()) -Format HH:mm:ss } }, `
        "ComputerName", "Username", "Level", "FunctionName", "Message", "Type", "ModuleName", "File", "Line", "Tags", "TargetObject", "Runspace", "Callstack" | Sort-Object Date -Descending

    Switch ( $OutputType) {
        CSV { $output | export-csv -Path $FilePath -NoTypeInformation }
        GridView { $output | Out-GridView }
    }
}


function Import-ExoGraphGUIAADAppDataa {
    <#
    .SYNOPSIS
    Function to Import ClientID, TenantID and ClientSecret to the ExoGraphGUI powershell module.
 
    .DESCRIPTION
    Function to Import ClientID, TenantID and ClientSecret to the ExoGraphGUI powershell module.
     
    .PARAMETER ClientID
    String parameter with the ClientID (or AppId) of your AzureAD Registered App.
 
    .PARAMETER TenantID
    String parameter with the TenantID your AzureAD tenant.
 
    .PARAMETER CertificateThumbprint
    String parameter with the certificate's thumbprint associated to your AzureAD App registration.
 
    .PARAMETER ClientSecret
    String parameter with the Client Secret which is configured in the AzureAD App.
     
    .EXAMPLE
    PS C:\> Import-ExoGraphGUIAADAppDataa -ClientID "your app client ID" -TenantID "Your tenant ID" -ClientSecret "your Secret passcode"
 
    The script will Import these values in the ExoGraphGUI module to be used automatically.
    #>

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

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

        [Parameter(Mandatory = $false, ParameterSetName = "Certificate")]
        $CertificateThumbprint,

        [Parameter(Mandatory = $false, ParameterSetName = "ClientSecret")]
        [String] $ClientSecret
    )

    begin {

        if ( $ClientID -eq '' -or $TenantID -eq '' -or $CertificateThumbprint -eq '' -or $ClientSecret -eq '') {
            throw "Either ClientID, TenantID or CertificateThumbprint/ClientSecret are null or empty."
        }
    }

    process {
        Write-PSFMessage -Level Important -Message "Importing ClientID string to ExoGraphGUI Module."
        Set-PSFConfig -Module ExoGraphGUI -Name "ClientID" -Value $ClientID -Description "AppID of your Azure Registered App" -AllowDelete -PassThru | Register-PSFConfig
        
        Write-PSFMessage -Level Important -Message "Importing TenantID string to ExoGraphGUI Module."
        Set-PSFConfig -Module ExoGraphGUI -Name "TenantID" -Value $TenantID -Description "TenantID where your Azure App is registered." -AllowDelete -PassThru | Register-PSFConfig
        
        if ( $PSBoundParameters.ContainsKey("CertificateThumbprint") ) {
                Write-PSFMessage -Level Important -Message "Importing CertificateThumbprint string to ExoGraphGUI Module."
                Set-PSFConfig -Module ExoGraphGUI -Name "CertificateThumbprint" -Value $CertificateThumbprint -Description "CertificateThumbprint for your Azure App" -AllowDelete -PassThru | Register-PSFConfig
            }
        elseif ($PSBoundParameters.ContainsKey("ClientSecret") ) {
            Write-PSFMessage -Level Important -Message "Importing ClientSecret string to ExoGraphGUI Module."
            Set-PSFConfig -Module ExoGraphGUI -Name "ClientSecret" -Value $ClientSecret -Description "ClientSecret passcode for your Azure App" -AllowDelete -PassThru | Register-PSFConfig
        }
    }
}

Function Register-ExoGraphGUIApp {
    <#
    .SYNOPSIS
    Function to create the Azure App Registration for ExoGraphGUI.
 
    .DESCRIPTION
    Function to create the Azure App Registration for ExoGraphGUI.
    It will require an additional PS module "Microsoft.Graph.Applications", if not already installed it will download it.
    It will use these app scopes for the app "Mail.ReadWrite", "Mail.Send", "MailboxSettings.Read".
    You can use the "UseClientSecret" switch parameter to configure a new ClientSecret for the app. If this parameter is ommitted, we will use a Certificate.
    You can pass a certificate path if you have an existing certificate, or leave the parameter blank and a new self-signed certificate will be created.
 
    .PARAMETER AppName
    The friendly name of the app registration. By default will be "ExoGraphGUI Registered App".
 
    .PARAMETER TenantId
    Optional parameter to set the TenantID GUID.
 
    .PARAMETER CertPath
    The file path to your .CER public key file. If this parameter is ommitted, and the "UseClientSecret" is not used, we will be creating a new self-signed certificate (with a validity period of 1 year) for the app.
 
    .PARAMETER UseClientSecret
    Use this optional parameter, to configure a ClientSecret (with a validity period of 1 year) instead of a certificate.
 
    .PARAMETER ImportAppDataToModule
    Use this optional parameter to import your app's ClientId, TenantId and ClientSecret into the ExoGraphGUI module. In this way, the next time you run the app it will use the Application flow to authenticate with these values.
 
    .EXAMPLE
    PS C:\> Register-ExoGraphGUIApp.ps1 -AppName "Graph DemoApp"
 
    The Function will create a new AzureAD App Registration.
    The name of the app will be "ExoGraphGui Registered App".
    It will add the following API Permissions: **"Mail.ReadWrite", "MailboxSettings.Read"**.
    It will use a self-signed Certificate.
 
    Once the app is created, the Function will expose the link to grant "Admin consent" for the permissions requested.
     
    .NOTES
    General notes
#>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")]
    [Cmdletbinding()]
    param(
        [Parameter(Mandatory = $false)]
        [String]
        $AppName = "ExoGraphGUI Registered App",

        [Parameter(Mandatory = $false)]
        [String]
        $TenantId,

        [Parameter(Mandatory = $false)]
        [String]
        $CertPath,

        [Parameter(Mandatory = $false)]
        [Switch]
        $UseClientSecret,
    
        [Parameter(Mandatory = $false)]
        [Switch]
        $ImportAppDataToModule
    )
    # Required modules
    Write-PSFMessage -Level Verbose -Message "Looking for required 'Microsoft.Graph.Applications' powershell module"
    if ( -not(Get-module "Microsoft.Graph.Applications" -ListAvailable) ) {
        Install-Module "Microsoft.Graph.Applications" -Scope CurrentUser -Force
    }
    Import-Module "Microsoft.Graph.Applications"

    # Graph permissions variables
    #$graphResourceId = "00000002-0000-0ff1-ce00-000000000000"
    $graphResourceId = "00000003-0000-0000-c000-000000000000"
    
    $scopesArray = New-Object System.Collections.ArrayList
    @("Mail.ReadWrite", "Mail.Send", "MailboxSettings.Read") | ForEach-Object {
        New-Variable perm -Value @{
            Id   = (Find-MgGraphPermission -SearchString $_ -PermissionType Application -ExactMatch).id
            Type = "Role"
        }
        $null = $scopesArray.add($perm)
        remove-variable perm
    }

    # Get context for access to tenant ID
    $context = Get-MgContext
    if ( $null -eq $context -or $context.Scopes -notcontains "Application.ReadWrite.All") {
        # Requires an admin
        Write-PSFMessage -Level Important -Message "Connecting to MgGraph"
        if ($TenantId) {
            Connect-MgGraph -Scopes "Application.ReadWrite.All User.Read" -TenantId $TenantId
        }
        else {
            Connect-MgGraph -Scopes "Application.ReadWrite.All User.Read"
        }
    }
    
    # Load cert
    if ( $CertPath ) {
        $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertPath)
        Write-PSFMessage -Level Host -Message "Certificate loaded from Path '$CertPath'."
    }
    elseif ( -not($UseClientSecret) ) {
        # Create certificate
        $docsPath = [Environment]::GetFolderPath("myDocuments")
        $mycert = New-SelfSignedCertificate -DnsName $context.Account.Split("@")[1] -CertStoreLocation "cert:\CurrentUser\My" -NotAfter (Get-Date).AddYears(1) -KeySpec KeyExchange

        # Export certificate to .pfx file
        $mycert | Export-PfxCertificate -FilePath "$docsPath\exographgui_cert.pfx" -Password (ConvertTo-SecureString -String "LS1setup!" -AsPlainText -Force ) -Force

        # Export certificate to .cer file
        $mycert | Export-Certificate -FilePath "$docsPath\exographgui_mycert.cer" -Force
        $cerPath = Get-ChildItem -Path "$docsPath\exographgui_mycert.cer"
        $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($cerPath.FullName)
        Write-PSFMessage -Level Host -Message "Certificate created in Path '$($cerPath.FullName)'."
    }

    # Create app registration
    if ( -not($UseClientSecret) ) {
        $appRegistration = New-MgApplication -DisplayName $AppName -SignInAudience "AzureADMyOrg" `
            -Web @{ RedirectUris = "http://localhost"; } `
            -RequiredResourceAccess @{ ResourceAppId = $graphResourceId; ResourceAccess = $scopesArray.ToArray() } `
            -AdditionalProperties @{} -KeyCredentials @(@{ Type = "AsymmetricX509Cert"; Usage = "Verify"; Key = $cert.RawData })
        Write-PSFMessage -Level Important -Message "App registration created with app ID $($appRegistration.AppId)"
        Write-PSFMessage -Level Important -Message "You can now connect running: Start-ExoGraphGUI -ClientID $($appRegistration.AppId) -TenantID $($context.TenantId) -CertificateThumbprint $($cert.Thumbprint)"
    }
    else {
        $appRegistration = New-MgApplication -DisplayName $AppName -SignInAudience "AzureADMyOrg" `
            -Web @{ RedirectUris = "http://localhost"; } `
            -RequiredResourceAccess @{ ResourceAppId = $graphResourceId; ResourceAccess = $scopesArray.ToArray() } `
            -AdditionalProperties @{}

        $appObjId = Get-MgApplication -Filter "AppId eq '$($appRegistration.Appid)'"
        $passwordCred = @{
            displayName = 'Secret created in PowerShell'
            endDateTime = (Get-Date).Addyears(1)
        }
        $secret = Add-MgApplicationPassword -applicationId $appObjId.Id -PasswordCredential $passwordCred
        Write-PSFMessage -Level Important -Message "App registration created with app ID $($appRegistration.AppId)"
        Write-PSFMessage -Level Important -Message "Please take note of your client secret as it will not be shown anymore"
        Write-PSFMessage -Level Important -Message "You can now connect running: Start-ExoGraphGUI -ClientID $($appRegistration.AppId) -TenantID $($context.TenantId) -ClientSecret $($secret.SecretText)"
    }
    
    # Create corresponding service principal
    New-MgServicePrincipal -AppId $appRegistration.AppId -AdditionalProperties @{} | Out-Null
    Write-PSFMessage -Level Verbose -Message "Service principal created"
    
    # Generate admin consent URL
    $adminConsentUrl = "https://login.microsoftonline.com/" + $context.TenantId + "/adminconsent?client_id=" + $appRegistration.AppId
    Write-PSFMessage -Level Important -Message "Please go to the following URL in your browser to provide admin consent:"
    Write-PSFMessage -Level Important -Message "$adminConsentUrl"

    if ( $ImportAppDataToModule ) {
        if ( -not($UseClientSecret) ) {
            Import-ExoGraphGUIAADAppData -ClientID $appRegistration.AppId -TenantID $context.TenantId -CertificateThumbprint $($cert.Thumbprint)
        }
        else {
            Import-ExoGraphGUIAADAppData -ClientID $appRegistration.AppId -TenantID $context.TenantId -ClientSecret $secret.SecretText
        }
    }
}

function Remove-ExoGraphGUIAADAppData {
    <#
    .SYNOPSIS
    Function to remove ClientID, TenantID and ClientSecret to the ExoGraphGUI powershell module.
     
    .DESCRIPTION
    Function to remove ClientID, TenantID and ClientSecret to the ExoGraphGUI powershell module.
     
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
 
    .EXAMPLE
    PS C:\> Remove-ExoGraphGUIAADAppData
 
    The script will Remove these values in the ExoGraphGUI module to be used automatically.
    #>

    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    param (
        # Parameters
    )
    
    begin {

    }
    
    process {
        Write-PSFMessage -Level Important -Message "Removing ClientID, TenantID and ClientSecret strings from ExoGraphGUI Module."
        Unregister-PSFConfig -Module ExoGraphGUI
        remove-PSFConfig -Module ExoGraphGUI -Name clientID -Confirm:$false
        remove-PSFConfig -Module ExoGraphGUI -Name tenantID -Confirm:$false
        remove-PSFConfig -Module ExoGraphGUI -Name ClientSecret -Confirm:$false
    }
    
    end {
        
    }
}

Function Start-ExoGraphGUI {
    <#
    .SYNOPSIS
        Allows to perform 11 different operations using Graph with Exchange Online.
 
    .DESCRIPTION
        Allows to perform 11 different operations using Graph with Exchange Online:
        1) List Folders in Root
        2) List folders in Recoverable Items Root folder
        3) List Items in a desired Folder
        4) Create a custom Folder in Root
        5) Delete a Folder
        6) Get user's Inbox Rules
        7) Get user's OOF Settings
        8) Move items between folders
        9) Delete a subset of items in a folder
        10) Get user's Delegate information
        11) Send mail message
        12) Switch to another Mailbox
     
    .PARAMETER ClientID
    This is an optional parameter. String parameter with the ClientID (or AppId) of your AzureAD Registered App.
 
    .PARAMETER TenantID
    This is an optional parameter. String parameter with the TenantID your AzureAD tenant.
 
    .PARAMETER CertificateThumbprint
    This is an optional parameter. String parameter with the certificate thumbprint which is configured in the AzureAD App.
 
    .PARAMETER ClientSecret
    This is an optional parameter. String parameter with the Client Secret which is configured in the AzureAD App.
 
    .PARAMETER Confirm
    If this switch is enabled, you will be prompted for confirmation before executing any operations that change state.
 
    .PARAMETER WhatIf
    If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
 
    .EXAMPLE
    PS C:\ Start-ExoGraphGUI
    Runs the GUI tool to use with Exchange Online.
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")]
    [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
    param(
        [String] $ClientID,

        [String] $TenantID,

        #[Parameter(Mandatory = $false, ParameterSetName="Certificate")]
        [String] $CertificateThumbprint,

        #[Parameter(Mandatory = $false, ParameterSetName="ClientSecret")]
        [String] $ClientSecret
    )
    $script:nl = "`r`n"
    #$ProgressPreference = "SilentlyContinue"

    $runspaceData = Start-ModuleUpdate -ModuleRoot $script:ModuleRoot
    function GenerateForm {
   
        #region Import the Assemblies
        Add-Type -AssemblyName System.Windows.Forms
        Add-Type -AssemblyName System.Drawing
        Add-Type -AssemblyName Microsoft.VisualBasic
        [System.Windows.Forms.Application]::EnableVisualStyles()
        #endregion
 
        #region Generated Form Objects
        $PremiseForm = New-Object System.Windows.Forms.Form
        $radiobutton1 = New-Object System.Windows.Forms.RadioButton
        $radiobutton2 = New-Object System.Windows.Forms.RadioButton
        $radiobutton3 = New-Object System.Windows.Forms.RadioButton
        $radiobutton4 = New-Object System.Windows.Forms.RadioButton
        $radiobutton5 = New-Object System.Windows.Forms.RadioButton
        $radiobutton6 = New-Object System.Windows.Forms.RadioButton
        $radiobutton7 = New-Object System.Windows.Forms.RadioButton
        $radiobutton8 = New-Object System.Windows.Forms.RadioButton
        $radiobutton9 = New-Object System.Windows.Forms.RadioButton
        $radiobutton10 = New-Object System.Windows.Forms.RadioButton
        $radiobutton11 = New-Object System.Windows.Forms.RadioButton
        $radiobutton12 = New-Object System.Windows.Forms.RadioButton
        $radiobutton13 = New-Object System.Windows.Forms.RadioButton
        $radiobutton14 = New-Object System.Windows.Forms.RadioButton
        $radiobutton15 = New-Object System.Windows.Forms.RadioButton
        $radiobutton16 = New-Object System.Windows.Forms.RadioButton
        $labImpersonation = New-Object System.Windows.Forms.Label
        $buttonGo = New-Object System.Windows.Forms.Button
        $buttonExit = New-Object System.Windows.Forms.Button

        $labFromDate = New-Object System.Windows.Forms.Label
        $global:FromDatePicker = New-Object System.Windows.Forms.DateTimePicker
        $labToDate = New-Object System.Windows.Forms.Label
        $global:ToDatePicker = New-Object System.Windows.Forms.DateTimePicker
        $labSubject = New-Object System.Windows.Forms.Label
        $global:txtBoxSubject = New-Object System.Windows.Forms.TextBox
        $labFolderID = New-Object System.Windows.Forms.Label
        $global:txtBoxFolderID = New-Object System.Windows.Forms.TextBox
        $labTargetFolderID = New-Object System.Windows.Forms.Label
        $global:txtBoxTargetFolderID = New-Object System.Windows.Forms.TextBox
        $labToRecipients = New-Object System.Windows.Forms.Label
        $global:txtBoxToRecipients = New-Object System.Windows.Forms.TextBox
        $labCCRecipients = New-Object System.Windows.Forms.Label
        $global:txtBoxCCRecipients = New-Object System.Windows.Forms.TextBox
        $labBCCRecipients = New-Object System.Windows.Forms.Label
        $global:txtBoxBCCRecipients = New-Object System.Windows.Forms.TextBox
        $labMailSubject = New-Object System.Windows.Forms.Label
        $global:txtboxMailSubject = New-Object System.Windows.Forms.TextBox
        $labMailBody = New-Object System.Windows.Forms.Label
        $global:txtBoxMailBody = New-Object System.Windows.Forms.TextBox
        $labNumOfMsgs = New-Object System.Windows.Forms.Label
        $global:NumericNumOfMsgs = New-Object System.Windows.Forms.NumericUpDown
        $UseAttachment = New-Object System.Windows.Forms.Label
        $global:checkboxUseAttachment = New-Object System.Windows.Forms.Checkbox
        $labAttachmentsWarning = New-Object System.Windows.Forms.Label
        $dgResults = New-Object System.Windows.Forms.DataGridView
        $txtBoxResults = New-Object System.Windows.Forms.Label
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        #endregion Generated Form Objects

        # Connecting to EWS and creating service object
        $service = Connect-ExoGraphGuiService -ClientID $ClientID -TenantID $TenantID -CertificateThumbprint $CertificateThumbprint
        $Global:Account = $service.Account
        if (-not($service.Account)) {
            $Global:Account = [Microsoft.VisualBasic.Interaction]::InputBox("Enter user's UPN to work with", "ExoGraphGUI", "")
        }

        $ExpandFilters = {
            # Removing all controls, in order to reload the screen appropiately for each selection
            $PremiseForm.Controls.RemoveByKey("FromDate")
            $PremiseForm.Controls.RemoveByKey("FromDatePicker")
            $PremiseForm.Controls.RemoveByKey("ToDate")
            $PremiseForm.Controls.RemoveByKey("ToDatePicker")
            $PremiseForm.Controls.RemoveByKey("labSubject")
            $PremiseForm.Controls.RemoveByKey("txtBoxSubject")
            $PremiseForm.Controls.RemoveByKey("labFolderID")
            $PremiseForm.Controls.RemoveByKey("txtBoxFolderID")
            $PremiseForm.Controls.RemoveByKey("txtBoxTargetFolderID")
            $PremiseForm.Controls.RemoveByKey("labTargetFolderID")
            $PremiseForm.Controls.RemoveByKey("labToRecipients")
            $PremiseForm.Controls.RemoveByKey("txtBoxToRecipients")
            $PremiseForm.Controls.RemoveByKey("labCCRecipients")
            $PremiseForm.Controls.RemoveByKey("txtBoxCCRecipients")
            $PremiseForm.Controls.RemoveByKey("labBCCRecipients")
            $PremiseForm.Controls.RemoveByKey("txtBoxBCCRecipients")
            $PremiseForm.Controls.RemoveByKey("labMailSubject")
            $PremiseForm.Controls.RemoveByKey("txtBoxMailSubject")
            $PremiseForm.Controls.RemoveByKey("labMailbody")
            $PremiseForm.Controls.RemoveByKey("txtboxMailBody")
            $PremiseForm.Controls.RemoveByKey("labNumOfMsgs")
            $PremiseForm.Controls.RemoveByKey("NumericNumOfMsgs")
            $PremiseForm.Controls.RemoveByKey("UseAttachment")
            $PremiseForm.Controls.RemoveByKey("checkboxUseAttachment")

            #Label FromDate
            $labFromDate.Location = New-Object System.Drawing.Point(5, 285)
            $labFromDate.Size = New-Object System.Drawing.Size(80, 35)
            $labFromDate.Name = "FromDate"
            $labFromDate.Text = "From or greater than"

            # FromDate Date Picker
            $FromDatePicker.DataBindings.DefaultDataSourceUpdateMode = 0
            $FromDatePicker.Location = New-Object System.Drawing.Point(100, 285)
            $FromDatePicker.Name = "FromDatePicker"
            $FromDatePicker.Text = ""

            #Label ToDate
            $labToDate.Location = New-Object System.Drawing.Point(5, 330)
            $labToDate.Name = "ToDate"
            $labToDate.Size = New-Object System.Drawing.Size(80, 40)
            $labToDate.Text = "To or less than"

            # ToDate Date Picker
            $ToDatePicker.DataBindings.DefaultDataSourceUpdateMode = 0
            $ToDatePicker.Location = New-Object System.Drawing.Point(100, 330)
            $ToDatePicker.Name = "ToDatePicker"
            $ToDatePicker.Text = ""

            #Label Subject
            $labSubject.Location = New-Object System.Drawing.Point(5, 370)
            $labSubject.Size = New-Object System.Drawing.Size(50, 20)
            $labSubject.Name = "labSubject"
            $labSubject.Text = "Subject: "
 
            #TextBox Subject
            $txtBoxSubject.Location = New-Object System.Drawing.Point(100, 370)
            $txtBoxSubject.Size = New-Object System.Drawing.Size(280, 20)
            $txtBoxSubject.Name = "txtBoxSubject"
            $txtBoxSubject.Text = ""

            #Label FolderID
            $labFolderID.Location = New-Object System.Drawing.Point(5, 400)
            $labFolderID.Size = New-Object System.Drawing.Size(55, 20)
            $labFolderID.Name = "labFolderID"
            $labFolderID.Text = "FolderID:"

            #TextBox FolderID
            $txtBoxFolderID.Location = New-Object System.Drawing.Point(100, 400)
            $txtBoxFolderID.Size = New-Object System.Drawing.Size(280, 20)
            $txtBoxFolderID.Name = "txtBoxFolderID"
            $txtBoxFolderID.Text = ""

            #Adapting FolderID and TxtBoxFolderID based on the selection
            if ($radiobutton4.Checked -or $radiobutton5.Checked) {
                $labFolderID.Location = New-Object System.Drawing.Point(5, 285)
                $txtBoxFolderID.Location = New-Object System.Drawing.Point(100, 285)
            }
            elseif ($radiobutton8.Checked) {
                $labFolderID.Size = New-Object System.Drawing.Size(95, 20)
                $labFolderID.Text = "SourceFolderID:"
            }
            elseif ($radiobutton13.Checked) {
                $labFolderID.Location = New-Object System.Drawing.Point(5, 285)
                $labFolderID.Size = New-Object System.Drawing.Size(95, 20)
                $labFolderID.Text = "E-mail Address:"
                $txtBoxFolderID.Location = New-Object System.Drawing.Point(100, 285)
            }

            #Label Target FolderID
            $labTargetFolderID.Location = New-Object System.Drawing.Point(5, 430)
            $labTargetFolderID.Size = New-Object System.Drawing.Size(95, 20)
            $labTargetFolderID.Name = "labTargetFolderID"
            $labTargetFolderID.Text = "TargetFolderID:"

            #TextBox Target FolderID
            $txtBoxTargetFolderID.Location = New-Object System.Drawing.Point(100, 430)
            $txtBoxTargetFolderID.Size = New-Object System.Drawing.Size(280, 20)
            $txtBoxTargetFolderID.Name = "txtBoxTargetFolderID"
            $txtBoxTargetFolderID.Text = ""

            #Label TO recipients
            $labToRecipients.Location = New-Object System.Drawing.Point(5, 287)
            $labToRecipients.Size = New-Object System.Drawing.Size(25, 25)
            $labToRecipients.Name = "labToRecipients"
            $labToRecipients.Text = "To:"

            #TextBox TO recipients
            $txtBoxToRecipients.Location = New-Object System.Drawing.Point(95, 285)
            $txtBoxToRecipients.Size = New-Object System.Drawing.Size(280, 20)
            $txtBoxToRecipients.Name = "txtBoxToRecipients"
            $txtBoxToRecipients.Text = ""

            #Label CC Recipients
            $labCCRecipients.Location = New-Object System.Drawing.Point(5, 312)
            $labCCRecipients.Size = New-Object System.Drawing.Size(25, 25)
            $labCCRecipients.Name = "labCCRecipients"
            $labCCRecipients.Text = "Cc:"

            #TextBox CC recipients
            $txtBoxCCRecipients.Location = New-Object System.Drawing.Point(95, 310)
            $txtBoxCCRecipients.Size = New-Object System.Drawing.Size(280, 20)
            $txtBoxCCRecipients.Name = "txtBoxCCRecipients"
            $txtBoxCCRecipients.Text = ""

            #Label BCC Recipients
            $labBCCRecipients.Location = New-Object System.Drawing.Point(5, 337)
            $labBCCRecipients.Size = New-Object System.Drawing.Size(30, 25)
            $labBCCRecipients.Name = "labBCCRecipients"
            $labBCCRecipients.Text = "Bcc:"

            #TextBox BCC recipients
            $txtBoxBCCRecipients.Location = New-Object System.Drawing.Point(95, 335)
            $txtBoxBCCRecipients.Size = New-Object System.Drawing.Size(280, 20)
            $txtBoxBCCRecipients.Name = "txtBoxBCCRecipients"
            $txtBoxBCCRecipients.Text = ""

            #Label Mail Subject
            $labMailSubject.Location = New-Object System.Drawing.Point(5, 362)
            $labMailSubject.Size = New-Object System.Drawing.Size(50, 25)
            $labMailSubject.Name = "labMailSubject"
            $labMailSubject.Text = "Subject:"

            #TextBox Mail Subject
            $txtboxMailSubject.Location = New-Object System.Drawing.Point(95, 360)
            $txtboxMailSubject.Size = New-Object System.Drawing.Size(280, 20)
            $txtboxMailSubject.Name = "txtboxMailSubject"
            $txtboxMailSubject.Text = ""

            #Label Mail Body
            $labMailBody.Location = New-Object System.Drawing.Point(5, 387)
            $labMailBody.Size = New-Object System.Drawing.Size(45, 25)
            $labMailBody.Name = "labMailBody"
            $labMailBody.Text = "Body:"

            #TextBox Mail Body
            $txtboxMailBody.Location = New-Object System.Drawing.Point(95, 385)
            $txtboxMailBody.Size = New-Object System.Drawing.Size(280, 50)
            $txtboxMailBody.Name = "txtboxMailBody"
            $txtboxMailBody.Text = ""

            #Label Number of Messages
            $labNumOfMsgs.Location = New-Object System.Drawing.Point(5, 312)
            $labNumOfMsgs.Size = New-Object System.Drawing.Size(90, 28)
            $labNumOfMsgs.Name = "labNumOfMsgs"
            $labNumOfMsgs.Text = "# of Messages:"

            # NumericNumOfMsgs
            $NumericNumOfMsgs.DataBindings.DefaultDataSourceUpdateMode = 0
            $NumericNumOfMsgs.Location = New-Object System.Drawing.Point(95, 310)
            $NumericNumOfMsgs.Size = New-Object System.Drawing.Size(40, 30)
            $NumericNumOfMsgs.Name = "NumericNumOfMsgs"
            $NumericNumOfMsgs.Minimum = 1
            $NumericNumOfMsgs.Maximum = 9999
            $NumericNumOfMsgs.Value = 1

            # Label Use Attachment
            $UseAttachment.Location = New-Object System.Drawing.Point(5, 337)
            $UseAttachment.Size = New-Object System.Drawing.Size(110, 35)
            $UseAttachment.Name = "UseAttachment"
            $UseAttachment.Text = "Add attachment"

            # checkbox Use Attachment
            $checkboxUseAttachment.DataBindings.DefaultDataSourceUpdateMode = 0
            $checkboxUseAttachment.Location = New-Object System.Drawing.Point(117, 335)
            $checkboxUseAttachment.Size = New-Object System.Drawing.Size(15, 20)
            $checkboxUseAttachment.Name = "checkboxUseAttachment"
            $checkboxUseAttachment.Checked = $false

            # Label Attachments warning
            $labAttachmentsWarning.Location = New-Object System.Drawing.Point(660, 82)
            $labAttachmentsWarning.Size = New-Object System.Drawing.Size(10, 20)
            $labAttachmentsWarning.Name = "labAttachmentsWarning"
            $labAttachmentsWarning.Font = New-Object System.Drawing.Font("Arial",9,[System.Drawing.FontStyle]::Underline)
            $labAttachmentsWarning.ForeColor = "Blue"
            $labAttachmentsWarning.Text = "?"
            $labAttachmentsWarning.add_Click({
                [Microsoft.VisualBasic.Interaction]::MsgBox("Injecting sample messages with no attachments should be pretty fast.
But when using attachments, it might take considerable seconds."
,[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message")
            })
            $PremiseForm.Controls.Add($labAttachmentsWarning)

            if ($radiobutton3.Checked) {
                $PremiseForm.Controls.Add($labFolderID)
                $PremiseForm.Controls.Add($txtBoxFolderID)
                $PremiseForm.Controls.Add($labFromDate)
                $PremiseForm.Controls.Add($FromDatePicker)
                $PremiseForm.Controls.Add($labToDate)
                $PremiseForm.Controls.Add($ToDatePicker)
                $PremiseForm.Controls.Add($labSubject)
                $PremiseForm.Controls.Add($txtBoxSubject)
            }
            elseif ($radiobutton4.Checked) {
                $labFolderID.Size = New-Object System.Drawing.Size(95, 20)
                $labFolderID.Text = "Folder Name:"
                $PremiseForm.Controls.Add($labFolderID)
                $PremiseForm.Controls.Add($txtBoxFolderID)
            }
            elseif ($radiobutton5.Checked) {
                $PremiseForm.Controls.Add($labFolderID)
                $PremiseForm.Controls.Add($txtBoxFolderID)
            }
            elseif ($radiobutton8.Checked) {
                $PremiseForm.Controls.Add($labFromDate)
                $PremiseForm.Controls.Add($FromDatePicker)
                $PremiseForm.Controls.Add($labToDate)
                $PremiseForm.Controls.Add($ToDatePicker)
                $PremiseForm.Controls.Add($labSubject)
                $PremiseForm.Controls.Add($txtBoxSubject)
                $PremiseForm.Controls.Add($labFolderID)
                $PremiseForm.Controls.Add($txtBoxFolderID)
                $PremiseForm.Controls.Add($labTargetFolderID)
                $PremiseForm.Controls.Add($txtBoxTargetFolderID)
            }
            elseif ($radiobutton9.Checked) {
                $PremiseForm.Controls.Add($labFromDate)
                $PremiseForm.Controls.Add($FromDatePicker)
                $PremiseForm.Controls.Add($labToDate)
                $PremiseForm.Controls.Add($ToDatePicker)
                $PremiseForm.Controls.Add($labSubject)
                $PremiseForm.Controls.Add($txtBoxSubject)
                $PremiseForm.Controls.Add($labFolderID)
                $PremiseForm.Controls.Add($txtBoxFolderID)
            }
            elseif ( $radiobutton11.Checked) {
                $PremiseForm.Controls.Add($labToRecipients)
                $PremiseForm.Controls.Add($txtBoxToRecipients)
                $PremiseForm.Controls.Add($labCCRecipients)
                $PremiseForm.Controls.Add($txtBoxCCRecipients)
                $PremiseForm.Controls.Add($labBCCRecipients)
                $PremiseForm.Controls.Add($txtBoxBCCRecipients)
                $PremiseForm.Controls.Add($labMailSubject)
                $PremiseForm.Controls.Add($txtboxMailSubject)
                $PremiseForm.Controls.Add($labMailBody)
                $PremiseForm.Controls.Add($txtboxMailBody)
            }
            elseif ( $radiobutton12.Checked) {
                $PremiseForm.Controls.Add($labToRecipients)
                $PremiseForm.Controls.Add($txtBoxToRecipients)
                $PremiseForm.Controls.Add($labNumOfMsgs)
                $PremiseForm.Controls.Add($NumericNumOfMsgs)
                $PremiseForm.Controls.Add($labMailSubject)
                $PremiseForm.Controls.Add($txtboxMailSubject)
                $PremiseForm.Controls.Add($labMailBody)
                $PremiseForm.Controls.Add($txtboxMailBody)
                $PremiseForm.Controls.Add($UseAttachment)
                $PremiseForm.Controls.Add($checkboxUseAttachment)
            }
            elseif ($radiobutton13.Checked) {
                $PremiseForm.Controls.Add($labFolderID)
                $PremiseForm.Controls.Add($txtBoxFolderID)
            }
            $PremiseForm.refresh()
        }

        $OnLoadMainWindow_StateCorrection = { #Correct the initial state of the form to prevent the .Net maximized form issue
            $PremiseForm.WindowState = $InitialFormWindowState
        }

        #----------------------------------------------
        #region Generated Form Code

        $PremiseForm.Controls.Add($radiobutton1)
        $PremiseForm.Controls.Add($radiobutton2)
        $PremiseForm.Controls.Add($radiobutton3)
        $PremiseForm.Controls.Add($radiobutton4)
        $PremiseForm.Controls.Add($radiobutton5)
        $PremiseForm.Controls.Add($radiobutton6)
        $PremiseForm.Controls.Add($radiobutton7)
        $PremiseForm.Controls.Add($radiobutton8)
        $PremiseForm.Controls.Add($radiobutton9)
        $PremiseForm.Controls.Add($radiobutton10)
        $PremiseForm.Controls.Add($radiobutton11)
        $PremiseForm.Controls.Add($radiobutton12)
        if ( $null -eq $service.Account ) {
            $PremiseForm.Controls.Add($radiobutton13)
        }
        
        $PremiseForm.Controls.Add($buttonGo)
        $PremiseForm.Controls.Add($buttonExit)

        $statusBar = New-Object System.Windows.Forms.StatusStrip
        $statusBar.Name = "statusBar"
        $statusBarLabel = New-Object System.Windows.Forms.ToolStripStatusLabel
        $null = $statusBar.Items.Add($statusBarLabel)
        $statusBarLabel.Text = "Ready..."
        $PremiseForm.Controls.Add($statusBar)
        $PremiseForm.ClientSize = New-Object System.Drawing.Size(850, 720)
        $PremiseForm.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $PremiseForm.Name = "form1"
        $PremiseForm.Text = "Managing user: $Account. Choose your Option"
        $PremiseForm.StartPosition = "CenterScreen"
        $PremiseForm.KeyPreview = $True
        $PremiseForm.Add_KeyDown({ if ($_.KeyCode -eq "Escape") { $PremiseForm.Close() } })
        #
        # radiobutton1
        #
        $radiobutton1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton1.Location = New-Object System.Drawing.Point(20, 20)
        $radiobutton1.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton1.Text = "1 - List Folders in Root"
        $radioButton1.Checked = $true
        $radiobutton1.UseVisualStyleBackColor = $True
        $radiobutton1.Add_Click({ & $ExpandFilters })
        #
        # radiobutton2
        #
        $radiobutton2.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton2.Location = New-Object System.Drawing.Point(20, 50)
        $radiobutton2.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton2.Text = "2 - List folders in Recoverable Items Root folder"
        $radioButton2.Checked = $false
        $radiobutton2.UseVisualStyleBackColor = $True
        $radiobutton2.Add_Click({ & $ExpandFilters })
        #
        # radiobutton3
        #
        $radiobutton3.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton3.Location = New-Object System.Drawing.Point(20, 80)
        $radiobutton3.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton3.Text = "3 - List Items in a desired Folder"
        $radiobutton3.Checked = $false
        $radiobutton3.UseVisualStyleBackColor = $True
        $radiobutton3.Add_Click({ & $ExpandFilters })
        #
        # radiobutton4
        #
        $radiobutton4.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton4.Location = New-Object System.Drawing.Point(20, 110)
        $radiobutton4.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton4.Text = "4 - Create a custom Folder in Root"
        $radiobutton4.Checked = $false
        $radiobutton4.UseVisualStyleBackColor = $True
        $radiobutton4.Add_Click({ & $ExpandFilters })
        #
        # radiobutton5
        #
        $radiobutton5.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton5.Location = New-Object System.Drawing.Point(20, 140)
        $radiobutton5.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton5.Text = "5 - Delete a Folder"
        $radiobutton5.Checked = $false
        $radiobutton5.UseVisualStyleBackColor = $True
        $radiobutton5.Add_Click({ & $ExpandFilters })
        #
        # radiobutton6
        #
        $radiobutton6.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton6.Location = New-Object System.Drawing.Point(20, 170)
        $radiobutton6.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton6.Text = "6 - Get user's Inbox Rules"
        $radiobutton6.Checked = $false
        $radiobutton6.UseVisualStyleBackColor = $True
        $radiobutton6.Add_Click({ & $ExpandFilters })
        #
        # radiobutton7
        #
        $radiobutton7.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton7.Location = New-Object System.Drawing.Point(20, 200)
        $radiobutton7.Name = "radiobutton7"
        $radiobutton7.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton7.Text = "7 - Get user's OOF Settings"
        $radiobutton7.Checked = $false
        $radiobutton7.UseVisualStyleBackColor = $True
        $radiobutton7.Add_Click({ & $ExpandFilters })
        #
        # radiobutton8
        #
        $radiobutton8.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton8.Location = New-Object System.Drawing.Point(20, 230)
        $radiobutton8.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton8.Text = "8 - Move items between folders"
        $radiobutton8.Checked = $false
        $radiobutton8.UseVisualStyleBackColor = $True
        $radiobutton8.Add_Click({ & $ExpandFilters })
        #
        # radiobutton9
        #
        $radiobutton9.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton9.Location = New-Object System.Drawing.Point(20, 260)
        $radiobutton9.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton9.TabIndex = 9
        $radiobutton9.Text = "9 - Delete a subset of items in a folder"
        $radiobutton9.Checked = $false
        $radiobutton9.UseVisualStyleBackColor = $True
        $radiobutton9.Add_Click({ & $ExpandFilters })
        #
        # radiobutton10
        #
        $radiobutton10.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton10.Location = New-Object System.Drawing.Point(400, 20)
        $radiobutton10.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton10.Text = "10 - Get user's Delegate information"
        $radiobutton10.Checked = $false
        $radiobutton10.UseVisualStyleBackColor = $True
        $radiobutton10.Add_Click({ & $ExpandFilters })
        #
        # radiobutton11
        #
        $radiobutton11.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton11.Location = New-Object System.Drawing.Point(400, 50)
        $radiobutton11.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton11.Text = "11 - Send mail message"
        $radiobutton11.Checked = $false
        $radiobutton11.UseVisualStyleBackColor = $True
        $radiobutton11.Add_Click({ & $ExpandFilters })
        #
        # radiobutton12
        #
        $radiobutton12.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton12.Location = New-Object System.Drawing.Point(400, 80)
        $radiobutton12.Size = New-Object System.Drawing.Size(260, 20)
        $radiobutton12.Text = "12 - Inject mail messages into 'Inbox' folder"
        $radiobutton12.Checked = $false
        $radiobutton12.UseVisualStyleBackColor = $True
        $radiobutton12.Add_Click({ & $ExpandFilters })
        #
        # radiobutton13
        #
        $radiobutton13.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton13.Location = New-Object System.Drawing.Point(400, 110)
        $radiobutton13.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton13.Text = "13 - Switch to another Mailbox:"
        $radiobutton13.Checked = $false
        $radiobutton13.UseVisualStyleBackColor = $True
        $radiobutton13.Add_Click({ & $ExpandFilters })
        #
        # radiobutton14
        #
        $radiobutton14.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton14.Location = New-Object System.Drawing.Point(400, 140)
        $radiobutton14.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton14.Text = "14"
        $radiobutton14.Checked = $false
        $radiobutton14.UseVisualStyleBackColor = $True
        $radiobutton14.Add_Click({ & $ExpandFilters })
        #
        # radiobutton15
        #
        $radiobutton15.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton15.Location = New-Object System.Drawing.Point(400, 170)
        $radiobutton15.Size = New-Object System.Drawing.Size(300, 20)
        $radiobutton15.Text = "15"
        $radiobutton15.Checked = $false
        $radiobutton15.UseVisualStyleBackColor = $True
        $radiobutton15.Add_Click({ & $ExpandFilters })
        #
        # radiobutton16
        #
        $radiobutton16.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
        $radiobutton16.Location = New-Object System.Drawing.Point(400, 200)
        $radiobutton16.Size = New-Object System.Drawing.Size(190, 20)
        $radiobutton16.Text = "16"
        $radiobutton16.Checked = $false
        $radiobutton16.UseVisualStyleBackColor = $True
        $radiobutton16.Add_Click({ & $ExpandFilters })

        #"Go" button
        $buttonGo.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonGo.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonGo.Location = New-Object System.Drawing.Point(700, 20)
        $buttonGo.Size = New-Object System.Drawing.Size(50, 25)
        $buttonGo.Name = "Go"
        $buttonGo.Text = "Go"
        $buttonGo.UseVisualStyleBackColor = $True
        $buttonGo.add_Click({
                if ($radiobutton1.Checked) { Method1 -Account $Account }
                elseif ($radiobutton2.Checked) { Method1 -Account $Account }
                elseif ($radiobutton3.Checked) { Method3 -Account $Account -FolderId $txtBoxFolderID.Text -StartDate $FromDatePicker.Value.ToString("yyyy-MM-dd") -EndDate $ToDatePicker.Value.ToString("yyyy-MM-dd") -MsgSubject $txtBoxSubject.Text }
                elseif ($radiobutton4.Checked) { Method4 -Account $Account -DisplayName $txtBoxFolderID.Text }
                elseif ($radiobutton5.Checked) { Method5 -Account $Account -Folderid $txtBoxFolderID.Text }
                elseif ($radiobutton6.Checked) { Method6 -Account $Account }
                elseif ($radiobutton7.Checked) { Method7 -Account $Account }
                elseif ($radiobutton8.Checked) { Method8 -Account $Account -FolderId $txtBoxFolderID.Text -TargetFolderID $txtBoxTargetFolderID.Text -StartDate $FromDatePicker.Value.ToString("yyyy-MM-dd") -EndDate $ToDatePicker.Value.ToString("yyyy-MM-dd") -MsgSubject $txtBoxSubject.Text }
                elseif ($radiobutton9.Checked) { Method9 -Account $Account -FolderId $txtBoxFolderID.Text -StartDate $FromDatePicker.Value.ToString("yyyy-MM-dd") -EndDate $ToDatePicker.Value.ToString("yyyy-MM-dd") -MsgSubject $txtBoxSubject.Text }
                elseif ($radiobutton10.Checked) { Method10 -Account $Account }
                elseif ($radiobutton11.Checked) { Method11 -Account $Account -ToRecipients $txtBoxToRecipients.Text -CCRecipients $txtBoxCCRecipients.Text -BCCRecipients $txtBoxBCCRecipients.text -Subject $txtboxMailSubject.Text -Body $txtboxMailBody.Text }
                elseif ($radiobutton12.Checked) { Method12 -Account $Account -ToRecipients $txtBoxToRecipients.Text -Subject $txtboxMailSubject.Text -Body $txtboxMailBody.Text -NumberOfMessages $NumericNumOfMsgs.Value -UseAttachment:$checkboxUseAttachment.Checked }
                elseif ($radiobutton13.Checked) { $Global:Account = Method13 -Account $txtBoxFolderID.Text }
            })

        #"Exit" button
        $buttonExit.DataBindings.DefaultDataSourceUpdateMode = 0
        $buttonExit.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
        $buttonExit.Location = New-Object System.Drawing.Point(700, 50)
        $buttonExit.Size = New-Object System.Drawing.Size(50, 25)
        $buttonExit.Name = "Exit"
        $buttonExit.Text = "Exit"
        $buttonExit.UseVisualStyleBackColor = $True
        $buttonExit.add_Click({ $PremiseForm.Close(); return })
        
        #TextBox results
        $txtBoxResults.DataBindings.DefaultDataSourceUpdateMode = 0
        $txtBoxResults.Location = New-Object System.Drawing.Point(5, 460)
        $txtBoxResults.Size = New-Object System.Drawing.Size(840, 240)
        $txtBoxResults.Name = "TextResults"
        $txtBoxResults.BackColor = [System.Drawing.Color]::White
        $txtBoxResults.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D
        $txtBoxResults.Font = New-Object System.Drawing.Font("Consolas", 8)
        $PremiseForm.Controls.Add($txtBoxResults)

        #dataGrid

        $dgResults.Anchor = 15
        $dgResults.DataBindings.DefaultDataSourceUpdateMode = 0
        $dgResults.DataMember = ""
        $dgResults.Location = New-Object System.Drawing.Point(5, 460)
        $dgResults.Size = New-Object System.Drawing.Size(840, 240)
        $dgResults.Name = "dgResults"
        $dgResults.ReadOnly = $True
        $dgResults.RowHeadersVisible = $False
        $dgResults.Visible = $False
        $dgResults.AllowUserToOrderColumns = $True
        $dgResults.AllowUserToResizeColumns = $True
        $PremiseForm.Controls.Add($dgResults)

        #endregion Generated Form Code

        # Show Form
        #Save the initial state of the form
        $InitialFormWindowState = $PremiseForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $PremiseForm.add_Load($OnLoadMainWindow_StateCorrection)
        $PremiseForm.Add_Shown({ $PremiseForm.Activate() })
        $PremiseForm.ShowDialog() | Out-Null
    } #End Function

    #Call the Function
    try {
        GenerateForm
    }
    finally {
        Stop-ModuleUpdate -RunspaceData $runspaceData
    }
}

<#
This is an example configuration file
 
By default, it is enough to have a single one of them,
however if you have enough configuration settings to justify having multiple copies of it,
feel totally free to split them into multiple files.
#>


<#
# Example Configuration
Set-PSFConfig -Module 'ExoGraphGUI' -Name 'Example.Setting' -Value 10 -Initialize -Validation 'integer' -Handler { } -Description "Example configuration setting. Your module can then use the setting using 'Get-PSFConfigValue'"
#>


Set-PSFConfig -Module 'ExoGraphGUI' -Name 'Import.DoDotSource' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be dotsourced on import. By default, the files of this module are read as string value and invoked, which is faster but worse on debugging."
Set-PSFConfig -Module 'ExoGraphGUI' -Name 'Import.IndividualFiles' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be imported individually. During the module build, all module code is compiled into few files, which are imported instead by default. Loading the compiled versions is faster, using the individual files is easier for debugging and testing out adjustments."
Set-PSFConfig -FullName PSFramework.Logging.FileSystem.ModernLog -Value $True -Validation 'bool' -Description "Enables the modern, more powereful version of the filesystem log, including headers and extra columns." -PassThru | Register-PSFConfig

<#
Stored scriptblocks are available in [PsfValidateScript()] attributes.
This makes it easier to centrally provide the same scriptblock multiple times,
without having to maintain it in separate locations.
 
It also prevents lengthy validation scriptblocks from making your parameter block
hard to read.
 
Set-PSFScriptblock -Name 'ExoGraphGUI.ScriptBlockName' -Scriptblock {
     
}
#>


<#
# Example:
Register-PSFTeppScriptblock -Name "ExoGraphGUI.alcohol" -ScriptBlock { 'Beer','Mead','Whiskey','Wine','Vodka','Rum (3y)', 'Rum (5y)', 'Rum (7y)' }
#>


<#
# Example:
Register-PSFTeppArgumentCompleter -Command Get-Alcohol -Parameter Type -Name ExoGraphGUI.alcohol
#>


New-PSFLicense -Product 'ExoGraphGUI' -Manufacturer 'agallego' -ProductVersion $script:ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date "2023-01-10") -Text @"
Copyright (c) 2023 agallego
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"@

#endregion Load compiled code