diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6dde0b63..31ce022aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,13 +10,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
## [3.23.2007.0]
### Added
-- Added `-WithRightsAssignedDetailed` parameter to `Get-PnPUser` allowing for fine grained (broken) permissions on item, list and site level to be shown [PR #2754](https://github.com/pnp/PnP-PowerShell/pull/2754)
+- Added `-WithRightsAssignedDetailed` parameter to `Get-PnPUser` when used against SharePoint Online allowing for fine grained (broken) permissions on item, list and site level to be shown [PR #2754](https://github.com/pnp/PnP-PowerShell/pull/2754)
- Added a `-RowLimit` parameter to `Clear-PnPRecycleBinItem` and `Restore-PnPRecycleBinItem` so that it can be used on recycle bins which hold more than 5000 items [PR #2760](https://github.com/pnp/PnP-PowerShell/pull/2760)
- Added connection option to `Connect-PnPOnline` taking `-Scopes` and `-Credentials` to allow setting up a delegated permission token for use with Microsoft Graph and the Office 365 Management API. See [this wiki page](https://github.com/pnp/PnP-PowerShell/wiki/Connect-options#connect-using-scopes-and-credentials) for more details. [PR #2746](https://github.com/pnp/PnP-PowerShell/pull/2746)
- Added support for enabling and disabling fields using `Set-PnPField -Identity FieldName -Values @{AllowDeletion=$false}` [PR #2766](https://github.com/pnp/PnP-PowerShell/pull/2766)
- Added the following cmdlets to add/remove/clear owners and members of Microsoft 365 Groups: `Add-PnPMicrosoft365GroupMember`, `Add-PnPMicrosoft365GroupOwner`, `Remove-PnPMicrosoft365GroupMember`, `Remove-PnPMicrosoft365GroupOwner`, `Clear-PnPMicrosoft365GroupMember`, `Clear-PnPMicrosoft365GroupOwner` [PR #2750](https://github.com/pnp/PnP-PowerShell/pull/2750)
- Added Add-PnPTeamsChannel, Add-PnPTeamsTab, Add-PnPTeamsUser, Get-PnPTeamsApp, Get-PnPTeamsChannel, Get-PnPTeamsChannelMessage, Get-PnPTeamsTab, Get-PnPTeamsTeam, Get-PnPTeamsUser, New-PnPTeamsApp, New-PnPTeamsTeam, Remove-PnPTeamsChannel, Remove-PnPTeamsTab, Remove-PnPTeamsTeam, Remove-PnPTeamsUser, Set-PnPTeamsChannel, Set-PnPTeamsTab, Set-PnPTeamsTeam, Set-PnPTeamsPicture, Submit-PnPTeamsChannelMessage, Update-PnPTeamsApp cmdlets
- Added Get-PnPFileVersion, Remove-PnPFileVersion, Restore-PnPFileVersion cmdlets
+- Added `-HideFromAddressLists` and `-HideFromOutlookClients` to `Set-PnPUnifiedGroup` to allow for setting the visibility of Microsoft 365 Groups [PR #2717](https://github.com/pnp/PnP-PowerShell/pull/2717)
### Changed
- Updated implementation of `Move-PnPFile` to now also support moving of files and folders accross site collections [PR #2749](https://github.com/pnp/PnP-PowerShell/pull/2749)
diff --git a/Commands/Files/CopyFile.cs b/Commands/Files/CopyFile.cs
index 415dbf024..af11c8e9a 100644
--- a/Commands/Files/CopyFile.cs
+++ b/Commands/Files/CopyFile.cs
@@ -14,6 +14,7 @@ namespace SharePointPnP.PowerShell.Commands.Files
[Cmdlet(VerbsCommon.Copy, "PnPFile", SupportsShouldProcess = true)]
[CmdletHelp("Copies a file or folder to a different location. This location can be within the same document library, same site, same site collection or even to another site collection on the same tenant. Currently there is a 200MB file size limit for the file or folder to be copied.",
Category = CmdletHelpCategory.Files)]
+#if !ONPREMISES
[CmdletExample(
Remarks = "Copies a file named company.docx located in a document library called Shared Documents in the site collection project to the Shared Documents library in the site collection otherproject. If a file named company.docx already exists, it won't perform the copy.",
Code = @"PS:>Copy-PnPFile -ServerRelativeUrl ""/sites/project/Shared Documents/company.docx"" -TargetServerRelativeLibrary ""/sites/otherproject/Shared Documents""",
@@ -22,6 +23,7 @@ namespace SharePointPnP.PowerShell.Commands.Files
Remarks = "Copies a folder named Archive located in a document library called Shared Documents in the site collection project to the Shared Documents library in the site collection otherproject. If a folder named Archive already exists, it will overwrite it.",
Code = @"PS:>Copy-PnPFile -ServerRelativeUrl ""/sites/project/Shared Documents/Archive"" -TargetServerRelativeLibrary ""/sites/otherproject/Shared Documents"" -OverwriteIfAlreadyExists",
SortOrder = 2)]
+#endif
[CmdletExample(
Remarks = "Copies a file named company.docx located in a document library called Documents to a new document named company2.docx in the same library.",
Code = @"PS:>Copy-PnPFile -SourceUrl Documents/company.docx -TargetUrl Documents/company2.docx",
@@ -75,7 +77,9 @@ public class CopyFile : PnPWebCmdlet
public string SourceUrl = string.Empty;
[Parameter(Mandatory = true, Position = 1, HelpMessage = "Server relative Url where to copy the file or folder to. Must not include the file name.")]
+#if !ONPREMISES
[Alias(nameof(MoveFile.TargetServerRelativeLibrary))] // Aliases is present to allow for switching between Move-PnPFile and Copy-PnPFile keeping the same parameters.
+#endif
public string TargetUrl = string.Empty;
[Parameter(Mandatory = false, HelpMessage = "If provided, if a file already exists at the TargetUrl, it will be overwritten. If omitted, the copy operation will be canceled if the file already exists at the TargetUrl location.")]
@@ -113,14 +117,18 @@ protected override void ExecuteCmdlet()
if (Force || ShouldContinue(string.Format(Resources.CopyFile0To1, SourceUrl, TargetUrl), Resources.Confirm))
{
+#if !ONPREMISES
if (sourceWebUri != targetWebUri)
{
CopyToOtherSiteCollection(sourceUri, targetUri);
}
else
{
+#endif
CopyWithinSameSiteCollection(currentContextUri, sourceWebUri, targetWebUri);
+#if !ONPREMISES
}
+#endif
}
}
@@ -271,6 +279,7 @@ private void CopyWithinSameSiteCollection(Uri currentContextUri, Uri sourceWebUr
}
}
+#if !ONPREMISES
///
/// Allows copying to another site collection
///
@@ -284,6 +293,7 @@ private void CopyToOtherSiteCollection(Uri source, Uri destination)
});
ClientContext.ExecuteQueryRetry();
}
+#endif
private void CopyFolder(Folder sourceFolder, Folder targetFolder)
{
diff --git a/Commands/Graph/SetMicrosoft365Group.cs b/Commands/Graph/SetMicrosoft365Group.cs
index f5885661b..637a48ad6 100644
--- a/Commands/Graph/SetMicrosoft365Group.cs
+++ b/Commands/Graph/SetMicrosoft365Group.cs
@@ -35,6 +35,10 @@ namespace SharePointPnP.PowerShell.Commands.Graph
Code = @"PS:> Set-PnPMicrosoft365Group -Identity $group -Owners demo@contoso.com",
Remarks = "Sets demo@contoso.com as owner of the group",
SortOrder = 5)]
+ [CmdletExample(
+ Code = @"PS:> Set-PnPMicrosoft365Group -Identity $group -HideFromOutlookClients:$false",
+ Remarks = "Ensures the provided group will be shown in Outlook clients",
+ SortOrder = 6)]
[CmdletRelatedLink(Text = "Documentation", Url = "https://docs.microsoft.com/graph/api/group-update")]
[CmdletMicrosoftGraphApiPermission(MicrosoftGraphApiPermission.Group_ReadWrite_All)]
public class SetMicrosoft365Group : PnPGraphCmdlet
@@ -63,6 +67,12 @@ public class SetMicrosoft365Group : PnPGraphCmdlet
[Parameter(Mandatory = false, HelpMessage = "Creates a Microsoft Teams team associated with created group")]
public SwitchParameter CreateTeam;
+ [Parameter(Mandatory = false, HelpMessage = "Hides the group from the Global Address List")]
+ public bool? HideFromAddressLists;
+
+ [Parameter(Mandatory = false, HelpMessage = "Hides the group from Outlook Clients")]
+ public bool? HideFromOutlookClients;
+
protected override void ExecuteCmdlet()
{
UnifiedGroupEntity group = null;
@@ -101,6 +111,12 @@ protected override void ExecuteCmdlet()
groupLogo: groupLogoStream,
isPrivate: isPrivateGroup,
createTeam: CreateTeam);
+
+ if (ParameterSpecified(nameof(HideFromAddressLists)) || ParameterSpecified(nameof(HideFromOutlookClients)))
+ {
+ // For this scenario a separate call needs to be made
+ UnifiedGroupsUtility.SetUnifiedGroupVisibility(group.GroupId, AccessToken, HideFromAddressLists, HideFromOutlookClients);
+ }
}
catch(Exception e)
{
@@ -115,4 +131,4 @@ protected override void ExecuteCmdlet()
}
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/Commands/Principals/GetUser.cs b/Commands/Principals/GetUser.cs
index bd9e87fde..a6f8770db 100644
--- a/Commands/Principals/GetUser.cs
+++ b/Commands/Principals/GetUser.cs
@@ -41,15 +41,19 @@ namespace SharePointPnP.PowerShell.Commands.Principals
Code = @"PS:> Get-PnPUser -WithRightsAssigned -Web subsite1",
Remarks = "Returns only those users from the User Information List of the current site collection who currently have any kind of access rights given either directly to the user or Active Directory Group or given to the user or Active Directory Group via membership of a SharePoint Group to subsite 'subsite1'",
SortOrder = 6)]
+#if !ONPREMISES
[CmdletExample(
Code = @"PS:> Get-PnPUser -WithRightsAssignedDetailed",
Remarks = "Returns all users who have been granted explicit access to the current site, lists and listitems",
SortOrder = 7)]
+#endif
public class GetUser : PnPWebCmdlet
{
private const string PARAMETERSET_IDENTITY = "Identity based request";
private const string PARAMETERSET_WITHRIGHTSASSIGNED = "With rights assigned";
+#if !ONPREMISES
private const string PARAMETERSET_WITHRIGHTSASSIGNEDDETAILED = "With rights assigned detailed";
+#endif
[Parameter(Mandatory = false, ValueFromPipeline = true, ParameterSetName = PARAMETERSET_IDENTITY, HelpMessage = "User ID or login name")]
public UserPipeBind Identity;
@@ -57,8 +61,10 @@ public class GetUser : PnPWebCmdlet
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_WITHRIGHTSASSIGNED, HelpMessage = "If provided, only users that currently have any kinds of access rights assigned to the current site collection will be returned. Otherwise all users, even those who previously had rights assigned, but not anymore at the moment, will be returned as the information is pulled from the User Information List. Only works if you don't provide an -Identity.")]
public SwitchParameter WithRightsAssigned;
+#if !ONPREMISES
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_WITHRIGHTSASSIGNEDDETAILED, HelpMessage = "If provided, only users that currently have any specific kind of access rights assigned to the current site, lists or listitems/documents will be returned. Otherwise all users, even those who previously had rights assigned, but not anymore at the moment, will be returned as the information is pulled from the User Information List. Only works if you don't provide an -Identity.")]
public SwitchParameter WithRightsAssignedDetailed;
+#endif
///
/// Output type used with parameter WithRightsAssignedDetailed
@@ -103,7 +109,11 @@ protected override void ExecuteCmdlet()
List users = new List();
- if (WithRightsAssigned || WithRightsAssignedDetailed)
+ if (WithRightsAssigned
+#if !ONPREMISES
+ || WithRightsAssignedDetailed
+#endif
+ )
{
// Get all the role assignments and role definition bindings to be able to see which users have been given rights directly on the site level
SelectedWeb.Context.Load(SelectedWeb.RoleAssignments, ac => ac.Include(a => a.RoleDefinitionBindings, a => a.Member));
@@ -125,6 +135,7 @@ protected override void ExecuteCmdlet()
allUsersWithPermissions.AddRange(usersWithDirectPermissions);
allUsersWithPermissions.AddRange(usersWithGroupPermissions);
+#if !ONPREMISES
// Add the found users and add them to the custom object
if (WithRightsAssignedDetailed)
{
@@ -144,6 +155,7 @@ protected override void ExecuteCmdlet()
}
}
else
+#endif
{
// Filter out the users that have been given rights at both places so they will only be returned once
WriteObject(allUsersWithPermissions.GroupBy(u => u.Id).Select(u => u.First()), true);
@@ -155,6 +167,7 @@ protected override void ExecuteCmdlet()
WriteObject(SelectedWeb.SiteUsers, true);
}
+#if !ONPREMISES
if (WithRightsAssignedDetailed)
{
SelectedWeb.Context.Load(SelectedWeb.Lists, l => l.Include(li => li.ItemCount, li => li.IsSystemList, li=>li.IsCatalog, li => li.RootFolder.ServerRelativeUrl, li => li.RoleAssignments, li => li.Title, li => li.HasUniqueRoleAssignments));
@@ -310,6 +323,7 @@ protected override void ExecuteCmdlet()
WriteObject(new { userInformation.Title, userInformation.LoginName, userInformation.Email, Groups, Permissions }, true);
}
}
+#endif
}
else
{
@@ -335,6 +349,7 @@ protected override void ExecuteCmdlet()
}
}
+#if !ONPREMISES
private void WriteProgress(ProgressRecord record, string message, int step, int count)
{
var percentage = Convert.ToInt32((100 / Convert.ToDouble(count)) * Convert.ToDouble(step));
@@ -373,5 +388,6 @@ private static List GetPermissions(RoleAssignmentCollection roleAs
}
return users;
}
+#endif
}
}