functions/exchange/mail/message/Get-MgaMailMessage.ps1

function Get-MgaMailMessage {
    <#
    .SYNOPSIS
        Retrieves messages from a email folder from Exchange Online using the graph api.
 
    .DESCRIPTION
        Retrieves messages from a email folder from Exchange Online using the graph api.
 
    .PARAMETER InputObject
        Carrier object for Pipeline input
        Accepts messages or folders from other Mga-functions
 
    .PARAMETER FolderName
        The display name of the folder to search.
        Defaults to the inbox.
 
    .PARAMETER User
        The user-account to access. Defaults to the main user connected as.
        Can be any primary email name of any user the connected token has access to.
 
    .PARAMETER Subject
        The subject to filter by (Client Side filtering)
 
    .PARAMETER Delta
        Indicates a "delta-query" for incremental changes on mails.
        The switch allows you to query mutliple times against the same user and folder while only getting additional,
        updated or deleted messages.
 
        Please notice, that delta queries needs to be handeled right. See the examples for correct usage.
 
    .PARAMETER ResultSize
        The amount of objects to query within API calls to MSGraph.
        To avoid long waitings while query a large number of items, the graph api only
        query a special amount of items within one call.
 
        A value of 0 represents "unlimited" and results in query all items wihtin a call.
        The default is 100.
 
    .PARAMETER Token
        The token representing an established connection to the Microsoft Graph Api.
        Can be created by using New-MgaAccessToken.
        Can be omitted if a connection has been registered using the -Register parameter on New-MgaAccessToken.
 
    .EXAMPLE
        PS C:\> Get-MgaMailMessage
 
        Return emails in the inbox of the user connected to through a token.
 
    .EXAMPLE
        PS C:\> $mails = Get-MgaMailMessage -Delta
 
        Return emails in the inbox of the user connected to through a token and write the output in the variable $mails.
        IMPORTANT, the -Delta switch needs to be specified on the first call, because the outputobject will has to be piped
        into the next delta query.
 
        The content of $mails can be used and processed:
        PS C:\> $mails
 
        So the second Get-MgaMailMessage call has to be:
        PS C:\> $deltaMails = Get-MgaMailMessage -InputObject $mails -Delta
 
        This return only unqueried, updated, or new messages from the previous call and writes the result in the
        variable $deltaMails.
 
        The content of the $deltaMails variable can be used as output and should only overwrites the $mail variable if there is content in $deltaMails:
        PS C:\> if($deltaMails) {
            $mails = $deltaMails
            $deltaMails
        }
 
        From the second call, the procedure can be continued as needed, only updates will be outputted by Get-MgaMailMessage.
 
        .EXAMPLE
        PS C:\> Get-MgaMailFolder -Name "Junkemail" | Get-MgaMailMessage
 
        Return emails from the Junkemail folder of the user connected to through a token.
 
        .EXAMPLE
        PS C:\> Get-MgaMailMessage -FolderName "MyFolder" -Subject "Important*"
 
        Return emails where the subject starts with "Important" from the folder "MyFolder" of the user connected to through a token.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")]
    [CmdletBinding(DefaultParameterSetName = 'ByInputObject')]
    [OutputType([MSGraph.Exchange.Mail.Message])]
    param (
        [Parameter(ParameterSetName = 'ByInputObject', Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('Input', 'Id')]
        [MSGraph.Exchange.Mail.MessageOrFolderParameter[]]
        $InputObject,

        [Parameter(ParameterSetName = 'ByFolderName', Position = 0)]
        [Alias('FolderId', 'Folder')]
        [string[]]
        $FolderName,

        [string]
        $User,

        [string]
        $Subject = "*",

        [switch]
        $Delta,

        [Int64]
        $ResultSize = (Get-PSFConfigValue -FullName 'MSGraph.Query.ResultSize' -Fallback 100),

        [MSGraph.Core.AzureAccessToken]
        $Token
    )

    begin {
        $requiredPermission = "Mail.Read"
        $Token = Invoke-TokenScopeValidation -Token $Token -Scope $requiredPermission -FunctionName $MyInvocation.MyCommand

        $InvokeParams = @()
    }

    process {
        Write-PSFMessage -Level VeryVerbose -Message "Gettings mails by parameter set $($PSCmdlet.ParameterSetName)" -Tag "ParameterSetHandling"
        if ($PSCmdlet.ParameterSetName -like "ByInputObject" -and -not $InputObject) {
            Write-PSFMessage -Level Verbose -Message "No InputObject specified. Gettings mail from default folder (inbox)." -Tag "ParameterSetHandling"
            [MSGraph.Exchange.Mail.MessageOrFolderParameter]$InputObject = [MSGraph.Exchange.Mail.WellKnownFolder]::Inbox.ToString()
        }
        if ($PSCmdlet.ParameterSetName -like "ByFolderName") {
            foreach ($folderItem in $FolderName) {
                $folderItem = [MSGraph.Exchange.Mail.MessageOrFolderParameter]$folderItem
                if ($folderItem.Name -and (-not $folderItem.IsWellKnownName)) {
                    [MSGraph.Exchange.Mail.MessageOrFolderParameter]$folderItem = Get-MgaMailFolder -Name $folderItem.Name -User $User -Token $Token
                }
                $InputObject = $InputObject + $folderItem
            }
        }

        foreach ($InputObjectItem in $InputObject) {
            Write-PSFMessage -Level VeryVerbose -Message "Parsing input $($InputObjectItem.TypeName) object '$($InputObjectItem)'"
            switch ($InputObjectItem.TypeName) {
                "MSGraph.Exchange.Mail.Message" {
                    if ($Delta -and ('@odata.deltaLink' -in $InputObjectItem.InputObject.BaseObject.psobject.Properties.Name)) {
                        # if delta message, construct a delta query from mail
                        Write-PSFMessage -Level VeryVerbose -Message "Delta parameter specified and delta message found. Checking on message '$($InputObjectItem)' from the pipeline"
                        $invokeParam = @{
                            "deltaLink"    = $InputObjectItem.InputObject.BaseObject.'@odata.deltaLink'
                            "Token"        = $Token
                            "ResultSize"   = $ResultSize
                            "FunctionName" = $MyInvocation.MyCommand
                        }
                    } else {
                        # if non delta message is parsed in, the message will be queried again (refreshed)
                        # Not really necessary, but works as intend from pipeline usage
                        Write-PSFMessage -Level VeryVerbose -Message "Refresh message '$($InputObjectItem)' from the pipeline"
                        $invokeParam = @{
                            "Field"        = "messages/$($InputObjectItem.Id)"
                            "User"         = $InputObjectItem.InputObject.BaseObject.User
                            "Token"        = $Token
                            "ResultSize"   = $ResultSize
                            "FunctionName" = $MyInvocation.MyCommand
                        }
                        if ($Delta) { $invokeParam.Add("Delta", $true) }
                    }
                    $invokeParams = $invokeParams + $invokeParam
                }

                "MSGraph.Exchange.Mail.Folder" {
                    Write-PSFMessage -Level VeryVerbose -Message "Gettings messages in folder '$($InputObjectItem)' from the pipeline"
                    $invokeParam = @{
                        "Field"        = "mailFolders/$($InputObjectItem.Id)/messages"
                        "User"         = $InputObjectItem.InputObject.User
                        "Token"        = $Token
                        "ResultSize"   = $ResultSize
                        "FunctionName" = $MyInvocation.MyCommand
                    }
                    if ($Delta) { $invokeParam.Add("Delta", $true) }
                    $invokeParams = $invokeParams + $invokeParam
                }

                "System.String" {
                    $invokeParam = @{
                        "User"         = $User
                        "Token"        = $Token
                        "ResultSize"   = $ResultSize
                        "FunctionName" = $MyInvocation.MyCommand
                    }
                    if ($Delta) { $invokeParam.Add("Delta", $true) }

                    $name = if ($InputObjectItem.IsWellKnownName) { $InputObjectItem.Name } else { $InputObjectItem.Id }
                    if ($name.length -eq 152 -or $name.length -eq 136) {
                        # Id is a message
                        Write-PSFMessage -Level VeryVerbose -Message "Gettings messages with Id '$($InputObjectItem)'" -Tag "InputValidation"
                        $invokeParam.Add("Field", "messages/$($name)")
                    } elseif ($name.length -eq 120 -or $name.length -eq 104) {
                        # Id is a folder
                        Write-PSFMessage -Level VeryVerbose -Message "Gettings messages in folder with Id '$($InputObjectItem)'" -Tag "InputValidation"
                        $invokeParam.Add("Field", "mailFolders/$($name)/messages")
                    } elseif ($InputObjectItem.IsWellKnownName -and $name) {
                        # a well known folder is specified by name
                        $invokeParam.Add("Field", "mailFolders/$($name)/messages")
                    } else {
                        # not a valid Id -> should not happen
                        Write-PSFMessage -Level Warning -Message "The specified Id seeams not be a valid Id. Skipping object '$($name)'" -Tag "InputValidation"
                        continue
                    }

                    $invokeParams = $invokeParams + $invokeParam
                    Remove-Variable -Name name -Force -ErrorAction Ignore -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false
                }

                Default { Write-PSFMessage -Level Critical -Message "Failed on type validation. Can not handle $($InputObjectItem.TypeName)" -EnableException $true -Tag "TypeValidation" }
            }
        }
    }

    end {
        $fielList = @()
        $InvokeParamsUniqueList = @()
        Write-PSFMessage -Level Verbose -Message "Checking $( ($InvokeParams | Measure-Object).Count ) objects on unique calls..."
        foreach ($invokeParam in $InvokeParams) {
            if ($invokeParam.Field -and ($invokeParam.Field -notin $fielList)) {
                $InvokeParamsUniqueList = $InvokeParamsUniqueList + $invokeParam
                $fielList = $fielList + $invokeParam.Field
            } elseif ($invokeParam.deltaLink -notin $fielList) {
                $InvokeParamsUniqueList = $InvokeParamsUniqueList + $invokeParam
                $fielList = $fielList + $invokeParam.deltaLink
            }
        }
        Write-PSFMessage -Level Verbose -Message "Invoking $( ($InvokeParamsUniqueList | Measure-Object).Count ) REST calls for gettings messages"

        # run the message query and process the output
        foreach ($invokeParam in $InvokeParamsUniqueList) {
            $data = Invoke-MgaRestMethodGet @invokeParam | Where-Object { $_.subject -like $Subject }
            $output = foreach ($messageOutput in $data) {
                New-MgaMailMessageObject -RestData $messageOutput
            }
        }

        if ($output) {
            $output
        } else {
            Write-PSFMessage -Level Warning -Message "Message not found." -Tag "QueryData"
        }
    }
}