About the Task
I received a request to create Microsoft 365 groups in bulk using PowerShell. While attempting to use the New-UnifiedGroup command (part of the EXO V2 PowerShell Module), I successfully created the Microsoft 365 group.
However, I encountered an issue as this command did not generate the corresponding SharePoint site. Consequently, I used the ‘New-PnPMicrosoft365Group‘ command, which is a part of the PnP.Powershell PowerShell module.
In this blog post, I provide a detailed explanation of how to use the ‘New-PnPMicrosoft365Group‘ command to create one or more Microsoft 365 groups which also created a Sharepoint site as well.
Please note that New-PnPMicrosoft365Group cmdlet does not work when you use Connect-PnPOnline with -useWeblogin parameter. Therefore, we have to first make a connection with Sharepoint in a non-interactive way.
To observe the effects of using the -useWebLogin
switch with the Connect-PnPOnline
command, open PowerShell as an Administrator, type the following command, and press Enter.
Make sure the PnP.Powershell module is installed on the system; otherwise, the command below will not work. To Install Pnp.Powershell module use: Install-Module -Name PnP.PowerShell -Force -AllowClobber command.
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.
After authenticating using the -UseWebLogin parameter, attempt to create a new Microsoft 365 group using the New-PnPMicrosoft365Group
cmdlet. It will fail with below error message:
“This cmdlet does not work with WebLogin/Cookie based connection towards Sharepoint“
Therefore, We will use a non-interactive way which can be achieved by using Entra ID App registration. Let’s check the steps:
Table of Contents
Step 1 – Create an Entra ID App Registration
To Create an App registration on the Entra admin center. Follow the below steps:
- Login on Entra admin center.
- Expand Applications > App registrations.
- Click on New registrations
- Provide the Name of the Application and select “Accounts in this organizational directory only“. Click Register.
- Once the application is registered, click on the ‘Overview‘ link, and then copy the Client ID. The Client ID will be used when connecting to SharePoint via the
Connect-PnPOnline
command.
- The next step is to grant minimum permissions to this app for our task. To do this, click on ‘API Permissions‘ and then select ‘Add a Permission“.
- Click on Microsoft Graph.
- 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
Step 2 – Create a Self-signed Certificate
The next step is to create a self-signed certificate and upload it to the PnP PowerShell app we registered in Entra ID. Let’s see how we can generate and upload the certificate.
- For creating a self-signed certificate, Copy the code from the Microsoft Docs link and save it in a .ps1 file: https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread.
- Use the following command to generate a self-signed certificate. Please note that the date format is YYYY-MM-dd. Adjust the start date and end date according to your requirements.
.\Create-SelfSignedCertificate.ps1 -CommonName "TechPress" -StartDate 2021-08-13 -EndDate 2022-08-13
- Self-signed Certificate has been generated
Step 3 – Upload the Self Signed Certificate
- Click on the ‘Certificates & Secrets‘.
- 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 a few values that will be used to connect to SharePoint using the Connect-PnPonline command. Below are the values required for this command.
Client ID = Copy the 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 |
Step 1 – Install PnP.Powershell
To install the PnP.Powershell module on your system, open the PowerShell console as an Administrator and type the following command:
Install-Module -Name PnP.PowerShell -Force -AllowClobber
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 = "[email protected]", "[email protected]"
$arrayOfMembers = "[email protected]"
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 = "[email protected]", "[email protected]"
$arrayOfMembers = "[email protected]"
New-PnPMicrosoft365Group -Displayname $displayName -Description "TechPress Finance Group" -MailNickname $nickname -Owners $arrayOfOwners -Members $arrayOfMembers -IsPrivate -CreateTeam
Also Read: Exchange Online / Exchange 2010 useful PowerShell Commands
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 = “[email protected]”, “[email protected]” $arrayOfMembers = “[email protected]” $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
C:\Apps\Logs\M365GroupLog-08-13-2021_06-54-59.csv File |
---|
Tip – Use 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://techpress.net
.LINK
https://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 = "[email protected]", "[email protected]"
$arrayOfMembers = "[email protected]"
$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"
}
}
}
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
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.
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.
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.
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.