Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
## [Current nightly]

### Added
- Added `Remove-PnPGeoAdministrator` cmdlet to remove SharePoint Online geo administrators. [#5380](https://github.com/pnp/powershell/pull/5380)
- Added `Get-PnPGeoAdministrator` cmdlet to retrieve SharePoint Online geo administrators. [#5378](https://github.com/pnp/powershell/pull/5378)
- Added `Get-PnPMultiGeoExperience` cmdlet to retrieve the SharePoint Online multi-geo experience mode. [#5372](https://github.com/pnp/powershell/pull/5372)
- Added `Set-PnPMultiGeoExperience` cmdlet to upgrade the tenant multi-geo experience to include SharePoint Online Multi-Geo. [#5369](https://github.com/pnp/powershell/pull/5369)
Expand Down
118 changes: 118 additions & 0 deletions documentation/Remove-PnPGeoAdministrator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
Module Name: PnP.PowerShell
title: Remove-PnPGeoAdministrator
schema: 2.0.0
applicable: SharePoint Online
external help file: PnP.PowerShell.dll-Help.xml
online version: https://pnp.github.io/powershell/cmdlets/Remove-PnPGeoAdministrator.html
---

# Remove-PnPGeoAdministrator

## SYNOPSIS
Removes a SharePoint Online geo administrator.

## SYNTAX

```powershell
Remove-PnPGeoAdministrator [-UserPrincipalName] <String> [-Connection <PnPConnection>]

Remove-PnPGeoAdministrator [-GroupAlias] <String> [-Connection <PnPConnection>]

Remove-PnPGeoAdministrator [-ObjectId] <Guid> [-Connection <PnPConnection>]
```

## DESCRIPTION
Removes a user or group as a SharePoint Online geo administrator.

## EXAMPLES

### EXAMPLE 1

```powershell
Remove-PnPGeoAdministrator -UserPrincipalName user@contoso.onmicrosoft.com
```

Removes the specified user as a geo administrator.

### EXAMPLE 2

```powershell
Remove-PnPGeoAdministrator -GroupAlias spo-geo-admins
```

Removes the specified group as a geo administrator.

### EXAMPLE 3

```powershell
Remove-PnPGeoAdministrator -ObjectId 11111111-1111-1111-1111-111111111111
```

Removes the geo administrator with the specified object ID.

## PARAMETERS

### -Connection
Optional connection to be used by the cmdlet. Retrieve the value for this parameter by specifying `-ReturnConnection` on `Connect-PnPOnline` or by executing `Get-PnPConnection`.

```yaml
Type: PnPConnection
Parameter Sets: (All)

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -GroupAlias
Specifies the alias of the group to remove as a geo administrator.

```yaml
Type: String
Parameter Sets: Group

Required: True
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -ObjectId
Specifies the object ID of the user or group to remove as a geo administrator.

```yaml
Type: Guid
Parameter Sets: ObjectId

Required: True
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -UserPrincipalName
Specifies the user principal name of the user to remove as a geo administrator.

```yaml
Type: String
Parameter Sets: User

Required: True
Position: 0
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

## OUTPUTS

### None

## RELATED LINKS

[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
52 changes: 52 additions & 0 deletions src/Commands/Admin/RemoveGeoAdministrator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using PnP.PowerShell.Commands.Attributes;
using PnP.PowerShell.Commands.Base;
using PnP.PowerShell.Commands.Utilities.MultiGeo;
using System;
using System.Management.Automation;

namespace PnP.PowerShell.Commands.Admin
{
[Cmdlet(VerbsCommon.Remove, "PnPGeoAdministrator", DefaultParameterSetName = ParameterSetUser)]
[RequiredApiApplicationPermissions("sharepoint/Sites.FullControl.All")]
[RequiredApiDelegatedPermissions("sharepoint/AllSites.FullControl")]
public class RemoveGeoAdministrator : PnPSharePointOnlineAdminCmdlet
{
private const string ParameterSetUser = "User";
private const string ParameterSetGroup = "Group";
private const string ParameterSetObjectId = "ObjectId";

[Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSetUser)]
[ValidateNotNullOrEmpty]
public string UserPrincipalName { get; set; }

[Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSetGroup)]
[ValidateNotNullOrEmpty]
public string GroupAlias { get; set; }

[Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSetObjectId)]
[ValidateNotNullOrEmpty]
public Guid ObjectId { get; set; }

protected override void ExecuteCmdlet()
{
var multiGeoRestApiClient = new MultiGeoRestApiClient(AdminContext);
switch (ParameterSetName)
{
case ParameterSetGroup:
multiGeoRestApiClient.RemoveGeoAdministrator(GroupAlias, isGroup: true);
break;

case ParameterSetUser:
multiGeoRestApiClient.RemoveGeoAdministrator(UserPrincipalName, isGroup: false);
break;

case ParameterSetObjectId:
multiGeoRestApiClient.RemoveGeoAdministrator(ObjectId);
break;

default:
throw new ArgumentException("Parameter set cannot be resolved using the specified named parameters.");
}
}
}
}
61 changes: 61 additions & 0 deletions src/Commands/Utilities/MultiGeo/MultiGeoRestApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,16 @@ internal class MultiGeoRestApiClient
private const string UpdateAllInstancesExperienceModePath = "GeoExperience/UpgradeAllInstancesToSPOMode";
private const string AllowedDataLocationsApiVersion = "1.3.11";
private const string AllowedDataLocationsPath = "AllowedDataLocations";
private const string GeoAdministratorsByLoginNameMaximumApiVersion = "1.3.8";
private const string GeoAdministratorsByPrincipalMinimumApiVersion = "1.3.9";
private const string GeoAdministratorsByLoginNamePath = "GeoAdministrators(loginName='{0}')";
private const string GeoAdministratorsByLoginNameAndTypePath = "GeoAdministrators/GetByLoginNameAndType(loginName='{0}', memberType={1:D})";
private const string GeoAdministratorsByObjectIdPath = "GeoAdministrators/GetByObjectId(guid'{0:D}')";
private const string StorageQuotasMinimumApiVersion = "1.3.1";
private const string StorageQuotasPath = "StorageQuotas";
private const string StorageQuotaByLocationPath = "StorageQuotas(geoLocation='{0}')";
private const string MultiGeoApiVersionsPath = "MultiGeoApiVersions";
private const string DeleteVerbString = "DELETE";
private const string PatchVerbString = "PATCH";
private const string UserMoveJobsMinimumApiVersion = "1.0";
private const string UserMoveJobsByMoveIdMinimumApiVersion = "1.2.2";
Expand All @@ -66,6 +72,8 @@ internal class MultiGeoRestApiClient
private const int SiteMoveRunsWorkflow2013ErrorCode = -113;
private const int SiteMoveRequiresForceErrorCode = -116;
private const int SiteMoveContainsBcsErrorCode = -139;
private const int GeoAdministratorUserMemberType = 1;
private const int GeoAdministratorGroupMemberType = 2;
private const int MaximumPagination = 10;
private const int ApiVersionCacheValidTimeInHours = 1;
private static readonly TimeSpan CreateTenantRenameJobTimeout = TimeSpan.FromSeconds(300);
Expand Down Expand Up @@ -340,6 +348,23 @@ internal void PartialUpdateStorageQuota(StorageQuotaEntityData quota)
PostWithMethodOverride(path, quota, PatchVerbString, apiVersion);
}

internal void RemoveGeoAdministrator(string loginName, bool isGroup)
{
var apiVersion = GetGeoAdministratorsApiVersion();
var path = IsSupportedApiVersionRange(apiVersion, GeoAdministratorsMinimumApiVersion, GeoAdministratorsByLoginNameMaximumApiVersion)
? string.Format(CultureInfo.InvariantCulture, GeoAdministratorsByLoginNamePath, ProcessSpecialChars(loginName))
: string.Format(CultureInfo.InvariantCulture, GeoAdministratorsByLoginNameAndTypePath, ProcessSpecialChars(loginName), isGroup ? GeoAdministratorGroupMemberType : GeoAdministratorUserMemberType);

PostWithMethodOverrideEmptyBody(path, DeleteVerbString, apiVersion);
}

internal void RemoveGeoAdministrator(Guid objectId)
{
var apiVersion = GetGeoAdministratorsByPrincipalApiVersion();
var path = string.Format(CultureInfo.InvariantCulture, GeoAdministratorsByObjectIdPath, objectId);
PostWithMethodOverrideEmptyBody(path, DeleteVerbString, apiVersion);
}

internal void CancelUserMoveJob(string userPrincipalName)
{
var apiVersion = GetCurrentApiVersion(UserMoveJobsMinimumApiVersion);
Expand Down Expand Up @@ -442,6 +467,21 @@ private void PostWithMethodOverride(string path, object payload, string methodOv
}, timeout: null, allowRetries: false);
}

