'Microsoft GraphAPI PowerShell download attachment

How can I download the attachment from the Microsoft Graph API for Mail message?

'$attachment=Get-MgUserMessageAttachment -MessageId AAMkAGIzZWEyN2MxLWJmNTktNDBkMi05ZWY2LWE3YjFhYWJjNmEwOABGAAAAAAA2OVriHzx8TL2ku-KbIgYgBwChRsRs-pG2QpRCaG5OA-T0FcAAA= -UserId [email protected]

$attachment
ContentType          : application/octet-stream
Id                   : AAMkAGIzZWEyN2MxLWJmNTktNDBkMi05ZWY2LWE3YjFhYWJjNmEwOABGAAAAAAA2OVriHzx8TL2ku-KbIgYgBwChRsRs-pG2QpRCaG5OgRLxAAAAAAEMAAChRsRs-pG2QpRCaG5OgRLxAAA-T0FcAAABEg
                       AQANUHCnnWvO5Dr-D2VilhKP8=
IsInline             : False
LastModifiedDateTime : 4/14/2020 7:21:32 PM
Name                 : report.csv
Size                 : 707'


Solution 1:[1]

The Microsoft graph API is based on Web API. So if you want to download an attachment you can use the HTTP GET command directly with the Microsoft Graph API Get Attachment API.

In PowerShell, if you want to use an HTTP call natively, you can use Invoke-WebRequest (for more details you can see How can I use HTTP GET in PowerShell?).

But Microsoft provides some facilities (modules) for making Microsoft Graph API easy to use in PowerShell. That say Microsoft.Graph Module. This module is in the preview stage, but it is very useful.

If you want to use this module and download an attachment, you can use the below command:

Get-MgUserMessageAttachment -MessageId <String> -UserId <String> [-Count] [-Expand <String[]>]
 [-Filter <String>] [-Orderby <String[]>] [-Search <String>] [-Select <String[]>] [-Skip <Int32>]
 [-Top <Int32>] [<CommonParameters>]

For more information about this command, you can see the Microsoft Graph SDK PowerShell documentation.

Get-MgUserMessageAttachment returns IMicrosoftGraphAttachment that has some properties like below (JSON representation):

{
  "contentType": "string",
  "id": "string (identifier)",
  "isInline": true,
  "lastModifiedDateTime": "String (timestamp)",
  "name": "string",
  "size": 1024
}

But this type is based type of fileAttachment that has some properties like below (JSON representation):

{
  "contentBytes": "string (binary)",
  "contentId": "string",
  "contentLocation": "string",
  "contentType": "string",
  "id": "string (identifier)",
  "isInline": true,
  "lastModifiedDateTime": "String (timestamp)",
  "name": "string",
  "size": 1024
}

For file download, you can use the ContentBytes property. This property is Base64 encoded so you have to decode it and then save to a file with some of commands like Out-File.

As you can see in the GitHub repository of PowerShell Module, in the current state of this PowerShell you cannot use it directly with this SDK to download an attachment, and you have to use Web API directly in PowerShell for downloading the attachment.

Solution 2:[2]

This works ("Log" basically just calls write-verbose):

# Install Microsoft Graph API PowerShell module if not already installed
if (Get-Module 'Microsoft.Graph' -ListAvailable) {
    Log 'PowerShell Module Microsoft.Graph is already installed.'
} else {
    Log 'PowerShell Module Microsoft.Graph not installed. Installing...'
    try {
        Install-Module 'Microsoft.Graph' -Force
        Log 'Installed successfully.'
    }
    catch {
        throw 'Error: unable to install PowerShell Module Microsoft.Graph Module.'
    }
}

$UserId     = ''
$FolderId   = ''
$Filename   = "$( $env:USERPROFILE )\Downloads\test.pdf"
$TId        = ''
$AppId      = ''
$CertThumb  = ''

# Connect to Microsoft Graph API
$null = Connect-MgGraph -TenantId $TId -AppId $AppId -CertificateThumbprint $CertThumb
# Using null suppresses the output

# Get Message from Folder in User
$Msgs = Get-MgUserMailFolderMessage -UserId $UserId -MailFolderId $FolderId
$MsgId = $Msgs[0].Id

# Get Attachment
$Attachm = Get-MgUserMailFolderMessageAttachment -UserId $UserId -MailFolderId $FolderId -MessageId $MsgId

# Get Attachment as Base64
$Base64B = ($Attachm).AdditionalProperties.contentBytes
# Works also: Get-MgUserMessageAttachment

# Save Base64 to file
$Bytes = [Convert]::FromBase64String($Base64B)
[IO.File]::WriteAllBytes($Filename, $Bytes)

Disconnect-MgGraph

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter Mortensen
Solution 2 Michael