Skip to content

Commit a4eadfe

Browse files
authored
Add Set-PnPMultiGeoCompanyAllowedDataLocation (#5368)
* Add Set-PnPMultiGeoCompanyAllowedDataLocation Adds the PnP cmdlet and matching multigeo REST client path to start setting up an allowed SharePoint Online data location. * Address Set-PnPMultiGeo review feedback Adds output metadata and the changelog PR reference while preserving SPO-compatible REST and confirmation behavior.
1 parent a234286 commit a4eadfe

8 files changed

Lines changed: 272 additions & 0 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
99
## [Current nightly]
1010

1111
### Added
12+
- Added `Set-PnPMultiGeoCompanyAllowedDataLocation` cmdlet to start setting up a SharePoint Online multi-geo allowed data location. [#5368](https://github.com/pnp/powershell/pull/5368)
1213
- Added `Get-PnPSiteContentMoveState` cmdlet to retrieve SharePoint Online site content move states. [#5365](https://github.com/pnp/powershell/pull/5365)
1314
- Added `Stop-PnPSiteContentMove` cmdlet to stop SharePoint Online multi-geo site content move jobs. [#5366](https://github.com/pnp/powershell/pull/5366)
1415
- Added `Get-PnPUnifiedGroupMoveState` cmdlet to retrieve SharePoint Online Microsoft 365 group move states. [#5362](https://github.com/pnp/powershell/pull/5362)

documentation/Get-PnPMultiGeoCompanyAllowedDataLocation.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,6 @@ Returns objects with `Location`, `Domain`, and `IsDefault` properties.
5454

5555
## RELATED LINKS
5656

57+
[Set-PnPMultiGeoCompanyAllowedDataLocation](Set-PnPMultiGeoCompanyAllowedDataLocation.md)
58+
5759
[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
---
2+
Module Name: PnP.PowerShell
3+
title: Set-PnPMultiGeoCompanyAllowedDataLocation
4+
schema: 2.0.0
5+
applicable: SharePoint Online
6+
external help file: PnP.PowerShell.dll-Help.xml
7+
online version: https://pnp.github.io/powershell/cmdlets/Set-PnPMultiGeoCompanyAllowedDataLocation.html
8+
---
9+
10+
# Set-PnPMultiGeoCompanyAllowedDataLocation
11+
12+
## SYNOPSIS
13+
Starts setting up a multi-geo data location for the SharePoint Online tenant.
14+
15+
## SYNTAX
16+
17+
```powershell
18+
Set-PnPMultiGeoCompanyAllowedDataLocation [-Location] <String> [-InitialDomain] <String> [-Connection <PnPConnection>] [-WhatIf] [-Confirm]
19+
```
20+
21+
## DESCRIPTION
22+
Starts setting up an allowed SharePoint Online multi-geo data location for the tenant.
23+
24+
## EXAMPLES
25+
26+
### EXAMPLE 1
27+
28+
```powershell
29+
Set-PnPMultiGeoCompanyAllowedDataLocation -Location EUR -InitialDomain contoso.onmicrosoft.com
30+
```
31+
32+
Starts setting up the EUR multi-geo data location for the tenant with the initial domain `contoso.onmicrosoft.com`.
33+
34+
## PARAMETERS
35+
36+
### -Confirm
37+
Prompts you for confirmation before running the cmdlet.
38+
39+
```yaml
40+
Type: SwitchParameter
41+
Parameter Sets: (All)
42+
43+
Required: False
44+
Position: Named
45+
Default value: None
46+
Accept pipeline input: False
47+
Accept wildcard characters: False
48+
```
49+
50+
### -Connection
51+
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`.
52+
53+
```yaml
54+
Type: PnPConnection
55+
Parameter Sets: (All)
56+
57+
Required: False
58+
Position: Named
59+
Default value: None
60+
Accept pipeline input: False
61+
Accept wildcard characters: False
62+
```
63+
64+
### -InitialDomain
65+
Specifies the initial SharePoint Online domain for the data location.
66+
67+
```yaml
68+
Type: String
69+
Parameter Sets: (All)
70+
71+
Required: True
72+
Position: 1
73+
Default value: None
74+
Accept pipeline input: False
75+
Accept wildcard characters: False
76+
```
77+
78+
### -Location
79+
Specifies the multi-geo location code to set up.
80+
81+
```yaml
82+
Type: String
83+
Parameter Sets: (All)
84+
85+
Required: True
86+
Position: 0
87+
Default value: None
88+
Accept pipeline input: False
89+
Accept wildcard characters: False
90+
```
91+
92+
### -WhatIf
93+
Shows what would happen if the cmdlet runs. The cmdlet is not run.
94+
95+
```yaml
96+
Type: SwitchParameter
97+
Parameter Sets: (All)
98+
99+
Required: False
100+
Position: Named
101+
Default value: None
102+
Accept pipeline input: False
103+
Accept wildcard characters: False
104+
```
105+
106+
## OUTPUTS
107+
108+
### System.String
109+
Returns a message indicating that setting up the new location has started.
110+
111+
## RELATED LINKS
112+
113+
[Get-PnPMultiGeoCompanyAllowedDataLocation](Get-PnPMultiGeoCompanyAllowedDataLocation.md)
114+
115+
[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using PnP.PowerShell.Commands.Attributes;
2+
using PnP.PowerShell.Commands.Base;
3+
using PnP.PowerShell.Commands.Model;
4+
using PnP.PowerShell.Commands.Properties;
5+
using PnP.PowerShell.Commands.Utilities.MultiGeo;
6+
using System.Globalization;
7+
using System.Management.Automation;
8+
9+
namespace PnP.PowerShell.Commands.Admin
10+
{
11+
[Cmdlet(VerbsCommon.Set, "PnPMultiGeoCompanyAllowedDataLocation", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
12+
[RequiredApiApplicationPermissions("sharepoint/Sites.FullControl.All")]
13+
[RequiredApiDelegatedPermissions("sharepoint/AllSites.FullControl")]
14+
[OutputType(typeof(string))]
15+
public class SetMultiGeoCompanyAllowedDataLocation : PnPSharePointOnlineAdminCmdlet
16+
{
17+
private const string SharePointAppId = "00000003-0000-0ff1-ce00-000000000000";
18+
19+
[Parameter(Mandatory = true, Position = 0)]
20+
[ValidateNotNullOrEmpty]
21+
public string Location { get; set; }
22+
23+
[Parameter(Mandatory = true, Position = 1)]
24+
[ValidateNotNullOrEmpty]
25+
public string InitialDomain { get; set; }
26+
27+
protected override void ExecuteCmdlet()
28+
{
29+
var tenantName = InitialDomain.Split('.')[0];
30+
var mySiteHostUrl = string.Format(CultureInfo.InvariantCulture, "https://{0}-my.sharepoint.com", tenantName);
31+
var sharePointHostUrl = string.Format(CultureInfo.InvariantCulture, "https://{0}.sharepoint.com", tenantName);
32+
var warningMessage = string.Format(CultureInfo.InvariantCulture, Resources.CrossGeoWarningAddAdlMessage, mySiteHostUrl, sharePointHostUrl);
33+
34+
if (!ShouldProcess(warningMessage, warningMessage, Resources.CrossGeoWarningAddAdlMessageQuery))
35+
{
36+
return;
37+
}
38+
39+
var multiGeoRestApiClient = new MultiGeoRestApiClient(AdminContext);
40+
multiGeoRestApiClient.AddAllowedDataLocation(new MultiGeoCompanyAllowedDataLocationEntityData
41+
{
42+
AppId = SharePointAppId,
43+
Domain = InitialDomain,
44+
Location = Location
45+
});
46+
47+
WriteObject(Resources.CrossGeoWarningAddAdlSuccessMessage);
48+
}
49+
}
50+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace PnP.PowerShell.Commands.Model
4+
{
5+
/// <summary>
6+
/// Contains the payload used to add an allowed multi-geo data location.
7+
/// </summary>
8+
internal class MultiGeoCompanyAllowedDataLocationEntityData
9+
{
10+
/// <summary>
11+
/// The application identifier used by SharePoint Online for the allowed data location.
12+
/// </summary>
13+
[JsonPropertyName("appId")]
14+
public string AppId { get; set; }
15+
16+
/// <summary>
17+
/// The initial SharePoint Online domain for the geo location.
18+
/// </summary>
19+
[JsonPropertyName("domain")]
20+
public string Domain { get; set; }
21+
22+
/// <summary>
23+
/// The geo location code, such as NAM or EUR.
24+
/// </summary>
25+
[JsonPropertyName("location")]
26+
public string Location { get; set; }
27+
}
28+
}

src/Commands/Properties/Resources.Designer.cs

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Commands/Properties/Resources.resx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,18 @@
126126
<data name="Confirm" xml:space="preserve">
127127
<value>Confirm</value>
128128
</data>
129+
<data name="CrossGeoInvalidVersion" xml:space="preserve">
130+
<value>The client version '{0}' is not supported. Please try to upgrade client version first.</value>
131+
</data>
132+
<data name="CrossGeoWarningAddAdlMessage" xml:space="preserve">
133+
<value>The new location will use the following addresses for OneDrive and SharePoint sites:&#xD;&#xA;&#xD;&#xA;{0}&#xD;&#xA;{1}&#xD;&#xA;&#xD;&#xA;</value>
134+
</data>
135+
<data name="CrossGeoWarningAddAdlMessageQuery" xml:space="preserve">
136+
<value>Do you want to set up this location?</value>
137+
</data>
138+
<data name="CrossGeoWarningAddAdlSuccessMessage" xml:space="preserve">
139+
<value>Successfully started setting up the new location. You will receive a notification when the process completes. You can check status using the following command: Get-SPOMultiGeoCompanyAllowedDataLocation.</value>
140+
</data>
129141
<data name="CurrentSiteIsNoTenantAdminSite" xml:space="preserve">
130142
<value>Current site is not a tenant administration site</value>
131143
</data>

src/Commands/Utilities/MultiGeo/MultiGeoRestApiClient.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.Text.Json;
1414
using System.Threading;
1515
using System.Threading.Tasks;
16+
using CommandResources = PnP.PowerShell.Commands.Properties.Resources;
1617

1718
namespace PnP.PowerShell.Commands.Utilities.MultiGeo
1819
{
@@ -147,6 +148,22 @@ internal IEnumerable<MultiGeoCompanyAllowedDataLocation> GetAllowedDataLocations
147148
return GetFeed<MultiGeoCompanyAllowedDataLocation>(AllowedDataLocationsPath, AllowedDataLocationsApiVersion);
148149
}
149150

151+
internal void AddAllowedDataLocation(MultiGeoCompanyAllowedDataLocationEntityData allowedDataLocation)
152+
{
153+
if (allowedDataLocation == null)
154+
{
155+
throw new ArgumentNullException(nameof(allowedDataLocation));
156+
}
157+
158+
var apiVersion = GetCurrentApiVersion();
159+
if (!IsSupportedApiVersion(apiVersion, AllowedDataLocationsApiVersion))
160+
{
161+
throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, CommandResources.CrossGeoInvalidVersion, typeof(MultiGeoRestApiClient).Assembly.GetName().Version));
162+
}
163+
164+
PostWithoutResponse(AllowedDataLocationsPath, allowedDataLocation, apiVersion);
165+
}
166+
150167
internal UserAndContentMoveState GetUserAndContentMoveState(string userPrincipalName)
151168
{
152169
var apiVersion = GetCurrentApiVersion(UserMoveJobsMinimumApiVersion);
@@ -311,6 +328,12 @@ private T Post<T>(string path, object payload, TimeSpan? timeout = null, string
311328
return DeserializeResponse<T>(responseText);
312329
}
313330

331+
private void PostWithoutResponse(string path, object payload, string apiVersion)
332+
{
333+
var jsonPayload = payload == null ? null : JsonSerializer.Serialize(payload, SerializerOptions);
334+
Send(() => CreateRequest(HttpMethod.Post, path, apiVersion, jsonPayload), timeout: null, allowRetries: false);
335+
}
336+
314337
private void PostWithEmptyBody(string path, string apiVersion)
315338
{
316339
Send(() => CreateRequest(HttpMethod.Post, path, apiVersion, string.Empty), timeout: null, allowRetries: false);

0 commit comments

Comments
 (0)