Create Custom Folder in Exchange Online Mailboxes using Graph API using Windows PowerShell

I am hear by explaining the step-by-step procedure to create Custom Folder for all Exchange Online Mailboxes using Graph API. Using the cmdlet New-MailboxFolder, Administrators can’t create folders in other mailboxes and use an alternate option like Graph API, when there is a special requirement to access all the mailboxes in your Exchange Online Organization.

Prerequisites

  • Windows PowerShell 5.1
  • Azure tenant and Exchange Online account Access
  • App registration permissions on the subscription

Create an Application Identity in Azure

In this example, I am explaining a method in which, you access the Microsoft Graph API with an OAuth token.

The following steps with help to create an application Identity in your Azure Tenant with privileges to access the Exchange Online Mailboxes
1. Login Azure Portal and search for ‘Application Registrations’ as below:

2. Register an Application

3. Name your application Registration and follow the below settings

4. Application Details can be noted from the following window

5. Create Application Secret from the following page and note the secret up on completion

6. Assign API permissions to access your Exchange Online mailboxes from the following window

We need to select Graph ‘Application permission’ for the purpose of mailbox access as below:

Select the following permissions and save

7. Grand Admin Consent to the selected permissions in the tenant. Finally, your permissions page will show as follows

8. Now we are ready to run the PowerShell cmdlet.

  • Copy the cmdlet to a notepad and save as .ps1 file
  • Edit the following parameters as per your tenant settings
    • $Mailboxes = @(“mailbox1@domain.com”,”mailbox2@domain.com”)
    • $Folders = @(“folder1″,”folder2”)
    • $AppId = ‘Your App ID’
    • $AppSecret = ‘Your app secret’
    • $TenantName = “yourtenantname.onmicrosoft.com”
##Create Custom Folder for Exchange Online Mailboxes using Graph API

$Mailboxes = @("mailbox1@domain.com","mailbox2@domain.com")
$Folders = @("folder1","folder2")
$AppId = 'Your App ID'
$AppSecret = 'Your app secret'
$Scope = "https://graph.microsoft.com/.default"
$TenantName = "yourtenantname.onmicrosoft.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
# Add System.Web for urlencode
Add-Type -AssemblyName System.Web
# Create body
$Body = @{
    client_id = $AppId
	client_secret = $AppSecret
	scope = $Scope
	grant_type = 'client_credentials'
}
# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
    ContentType = 'application/x-www-form-urlencoded'
    Method = 'POST'
    # Create string by joining bodylist with '&'
    Body = $Body
    Uri = $Url
}
# Request the token!
$Request = Invoke-RestMethod @PostSplat
# Create header
$Header = @{
    Authorization = "$($Request.token_type) $($Request.access_token)"
}
## Access Mailboxes

foreach($mailbox in $Mailboxes) {
    $Uri = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders"
#Comment the above line and use the following line, in case your requirement is to create folder inside 'Inbox' of your mailbox
#$Uri = "https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders/Inbox/ChildFolders"
    ## Fetch Folder Names
    $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'
    }

## Loop folders
    foreach($Folder in $Folders) {
$Body = @"
{
"displayName": "$Folder"
}
"@
        ## Show Progress
        Write-Host "Checking the folder with similar name..."
        if($($MailboxfoldersList) -contains $folder) {
            write-host "$folder already exists. Unable to create the folder..."
        }
        else {
            $Newfolder = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Post -Body $Body -ContentType "application/json"
            write-host "Created Folder: $($Newfolder.displayName) in mailbox $mailbox...`n"
        }
    }
}

9. Run the script. Open a PowerShell and run as below:

As you can see from the report above, folders are being created and you may check this from your mailboxes too.

Hope, the above article help you a lot in managing your Exchange Online mailbox’s folder creation !!!

16 Responses

  1. Hello Manu,
    Thank you very much for posting this. It worked perfectly! One issue though…. I need the folders created to be a sub folder in the Inbox. Can I edit the script to accomplish this?

  2. Hello,
    Great Article! Is there a way to edit the script to add folders as subfolders in the inbox instead of creating the folders in the mailbox?

    • Good news ! Following code change has updated in the PowerShell code to help on your requirement. Please check the corresponding updates in the code
      foreach($mailbox in $Mailboxes) {
      $Uri = “https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders”
      #Comment the above line and use the following line, in case your requirement is to create folder inside ‘Inbox’ of your mailbox
      #$Uri = “https://graph.microsoft.com/v1.0/users/$mailbox/mailFolders/Inbox/ChildFolders”

      Thanks,
      Manu

  3. Hi Manu,
    this is superb, thank you so much.

    I need to move it on slightly: I also want to create a new mailbox rule for each mailbox to move an email with a specific subject into the folder I’ve just created. In Powershell, it would be something like:

    New-InboxRule -Name “NewRuleName” -Mailbox $mailbox -MoveToFolder $Newfolder -SubjectContainsWords “MyText” -StopProcessingRules $True

    That’s not working, so I guess I need to do something with “Invoke-RestMethod” instead?

    • Hey,
      Glad to hear that the article helped you !

      I think, the PowerShell cmdlet should be modified as follows: I haven’t personally tried it. However, you can have a try
      New-InboxRule -Name “NewRuleName” -Mailbox $mailbox -MoveToFolder $mailbox\$Newfolder -SubjectContainsWords “MyText” -StopProcessingRules $True

      Thanks,
      Manu

  4. Manu, this script is brilliant – it’s a major improvement on our current process, which requires either prompting or insecure storage of a password to create the folders. Is it possible to also assign a retention policy to the folder when created, or another script to do this?

    • Hello Jason,
      It is recommended to use a separate script to manage retention policy as the requirement is not applicable to all those who use the approach. I haven’t prepared an approach to frame a procedure on that. Let me know, if you are still looking for that

      Thanks,
      Manu

      • Thank you Manu,

        I’m definitely looking for such a procedure, primarily as we’re encountering an issue using the current method via an old Powershell script that creates the folder, then applies the retention policy, which often returns an error ‘New-Object : Cannot find an overload for “PolicyTag” and the argument count: “2”.’ unless we wait an indeterminate amount of time – sometimes within a couple days of creating the account, others up to two weeks.

        Jason

      • Manu,
        Thank you so much for this, it is really brilliant and works so well for what we need. One thing, if I wanted to run this for all mailboxes do I just leave it as “$Mailboxes = @”, please let me know.
        Thanks.

  5. Manu,
    Also, how can I do this just for specific mailboxes maybe based on a criteria/attribute? My company is looking to do this just for specific users and I am thinking for us to automate this we can go based on a attribute in their account.
    Thanks.

    • Or maybe it is possible to run the script only for Mailboxes which are in a AD-Groupe.

      So i dont have to add all Mailboxes manual just put theese Member in a Group.

      Thanks
      Boris

    • I changed the $Uri to “$Uri = “https://graph.microsoft.com/v1.0/users/$mailbox/contactFolders/Contacts/ChildFolders””. Now it creates ContactFolders.

  6. Manu,
    I am successfully using this script to create mail folders under the Inbox, but I am struggling to figure out how to create nested folders. I would like to have “Inbox > Retain > 3 year”; “Inbox > Retain > 1 year”; “Inbox > Retain > 30 days”

    Thanks,
    Ike

  7. Hello, i’m trying to create a folder like this but without success:
    inbox\Folder\SubFolder

    I can create correctly Folder but not SubFolder. Can’t get how to compose the correct uri.
    Tried with FolderID, ParentId but failed. Always error 400

Leave a Reply to Bryan Brown Cancel reply

Your email address will not be published. Required fields are marked *

Recent Comments