private void PostWithMethodOverrideEmptyBody(string path, string methodOverride, string apiVersion)
{
Send(() =>
{
var request = CreateRequest(HttpMethod.Post, path, apiVersion, string.Empty);
request.Headers.TryAddWithoutValidation("X-HTTP-Method", methodOverride);
if (request.Content != null)
{
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;charset=UTF-8");
}

return request;
}, timeout: null, allowRetries: false);
}

private HttpRequestMessage CreateRequest(HttpMethod method, string path, string apiVersion, string jsonPayload = null)
{
return CreateRequest(method, CreateApiUri(path, apiVersion), jsonPayload);
Expand Down Expand Up @@ -535,6 +575,16 @@ private static bool IsSupportedApiVersion(string apiVersion, string minimumApiVe
return apiVersionIndex >= 0 && minimumApiVersionIndex >= 0 && apiVersionIndex <= minimumApiVersionIndex;
}

private static bool IsSupportedApiVersionRange(string apiVersion, string minimumApiVersion, string maximumApiVersion)
{
var apiVersionIndex = Array.IndexOf(ClientSupportedApiVersions, apiVersion);
var minimumApiVersionIndex = Array.IndexOf(ClientSupportedApiVersions, minimumApiVersion);
var maximumApiVersionIndex = Array.IndexOf(ClientSupportedApiVersions, maximumApiVersion);
return apiVersionIndex >= 0 && minimumApiVersionIndex >= 0 && maximumApiVersionIndex >= 0
&& apiVersionIndex <= minimumApiVersionIndex
&& apiVersionIndex >= maximumApiVersionIndex;
}

private string GetStorageQuotasApiVersion()
{
var apiVersion = GetCurrentApiVersion();
Expand All @@ -557,6 +607,17 @@ private string GetGeoAdministratorsApiVersion()
return apiVersion;
}

private string GetGeoAdministratorsByPrincipalApiVersion()
{
var apiVersion = GetCurrentApiVersion();
if (!IsSupportedApiVersion(apiVersion, GeoAdministratorsByPrincipalMinimumApiVersion))
{
throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, CommandResources.CrossGeoInvalidVersion, GetApplicationVersion()));
}

return apiVersion;
}

private string GetGeoExperienceApiVersion()
{
var apiVersion = GetCurrentApiVersion();
Expand Down
Loading