From 38a30051798f5d1452c479a630c146c148b64375 Mon Sep 17 00:00:00 2001 From: reusto <1266516+reusto@users.noreply.github.com> Date: Tue, 14 Feb 2023 20:28:14 +0100 Subject: [PATCH 1/2] Add conection parameter to Connect-PnPOnline to reuse specific connections. --- documentation/Connect-PnPOnline.md | 28 ++++++-- src/Commands/Base/ConnectOnline.cs | 106 ++++++++++++++++------------- 2 files changed, 79 insertions(+), 55 deletions(-) diff --git a/documentation/Connect-PnPOnline.md b/documentation/Connect-PnPOnline.md index c89168aef..6d6a26f85 100644 --- a/documentation/Connect-PnPOnline.md +++ b/documentation/Connect-PnPOnline.md @@ -19,14 +19,14 @@ Connect to a SharePoint site Connect-PnPOnline [-ReturnConnection] [-Url] [-Credentials ] [-CurrentCredentials] [-CreateDrive] [-DriveName ] [-ClientId ] [-RedirectUri ] [-AzureEnvironment ] [-TenantAdminUrl ] - [-TransformationOnPrem] [-ValidateConnection] + [-TransformationOnPrem] [-ValidateConnection] [-Connection ] ``` ### SharePoint ACS (Legacy) App Only ``` Connect-PnPOnline [-ReturnConnection] [-Url] [-Realm ] -ClientSecret [-CreateDrive] [-DriveName ] -ClientId [-AzureEnvironment ] [-TenantAdminUrl ] - [-ValidateConnection] + [-ValidateConnection] [-Connection ] ``` ### App-Only with Azure Active Directory @@ -34,21 +34,21 @@ Connect-PnPOnline [-ReturnConnection] [-Url] [-Realm ] -ClientS Connect-PnPOnline [-ReturnConnection] [-Url] [-CreateDrive] [-DriveName ] -ClientId -Tenant [-CertificatePath ] [-CertificateBase64Encoded ] [-CertificatePassword ] [-AzureEnvironment ] [-TenantAdminUrl ] - [-ValidateConnection] + [-ValidateConnection] [-Connection ] ``` ### App-Only with Azure Active Directory using a certificate from the Windows Certificate Management Store by thumbprint ``` Connect-PnPOnline [-ReturnConnection] [-Url] [-CreateDrive] [-DriveName ] -ClientId -Tenant -Thumbprint [-AzureEnvironment ] [-TenantAdminUrl ] - [-ValidateConnection] + [-ValidateConnection] [-Connection ] ``` ### PnP Management Shell / DeviceLogin ``` Connect-PnPOnline [-ReturnConnection] [-Url] [-CreateDrive] [-DriveName ] [-DeviceLogin] [-LaunchBrowser] [-ClientId ] [-AzureEnvironment ] - [-ValidateConnection] + [-ValidateConnection] [-Connection ] ``` ### Web Login for Multi Factor Authentication @@ -61,7 +61,7 @@ Connect-PnPOnline [-ReturnConnection] [-Url] [-CreateDrive] [-DriveName ### Interactive for Multi Factor Authentication ``` Connect-PnPOnline -Interactive [-ReturnConnection] -Url [-CreateDrive] [-DriveName ] [-LaunchBrowser] - [-ClientId ] [-AzureEnvironment ] [-TenantAdminUrl ] [-ForceAuthentication] [-ValidateConnection] + [-ClientId ] [-AzureEnvironment ] [-TenantAdminUrl ] [-ForceAuthentication] [-ValidateConnection] [-Connection ] ``` ### On-premises login for page transformation from on-premises SharePoint to SharePoint Online @@ -84,7 +84,7 @@ Connect-PnPOnline -Url [-UserAssignedManagedIdentityObjectId ] Connect-PnPOnline [-ReturnConnection] [-Url] [-EnvironmentVariable] [-CurrentCredentials] [-CreateDrive] [-DriveName ] [-RedirectUri ] [-AzureEnvironment ] [-TenantAdminUrl ] - [-TransformationOnPrem] [-ValidateConnection] + [-TransformationOnPrem] [-ValidateConnection] [-Connection ] ``` ## DESCRIPTION @@ -343,6 +343,20 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Connection +Optional connection to be reused by the new connection. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing Get-PnPConnection. + +```yaml +Type: PnPConnection +Parameter Sets: Credentials, SharePoint ACS (Legacy) App Only, App-Only with Azure Active Directory, App-Only with Azure Active Directory using a certificate from the Windows Certificate Management Store by thumbprint, SPO Management Shell Credentials, PnP Management Shell / DeviceLogin, Interactive login for Multi Factor Authentication, Environment Variable + +Required: False +Position: Named +Default value: PnPConnection.Current +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -CreateDrive If you want to create a PSDrive connected to the URL diff --git a/src/Commands/Base/ConnectOnline.cs b/src/Commands/Base/ConnectOnline.cs index e7a9a470b..ec058f33b 100644 --- a/src/Commands/Base/ConnectOnline.cs +++ b/src/Commands/Base/ConnectOnline.cs @@ -75,6 +75,16 @@ public class ConnectOnline : BasePSCmdlet [Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_ENVIRONMENTVARIABLE, ValueFromPipeline = true)] public string Url; + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_CREDENTIALS)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACSAPPONLY)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCERTIFICATE)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADTHUMBPRINT)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_DEVICELOGIN)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_INTERACTIVE)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ENVIRONMENTVARIABLE)] + public PnPConnection Connection = PnPConnection.Current; + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_CREDENTIALS)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT)] public CredentialPipeBind Credentials; @@ -237,7 +247,7 @@ protected void Connect(ref CancellationToken cancellationToken) } } - PnPConnection connection = null; + PnPConnection newConnection = null; PSCredential credentials = null; if (Credentials != null) @@ -249,42 +259,42 @@ protected void Connect(ref CancellationToken cancellationToken) switch (ParameterSetName) { case ParameterSet_SPOMANAGEMENT: - connection = ConnectSpoManagement(); + newConnection = ConnectSpoManagement(); break; case ParameterSet_DEVICELOGIN: - connection = ConnectDeviceLogin(); + newConnection = ConnectDeviceLogin(); break; case ParameterSet_APPONLYAADCERTIFICATE: - connection = ConnectAppOnlyWithCertificate(); + newConnection = ConnectAppOnlyWithCertificate(); break; case ParameterSet_APPONLYAADTHUMBPRINT: - connection = ConnectAppOnlyWithCertificate(); + newConnection = ConnectAppOnlyWithCertificate(); break; case ParameterSet_ACCESSTOKEN: - connection = ConnectAccessToken(); + newConnection = ConnectAccessToken(); break; case ParameterSet_ACSAPPONLY: - connection = ConnectACSAppOnly(); + newConnection = ConnectACSAppOnly(); break; case ParameterSet_CREDENTIALS: - connection = ConnectCredentials(credentials); + newConnection = ConnectCredentials(credentials); break; case ParameterSet_MANAGEDIDENTITY: - connection = ConnectManagedIdentity(); + newConnection = ConnectManagedIdentity(); break; case ParameterSet_WEBLOGIN: - connection = ConnectWebLogin(); + newConnection = ConnectWebLogin(); break; case ParameterSet_INTERACTIVE: - connection = ConnectInteractive(); + newConnection = ConnectInteractive(); break; case ParameterSet_ENVIRONMENTVARIABLE: - connection = ConnectEnvironmentVariable(); + newConnection = ConnectEnvironmentVariable(); break; } // Ensure a connection instance has been created by now - if (connection == null) + if (newConnection == null) { // No connection instance was created throw new PSInvalidOperationException("Unable to connect using provided arguments"); @@ -293,9 +303,9 @@ protected void Connect(ref CancellationToken cancellationToken) // Connection has been established WriteVerbose($"PnP PowerShell Cmdlets ({new SemanticVersion(Assembly.GetExecutingAssembly().GetName().Version)})"); - if (connection.Url != null) + if (newConnection.Url != null) { - var hostUri = new Uri(connection.Url); + var hostUri = new Uri(newConnection.Url); Environment.SetEnvironmentVariable("PNPPSHOST", hostUri.Host); Environment.SetEnvironmentVariable("PNPPSSITE", hostUri.LocalPath); } @@ -309,11 +319,11 @@ protected void Connect(ref CancellationToken cancellationToken) { // Try requesting the site Id to validate that the site to which is being connected exists WriteVerbose($"Validating if the site at {Url} exists"); - connection.Context.Load(connection.Context.Site, p => p.Id); + newConnection.Context.Load(newConnection.Context.Site, p => p.Id); try { - connection.Context.ExecuteQueryRetry(); + newConnection.Context.ExecuteQueryRetry(); WriteVerbose($"Site at {Url} exists"); } catch (System.Net.WebException e) when (e.Message.Contains("404")) @@ -325,13 +335,13 @@ protected void Connect(ref CancellationToken cancellationToken) if (ReturnConnection) { - WriteObject(connection); + WriteObject(newConnection); } else { - PnPConnection.Current = connection; + PnPConnection.Current = newConnection; } - if (CreateDrive && connection.Context != null) + if (CreateDrive && newConnection.Context != null) { var provider = SessionState.Provider.GetAll().FirstOrDefault(p => p.Name.Equals(SPOProvider.PSProviderName, StringComparison.InvariantCultureIgnoreCase)); if (provider != null) @@ -357,9 +367,9 @@ protected void Connect(ref CancellationToken cancellationToken) private PnPConnection ConnectACSAppOnly() { CmdletMessageWriter.WriteFormattedMessage(this, new CmdletMessageWriter.Message { Text = "Connecting with Client Secret uses legacy authentication and provides limited functionality. We can for instance not execute requests towards the Microsoft Graph, which limits cmdlets related to Microsoft Teams, Microsoft Planner, Microsoft Flow and Microsoft 365 Groups. You can hide this warning by using Connect-PnPOnline [your parameters] -WarningAction Ignore", Formatted = true, Type = CmdletMessageWriter.MessageType.Warning }); - if (PnPConnection.Current?.ClientId == ClientId && - PnPConnection.Current?.ClientSecret == ClientSecret && - PnPConnection.Current?.Tenant == Realm) + if (Connection?.ClientId == ClientId && + Connection?.ClientSecret == ClientSecret && + Connection?.Tenant == Realm) { ReuseAuthenticationManager(); } @@ -397,14 +407,14 @@ private PnPConnection ConnectDeviceLogin() { Uri oldUri = null; - if (PnPConnection.Current != null) + if (Connection != null) { - if (PnPConnection.Current.Url != null) + if (Connection.Url != null) { - oldUri = new Uri(PnPConnection.Current.Url); + oldUri = new Uri(Connection.Url); } } - if (oldUri != null && oldUri.Host == new Uri(Url).Host && PnPConnection.Current?.ConnectionMethod == ConnectionMethod.DeviceLogin) + if (oldUri != null && oldUri.Host == new Uri(Url).Host && Connection?.ConnectionMethod == ConnectionMethod.DeviceLogin) { ReuseAuthenticationManager(); } @@ -447,9 +457,9 @@ private PnPConnection ConnectAppOnlyWithCertificate() throw new FileNotFoundException("Certificate not found"); } X509Certificate2 certificate = CertificateHelper.GetCertificateFromPath(CertificatePath, CertificatePassword); - if (PnPConnection.Current?.ClientId == ClientId && - PnPConnection.Current?.Tenant == Tenant && - PnPConnection.Current?.Certificate?.Thumbprint == certificate.Thumbprint) + if (Connection?.ClientId == ClientId && + Connection?.Tenant == Tenant && + Connection?.Certificate?.Thumbprint == certificate.Thumbprint) { ReuseAuthenticationManager(); } @@ -460,9 +470,9 @@ private PnPConnection ConnectAppOnlyWithCertificate() var certificateBytes = Convert.FromBase64String(CertificateBase64Encoded); var certificate = new X509Certificate2(certificateBytes, CertificatePassword); - if (PnPConnection.Current?.ClientId == ClientId && - PnPConnection.Current?.Tenant == Tenant && - PnPConnection.Current?.Certificate?.Thumbprint == certificate.Thumbprint) + if (Connection?.ClientId == ClientId && + Connection?.Tenant == Tenant && + Connection?.Certificate?.Thumbprint == certificate.Thumbprint) { ReuseAuthenticationManager(); } @@ -482,9 +492,9 @@ private PnPConnection ConnectAppOnlyWithCertificate() { throw new PSArgumentException("The certificate specified does not have a private key.", nameof(Thumbprint)); } - if (PnPConnection.Current?.ClientId == ClientId && - PnPConnection.Current?.Tenant == Tenant && - PnPConnection.Current?.Certificate?.Thumbprint == certificate.Thumbprint) + if (Connection?.ClientId == ClientId && + Connection?.Tenant == Tenant && + Connection?.Certificate?.Thumbprint == certificate.Thumbprint) { ReuseAuthenticationManager(); } @@ -531,10 +541,10 @@ private PnPConnection ConnectCredentials(PSCredential credentials, Initializatio ClientId = PnPConnection.PnPManagementShellClientId; } - if (PnPConnection.Current?.ClientId == ClientId) + if (Connection?.ClientId == ClientId) { - if (credentials != null && PnPConnection.Current?.PSCredential?.UserName == credentials.UserName && - PnPConnection.Current?.PSCredential.GetNetworkCredential().Password == credentials.GetNetworkCredential().Password) + if (credentials != null && Connection?.PSCredential?.UserName == credentials.UserName && + Connection?.PSCredential.GetNetworkCredential().Password == credentials.GetNetworkCredential().Password) { ReuseAuthenticationManager(); } @@ -574,9 +584,9 @@ private PnPConnection ConnectInteractive() { ClientId = PnPConnection.PnPManagementShellClientId; } - if (PnPConnection.Current?.ClientId == ClientId && PnPConnection.Current?.ConnectionMethod == ConnectionMethod.Credentials) + if (Connection?.ClientId == ClientId && Connection?.ConnectionMethod == ConnectionMethod.Credentials) { - if (IsSameOrAdminHost(new Uri(Url), new Uri(PnPConnection.Current.Url))) + if (IsSameOrAdminHost(new Uri(Url), new Uri(Connection.Url))) { ReuseAuthenticationManager(); } @@ -618,9 +628,9 @@ private PnPConnection ConnectEnvironmentVariable(InitializationType initializati SecureString secPassword = StringToSecureString(azureCertPassword); X509Certificate2 certificate = CertificateHelper.GetCertificateFromPath(azureCertificatePath, secPassword); - if (PnPConnection.Current?.ClientId == azureClientId && - PnPConnection.Current?.Tenant == Tenant && - PnPConnection.Current?.Certificate?.Thumbprint == certificate.Thumbprint) + if (Connection?.ClientId == azureClientId && + Connection?.Tenant == Tenant && + Connection?.Certificate?.Thumbprint == certificate.Thumbprint) { ReuseAuthenticationManager(); } @@ -637,10 +647,10 @@ private PnPConnection ConnectEnvironmentVariable(InitializationType initializati SecureString secPassword = StringToSecureString(password); var credentials = new PSCredential(username, secPassword); - if (PnPConnection.Current?.ClientId == azureClientId) + if (Connection?.ClientId == azureClientId) { - if (credentials != null && PnPConnection.Current?.PSCredential?.UserName == credentials.UserName && - PnPConnection.Current?.PSCredential.GetNetworkCredential().Password == credentials.GetNetworkCredential().Password) + if (credentials != null && Connection?.PSCredential?.UserName == credentials.UserName && + Connection?.PSCredential.GetNetworkCredential().Password == credentials.GetNetworkCredential().Password) { ReuseAuthenticationManager(); } @@ -739,7 +749,7 @@ protected override void StopProcessing() private void ReuseAuthenticationManager() { - var contextSettings = PnPConnection.Current.Context?.GetContextSettings(); + var contextSettings = Connection.Context?.GetContextSettings(); PnPConnection.CachedAuthenticationManager = contextSettings?.AuthenticationManager; } From 6cc2dae3d59870b1b5cc55da3b813d58e21d39c1 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Thu, 16 Feb 2023 00:38:01 +0100 Subject: [PATCH 2/2] Adding changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dff4ef897..328c0b61c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added support for specifying the ContentUrl and WebsiteUrl configuration in `Add-PnPTeamsTab` cmdlet when trying to add a SharePoint page or list as a tab in Teams channel. [#2807](https://github.com/pnp/powershell/pull/2807) - Added `-CheckinType` parameter to `Add-PnPFile` cmdlet which provides the option to specify the checkin type for a file. The default value is set to `MinorCheckIn`. [#2806](https://github.com/pnp/powershell/pull/2806) - Added `-ApplicationId` as alias for `-ClientId` in `Connect-PnPOnline` and `Request-PnPAccessToken` cmdlets. [#2805](https://github.com/pnp/powershell/pull/2805) +- Added `-Connection` option to `Connect-PnPOnline` which allows of reusing an authenticated connection to connect to a different site [#2821](https://github.com/pnp/powershell/pull/2821) ### Changed @@ -78,6 +79,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Contributors +- [reusto] - Ronald Mavarez [ronaldmavarez] - [lilealdai] - Martin Lingstuyl [martinlingstuyl]