Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Added `Add-PnPTenantSearchCrawledProperty` cmdlet which allows creation of a tenant level crawled property for SharePoint Online search. [#5373](https://github.com/pnp/powershell/pull/5373)
- Added `GitLab CI/CD` support to `Connect-PnPOnline -FederatedIdentity`. [#5395](https://github.com/pnp/powershell/pull/5395)
- Added `PreferredDataLocation` support to `Set-PnPMicrosoft365Group` and documented it for `Get-PnPMicrosoft365Group` and `New-PnPMicrosoft365Group`. [#5402](https://github.com/pnp/powershell/pull/5402)
- Added `Standard` and `EDU_Staff` template support to `New-PnPTeamsTeam` and provision Teams templates through Microsoft Graph team templates. [#999](https://github.com/pnp/powershell/issues/999)
Comment thread
gautamdsheth marked this conversation as resolved.
Outdated

### Changed

Expand Down
53 changes: 48 additions & 5 deletions documentation/New-PnPTeamsTeam.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ online version: https://pnp.github.io/powershell/cmdlets/New-PnPTeamsTeam.html
**Required Permissions**

* Microsoft Graph API: Group.ReadWrite.All
* Microsoft Graph API: Team.Create when using -Template

Creates a new team in Microsoft Teams or teamifies an existing Microsoft 365 Group. If the Microsoft 365 Group does not exist yet, it will create it first and then add a Microsoft Teams team to the group. If it does already exist, it will use the provided Microsoft 365 Group and just teamify it by adding a Microsoft Teams team to it.

Expand Down Expand Up @@ -46,7 +47,8 @@ New-PnPTeamsTeam -DisplayName <String> [-MailNickName <String>] [-Description <S
[-Owners <String[]>] [-Members <String[]>]
[-ResourceBehaviorOptions <TeamResourceBehaviorOptions>]
[-SensitivityLabels <GUID[]>]

[-Template <TeamsTemplateType>]

```

## DESCRIPTION
Expand Down Expand Up @@ -98,6 +100,34 @@ New-PnPTeamsTeam -DisplayName "myPnPDemo1" -Visibility Private -Owners "user1@co

This will create a new Microsoft Teams team called "myPnPDemo1" and sets the privacy to Private. User1 and user2 will be added as owners. User3 will be added as a member. The team will also get the sensitivity label value corresponding to the GUID specified.

### EXAMPLE 7
```powershell
New-PnPTeamsTeam -DisplayName "Staff Team" -Visibility Private -Template EDU_Staff -Owners "principal@contoso.onmicrosoft.com"
```

This will create a new Microsoft Teams education staff team called "Staff Team" and adds the provided user as owner. Owners are required when using application permissions.

### EXAMPLE 8
```powershell
New-PnPTeamsTeam -DisplayName "Biology 101" -Template EDU_Class -Owners "teacher@contoso.onmicrosoft.com" -Members "student@contoso.onmicrosoft.com"
```

This will create a new Microsoft Teams education class team called "Biology 101". Microsoft Graph sets class team visibility to HiddenMembership.

### EXAMPLE 9
```powershell
New-PnPTeamsTeam -DisplayName "Math PLC" -Visibility Private -Template EDU_PLC -Owners "lead@contoso.onmicrosoft.com"
```

This will create a new Microsoft Teams education professional learning community team called "Math PLC".

### EXAMPLE 10
```powershell
New-PnPTeamsTeam -DisplayName "Project Team" -Visibility Private -Template Standard -Owners "owner@contoso.onmicrosoft.com"
```

This will create a new standard Microsoft Teams team through Microsoft Graph team templates. Omitting Template keeps the existing Microsoft 365 Group creation and teamify behavior.

## PARAMETERS

### -AllowAddRemoveApps
Expand Down Expand Up @@ -381,7 +411,7 @@ Accept wildcard characters: False
```

### -MailNickName
The MailNickName parameter specifies the alias for the associated Microsoft 365 Group. This value will be used for the mail enabled object and will be used as PrimarySmtpAddress for this Microsoft 365 Group.The value of the MailNickName parameter has to be unique across your tenant.
The MailNickName parameter specifies the alias for the associated Microsoft 365 Group. This value will be used for the mail enabled object and will be used as PrimarySmtpAddress for this Microsoft 365 Group.The value of the MailNickName parameter has to be unique across your tenant. This parameter is ignored when used together with Template because Microsoft Graph creates the backing group.

```yaml
Type: String
Expand Down Expand Up @@ -468,7 +498,7 @@ Accept wildcard characters: False

### -ResourceBehaviorOptions

Allows providing ResourceBehaviorOptions which accepts multiple values that specify group behaviors for a Microsoft 365 Group. This will only work when you create a new Microsoft 365 Group, it will not work for existing groups.
Allows providing ResourceBehaviorOptions which accepts multiple values that specify group behaviors for a Microsoft 365 Group. This will only work when you create a new Microsoft 365 Group, it will not work for existing groups. This parameter cannot be used together with Template.

```yaml
Type: TeamResourceBehaviorOptions
Expand All @@ -483,7 +513,7 @@ Accept wildcard characters: False
```

### -SensitivityLabels
The Sensitivity label to be set to the Microsoft 365 Group and Team. To retrieve the sensitivity label you need to use the Graph API mentioned [here](https://learn.microsoft.com/en-us/graph/api/informationprotectionlabel-get?view=graph-rest-beta&tabs=http).
The Sensitivity label to be set to the Microsoft 365 Group and Team. To retrieve the sensitivity label you need to use the Graph API mentioned [here](https://learn.microsoft.com/en-us/graph/api/informationprotectionlabel-get?view=graph-rest-beta&tabs=http). This parameter cannot be used together with Template.

```yaml
Type: GUID[]
Expand All @@ -495,7 +525,20 @@ Accept pipeline input: False
Accept wildcard characters: False
```

### -Template
The Microsoft Teams template to use for the new team. Use Standard for the standard team template, EDU_Class for the education class template, EDU_PLC for the education professional learning community template, or EDU_Staff for the education staff template. When this parameter is used, Microsoft Graph provisions the team using POST /teams with a teamsTemplates binding and creates the backing Microsoft 365 Group automatically. Owners are required when using application permissions. Omit this parameter to keep the existing Microsoft 365 Group creation and teamify behavior.
Comment thread
gautamdsheth marked this conversation as resolved.
Outdated

```yaml
Type: TeamsTemplateType
Parameter Sets: For a new group
Accepted values: None, Standard, EDU_Class, EDU_PLC, EDU_Staff
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

## RELATED LINKS

[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)

2 changes: 2 additions & 0 deletions src/Commands/Enums/TeamsTemplateType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ public enum TeamsTemplateType
None,
EDU_Class,
EDU_PLC,
EDU_Staff,
Standard
}
}
49 changes: 49 additions & 0 deletions src/Commands/Model/Graph/TeamsAsyncOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
namespace PnP.PowerShell.Commands.Model.Graph
{
/// <summary>
/// Represents a Microsoft Teams async operation returned by Microsoft Graph.
/// </summary>
public class TeamsAsyncOperation
{
/// <summary>
/// Unique identifier of the operation.
/// </summary>
public string Id { get; set; }

/// <summary>
/// Current status of the operation.
/// </summary>
public string Status { get; set; }

/// <summary>
/// Identifier of the team that was created or modified by the operation.
/// </summary>
public string TargetResourceId { get; set; }

/// <summary>
/// Location of the team that was created or modified by the operation.
/// </summary>
public string TargetResourceLocation { get; set; }

/// <summary>
/// Error details returned when the operation fails.
/// </summary>
public TeamsAsyncOperationError Error { get; set; }
}

/// <summary>
/// Represents Teams async operation error details returned by Microsoft Graph.
/// </summary>
public class TeamsAsyncOperationError
{
/// <summary>
/// Error code returned by Microsoft Graph.
/// </summary>
public string Code { get; set; }

/// <summary>
/// Error message returned by Microsoft Graph.
/// </summary>
public string Message { get; set; }
}
}
36 changes: 35 additions & 1 deletion src/Commands/Teams/NewTeamsTeam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
using PnP.PowerShell.Commands.Utilities;
using System;
using System.Management.Automation;
using ConnectionMethod = PnP.PowerShell.Commands.Model.ConnectionMethod;

namespace PnP.PowerShell.Commands.Teams
{
[Cmdlet(VerbsCommon.New, "PnPTeamsTeam")]
[RequiredApiDelegatedOrApplicationPermissions("graph/Group.ReadWrite.All")]
[RequiredApiDelegatedOrApplicationPermissions("graph/Team.Create")]
public class NewTeamsTeam : PnPGraphCmdlet
{
private const string ParameterSet_EXISTINGGROUP = "For an existing group";
Expand Down Expand Up @@ -109,6 +111,31 @@ public class NewTeamsTeam : PnPGraphCmdlet

protected override void ExecuteCmdlet()
{
var contextSettings = Connection.Context.GetContextSettings();

if (Template != TeamsTemplateType.None)
{
if (ParameterSpecified(nameof(MailNickName)))
{
LogWarning($"{nameof(MailNickName)} is ignored when using {nameof(Template)} because Microsoft Graph creates the backing group when provisioning a team from a template.");
}

if (ParameterSpecified(nameof(ResourceBehaviorOptions)) || ParameterSpecified(nameof(SensitivityLabels)))
{
throw new PSInvalidOperationException($"{nameof(ResourceBehaviorOptions)} and {nameof(SensitivityLabels)} are not supported when using {nameof(Template)} because Microsoft Graph creates the backing group when provisioning a team from a template.");
}

if (IsApplicationConnection(Connection.ConnectionMethod) && (Owners == null || Owners.Length == 0))
{
throw new PSInvalidOperationException($"{nameof(Owners)} is required when using {nameof(Template)} with application permissions because Microsoft Graph requires a user in the members collection when creating a team with application permissions.");
}

if (Template == TeamsTemplateType.EDU_Class && ParameterSpecified(nameof(Visibility)))
{
LogWarning("The EDU_Class template sets team visibility to HiddenMembership and does not allow overriding it. The Visibility value will be ignored by Microsoft Graph.");
}
}

var teamCI = new TeamCreationInformation()
{
AllowAddRemoveApps = AllowAddRemoveApps,
Expand Down Expand Up @@ -136,7 +163,6 @@ protected override void ExecuteCmdlet()
AllowCreatePrivateChannels = AllowCreatePrivateChannels
};

var contextSettings = Connection.Context.GetContextSettings();
if (contextSettings.Type == Framework.Utilities.Context.ClientContextType.AzureADCertificate)
{
if (SensitivityLabels != null && SensitivityLabels.Length > 0)
Expand All @@ -148,5 +174,13 @@ protected override void ExecuteCmdlet()

WriteObject(TeamsUtility.NewTeam(GraphRequestHelper, GroupId, DisplayName, Description, Classification, MailNickName, (GroupVisibility)Enum.Parse(typeof(GroupVisibility), Visibility.ToString()), teamCI, Owners, Members, SensitivityLabels, Template, ResourceBehaviorOptions));
}

private static bool IsApplicationConnection(ConnectionMethod connectionMethod)
{
return connectionMethod == ConnectionMethod.AzureADAppOnly ||
connectionMethod == ConnectionMethod.ManagedIdentity ||
connectionMethod == ConnectionMethod.AzureADWorkloadIdentity ||
connectionMethod == ConnectionMethod.FederatedIdentity;
}
}
}
Loading
Loading