PowerShell – Script to migrate a security group and all its members from AD to AAD

When you decide it’s time to migrate your security groups from on-premise AD to the Cloud, you might find it very tedious and prone to mistakes. Of course that is if you have lots of groups to move.

The script in this post should come to your aid as it finds the group you would like to migrate, creates a new group in AAD with a name you choose, then it adds all users and nested groups into the newly created group – the same as your AD group had.

A few nice things this script also does:

  • checks if the group you are about to migrate exists in AD;
  • makes sure a group you will be creating in AAD doesn’t already exist;
  • combines description and notes, then adds them to a newly created group in AAD.

Note that for this script to work well all nested groups must be synced from AD to AAD.

Do {
    Try {
            $adgroupname = Read-Host "Please provide a name of the group from AD"
            $adgroup = Get-ADGroup -Identity $adgroupname -ErrorAction Stop
            $success = $true
    Catch {
        $success = $false
        Write-host "A group with the name above doesn't exist in AD!"`n -ForegroundColor Red
Until ($success)

Write-host "Found the group!"`n -ForegroundColor Green

$adgroupdescription = (Get-ADGroup -Identity $adgroupname -Properties Description).Description

$adgroupnotes = (Get-ADGroup -Identity $adgroupname -Properties info).info

$adfulldescription = $adgroupdescription + "`n" + $adgroupnotes

$adgroupmembers = Get-ADGroupMember -Identity $adgroupname | Where-Object -FilterScript {$_.ObjectClass -eq 'user'}

$adgroupmembersids = $adgroupmembers.SID.Value

$emails = @()

ForEach ($adgroupmemebersid in $adgroupmembersids) {
    $email = (Get-ADUser -Identity $adgroupmemebersid -Properties Mail).Mail
    $emails += $email

$adgroupnestedgroups = Get-ADGroupMember -Identity $adgroupname | Where-Object -FilterScript {$_.ObjectClass -eq 'group'}

$adgroupnestedgroupnames = $adgroupnestedgroups.name

Do {
    $aadgroupname = Read-Host "Please provide a name of the group that will be created in AAD"
    $aadgroup = Get-MsolGroup | Where-Object {$_.DisplayName -eq $aadgroupname} -ErrorAction SilentlyContinue

Until ($aadgroup.Count -eq 0)

$newaadgroup = New-MsolGroup -DisplayName $aadgroupname -Description $adfulldescription

$users = @()

$emails | ForEach {
    Try {
        $user=(Get-MsolUser -UserPrincipalName $_ -ErrorAction Stop).ObjectID      
        $users += $user          
    Catch {}

If ($users.Count -gt 0) {
    $users | ForEach {
        Add-MsolGroupMember -GroupObjectId $newaadgroup.ObjectID -GroupMemberType User -GroupMemberObjectId $_

If ($adgroupnestedgroupnames.Count -gt 0) {
    ForEach ($adgroupnestedgroupname in $adgroupnestedgroupnames) {
        $aadnestedgroup = Get-MsolGroup | Where-Object {$_.DisplayName -eq $adgroupnestedgroupname}
        Add-MsolGroupMember -GroupObjectId $newaadgroup.ObjectID -GroupMemberType Group -GroupMemberObjectId $aadnestedgroup.ObjectID        

Remove-Variable * -ErrorAction SilentlyContinue

This Post Has 4 Comments

  1. Joe

    Can you make a script that will migrate Distribution Groups

    1. Paul Bludov

      Hi Joe,
      Unfortunately, I don’t have access to a tenant with an on-premise AD but it should be a similar approach as here. I understand it doesn’t help though.

  2. James Meszaros

    Unfortunately when I run it I get the following error:

    WARNING: More results are available. Please specify one of the All or MaxResults parameters.

    1. Paul Bludov

      Hi James,
      Not sure which cmdlet gives you that warning but I would surely follow its recommendation and add that key to the code to get all results. Thankfully it’s not an error.

Leave a Reply