How to create Microsoft 365 groups in bulk with sharepoint site and Teams using Powershell

About the Task

This week I received a request to create Microsoft 365 groups in bulk using Powershell. I tried to use New-UnifiedGroup command (part of EXO V2 Powershell Module) to create Microsoft 365 group which worked fine for creation of the group but this command did not create corresponding Sharepoint site. Therefore, I utilized New-PnPMicrosoft365Group command (part of PnP.Powershell powershell module). In this blog post, I have explained in detail on how to use New-PnPMicrosoft365Group command and create Microsoft 365 group(s).

First Step is to Install PnP.Powershell Module and authenticate using Connect-PnPOnline to Sharepoint before we can run New-PnPMicrosoft365Group cmdlet. There are many different ways you can authenticate to Sharepoint using Connect-PnPOnline. Two specific methods which we will see in this blog post, One method is to use -UseWebLogin which does not work with New-PnPMicrosoft365Group and Other One is using App Only Azure Active Directory which works fine with New-PnPMicrosoft365Group. This is the authentication method we will be using today to complete our task.

To Find out more information about various Authentication Methods while using connect-PnPOnline. Please check the link: Connect-PnPOnline (Connect to a Sharepoint Site)

Install PnP.Powershell

To Install PnP.Powershell Module on your system. Open Powershell Console as an Administrator and Type below Command:

Install-Module -Name PnP.PowerShell

Lets see what happens when we use -useWebLogin switch with Connect-PnPOnline command. Open Powershell as Administrator, type below command and Press Enter. Make sure PnP.Powershell Module is installed on the system otherwise below commmand will not work.

Connect-PnPOnline -Url https://<yoursitename>.sharepoint.com -UseWebLogin

A small window will pop-up on the screen, Enter your administrator credentials to authenticate to Sharepoint.

Now we will test New-PnPMicrosoft365Group command. As you can see in below screenshot New-PnPMicrosoft365Group cmdlet does not work with a WebLogin/Cookie based connection. Therefore we will use App based authentication using Azure Active Directory and then use New-PnPMicrosoft365Group command to create Microosft 365 groups. In the next section, I will be creating and configuring an Azure App Registration for App based authentication.

Azure AD App Registration

