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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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]
Expand Down
28 changes: 21 additions & 7 deletions documentation/Connect-PnPOnline.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,36 @@ Connect to a SharePoint site
Connect-PnPOnline [-ReturnConnection] [-Url] <String> [-Credentials <CredentialPipeBind>] [-CurrentCredentials]
[-CreateDrive] [-DriveName <String>] [-ClientId <String>] [-RedirectUri <String>]
[-AzureEnvironment <AzureEnvironment>] [-TenantAdminUrl <String>]
[-TransformationOnPrem] [-ValidateConnection]
[-TransformationOnPrem] [-ValidateConnection] [-Connection <PnPConnection>]
```

### SharePoint ACS (Legacy) App Only
```
Connect-PnPOnline [-ReturnConnection] [-Url] <String> [-Realm <String>] -ClientSecret <String> [-CreateDrive]
[-DriveName <String>] -ClientId <String> [-AzureEnvironment <AzureEnvironment>] [-TenantAdminUrl <String>]
[-ValidateConnection]
[-ValidateConnection] [-Connection <PnPConnection>]
```

### App-Only with Azure Active Directory
```
Connect-PnPOnline [-ReturnConnection] [-Url] <String> [-CreateDrive] [-DriveName <String>] -ClientId <String>
-Tenant <String> [-CertificatePath <String>] [-CertificateBase64Encoded <String>]
[-CertificatePassword <SecureString>] [-AzureEnvironment <AzureEnvironment>] [-TenantAdminUrl <String>]
[-ValidateConnection]
[-ValidateConnection] [-Connection <PnPConnection>]
```

### App-Only with Azure Active Directory using a certificate from the Windows Certificate Management Store by thumbprint
```
Connect-PnPOnline [-ReturnConnection] [-Url] <String> [-CreateDrive] [-DriveName <String>] -ClientId <String>
-Tenant <String> -Thumbprint <String> [-AzureEnvironment <AzureEnvironment>] [-TenantAdminUrl <String>]
[-ValidateConnection]
[-ValidateConnection] [-Connection <PnPConnection>]
```

### PnP Management Shell / DeviceLogin
```
Connect-PnPOnline [-ReturnConnection] [-Url] <String> [-CreateDrive] [-DriveName <String>] [-DeviceLogin]
[-LaunchBrowser] [-ClientId <String>] [-AzureEnvironment <AzureEnvironment>]
[-ValidateConnection]
[-ValidateConnection] [-Connection <PnPConnection>]
```

### Web Login for Multi Factor Authentication
Expand All @@ -61,7 +61,7 @@ Connect-PnPOnline [-ReturnConnection] [-Url] <String> [-CreateDrive] [-DriveName
### Interactive for Multi Factor Authentication
```
Connect-PnPOnline -Interactive [-ReturnConnection] -Url <String> [-CreateDrive] [-DriveName <String>] [-LaunchBrowser]
[-ClientId <String>] [-AzureEnvironment <AzureEnvironment>] [-TenantAdminUrl <String>] [-ForceAuthentication] [-ValidateConnection]
[-ClientId <String>] [-AzureEnvironment <AzureEnvironment>] [-TenantAdminUrl <String>] [-ForceAuthentication] [-ValidateConnection] [-Connection <PnPConnection>]
```

### On-premises login for page transformation from on-premises SharePoint to SharePoint Online
Expand All @@ -84,7 +84,7 @@ Connect-PnPOnline -Url <String> [-UserAssignedManagedIdentityObjectId <String>]
Connect-PnPOnline [-ReturnConnection] [-Url] <String> [-EnvironmentVariable] [-CurrentCredentials]
[-CreateDrive] [-DriveName <String>] [-RedirectUri <String>]
[-AzureEnvironment <AzureEnvironment>] [-TenantAdminUrl <String>]
[-TransformationOnPrem] [-ValidateConnection]
[-TransformationOnPrem] [-ValidateConnection] [-Connection <PnPConnection>]
```

## DESCRIPTION
Expand Down Expand Up @@ -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

Expand Down
106 changes: 58 additions & 48 deletions src/Commands/Base/ConnectOnline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -237,7 +247,7 @@ protected void Connect(ref CancellationToken cancellationToken)
}
}

PnPConnection connection = null;
PnPConnection newConnection = null;

PSCredential credentials = null;
if (Credentials != null)
Expand All @@ -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");
Expand All @@ -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);
}
Expand All @@ -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"))
Expand All @@ -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)
Expand All @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand All @@ -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();
}
Expand All @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand All @@ -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();
}
Expand Down Expand Up @@ -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;
}

Expand Down