Create a mailbox subfolder with MS Graph

Lucas Edson 21 Reputation points
2021-11-30T17:19:15.247+00:00

I am using PowerShell to connect to M365 mailboxes and am able to create a folder as per: https://learn.microsoft.com/en-us/graph/api/user-post-mailfolders however, I also need to create subfolders, and am unable to find any syntax help to do so.

Here is the script I'm using to create the folder: The variable $Folders only creates root level folders, no subfolders.

$Mailboxes = @("******@myemail.com")  
$Folders = @("FolderRoot","SubFolder")  
  
$AppId = "*******"  
$AppSecret = "********"  
$Scope = "https://graph.microsoft.com/.default"  
$TenantName = "**********"  
  
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"  
  
Add-Type -AssemblyName System.Web  
  
$Body = @{  
    client_id = $AppId  
	client_secret = $AppSecret  
	scope = $Scope  
	grant_type = 'client_credentials'  
}  
  
$PostSplat = @{  
    ContentType = 'application/x-www-form-urlencoded'  
    Method = 'POST'  
    # Create string by joining bodylist with '&'  
    Body = $Body  
    Uri = $Url  
}  
  
$Request = Invoke-RestMethod @PostSplat  
  
$Header = @{  
    Authorization = "$($Request.token_type) $($Request.access_token)"  
}  
  
foreach($mailbox in $Mailboxes) {  
  
    $Uri = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders"  
  
    $Mailboxfolders = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Get -ContentType "application/json"  
    $MailboxfoldersList = $Mailboxfolders.Value.Displayname  
    $NextPage = $Mailboxfolders.'@Odata.NextLink'  
     
    While($NextPage -ne $Null) {  
        $Mailboxfolders = Invoke-RestMethod -Uri $NextPage -Headers $Header -Method Get -ContentType "application/json"  
        $MailboxfoldersList += $Mailboxfolders.Value.Displayname  
        $NextPage = $Mailboxfolders.'@Odata.NextLink'  
    }  
  
    foreach($Folder in $Folders) {  
  
$Body = @"  
{  
"displayName": "$Folder"  
}  
"@  
  
        ## Output current operation  
  
        Write-Host "Mailbox: $mailbox`nMailboxfolders: $($MailboxfoldersList)`nFolder wanted: $folder"  
  
        if($($MailboxfoldersList) -contains $folder) {  
            write-host "$folder folder already found at mailbox $mailbox.`n"  
        }  
  
        else {  
            $Newfolder = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Post -Body $Body -ContentType "application/json"  
            write-host "Created new folder: $($Newfolder.displayName) to mailbox $mailbox!`n"  
        }  
    }  
}  
  
Windows for business | Windows Server | User experience | PowerShell
Microsoft Security | Microsoft Graph
0 comments No comments
{count} votes

Accepted answer
  1. Glen Scales 4,446 Reputation points
    2021-12-01T00:10:01.727+00:00

    The MailFolders Endpoint

    "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders"
    

    Lets you list and create a folder in the MailboxFolderRoot so it equivalent to

    /MailFolders('MsgFolderRoot')/childfolders
    

    There is no way of doing a deep traversal with the Graph at the moment (meaning you traverse every layer of childfolders) you can do one layer using expand eg

    https://graph.microsoft.com/v1.0/me/mailfolders?expand=childFolders
    

    This would for instance give you subfolders of the Inbox Folder in the ChildFolders property eg

                "id": "AQMk",
                "displayName": "Inbox",
                "childFolders@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('150bb06c-1c9a-4ac2-8b55-8cf15854b555')/mailFolders('AQ-0Y6jBNnUCxQousINAAAAIBDAAAAA%3D%3D')/childFolders",
                "childFolders": [
                    {
                        "id": "AAA=",
                        "displayName": "aa",
                        "parentFolderId": "AQM==",
                        "childFolderCount": 0,
                        "unreadItemCount": 178,
                        "totalItemCount": 209,
                        "isHidden": false
                    },
    

    There are a few different ways of solving your problem if all you wanted to do was create subfolders of the Inbox folder (or other wellknown folder) then if you changed line 36 to

    $Uri = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders/Inbox/ChildFolders"
    

    all the logic in your script should work okay else you should find the FolderId of the parentFolder you want to create those folders under

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Lucas Edson 21 Reputation points
    2021-12-01T00:58:29.747+00:00

    Thank you for answering. I kept failing at the /childFolders part, as I realized (after reading the error messages) that it was asking for the [id] of the parent folder, so I got it to work by doing the following (I'm sure there's a more elegant way):

            if($($MailboxfoldersList) -contains $folder) {
                write-host "$folder folder already found at mailbox $mailbox, creating subfolder.`n"
            }
    
            else {
                $Newfolder = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Post -Body $Body -ContentType "application/json"
                write-host "Created new folder: $($Newfolder.displayName) to mailbox $mailbox!`n"
                $ParentFolder = $Newfolder.id
                $UriSub = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders/$ParentFolder/childFolders"
            }
        }
        foreach($subFolder in $subFolders) {
    
            $Body2 = @"
            {
                "displayName": "$subFolder"
            }
    "@
    
            if($($MailboxfoldersList) -contains $subfolder) {
                write-host "$subfolder folder already found at mailbox $mailbox.`n"
            }
    
            else {
                $NewSubfolder = Invoke-RestMethod -Uri $UriSub -Headers $Header -Method Post -Body $Body2 -ContentType "application/json"
                write-host "Created new subfolder: $($NewSubfolder.displayName) in $Folder to mailbox $mailbox!`n"
            }
        }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.