Skip to content

Commit 8658f97

Browse files
authored
Merge pull request #1606 from gautamdsheth/feature/603
Feature #603 - added cmdlet to rename site URL
2 parents 993ac52 + 36bea2d commit 8658f97

File tree

4 files changed

+384
-0
lines changed

4 files changed

+384
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
2424
- Added `Publish\Unpublish-PnPContentType` to allow for content types to be published or unpublished on hub sites [#1597](https://github.com/pnp/powershell/pull/1597)
2525
- Added `Get-PnPContentTypePublishingStatus` to get te current publication state of a content type in the content type hub site [#1597](https://github.com/pnp/powershell/pull/1597)
2626
- Added ability to pipe the output of `Get-PnPTenantDeletedSite` to either `Restore-PnPTenantDeletedSite` or `Remove-PnPTenantDeletedSite` [#1596](https://github.com/pnp/powershell/pull/1596)
27+
- Added `Rename-PnPTenantSite` to rename a SharePoint Online site URL [#1606](https://github.com/pnp/powershell/pull/1606)
2728

2829
### Changed
2930

documentation/Rename-PnPTenantSite.md

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
---
2+
Module Name: PnP.PowerShell
3+
title: Rename-PnPTenantSite
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/Rename-PnPTenantSite.html
8+
---
9+
10+
# Rename-PnPTenantSite
11+
12+
## SYNOPSIS
13+
This command starts a rename of a site on a SharePoint Online site. You can change the URL, and optionally the site title along with changing the URL.
14+
15+
This will not work for Multi-geo environments.
16+
17+
## SYNTAX
18+
19+
```powershell
20+
Rename-PnPTenantSite [[-Identity] <SPOSitePipeBind>] [[-NewSiteUrl] <String>] [[-NewSiteTitle] <string>]
21+
[[-SuppressMarketplaceAppCheck] [<SwitchParameter>]] [[-SuppressWorkflow2013Check] [<SwitchParameter>]] [-Connection <PnPConnection>] [<CommonParameters>]
22+
```
23+
24+
## DESCRIPTION
25+
26+
## EXAMPLES
27+
28+
### EXAMPLE 1
29+
```powershell
30+
$currentSiteUrl = "https://<tenant>.sharepoint.com/site/samplesite"
31+
$updatedSiteUrl = "https://<tenant>.sharepoint.com/site/renamed"
32+
Rename-PnPTenantSite -Identity $currentSiteUrl -NewSiteUrl $updatedSiteUrl
33+
```
34+
35+
Starts the rename of the SharePoint Online site with name "samplesite" to "renamed" without modifying the title.
36+
37+
## PARAMETERS
38+
39+
### -Connection
40+
Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing Get-PnPConnection.
41+
42+
```yaml
43+
Type: PnPConnection
44+
Parameter Sets: (All)
45+
46+
Required: False
47+
Position: Named
48+
Default value: None
49+
Accept pipeline input: False
50+
Accept wildcard characters: False
51+
```
52+
53+
### -Identity
54+
Specifies the full URL of the SharePoint Online site collection that needs to be renamed.
55+
56+
```yaml
57+
Type: SPOSitePipeBind
58+
Parameter Sets: (All)
59+
60+
Required: False
61+
Position: Named
62+
Default value: None
63+
Accept pipeline input: True
64+
Accept wildcard characters: False
65+
```
66+
67+
### -NewSiteUrl
68+
Specifies the full URL of the SharePoint Online site collection to which it needs to be renamed.
69+
70+
```yaml
71+
Type: String
72+
Parameter Sets: (All)
73+
74+
Required: False
75+
Position: Named
76+
Default value: None
77+
Accept pipeline input: False
78+
Accept wildcard characters: False
79+
```
80+
81+
### -NewSiteTitle
82+
Specifies the new title of of the SharePoint Site.
83+
84+
```yaml
85+
Type: String
86+
Parameter Sets: (All)
87+
88+
Required: False
89+
Position: Named
90+
Default value: None
91+
Accept pipeline input: False
92+
Accept wildcard characters: False
93+
```
94+
95+
### -SuppressMarketplaceAppCheck
96+
Suppress checking compatibility of marketplace SharePoint Add-ins deployed to the associated site.
97+
98+
```yaml
99+
Type: SwitchParameter
100+
Parameter Sets: (All)
101+
102+
Required: False
103+
Position: Named
104+
Default value: None
105+
Accept pipeline input: False
106+
Accept wildcard characters: False
107+
```
108+
109+
### -SuppressWorkflow2013Check
110+
Suppress checking compatibility of SharePoint 2013 Workflows deployed to the associated site.
111+
112+
```yaml
113+
Type: SwitchParameter
114+
Parameter Sets: (All)
115+
116+
Required: False
117+
Position: Named
118+
Default value: None
119+
Accept pipeline input: False
120+
Accept wildcard characters: False
121+
```
122+
123+
### -SuppressBcsCheck
124+
Suppress checking compatibility of BCS connections deployed to the associated site.
125+
126+
```yaml
127+
Type: SwitchParameter
128+
Parameter Sets: (All)
129+
130+
Required: False
131+
Position: Named
132+
Default value: None
133+
Accept pipeline input: True
134+
Accept wildcard characters: False
135+
```
136+
137+
### -Wait
138+
Wait till the renaming of the new site collection is successfull. If not specified, a job will be created which you can use to check for its status.
139+
140+
```yaml
141+
Type: SwitchParameter
142+
Parameter Sets: (All)
143+
144+
Required: False
145+
Position: Named
146+
Default value: None
147+
Accept pipeline input: False
148+
Accept wildcard characters: False
149+
```
150+
151+
## RELATED LINKS
152+
153+
[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
using Microsoft.SharePoint.Client;
2+
using PnP.Framework.Http;
3+
using PnP.PowerShell.Commands.Base;
4+
using PnP.PowerShell.Commands.Base.PipeBinds;
5+
using PnP.PowerShell.Commands.Model;
6+
using PnP.PowerShell.Commands.Utilities;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Management.Automation;
10+
using System.Net.Http;
11+
using System.Text.Json;
12+
using System.Threading.Tasks;
13+
14+
namespace PnP.PowerShell.Commands.Admin
15+
{
16+
[Cmdlet(VerbsCommon.Rename, "PnPTenantSite")]
17+
public class RenameTenantSite : PnPAdminCmdlet
18+
{
19+
[Parameter(Mandatory = true)]
20+
[ValidateNotNullOrEmpty]
21+
public SPOSitePipeBind Identity { get; set; }
22+
23+
[Parameter(Mandatory = true)]
24+
[ValidateNotNullOrEmpty]
25+
public string NewSiteUrl { get; set; }
26+
27+
[Parameter(Mandatory = false)]
28+
[ValidateNotNullOrEmpty]
29+
public string NewSiteTitle { get; set; }
30+
31+
[Parameter(Mandatory = false)]
32+
public SwitchParameter SuppressMarketplaceAppCheck { get; set; }
33+
34+
[Parameter(Mandatory = false)]
35+
public SwitchParameter SuppressWorkflow2013Check { get; set; }
36+
37+
[Parameter(Mandatory = false)]
38+
public SwitchParameter SuppressBcsCheck { get; set; }
39+
40+
[Parameter(Mandatory = false)]
41+
public SwitchParameter Wait { get; set; }
42+
43+
protected override void ExecuteCmdlet()
44+
{
45+
ClientContext.ExecuteQueryRetry(); // fixes issue where ServerLibraryVersion is not available.
46+
47+
int optionsBitMask = 0;
48+
if (SuppressMarketplaceAppCheck.IsPresent)
49+
{
50+
optionsBitMask |= 8;
51+
}
52+
if (SuppressWorkflow2013Check.IsPresent)
53+
{
54+
optionsBitMask |= 16;
55+
}
56+
if (SuppressBcsCheck.IsPresent)
57+
{
58+
optionsBitMask |= 128;
59+
}
60+
61+
var body = new
62+
{
63+
SourceSiteUrl = Identity.Url,
64+
TargetSiteUrl = NewSiteUrl,
65+
TargetSiteTitle = NewSiteTitle ?? null,
66+
Option = optionsBitMask,
67+
Reserve = string.Empty,
68+
OperationId = Guid.Empty
69+
};
70+
71+
var tenantUrl = UrlUtilities.GetTenantAdministrationUrl(ClientContext.Url);
72+
73+
var results = Utilities.REST.RestHelper.PostAsync<SPOSiteRenameJob>(HttpClient, $"{tenantUrl.TrimEnd('/')}/_api/SiteRenameJobs?api-version=1.4.7", ClientContext, body, false).GetAwaiter().GetResult();
74+
if (!Wait.IsPresent)
75+
{
76+
if (results != null)
77+
{
78+
WriteObject(results);
79+
}
80+
}
81+
else
82+
{
83+
bool wait = true;
84+
var iterations = 0;
85+
86+
var method = new HttpMethod("GET");
87+
88+
var httpClient = PnPHttpClient.Instance.GetHttpClient(ClientContext);
89+
90+
var requestUrl = $"{tenantUrl.TrimEnd('/')}/_api/SiteRenameJobs/GetJobsBySiteUrl(url='{Identity.Url}')?api-version=1.4.7";
91+
92+
while (wait)
93+
{
94+
iterations++;
95+
try
96+
{
97+
using (HttpRequestMessage request = new HttpRequestMessage(method, requestUrl))
98+
{
99+
request.Headers.Add("accept", "application/json;odata=nometadata");
100+
request.Headers.Add("X-AttemptNumber", iterations.ToString());
101+
PnPHttpClient.AuthenticateRequestAsync(request, ClientContext).GetAwaiter().GetResult();
102+
103+
HttpResponseMessage response = httpClient.SendAsync(request, new System.Threading.CancellationToken()).Result;
104+
105+
if (response.IsSuccessStatusCode)
106+
{
107+
var responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
108+
if (responseString != null)
109+
{
110+
var jsonElement = JsonSerializer.Deserialize<JsonElement>(responseString);
111+
112+
if (jsonElement.TryGetProperty("value", out JsonElement valueProperty))
113+
{
114+
var siteRenameResults = JsonSerializer.Deserialize<List<SPOSiteRenameJob>>(valueProperty.ToString());
115+
116+
if (siteRenameResults != null && siteRenameResults.Count > 0)
117+
{
118+
var siteRenameResponse = siteRenameResults[0];
119+
if (!string.IsNullOrEmpty(siteRenameResponse.ErrorDescription))
120+
{
121+
wait = false;
122+
throw new PSInvalidOperationException(siteRenameResponse.ErrorDescription);
123+
}
124+
if (siteRenameResponse.JobState == "Success")
125+
{
126+
wait = false;
127+
WriteObject(siteRenameResponse);
128+
}
129+
else
130+
{
131+
Task.Delay(TimeSpan.FromSeconds(30)).GetAwaiter().GetResult();
132+
}
133+
}
134+
}
135+
}
136+
}
137+
}
138+
}
139+
catch (Exception)
140+
{
141+
if (iterations * 30 >= 300)
142+
{
143+
wait = false;
144+
throw;
145+
}
146+
else
147+
{
148+
Task.Delay(TimeSpan.FromSeconds(30)).GetAwaiter().GetResult();
149+
}
150+
}
151+
}
152+
}
153+
}
154+
}
155+
}

src/Commands/Model/SPOSiteRename.cs

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System;
2+
3+
namespace PnP.PowerShell.Commands.Model
4+
{
5+
/// <summary>
6+
/// Contains information about an ongoing SharePoint Online site collection rename
7+
/// </summary>
8+
public class SPOSiteRenameJob
9+
{
10+
/// <summary>
11+
/// State the rename process is in
12+
/// </summary>
13+
public string JobState { get; set; }
14+
15+
/// <summary>
16+
/// Id of the site that is being renamed
17+
/// </summary>
18+
public Guid? SiteId { get; set; }
19+
20+
/// <summary>
21+
/// Unique identifier of the rename job
22+
/// </summary>
23+
public Guid? JobId { get; set; }
24+
25+
/// <summary>
26+
/// Unknown
27+
/// </summary>
28+
public Guid? ParentId { get; set; }
29+
30+
/// <summary>
31+
/// Person or process having initiated the rename
32+
/// </summary>
33+
public string TriggeredBy { get; set; }
34+
35+
/// <summary>
36+
/// Error code, if any
37+
/// </summary>
38+
public int? ErrorCode { get; set; }
39+
40+
/// <summary>
41+
/// Error description, if any
42+
/// </summary>
43+
public string ErrorDescription { get; set; }
44+
45+
/// <summary>
46+
/// Url of the site collection before the rename
47+
/// </summary>
48+
public string SourceSiteUrl { get; set; }
49+
50+
/// <summary>
51+
/// Url of the site collection after the rename
52+
/// </summary>
53+
public string TargetSiteUrl { get; set; }
54+
55+
/// <summary>
56+
/// Unknown
57+
/// </summary>
58+
public object TargetSiteTitle { get; set; }
59+
60+
/// <summary>
61+
/// Unknown
62+
/// </summary>
63+
public int? Option { get; set; }
64+
65+
/// <summary>
66+
/// Unknown
67+
/// </summary>
68+
public object Reserve { get; set; }
69+
70+
/// <summary>
71+
/// Unknown
72+
/// </summary>
73+
public object SkipGestures { get; set; }
74+
}
75+
}

0 commit comments

Comments
 (0)