Skip to content
This repository was archived by the owner on Jan 19, 2021. It is now read-only.

Commit 7318423

Browse files
Merge pull request #2957 from pnp/dev
October 2020 Release
2 parents f9c1596 + 1adf0eb commit 7318423

37 files changed

+925
-100
lines changed
Binary file not shown.
Binary file not shown.

CHANGELOG.md

+31
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
55

66
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
77

8+
## [3.26.2010.0 - unreleased]
9+
10+
### Added
11+
- Added `Set-PnPTenant -EnableAutoNewsDigest` option to disable the automatic news digest mails sent to end users [PR #2901](https://github.com/pnp/PnP-PowerShell/pull/2901)
12+
- Added `Register-PnPManagementShellAccess` cmdlet to register correct access required for the multi-tenant application PnP Management Shell which is used behind the scenes of the Provisioning Engine for certain actions towards SharePoint Online.
13+
- Added the description being shown of a Site Script when running `Get-PnPSiteScript` [PR #2895](https://github.com/pnp/PnP-PowerShell/pull/2895)
14+
- Added -Includes to `Get-PnPUser` [PR #2939](https://github.com/pnp/PnP-PowerShell/pull/2939)
15+
- Added an sample for Azure Automation [PR #2835](https://github.com/pnp/PnP-PowerShell/pull/2835)
16+
- Added -DisableCustomAppAuthentication to `Set-PnPTenant` [PR #2923](https://github.com/pnp/PnP-PowerShell/pull/2923)
17+
18+
### Changed
19+
- Fixed example for `Get-PnPTeamsChannel` [PR #2919](https://github.com/pnp/PnP-PowerShell/pull/2919)
20+
- Fixed possible token acquisition issue when extracting a tenant template. [PR #2874](https://github.com/pnp/PnP-PowerShell/pull/2874)
21+
- Fixed scenario when no configuration file provided with Get-PnPTenantTemplate throws an undefined error [PR #2873](https://github.com/pnp/PnP-PowerShell/pull/2873)
22+
- Fixed examples for `New-PnPTeamsTeam` [PR #2870](https://github.com/pnp/PnP-PowerShell/pull/2870)
23+
- Updated documentation for `Get-PnPField` [PR #2856](https://github.com/pnp/PnP-PowerShell/pull/2856)
24+
- Updated documentation for `Get-PnPListItem` [PR #2806](https://github.com/pnp/PnP-PowerShell/pull/2806)
25+
- Improved certificate file handling and errors shown if the file does not exist, is empty or points to a folder [PR #2888](https://github.com/pnp/PnP-PowerShell/pull/2888)
26+
- Fixed issue with where connecting with Connect-PnPOnline to an URL ending on a slash could cause an exception when using some cmdlets.
27+
28+
### Contributors
29+
- Koen Zomers [koenzomers]
30+
- Gautam Sheth [gautamdsheth]
31+
- Giacomo Pozzoni [jackpoz]
32+
- James May [fowl2]
33+
- Aimery Thomas [a1mery]
34+
- Heinrich Ulbricht [heinrich-ulbricht]
35+
- Veronique Lengelle [veronicageek]
36+
- Todd Klindt [ToddKlindt]
37+
- Paul Bullock [pkbullock]
38+
839
## [3.25.2009.1]
940

1041
### Changed

Commands/Admin/GetStorageEntity.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace PnP.PowerShell.Commands
1313
{
14-
[Cmdlet(VerbsCommon.Get, "PnPStorageEntity", SupportsShouldProcess = true)]
14+
[Cmdlet(VerbsCommon.Get, "PnPStorageEntity")]
1515
[CmdletHelp(@"Retrieve Storage Entities / Farm Properties from either the Tenant App Catalog or from the current site if it has a site scope app catalog.",
1616
Category = CmdletHelpCategory.TenantAdmin,
1717
SupportedPlatform = CmdletSupportedPlatform.Online)]

Commands/Admin/GetTenantAppCatalogUrl.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace PnP.PowerShell.Commands
77
{
8-
[Cmdlet(VerbsCommon.Get, "PnPTenantAppCatalogUrl", SupportsShouldProcess = true)]
8+
[Cmdlet(VerbsCommon.Get, "PnPTenantAppCatalogUrl")]
99
[CmdletHelp(@"Retrieves the url of the tenant scoped app catalog",
1010
Category = CmdletHelpCategory.TenantAdmin,
1111
SupportedPlatform = CmdletSupportedPlatform.Online)]

Commands/Admin/GetTenantSite.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace PnP.PowerShell.Commands
1313
{
14-
[Cmdlet(VerbsCommon.Get, "PnPTenantSite", SupportsShouldProcess = true)]
14+
[Cmdlet(VerbsCommon.Get, "PnPTenantSite")]
1515
[CmdletHelp(@"Retrieve site information.", "Use this cmdlet to retrieve site information from your tenant administration.",
1616
Category = CmdletHelpCategory.TenantAdmin,
1717
SupportedPlatform = CmdletSupportedPlatform.SP2016 | CmdletSupportedPlatform.SP2019 | CmdletSupportedPlatform.Online,

Commands/Admin/SetTenant.cs

+16
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,12 @@ The only two characters that can be managed at this time are the # and % charact
405405

406406
[Parameter(Mandatory = false, HelpMessage = "Boolean indicating if Azure Information Protection (AIP) should be enabled on the tenant. For more information, see https://docs.microsoft.com/microsoft-365/compliance/sensitivity-labels-sharepoint-onedrive-files#use-powershell-to-enable-support-for-sensitivity-labels")]
407407
public bool? EnableAIPIntegration;
408+
409+
[Parameter(Mandatory = false)]
410+
public bool? DisableCustomAppAuthentication;
411+
412+
[Parameter(Mandatory = false, HelpMessage = "Boolean indicating if a news digest should automatically be sent to end users to inform them about news that they may have missed. On by default. For more information, see https://aka.ms/autonewsdigest")]
413+
public bool? EnableAutoNewsDigest;
408414

409415
protected override void ExecuteCmdlet()
410416
{
@@ -972,6 +978,16 @@ protected override void ExecuteCmdlet()
972978
Tenant.EnableAIPIntegration = EnableAIPIntegration.Value;
973979
isDirty = true;
974980
}
981+
if (DisableCustomAppAuthentication.HasValue)
982+
{
983+
Tenant.DisableCustomAppAuthentication = DisableCustomAppAuthentication.Value;
984+
isDirty = true;
985+
}
986+
if (EnableAutoNewsDigest.HasValue)
987+
{
988+
Tenant.EnableAutoNewsDigest = EnableAutoNewsDigest.Value;
989+
isDirty = true;
990+
}
975991
if (isDirty)
976992
{
977993
ClientContext.ExecuteQueryRetry();

Commands/Admin/SetTenantSyncClientRestriction.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class SetTenantSyncClientRestriction : PnPAdminCmdlet
4141
[Parameter(Mandatory = false, HelpMessage = @"Blocks certain file types from syncing with the new sync client (OneDrive.exe). Provide as one string separating the extensions using a semicolon (;). I.e. ""docx;pptx""")]
4242
public List<string> ExcludedFileExtensions;
4343

44-
[Parameter(Mandatory = false, HelpMessage = "Controls whether or not a tenant's users can sync OneDrive for Business libraries with the old OneDrive for Business sync client. The valid values are OptOut, HardOptin, and SoftOptin.")]
44+
[Parameter(Mandatory = false, HelpMessage = "Controls whether or not a tenant's users can sync OneDrive for Business libraries with the old OneDrive for Business sync client. The valid values are OptOut, HardOptin, and SoftOptin. GrooveBlockOption is planned to be deprecated. Please refrain from using the parameter.")]
4545
public Enums.GrooveBlockOption GrooveBlockOption;
4646

4747
protected override void ExecuteCmdlet()
@@ -90,4 +90,4 @@ protected override void ExecuteCmdlet()
9090
}
9191
}
9292
}
93-
#endif
93+
#endif

Commands/Base/ConnectOnline.cs

+5
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,11 @@ protected override void ProcessRecord()
651651
/// </summary>
652652
protected void Connect()
653653
{
654+
if (!string.IsNullOrEmpty(Url) && Url.EndsWith("/"))
655+
{
656+
Url = Url.Substring(0, Url.Length - 1);
657+
}
658+
654659
PnPConnection connection = null;
655660

656661
var latestVersion = PnPConnectionHelper.GetLatestVersion();

Commands/Base/InitializePowerShellAuthentication.cs

+3-11
Original file line numberDiff line numberDiff line change
@@ -250,24 +250,16 @@ protected override void ProcessRecord()
250250
record.Properties.Add(new PSVariableProperty(new PSVariable("AzureAppId", azureApp.AppId)));
251251

252252
var waitTime = 60;
253-
Host.UI.Write(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, $"Waiting {waitTime} seconds to launch consent flow in a browser window. This wait is required to make sure that Azure AD is able to initialize all required artifacts.");
254-
255-
Console.TreatControlCAsInput = true;
253+
Host.UI.Write(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, $"Waiting {waitTime} seconds to start the consent flow in a browser window. This wait is required to make sure that Azure AD is able to initialize all required artifacts.");
256254

257255
for (var i = 0; i < waitTime; i++)
258256
{
259257
Host.UI.Write(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, ".");
260258
System.Threading.Thread.Sleep(1000);
261259

262-
// Check if CTRL+C has been pressed and if so, abort the wait
263-
if (Host.UI.RawUI.KeyAvailable)
260+
if (Stopping)
264261
{
265-
var key = Host.UI.RawUI.ReadKey(ReadKeyOptions.AllowCtrlC | ReadKeyOptions.NoEcho | ReadKeyOptions.IncludeKeyUp);
266-
if ((key.ControlKeyState.HasFlag(ControlKeyStates.LeftCtrlPressed) || key.ControlKeyState.HasFlag(ControlKeyStates.RightCtrlPressed)) && key.VirtualKeyCode == 67)
267-
{
268-
269-
break;
270-
}
262+
break;
271263
}
272264
}
273265
Host.UI.WriteLine();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Microsoft.Identity.Client;
2+
using OfficeDevPnP.Core;
3+
using PnP.PowerShell.CmdletHelpAttributes;
4+
using PnP.PowerShell.Commands.Model;
5+
using System;
6+
using System.Management.Automation;
7+
8+
namespace PnP.PowerShell.Commands.Base
9+
{
10+
[Cmdlet(VerbsLifecycle.Register, "PnPManagementShellAccess")]
11+
[CmdletHelp("Registers the multi-tenant app PnP Management Shell for delegate access to the required environments",
12+
Category = CmdletHelpCategory.TenantAdmin)]
13+
[CmdletExample(
14+
Code = "PS:> Register-PnPManagementShellAccess -SiteUrl https://yourtenant.sharepoint.com",
15+
Remarks = "Will prompt you to authenticate and if needed will ask you to provide consent to specific required rights.",
16+
SortOrder = 1)]
17+
public class RegisterPnPManagementShellAccess : PSCmdlet
18+
{
19+
[Parameter(Mandatory = false)]
20+
public AzureEnvironment AzureEnvironment = AzureEnvironment.Production;
21+
22+
[Parameter(Mandatory = true)]
23+
public string SiteUrl;
24+
protected override void ProcessRecord()
25+
{
26+
var endPoint = GenericToken.GetAzureADLoginEndPoint(AzureEnvironment);
27+
var uri = new Uri(SiteUrl);
28+
var scopes = new[] { $"{uri.Scheme}://{uri.Authority}//.default" };
29+
30+
var application = PublicClientApplicationBuilder.Create(PnPConnection.PnPManagementShellClientId).WithAuthority($"{endPoint}/organizations/").WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient").Build();
31+
32+
var result = application.AcquireTokenInteractive(scopes).ExecuteAsync().GetAwaiter().GetResult();
33+
result = application.AcquireTokenInteractive(new[] { "https://graph.microsoft.com/.default" }).ExecuteAsync().GetAwaiter().GetResult();
34+
35+
}
36+
}
37+
}

Commands/Base/TokenHandling.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ internal static string AcquireToken(string resource, string scope = null)
2121
if (scope == null)
2222
{
2323
// SharePoint or Graph V1 resource
24-
var scopes = new[] { $"https://{resource}//.default" };
24+
var scopes = new[] { $"https://{resource.Replace("https://","").TrimEnd('/')}/.default" };
2525
token = GenericToken.AcquireDelegatedTokenWithCredentials(PnPConnection.PnPManagementShellClientId, scopes, "https://login.microsoftonline.com/organizations/", PnPConnection.CurrentConnection.PSCredential.UserName, PnPConnection.CurrentConnection.PSCredential.Password);
2626
}
2727
else

Commands/Fields/AddField.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace PnP.PowerShell.Commands.Fields
1010
{
1111
[Cmdlet(VerbsCommon.Add, "PnPField", DefaultParameterSetName = "Add field to list")]
1212
[CmdletHelp("Add a field",
13-
"Adds a field to a list or as a site column",
13+
"Adds a field (a column) to a list or as a site column. To add a column of type Managed Metadata use the Add-PnPTaxonomyField cmdlet",
1414
Category = CmdletHelpCategory.Fields,
1515
OutputType = typeof(Field),
1616
OutputTypeLink = "https://docs.microsoft.com/en-us/previous-versions/office/sharepoint-server/ee545882(v=office.15)",

Commands/Lists/GetListItem.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace PnP.PowerShell.Commands.Lists
4343
Remarks = "Retrieves all list items from the Tasks list in pages of 1000 items",
4444
SortOrder = 7)]
4545
[CmdletExample(
46-
Code = "PS:> Get-PnPListItem -List Tasks -PageSize 1000 -ScriptBlock { Param($items) $items.Context.ExecuteQuery() } | % { $_.BreakRoleInheritance($true, $true) }",
46+
Code = "PS:> Get-PnPListItem -List Tasks -PageSize 1000 -ScriptBlock { Param($items) $items.Context.ExecuteQuery() } | ForEach-Object { $_.BreakRoleInheritance($true, $true) }",
4747
Remarks = "Retrieves all list items from the Tasks list in pages of 1000 items and breaks permission inheritance on each item",
4848
SortOrder = 8)]
4949
[CmdletExample(

Commands/Model/GenericToken.cs

+75-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
using System.Threading.Tasks;
1212
using System.Security;
1313
using OfficeDevPnP.Core;
14+
using System.Management.Automation;
15+
using PnP.PowerShell.Commands.Base;
1416

1517
namespace PnP.PowerShell.Commands.Model
1618
{
@@ -181,11 +183,28 @@ public static GenericToken AcquireApplicationToken(string tenant, string clientI
181183

182184
try
183185
{
184-
tokenResult = confidentialClientApplication.AcquireTokenSilent(scopes, account.First()).ExecuteAsync().GetAwaiter().GetResult();
186+
tokenResult = confidentialClientApplication.AcquireTokenSilent(scopes, account.First()).WithForceRefresh(true).ExecuteAsync().GetAwaiter().GetResult();
185187
}
186188
catch
187189
{
188-
tokenResult = confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync().GetAwaiter().GetResult();
190+
try
191+
{
192+
tokenResult = confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync().GetAwaiter().GetResult();
193+
}
194+
catch (MsalUiRequiredException msalEx)
195+
{
196+
if (msalEx.Classification == UiRequiredExceptionClassification.ConsentRequired)
197+
{
198+
if (clientId == PnPConnection.PnPManagementShellClientId)
199+
{
200+
throw new PSInvalidOperationException("Please provide consent to the PnP Management Shell application with 'Register-PnPManagementShellAccess' and follow the steps on screen.");
201+
}
202+
else
203+
{
204+
throw msalEx;
205+
}
206+
}
207+
}
189208
}
190209

191210
return new GenericToken(tokenResult.AccessToken);
@@ -228,7 +247,24 @@ public static GenericToken AcquireApplicationToken(string tenant, string clientI
228247
}
229248
catch
230249
{
231-
tokenResult = confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync().GetAwaiter().GetResult();
250+
try
251+
{
252+
tokenResult = confidentialClientApplication.AcquireTokenForClient(scopes).ExecuteAsync().GetAwaiter().GetResult();
253+
}
254+
catch (MsalUiRequiredException msalEx)
255+
{
256+
if (msalEx.Classification == UiRequiredExceptionClassification.ConsentRequired)
257+
{
258+
if (clientId == PnPConnection.PnPManagementShellClientId)
259+
{
260+
throw new PSInvalidOperationException("Please provide consent to the PnP Management Shell application with 'Register-PnPManagementShellAccess' and follow the steps on screen.");
261+
}
262+
else
263+
{
264+
throw msalEx;
265+
}
266+
}
267+
}
232268
}
233269
return new GenericToken(tokenResult.AccessToken);
234270
}
@@ -267,7 +303,24 @@ public static GenericToken AcquireApplicationTokenInteractive(string clientId, s
267303
}
268304
catch
269305
{
270-
tokenResult = publicClientApplication.AcquireTokenInteractive(scopes).ExecuteAsync().GetAwaiter().GetResult();
306+
try
307+
{
308+
tokenResult = publicClientApplication.AcquireTokenInteractive(scopes).WithExtraScopesToConsent(new[] { "https://graph.microsoft.com/.default" }).ExecuteAsync().GetAwaiter().GetResult();
309+
}
310+
catch (MsalUiRequiredException msalEx)
311+
{
312+
if (msalEx.Classification == UiRequiredExceptionClassification.ConsentRequired)
313+
{
314+
if (clientId == PnPConnection.PnPManagementShellClientId)
315+
{
316+
throw new PSInvalidOperationException("Please provide consent to the PnP Management Shell application with 'Register-PnPManagementShellAccess' and follow the steps on screen.");
317+
}
318+
else
319+
{
320+
throw msalEx;
321+
}
322+
}
323+
}
271324
}
272325
return new GenericToken(tokenResult.AccessToken);
273326
}
@@ -351,7 +404,24 @@ public static GenericToken AcquireDelegatedTokenWithCredentials(string clientId,
351404
}
352405
catch
353406
{
354-
tokenResult = publicClientApplication.AcquireTokenByUsernamePassword(scopes, username, securePassword).ExecuteAsync().GetAwaiter().GetResult();
407+
try
408+
{
409+
tokenResult = publicClientApplication.AcquireTokenByUsernamePassword(scopes, username, securePassword).ExecuteAsync().GetAwaiter().GetResult();
410+
}
411+
catch (MsalUiRequiredException msalEx)
412+
{
413+
if (msalEx.Classification == UiRequiredExceptionClassification.ConsentRequired)
414+
{
415+
if (clientId == PnPConnection.PnPManagementShellClientId)
416+
{
417+
throw new PSInvalidOperationException("Please provide consent to the PnP Management Shell application with 'Register-PnPManagementShellAccess' and follow the steps on screen.");
418+
}
419+
else
420+
{
421+
throw msalEx;
422+
}
423+
}
424+
}
355425
}
356426

357427
return new GenericToken(tokenResult.AccessToken);

Commands/Model/GraphToken.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using PnP.PowerShell.Commands.Utilities;
66
using System;
77
using System.Linq;
8+
using System.Management.Automation;
89
using System.Security;
910
using System.Security.Cryptography.X509Certificates;
1011

@@ -39,7 +40,7 @@ public GraphToken(string accesstoken) : base(accesstoken)
3940
public static GraphToken AcquireApplicationToken(string tenant, string clientId, X509Certificate2 certificate, AzureEnvironment azureEnvironment)
4041
{
4142
var endPoint = GenericToken.GetAzureADLoginEndPoint(azureEnvironment);
42-
return new GraphToken(GenericToken.AcquireApplicationToken(tenant, clientId, $"{endPoint}/{tenant}", new[] { $"{ResourceIdentifier}/{DefaultScope}" }, certificate).AccessToken);
43+
return new GraphToken(GenericToken.AcquireApplicationToken(tenant, clientId, $"{endPoint}/{tenant}", new[] { $"{ResourceIdentifier}/{DefaultScope}" }, certificate).AccessToken);
4344
}
4445

4546
/// <summary>

Commands/Model/SPOTenant.cs

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public SPOTenant(Tenant tenant)
3737
this.provisionSharedWithEveryoneFolder = tenant.ProvisionSharedWithEveryoneFolder;
3838
this.signInAccelerationDomain = tenant.SignInAccelerationDomain;
3939
this.disabledWebPartIds = tenant.DisabledWebPartIds;
40+
4041
try
4142
{
4243
this.enableGuestSignInAcceleration = tenant.EnableGuestSignInAcceleration;
@@ -471,6 +472,8 @@ public SPOTenant(Tenant tenant)
471472

472473
public Guid[] DisabledWebPartIds => disabledWebPartIds;
473474

475+
public bool DisableCustomAppAuthentication => disableCustomAppAuthentication;
476+
474477
private bool hideDefaultThemes;
475478

476479
private long storageQuota;
@@ -600,6 +603,8 @@ public SPOTenant(Tenant tenant)
600603
private int emailAttestationReAuthDays;
601604

602605
private Guid[] disabledWebPartIds;
606+
607+
private bool disableCustomAppAuthentication;
603608
}
604609
}
605610
#endif

0 commit comments

Comments
 (0)