To Create an App registration, Login on Azure Portal (https://portal.azure.com) -> Azure Active Directory -> App registrations and click on New registration.

Provide a Name of the Application, Select Who can use this application or access this API ? and click on Register.

Once the Application is registered, Click on Overview link and then copy the Client ID. Client ID will be used when we will connect to Sharepoint via Connect-PnPOnline Command.

API Permissions

Next step is to provide minimum permissions to this app for our task. For this, click On API Permissions and then click on Add a Permission.

Click on Microsoft Graph on Request API Permissions Pane.

Click on Application Permissions

Search for Group and Provide Group.ReadWrite.All Permission.

Search for directory and Provide Directory.ReadWrite.All Permission.

Grant Admin Consent

Admin Consent Granted

Certificates & Secrets

Next Step is to create a self-signed certificate and upload it to the app PnP Powershell which we registered in Azure Active Directory and granted consent in previous steps. Let’s see how we can generate and upload the certificate.

For creating a self-signed certificate, I have used a script which you can copy from below Microsoft Docs Link: https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread.

Once you have copied the script and saved it in a .ps1 file. Use below command to generate a self signed certificate. Please note that the Date Format is YYYY-MM-dd. Change the Startdate and EndDate according to your certificate expiry requirements.

.\Create-SelfSignedCertificate.ps1 -CommonName "TechPress" -StartDate 2021-08-13 -EndDate 2022-08-13

Generated SelfSignedCertifcate Folder looks on my system. You can choose any name for the Folder or Certificate.

Upload Certificate

Click on Certificates & Secrets Link in Azure AD App PnP Powershell and then click on Upload Certificate.

Select .cer file to upload.

Certificate .cer file / Public Key is uploaded.

Create Microsoft365 Groups

For Creating Microsoft 365 Group(s), We need to gather few values which will be used to connect to sharepoint using Connect-PnPonline command. Below are the values required for this command.

Client ID = Copy Client ID of the App PnP Powershell from Azure Portal.
Certificate Path = Path of Certificate PFX File
CertificatePassword
= PFX File Password
Url =
Sharepoint site URL where you want to connect —- for example: https://jmittechpress.onmicrosoft.com
Tenant
= Azure Active Directory Tenant Name —— for example techpress.onmicrosoft.com

First connect to Sharepoint using Connect-PnPOnline command using the command shown below:

Connect-PnPOnline -ClientId <ClientID> -CertificatePath C:\SelfSignedCertificate\TechPress.pfx -CertificatePassword (ConvertTo-SecureString -AsPlainText "Welcome123" -Force) -Url https://<SharepointSite URL> -Tenant <Tenant Name>

Create one Microsoft 365 Group using New-PnPMicrosoft365Group without Team

$displayname = "London Finance"
$nickname = "LondonFinance"
$arrayOfOwners = "jmakhija@techpress.net", "tstark@techpress.net"
$arrayOfMembers = "jondoe@techpress.net"
New-PnPMicrosoft365Group -Displayname $displayName -Description "TechPress Finance Group" -MailNickname $nickname -Owners $arrayOfOwners -Members $arrayOfMembers -IsPrivate

Owners and Members of the group as we defined in our command.

Create one Microsoft 365 Group using New-PnPMicrosoft365Group with Team

Create Microsoft 365 Group with Sharepoint site and with connected Team. I am using the same example as above, the only difference is a switch added to the end of New-PnPMicrosoft365Group Command -CreateTeam.

$displayname = "London Finance"
$nickname = "LondonFinance"
$arrayOfOwners = "jmakhija@techpress.net", "tstark@techpress.net"
$arrayOfMembers = "jondoe@techpress.net"
New-PnPMicrosoft365Group -Displayname $displayName -Description "TechPress Finance Group" -MailNickname $nickname -Owners $arrayOfOwners -Members $arrayOfMembers -IsPrivate -CreateTeam

Create Microsoft 365 Groups in bulk

For creating Microsoft365 groups in bulk, I have created a small script which you can use. You can copy the script from this blog post or download it from TechPress GitHub Page as well. Please find the link of Github page in the next section. Before you can use the script, there are some important points to note as given below:

Script requirements and Important Points
– Make sure to use -verbose switch when running the function (It’s also explained and show in later section with screenshots). If its not run with -verbose switch, script will still run but will not have full information about the progress displayed on the console.

– An CSV File is required as a source data for this script. A Sample CSV File is shown in the later section. Create a CSV File using the same headings and update the data. When this script / function is run, it will prompt for CSV File path, provide the path of the CSV File.

– The Script checks for Powershell module PnP.Powershell and Installs / Imports it for you. There is a confirmation message before it gets installed.

– Script creates Log files everytime its run and its stored at C:\Apps\Logs. You can change the value of the variables $Logfile and $Logfolder as per your requirement.

– After dot sourcing the script, you can check more information about the script using >get-help Create-M365GroupwithSPOSite

Only few variables required to be updated in the script before you can run the script.

Example:

$arrayOfOwners = “jmakhija@techpress.net”, “tstark@techpress.net”
$arrayOfMembers = “jondoe@techpress.net”

$ClientID = “<clientID>”
$CertPath = “<Path of the Certificate File>”
$SiteUrl = “<Sharepoint Site URL>”
$tenant = “<Azure AD tenant name>”
Sample M365Groups.csv File
If Teams Column is set to Y –> Microsoft 365 group + SPO Site + Team will be created
If Teams Column is set to N –> Microsoft 365 group + SPO Site will be created without Teams

Once you have a sample csv file created and variables populated in the powershell script. Lets run it to see how it goes. This is how my folder looks like:

Script Folder contains Powershell script and CSV File
Copy these two files in any folder and on powershell console dot source it like >. .\<script>.ps1
GitHub Script Download link
https://github.com/Techpress-net/Powershell-Scripts.git

– After dot sourcing the script, you can check more information about the script using get-help Create-M365GroupwithSPOSite

get-help Create-M365GroupwithSPOSite
After the groups are created, it will not be shown on the PS Console. The script is updated as per comment: https://techpress.net/how-to-create-microsoft-365-groups-in-bulk-with-sharepoint-site-and-teams-using-powershell/#comment-79
C:\Apps\Logs\M365GroupLog-08-13-2021_06-54-59.csv File
TipUse Excel -> Data -> Text to Colums and use the Delimeter as * to separate data it in two columns
Disclaimer
I have created below script and used it in the test enviornment as well as Production Envionments. Its recommeded to use this script to create couple of groups first or to use it in test enviornment first to see if you are successful before creating 100’s of groups using this script in Production.

This script/function is provided AS IS without warranty of any kind. Author(s) disclaim all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall author(s) be held liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the script or documentation. Neither this script/function, nor any part of it other than those parts that are explicitly copied from others, may be republished without author(s) express written permission. Author(s) retain the right to alter this disclaimer at any time.
Function Create-M365GroupwithSPOSite { 
<# 
.SYNOPSIS 
Create Microsoft 365 Groups in bulk along with Sharepoint Sites.If Teams Column value is Y
Teams Site will also be linked to the group else Teams Site will not be linked/created. 
 
.DESCRIPTION 
This is Create-M365GroupwithSPOSite Function which can be used to Create Microsoft 365 Groups
with Sharepoint Sites (with or without Teams Site). 
 
.NOTES     
        Name       : Create-M365GroupwithSPOSite  
        Author     : Jatin Makhija  
        Version    : 1.0.1  
        DateCreated: 13-08-2021 
        DateUpdated: 24-08-2021
        Blog       : https://www.techpress.net
         
.LINK 
https://www.techpress.net
 
.EXAMPLE 
PS> Create-M365GroupwithSPOSite -verbose
 
For Example 
 
Create-M365GroupwithSPOSite -verbose 
#> [cmdletBinding()] 
    param( 
    [parameter(mandatory = $true, Position =0, HelpMessage="Please Enter the Path to CSV File")] 
    [string]${CSVFilePath} 
         ) 
 
Try { 
 
        #Check for PNP Powershell module 
        $Module=Get-Module -Name pnp.powershell -ListAvailable  
        if($Module.count -eq 0) 
        { 
        Write-Host PNP Powershell module is not available  -ForegroundColor yellow  
        $Confirm= Read-Host Are you sure you want to install module? [Y] Yes [N] No 
        if($Confirm -match "[yY]") 
        { 
        Write-Host "Installing PnP.Powershell Module"
        Install-Module -Name PnP.PowerShell -Confirm:$False -Force
        Write-Host "Importing PnP.Powershell Module"
        Import-Module -Name PnP.PowerShell -Verbose:$false
        } 
        else 
        { 
        Write-Host PNP Powershell module is required for this script to work. 
        Exit
        }
        }         
 
    } 
 
Catch { 
Write-Warning "PNP Powershell module is required for this script to work." 
Write-Warning $_ 
break 
} 
$arrayOfOwners = "jmakhija@techpress.net", "tstark@techpress.net"
$arrayOfMembers = "jondoe@techpress.net"
$ClientID =  "<clientID>"
$CertPath =  "<PFX Certificate File Location>"
$CertPass =   Read-Host -Prompt 'Enter Password of the PFX File' -AsSecureString
$SiteUrl  =  "<Sharepoint Site URL>"
$tenant   =  "<Azure AD Tenant Name>"
$Params = @{
    ClientId            = $ClientID
    CertificatePath     = $CertPath
    CertificatePassword = $CertPass
    Url                 = $SiteUrl
    Tenant              = $tenant
}
Write-host "Connecting to PNPOnline" -ForegroundColor Blue -BackgroundColor White
Connect-PnPOnline @Params
$LogTime = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"
$Logfile = "C:\Apps\Logs\M365GroupLog-$LogTime.csv"
$logfolder ="C:\Apps\Logs"
if(!(Test-Path -path $LogFolder)){
New-Item -ItemType Directory -path $logfolder
}
Else 
{
Write-Host "Great! log folder already exists, Please check C:\Apps\Log\ Folder for Log Files generated by this script"
}
Function LogWrite
{
    Param ([string]$logstring)
     Add-content $Logfile -value $logstring
}
Import-Csv ${CSVFilePath} -Header displayname, nickname, description, Teams | Select-Object -Skip 1 | ForEach-Object{ 
                                                    $displayname = $_.displayname 
                                                    $nickname = $_.nickname
                                                    $description = $_.description
                                                    $Teams = $_.Teams
if (Get-PnPMicrosoft365Group -identity $displayname) {
       Write-verbose "M365 Group $displayname already exists" 
       LogWrite "$displayname * Already Exists"
}
Elseif ($Teams -eq 'N') {
         Write-verbose "Teams Column Value set to $Teams for $displayname" 
         Write-verbose "Creating M365 Group + SPO Site without connected Teams for $displayname"
         try { 
         New-PnPMicrosoft365Group -DisplayName $displayname -Description $description -MailNickname $nickname -Owners $arrayOfOwners -Members $arrayOfMembers -IsPrivate | out-null
         } catch {
         LogWrite "$displayname *  could not be created"
         }
         LogWrite "$displayname *  created without Teams Site"
}
else {
    Write-verbose "Teams Column Value set to $Teams for $displayname"
    Write-verbose "Creating M365 Group + SPO Site with connected Teams for $displayname" 
    try{
    New-PnPMicrosoft365Group -DisplayName $displayname -Description $description -MailNickname $nickname -Owners $arrayOfOwners -Members $arrayOfMembers -IsPrivate -CreateTeam | out-null 
    } catch {
    LogWrite "$displayname *  could not be created"
    }
    LogWrite "$displayname * created with Teams Site"
     }
  }
}  

Subscribe to Stay Connected

Thank you for visiting TechPress 👍. When you subscribe to the blog, email notification ✉ will be sent to you when a new blog post is published. You can unsubscribe at any time.

6 thoughts on “How to create Microsoft 365 groups in bulk with sharepoint site and Teams using Powershell”

  1. Love this guide! Having an issue at the very end however. It seems like the script will create one group from the csv file and then hang. After a bit i get the below error. The group does actually get created in O365 but no group after that one will be created. If i run the script again it does see the first group was created and moves on to the next, then i get the same issue where it hangs and the below message appears

    New-PnPMicrosoft365Group : Access denied
    At C:\Scripts\M365Group.ps1:115 char:10
    +         New-PnPMicrosoft365Group -DisplayName $displayname -Descript …
    +         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       + CategoryInfo         : InvalidOperation: (:) [New-PnPMicrosoft365Group], PSInvalidOperationException
       + FullyQualifiedErrorId : InvalidOperation,PnP.PowerShell.Commands.Microsoft365Groups.NewPnPMicrosoft365Group

    Reply
    • Hi Jestoner, Thanks for the feedback. Make sure Directory.ReadWriteAll and Groups.ReadWriteAll Permissions are granted to the App in Azure AD. As it says Access Denied, I suspect this could be due to permissions issue. I understand you manage to create one group which is a bit strange. I had tested and used this scripts on different tenants but didn’t face any issues. I will test it again to replicate the issue, update the changes and release the updated version of the script.

      Update: Just tested this script again by using the csv file and adding a test group and it seems to be working fine.

      VERBOSE: M365 Group PMO Office already exists
      VERBOSE: M365 Group Accounting already exists
      VERBOSE: M365 Group Financial Services already exists
      VERBOSE: M365 Group InformationTech already exists
      VERBOSE: M365 Group ClientProjects already exists
      VERBOSE: M365 Group Team xyz already exists
      VERBOSE: M365 Group InternalMeeting already exists
      VERBOSE: Teams Column Value set to N for Jatin
      VERBOSE: Creating M365 Group + SPO Site without connected Teams for Jatin
      
      DisplayName               Id                                                     HasTeam                   SiteUrl        
      ----------- --                  -------                                                  -------        
      Jatin                    15e94953-da1d-8-fabe9cddd9d81af              False                           https://jmit...
      
      Reply
      • Thanks for the quick reply. I checked the permissions and they are both granted for Directory.ReadWriteAll and Groups.ReadWriteAll and to make things even more odd, i thought the script was failing after creating the first group however that is not actually the case. It just hangs for about 5 minutes before moving on to the next group while spitting out that error each time. So this works exactly as intended, just slowly and with “errors”. I’ve attached a screenshot of my powershell screen. While it might be annoying that it doesn’t do this quickly, I am happy that i can at least queue it up and let it do it’s thing.

        Reply
        • Hey Jestoner, No Problem.Thanks for the screenshot. I have seen this error while working on the script. The script creates groups as intended and then displays the created groups on the console as you would be able to see it in the screenshot i shared in the blog post. Only the part where it displays the groups on the console is failing. This error is caused by Azure AD app registration API permissions.Make sure Powershell is run as admin, Grant Consent is approved for both Directory.ReadWriteAll and Group.ReadWriteAll in azure app.

          Permissions Required by New-PnPMicrosoft365Group
          One of Directory.ReadWrite.All, Group.Create, Group.ReadWrite.All

          I can try to hide this in the next version of the script so that it does not display the groups on the console as log file will have the information about the groups creation status. However, with required permissions provided, this error should not appear.

          UPDATE: Script has been updated now (To version 1.0.1) to not produce the console output for created group and also a bit of error handling has been added. This should fix the error message you are getting on Powershell console. You can download the updated copy from GitHub link: https://github.com/Techpress-net/Powershell-Scripts/tree/master/CreateM365GroupswithSPOSite
          or copy it from this blog post as well.

          Reply
          • Thank you so much! It was the group.create that i didn’t have permissions granted for.

            On a side note, is it possible to disable the automated email that gets sent out to the members when the group is created?

          • You’r Welcome Jestoner. I thought so that it could be a permission issue. I am glad that you finally found the root cause of the error. However as the script has been updated, there is not need to provide Groups.ReadWriteAll.

            Disable Welcome Message to users in Microsoft 365 Groups:

            Connect to EXO PS Module and run below command to disable the Welcome message. Let me know if it works fine.

            Set-UnifiedGroup <groupname> -UnifiedGroupWelcomeMessageEnabled:$false
            

Leave a Reply