diff --git a/Binaries/SharePointPnP.Modernization.Framework.dll b/Binaries/SharePointPnP.Modernization.Framework.dll
index 6e8398b08..b4a8e35e8 100644
Binary files a/Binaries/SharePointPnP.Modernization.Framework.dll and b/Binaries/SharePointPnP.Modernization.Framework.dll differ
diff --git a/Binaries/SharePointPnP.Modernization.Framework.xml b/Binaries/SharePointPnP.Modernization.Framework.xml
index af3fc29eb..999ccd0f6 100644
--- a/Binaries/SharePointPnP.Modernization.Framework.xml
+++ b/Binaries/SharePointPnP.Modernization.Framework.xml
@@ -4,6 +4,384 @@
SharePointPnP.Modernization.Framework
+
+
+ MemoryDistributedCache options class
+
+
+ MemoryDistributedCache options class
+
+
+
+
+ Prefix value that will be prepended to the provided key value
+
+
+
+
+ Default cache entry configuration, will be used to save items to the cache
+
+
+
+
+ Returns the key value to use by the caching system, in this case this will mean prepending the KeyPrefix
+
+ Provided key
+ Key to use by the caching system
+
+
+
+ Extensions methods to make it easier to work with the distributed cache
+
+
+
+
+ Converts an object into a bytearray
+
+ Object to return as byte array
+ byte array
+
+
+
+ Converts a byte array to an object
+
+ Type of the object to return
+ Byte array
+ Object
+
+
+
+ Sets an object of type T in connected cache system
+
+ Type of the object to cache
+ Connected cache system
+ Key of the object in the cache
+ Value to be cached
+ Caching options
+ Cancellation token
+
+
+
+
+ Sets an object of type T in connected cache system
+
+ Type of the object to cache
+ Connected cache system
+ Key of the object in the cache
+ Value to be cached
+ Caching options
+
+
+
+ Gets an object from the connected cache system
+
+ Type of the object to return from cache
+ Connected cache system
+ Key of the object in the cache
+ Object of the type T
+
+
+
+ Gets an object from the connected cache system
+
+ Type of the object to return from cache
+ Connected cache system
+ Key of the object in the cache
+ Object of the type T
+
+
+
+ Gets an object from the connected cache system. If not cached the object will be created
+
+ Type of the object to return from cache
+ Connected cache system
+ Key of the object in the cache
+ Object of the type T
+
+
+
+ Interface to be implemented by each cache options implementation
+
+
+
+
+ Prefix value that will be prepended to the provided key value
+
+
+
+
+ Returns the key value to use by the caching system, typically this will mean prepending the KeyPrefix
+
+ Provided key
+ Key to use by the caching system
+
+
+
+ Default cache entry configuration, will be used to save items to the cache
+
+
+
+
+ Caching manager, singleton
+ Important: don't cache SharePoint Client objects as these are tied to a specific client context and hence will fail when there's context switching!
+
+
+
+
+ Get's the single cachemanager instance, singleton pattern
+
+
+
+
+ Get's the cached SharePoint version for a given site
+
+ Site to get the SharePoint version for
+ Found SharePoint version or "Unknown" if not found in cache
+
+
+
+ Sets the SharePoint version in cache
+
+ Site to the set the SharePoint version for
+ SharePoint version of the site
+
+
+
+ Get's the exact SharePoint version from cache
+
+ Site to get the exact version for
+ Exact version from cache
+
+
+
+ Adds exact SharePoint version for a given site to cache
+
+ Site to add the SharePoint version for to cache
+ Version to add
+
+
+
+ Returns the used AzureAD tenant id
+
+ Url of the site
+ Azure AD tenant id
+
+
+
+ Sets the Azure AD tenant Id in cache
+
+ Tenant Id
+ Site url
+
+
+
+ Get's the clientside components from cache or if needed retrieves and caches them
+
+ Page to grab the components for
+
+
+
+
+ Clear the clientside component cache
+
+
+
+
+ Get's the base template that will be used to filter out "OOB" fields
+
+ web to operate against
+ Provisioning template of the base template of STS#0
+
+
+
+ Clear base template cache
+
+
+
+
+ Get the list of fields that need to be copied from cache. If cache is empty the list will be calculated
+
+ Web to operate against
+ Pages library instance
+ List of fields that need to be copied
+
+
+
+ Get field information of a content type field
+
+ Pages library list
+ ID of the content type
+ Name of the field to get information from
+ FieldData object holding field information
+
+
+
+ Clear the fields to copy cache
+
+
+
+
+ Marks this web as a publishing web
+
+ Url of the web
+
+
+
+ Marks this web as a blog web
+
+ Url of the web
+
+
+
+ Checks if this is publishing web
+
+ Web url to check
+ True if publishing, false otherwise
+
+
+
+ Checks if this is blog web
+
+ Web url to check
+ True if blog, false otherwise
+
+
+
+ Get translation for the publishing pages library
+
+ Context of the site
+ Translated name of the pages library
+
+
+
+ Get translation for the blog list name
+
+ Context of the site
+ Translated name of the blog list
+
+
+
+ Returns the translated value for a resource string
+
+ Context of the site
+ Key of the resource (e.g. $Resources:core,ScriptEditorWebPartDescription;)
+ Translated string
+
+
+
+ Generate pagelayout mapping file for given publishing page
+
+ Publishing page
+ Page layout mapping model
+
+
+
+ Clear all the caches
+
+
+
+
+ Clears Cached SharePoint versions
+
+
+
+
+ Clears the cache of generated page layout mappings
+
+
+
+
+ Mapped users
+
+ A dictionary of mapped users
+
+
+
+ Adds a user to the dictionary of mapped users
+
+ Principal to map
+ mapped user
+
+
+
+ Run and cache the output value of EnsureUser for a given user
+
+ ClientContext to operate on
+ User name of user to ensure
+ ResolvedUser instance holding information about the ensured user
+
+
+
+ Lookup a user from the site's user list based upon the user's upn
+
+ Context of the web holding the user list
+ Upn of the user to fetch
+ A UserEntity instance holding information about the user
+
+
+
+ Lookup a user from the site's user list based upon the user's id
+
+ Context of the web holding the user list
+ Id of the user to fetch
+ A UserEntity instance holding information about the user
+
+
+
+ Get's the ID of a contenttype
+
+ Pages library holding the content type
+ Name of the content type
+ ID of the content type
+
+
+
+ Caches the last used page transformator instance, needed to postpone log writing when transforming multiple pages
+
+
+
+
+
+ Gets the last used page transformator instance
+
+
+
+
+
+ Returns a list of url mappings
+
+ File with url mappings
+ Attached list of log observers
+ List of url mappings
+
+
+
+ Gets the list of user mappings, if first time file will be laoded
+
+ File with the user mappings
+ Attached list of log observers
+ List of user mappings
+
+
+
+ Field data used to transfer information about a field
+
+
+
+
+ Internal name of the field
+
+
+
+
+ Id of the field
+
+
+
+
+ Type of the field
+
+
Information to initiate the transformation of a Delve blog page
@@ -769,6 +1147,13 @@
Server Relative Page Url
+
+
+ Uses the WebPartPages.asmx service to retrieve the page contents, needed to find ZoneId for SP2010 based v3 web parts
+
+ Page to load
+ The found page
+
Call SharePoint Web Services to extract web part properties not exposed by CSOM
@@ -1124,6 +1509,12 @@
Information about the publishing page to transform
The path to the created modern page
+
+
+ Loads the default page layout mapping model file
+
+
+
Use reflection to read the object properties and detail the values
@@ -2599,6 +2990,18 @@
Base page transformator class that contains logic that applies for all page transformations
+
+
+ Loads the default webpart mapping model
+
+
+
+
+
+ Loads the default webpart mapping model file
+
+
+
Gets the version of the assembly
@@ -3662,238 +4065,6 @@
List of web parts on the page
Updated list of web parts
-
-
- Caching manager, singleton
- Important: don't cache SharePoint Client objects as these are tied to a specific client context and hence will fail when there's context switching!
-
-
-
-
- Get's the single cachemanager instance, singleton pattern
-
-
-
-
- List of URLs and SharePoint Versions
-
-
-
-
- List of URLs and Exact SharePoint Versions
-
-
-
-
- AADTenantID's used
-
-
-
-
- List of assets transferred from source to destination
-
-
-
-
- Get's the clientside components from cache or if needed retrieves and caches them
-
- Page to grab the components for
-
-
-
-
- Clear the clientside component cache
-
-
-
-
- Get's the base template that will be used to filter out "OOB" fields
-
- web to operate against
- Provisioning template of the base template of STS#0
-
-
-
- Clear base template cache
-
-
-
-
- Get the list of fields that need to be copied from cache. If cache is empty the list will be calculated
-
- Web to operate against
- Pages library instance
- List of fields that need to be copied
-
-
-
- Get field information of a content type field
-
- Pages library list
- ID of the content type
- Name of the field to get information from
- FieldData object holding field information
-
-
-
- Clear the fields to copy cache
-
-
-
-
- Marks this web as a publishing web
-
- Url of the web
-
-
-
- Marks this web as a blog web
-
- Url of the web
-
-
-
- Checks if this is publishing web
-
- Web url to check
- True if publishing, false otherwise
-
-
-
- Checks if this is blog web
-
- Web url to check
- True if blog, false otherwise
-
-
-
- Get translation for the publishing pages library
-
- Context of the site
- Translated name of the pages library
-
-
-
- Get translation for the blog list name
-
- Context of the site
- Translated name of the blog list
-
-
-
- Returns the translated value for a resource string
-
- Context of the site
- Key of the resource (e.g. $Resources:core,ScriptEditorWebPartDescription;)
- Translated string
-
-
-
- Generate pagelayout mapping file for given publishing page
-
- Publishing page
- Page layout mapping model
-
-
-
- Clear all the caches
-
-
-
-
- Clears Cached SharePoint versions
-
-
-
-
- Clears the cache of generated page layout mappings
-
-
-
-
- Mapped users
-
-
-
-
- Run and cache the output value of EnsureUser for a given user
-
- ClientContext to operate on
- User name of user to ensure
- ResolvedUser instance holding information about the ensured user
-
-
-
- Lookup a user from the site's user list based upon the user's upn
-
- Context of the web holding the user list
- Upn of the user to fetch
- A UserEntity instance holding information about the user
-
-
-
- Lookup a user from the site's user list based upon the user's id
-
- Context of the web holding the user list
- Id of the user to fetch
- A UserEntity instance holding information about the user
-
-
-
- Get's the ID of a contenttype
-
- Pages library holding the content type
- Name of the content type
- ID of the content type
-
-
-
- Caches the last used page transformator instance, needed to postpone log writing when transforming multiple pages
-
-
-
-
-
- Gets the last used page transformator instance
-
-
-
-
-
- Returns a list of url mappings
-
- File with url mappings
- Attached list of log observers
- List of url mappings
-
-
-
- Gets the list of user mappings, if first time file will be laoded
-
- File with the user mappings
- Attached list of log observers
- List of user mappings
-
-
-
- Field data used to transfer information about a field
-
-
-
-
- Internal name of the field
-
-
-
-
- Id of the field
-
-
-
-
- Type of the field
-
-
Constants used
diff --git a/Binaries/release/SharePointPnP.Modernization.Framework.dll b/Binaries/release/SharePointPnP.Modernization.Framework.dll
index 495261a3c..fdc42c017 100644
Binary files a/Binaries/release/SharePointPnP.Modernization.Framework.dll and b/Binaries/release/SharePointPnP.Modernization.Framework.dll differ
diff --git a/Binaries/release/SharePointPnP.Modernization.Framework.xml b/Binaries/release/SharePointPnP.Modernization.Framework.xml
index af3fc29eb..999ccd0f6 100644
--- a/Binaries/release/SharePointPnP.Modernization.Framework.xml
+++ b/Binaries/release/SharePointPnP.Modernization.Framework.xml
@@ -4,6 +4,384 @@
SharePointPnP.Modernization.Framework
+
+
+ MemoryDistributedCache options class
+
+
+ MemoryDistributedCache options class
+
+
+
+
+ Prefix value that will be prepended to the provided key value
+
+
+
+
+ Default cache entry configuration, will be used to save items to the cache
+
+
+
+
+ Returns the key value to use by the caching system, in this case this will mean prepending the KeyPrefix
+
+ Provided key
+ Key to use by the caching system
+
+
+
+ Extensions methods to make it easier to work with the distributed cache
+
+
+
+
+ Converts an object into a bytearray
+
+ Object to return as byte array
+ byte array
+
+
+
+ Converts a byte array to an object
+
+ Type of the object to return
+ Byte array
+ Object
+
+
+
+ Sets an object of type T in connected cache system
+
+ Type of the object to cache
+ Connected cache system
+ Key of the object in the cache
+ Value to be cached
+ Caching options
+ Cancellation token
+
+
+
+
+ Sets an object of type T in connected cache system
+
+ Type of the object to cache
+ Connected cache system
+ Key of the object in the cache
+ Value to be cached
+ Caching options
+
+
+
+ Gets an object from the connected cache system
+
+ Type of the object to return from cache
+ Connected cache system
+ Key of the object in the cache
+ Object of the type T
+
+
+
+ Gets an object from the connected cache system
+
+ Type of the object to return from cache
+ Connected cache system
+ Key of the object in the cache
+ Object of the type T
+
+
+
+ Gets an object from the connected cache system. If not cached the object will be created
+
+ Type of the object to return from cache
+ Connected cache system
+ Key of the object in the cache
+ Object of the type T
+
+
+
+ Interface to be implemented by each cache options implementation
+
+
+
+
+ Prefix value that will be prepended to the provided key value
+
+
+
+
+ Returns the key value to use by the caching system, typically this will mean prepending the KeyPrefix
+
+ Provided key
+ Key to use by the caching system
+
+
+
+ Default cache entry configuration, will be used to save items to the cache
+
+
+
+
+ Caching manager, singleton
+ Important: don't cache SharePoint Client objects as these are tied to a specific client context and hence will fail when there's context switching!
+
+
+
+
+ Get's the single cachemanager instance, singleton pattern
+
+
+
+
+ Get's the cached SharePoint version for a given site
+
+ Site to get the SharePoint version for
+ Found SharePoint version or "Unknown" if not found in cache
+
+
+
+ Sets the SharePoint version in cache
+
+ Site to the set the SharePoint version for
+ SharePoint version of the site
+
+
+
+ Get's the exact SharePoint version from cache
+
+ Site to get the exact version for
+ Exact version from cache
+
+
+
+ Adds exact SharePoint version for a given site to cache
+
+ Site to add the SharePoint version for to cache
+ Version to add
+
+
+
+ Returns the used AzureAD tenant id
+
+ Url of the site
+ Azure AD tenant id
+
+
+
+ Sets the Azure AD tenant Id in cache
+
+ Tenant Id
+ Site url
+
+
+
+ Get's the clientside components from cache or if needed retrieves and caches them
+
+ Page to grab the components for
+
+
+
+
+ Clear the clientside component cache
+
+
+
+
+ Get's the base template that will be used to filter out "OOB" fields
+
+ web to operate against
+ Provisioning template of the base template of STS#0
+
+
+
+ Clear base template cache
+
+
+
+
+ Get the list of fields that need to be copied from cache. If cache is empty the list will be calculated
+
+ Web to operate against
+ Pages library instance
+ List of fields that need to be copied
+
+
+
+ Get field information of a content type field
+
+ Pages library list
+ ID of the content type
+ Name of the field to get information from
+ FieldData object holding field information
+
+
+
+ Clear the fields to copy cache
+
+
+
+
+ Marks this web as a publishing web
+
+ Url of the web
+
+
+
+ Marks this web as a blog web
+
+ Url of the web
+
+
+
+ Checks if this is publishing web
+
+ Web url to check
+ True if publishing, false otherwise
+
+
+
+ Checks if this is blog web
+
+ Web url to check
+ True if blog, false otherwise
+
+
+
+ Get translation for the publishing pages library
+
+ Context of the site
+ Translated name of the pages library
+
+
+
+ Get translation for the blog list name
+
+ Context of the site
+ Translated name of the blog list
+
+
+
+ Returns the translated value for a resource string
+
+ Context of the site
+ Key of the resource (e.g. $Resources:core,ScriptEditorWebPartDescription;)
+ Translated string
+
+
+
+ Generate pagelayout mapping file for given publishing page
+
+ Publishing page
+ Page layout mapping model
+
+
+
+ Clear all the caches
+
+
+
+
+ Clears Cached SharePoint versions
+
+
+
+
+ Clears the cache of generated page layout mappings
+
+
+
+
+ Mapped users
+
+ A dictionary of mapped users
+
+
+
+ Adds a user to the dictionary of mapped users
+
+ Principal to map
+ mapped user
+
+
+
+ Run and cache the output value of EnsureUser for a given user
+
+ ClientContext to operate on
+ User name of user to ensure
+ ResolvedUser instance holding information about the ensured user
+
+
+
+ Lookup a user from the site's user list based upon the user's upn
+
+ Context of the web holding the user list
+ Upn of the user to fetch
+ A UserEntity instance holding information about the user
+
+
+
+ Lookup a user from the site's user list based upon the user's id
+
+ Context of the web holding the user list
+ Id of the user to fetch
+ A UserEntity instance holding information about the user
+
+
+
+ Get's the ID of a contenttype
+
+ Pages library holding the content type
+ Name of the content type
+ ID of the content type
+
+
+
+ Caches the last used page transformator instance, needed to postpone log writing when transforming multiple pages
+
+
+
+
+
+ Gets the last used page transformator instance
+
+
+
+
+
+ Returns a list of url mappings
+
+ File with url mappings
+ Attached list of log observers
+ List of url mappings
+
+
+
+ Gets the list of user mappings, if first time file will be laoded
+
+ File with the user mappings
+ Attached list of log observers
+ List of user mappings
+
+
+
+ Field data used to transfer information about a field
+
+
+
+
+ Internal name of the field
+
+
+
+
+ Id of the field
+
+
+
+
+ Type of the field
+
+
Information to initiate the transformation of a Delve blog page
@@ -769,6 +1147,13 @@
Server Relative Page Url
+
+
+ Uses the WebPartPages.asmx service to retrieve the page contents, needed to find ZoneId for SP2010 based v3 web parts
+
+ Page to load
+ The found page
+
Call SharePoint Web Services to extract web part properties not exposed by CSOM
@@ -1124,6 +1509,12 @@
Information about the publishing page to transform
The path to the created modern page
+
+
+ Loads the default page layout mapping model file
+
+
+
Use reflection to read the object properties and detail the values
@@ -2599,6 +2990,18 @@
Base page transformator class that contains logic that applies for all page transformations
+
+
+ Loads the default webpart mapping model
+
+
+
+
+
+ Loads the default webpart mapping model file
+
+
+
Gets the version of the assembly
@@ -3662,238 +4065,6 @@
List of web parts on the page
Updated list of web parts
-
-
- Caching manager, singleton
- Important: don't cache SharePoint Client objects as these are tied to a specific client context and hence will fail when there's context switching!
-
-
-
-
- Get's the single cachemanager instance, singleton pattern
-
-
-
-
- List of URLs and SharePoint Versions
-
-
-
-
- List of URLs and Exact SharePoint Versions
-
-
-
-
- AADTenantID's used
-
-
-
-
- List of assets transferred from source to destination
-
-
-
-
- Get's the clientside components from cache or if needed retrieves and caches them
-
- Page to grab the components for
-
-
-
-
- Clear the clientside component cache
-
-
-
-
- Get's the base template that will be used to filter out "OOB" fields
-
- web to operate against
- Provisioning template of the base template of STS#0
-
-
-
- Clear base template cache
-
-
-
-
- Get the list of fields that need to be copied from cache. If cache is empty the list will be calculated
-
- Web to operate against
- Pages library instance
- List of fields that need to be copied
-
-
-
- Get field information of a content type field
-
- Pages library list
- ID of the content type
- Name of the field to get information from
- FieldData object holding field information
-
-
-
- Clear the fields to copy cache
-
-
-
-
- Marks this web as a publishing web
-
- Url of the web
-
-
-
- Marks this web as a blog web
-
- Url of the web
-
-
-
- Checks if this is publishing web
-
- Web url to check
- True if publishing, false otherwise
-
-
-
- Checks if this is blog web
-
- Web url to check
- True if blog, false otherwise
-
-
-
- Get translation for the publishing pages library
-
- Context of the site
- Translated name of the pages library
-
-
-
- Get translation for the blog list name
-
- Context of the site
- Translated name of the blog list
-
-
-
- Returns the translated value for a resource string
-
- Context of the site
- Key of the resource (e.g. $Resources:core,ScriptEditorWebPartDescription;)
- Translated string
-
-
-
- Generate pagelayout mapping file for given publishing page
-
- Publishing page
- Page layout mapping model
-
-
-
- Clear all the caches
-
-
-
-
- Clears Cached SharePoint versions
-
-
-
-
- Clears the cache of generated page layout mappings
-
-
-
-
- Mapped users
-
-
-
-
- Run and cache the output value of EnsureUser for a given user
-
- ClientContext to operate on
- User name of user to ensure
- ResolvedUser instance holding information about the ensured user
-
-
-
- Lookup a user from the site's user list based upon the user's upn
-
- Context of the web holding the user list
- Upn of the user to fetch
- A UserEntity instance holding information about the user
-
-
-
- Lookup a user from the site's user list based upon the user's id
-
- Context of the web holding the user list
- Id of the user to fetch
- A UserEntity instance holding information about the user
-
-
-
- Get's the ID of a contenttype
-
- Pages library holding the content type
- Name of the content type
- ID of the content type
-
-
-
- Caches the last used page transformator instance, needed to postpone log writing when transforming multiple pages
-
-
-
-
-
- Gets the last used page transformator instance
-
-
-
-
-
- Returns a list of url mappings
-
- File with url mappings
- Attached list of log observers
- List of url mappings
-
-
-
- Gets the list of user mappings, if first time file will be laoded
-
- File with the user mappings
- Attached list of log observers
- List of user mappings
-
-
-
- Field data used to transfer information about a field
-
-
-
-
- Internal name of the field
-
-
-
-
- Id of the field
-
-
-
-
- Type of the field
-
-
Constants used
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 078e37633..dedc39532 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,37 +5,49 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
-## [3.17.2001.0] (not yet released)
+## [3.17.2001.0]
### Added
-- Add/Remove/Set/Get-PnPApplicationCustomizer commands to allow working with SharePoint Framework Application Customizer Extensions [PR2312](https://github.com/SharePoint/PnP-PowerShell/pull/2312)
-- Ability to pipe in a result from Get-PnPFolder to Get-PnPFolderItem using the -Identity parameter [PR2279](https://github.com/SharePoint/PnP-PowerShell/pull/2279)
-- Added ability to pipe Get-PnPUnifiedGroup to Get-PnPUnifiedGroupOwners and Get-PnPUnifiedGroupMembers [PR2208](https://github.com/SharePoint/PnP-PowerShell/pull/2208)
-- Added permissions required for each of the \*-PnPUnifiedGroup\* commands in the Azure Active Directory App Registration to the help text of the commands [PR2205](https://github.com/SharePoint/PnP-PowerShell/pull/2205)
-- Added option to use Connect-PnPOnline with a base64 encoded private key for use in i.e. PnP PowerShell within an Azure Function v1 and an option to provide a certificate reference for use in i.e. Azure Function v2 [PR2201](https://github.com/SharePoint/PnP-PowerShell/pull/2201)
-- Added option to use Connect-PnPOnline with a public key certificate for use in i.e. Azure Runbooks [PR2292](https://github.com/SharePoint/PnP-PowerShell/pull/2292)
-- Added option -RowLimit to Get-PnPRecycleBinItem to avoid getting throttled on full recycle bins [PR2393](https://github.com/SharePoint/PnP-PowerShell/pull/2393)
-- Added `-WriteToConsole` option to `Set-PnPTraceLog` to allow writing trace listener output from the PnP Templating commands to both the console and to a file. Doesn't work for .NET Core. [PR2161](https://github.com/SharePoint/PnP-PowerShell/pull/2161)
-- Added `Reset-PnPLabel` command to allow removal of an Office 365 Retention Label from a list [PR2233](https://github.com/SharePoint/PnP-PowerShell/pull/2233)
+- Add/Remove/Set/Get-PnPApplicationCustomizer commands to allow working with SharePoint Framework Application Customizer Extensions
+- Ability to pipe in a result from Get-PnPFolder to Get-PnPFolderItem using the -Identity parameter
+- Added ability to pipe Get-PnPUnifiedGroup to Get-PnPUnifiedGroupOwners and Get-PnPUnifiedGroupMembers
+- Added permissions required for each of the \*-PnPUnifiedGroup\* commands in the Azure Active Directory App Registration to the help text of the commands
+- Added option to use Connect-PnPOnline with a base64 encoded private key for use in i.e. PnP PowerShell within an Azure Function v1 and an option to provide a certificate reference for use in i.e. Azure Function v2
+- Added option to use Connect-PnPOnline with a public key certificate for use in i.e. Azure Runbooks
+- Added option -RowLimit to Get-PnPRecycleBinItem to avoid getting throttled on full recycle bins
+- Added `-WriteToConsole` option to `Set-PnPTraceLog` to allow writing trace listener output from the PnP Templating commands to both the console and to a file. Doesn't work for .NET Core.
+- Added `Reset-PnPLabel` command to allow removal of an Office 365 Retention Label from a list
+- Add/Remove/Get-PnPOrgNewsSite commands to set site collections as authoritive news sources to SharePoint Online
+- Add/Remove/Get-PnPOrgAssetsLibrary commands to set document libraries as organizational asset sources on SharePoint Online
+- `-Recursive` option to `Get-PnPFolderItem` to allow retrieving all files and folders recursively
### Changed
-
-- Fixes issues with connections not properly closing under some conditions when using Disconnect-PnPOnline [PR2207](https://github.com/SharePoint/PnP-PowerShell/pull/2207)
-- When using commands that utilize the Graph API but not being connected to one of the Graph API Connect-PnPOnline methods, it would throw a NullReferenceException. It will now throw a cleaner exception indicating you should connect with the Graph API first. [PR2395](https://github.com/SharePoint/PnP-PowerShell/pull/2395)
-- Fixed an issue where using Get-PnPUser -WithRightsAssigned would not return the proper users with actually having access to that site [PR1685](https://github.com/SharePoint/PnP-PowerShell/pull/1685)
-- Fixed an issue when using ConvertTo-PnPClientSidePage to convert Delve Blog posts that it would throw a nullreference exception in some scenarios [PR2411](https://github.com/SharePoint/PnP-PowerShell/pull/2411)
-- Fixed an issue using `Add-PnPDataRowsToProvisioningTemp` to add data from a list containing a multi choice to a PnP Provisioning Template where the data would be shown as `System.String[]` instead of the actual data [PR2064](https://github.com/SharePoint/PnP-PowerShell/pull/2064)
+- Marked Get-PnPHealthScore as obsolete for SharePoint Online.
+- Fixes issues with connections not properly closing under some conditions when using Disconnect-PnPOnline
+- When using commands that utilize the Graph API but not being connected to one of the Graph API Connect-PnPOnline methods, it would throw a NullReferenceException. It will now throw a cleaner exception indicating you should connect with the Graph API first.
+- Fixed an issue where using Get-PnPUser -WithRightsAssigned would not return the proper users with actually having access to that site
+- Fixed an issue when using ConvertTo-PnPClientSidePage to convert Delve Blog posts that it would throw a nullreference exception in some scenarios
+- Fixed an issue using `Add-PnPDataRowsToProvisioningTemp` to add data from a list containing a multi choice to a PnP Provisioning Template where the data would be shown as `System.String[]` instead of the actual data
+- Bumped to .Net 4.6.1 as minimal .Net runtime version
+- Changed the way properties are being set in Set-PnPField to support setting field specific properties such as the Lookup list on a Lookup field
+- Fixed an issue where using Apply-PnPProvisioningTemplate -InputInstance $instance would throw a connectionString error if being executed from the root of a drive, i.e. c:\ or d:\
+- Fixed issue with access token not returning correctly after update to newer version of NewtonSoft JSON.
+- Fixes issue with pipeline not returning object correctly.
### Contributors
-- Koen Zomers \[[koenzomers](https://github.com/koenzomers)\]
-- Robin Meure \[[robinmeure](https://github.com/robinmeure)\]
-- Michael Rees Pullen \[[mrpullen](https://github.com/mrpullen)\]
-- Giacomo Pozzoni \[[jackpoz](https://github.com/jackpoz)\]
-- Rene Modery \[[modery](https://github.com/modery)\]
-- Krystian Niepsuj \[[MrDoNotBreak](https://github.com/MrDoNotBreak)\]
-- Piotr Siatka \[[siata13](https://github.com/siata13)\]
-- Heinrich Ulbricht \[[heinrich-ulbricht](https://github.com/heinrich-ulbricht)\]
-- Dan Cecil \[[danielcecil](https://github.com/danielcecil)\]
+- Koen Zomers [koenzomers]
+- Robin Meure [robinmeure]
+- Michael Rees Pullen [mrpullen]
+- Giacomo Pozzoni [jackpoz]
+- Rene Modery [modery]
+- Krystian Niepsuj [MrDoNotBreak]
+- Piotr Siatka [siata13]
+- Heinrich Ulbricht [heinrich-ulbricht]
+- Dan Cecil [danielcecil]
+- Gautam Sheth [gautamdsheth]
+- Giacomo Pozzoni [jackpoz]
+- Will Holland [willholland]
+- Ivan Vagunin [ivanvagunin]
## [3.16.1912.0]
diff --git a/Commands/Admin/AddOrgAssetsLibrary.cs b/Commands/Admin/AddOrgAssetsLibrary.cs
new file mode 100644
index 000000000..5564af267
--- /dev/null
+++ b/Commands/Admin/AddOrgAssetsLibrary.cs
@@ -0,0 +1,42 @@
+#if !ONPREMISES
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base;
+using System.Management.Automation;
+using Microsoft.Online.SharePoint.TenantAdministration;
+
+namespace SharePointPnP.PowerShell.Commands.Admin
+{
+ [Cmdlet(VerbsCommon.Add, "PnPOrgAssetsLibrary")]
+ [CmdletHelp("Adds a given document library as a organizational asset source",
+ DetailedDescription = @"Adds a given document library as an organizational asset source in your Sharepoint Online Tenant. All organizational asset sources you add must reside in the same site collection. Document libraries specified as organizational asset must be enabled as an Office 365 CDN source, either as private or public. It may take some time before this change will be reflected in the webinterface.",
+ SupportedPlatform = CmdletSupportedPlatform.Online,
+ Category = CmdletHelpCategory.TenantAdmin)]
+ [CmdletExample(
+ Code = @"PS:> Add-PnPOrgAssetsLibrary -LibraryUrl https://yourtenant.sharepoint.com/sites/branding/logos",
+ Remarks = @"Adds the document library with the url ""logos"" located in the sitecollection at ""https://yourtenant.sharepoint.com/sites/branding"" as an organizational asset not specifying a thumbnail image for it and enabling the document library as a public Office 365 CDN source", SortOrder = 1)]
+ [CmdletExample(
+ Code = @"PS:> Add-PnPOrgAssetsLibrary -LibraryUrl https://yourtenant.sharepoint.com/sites/branding/logos -ThumbnailUrl https://yourtenant.sharepoint.com/sites/branding/logos/thumbnail.jpg",
+ Remarks = @"Adds the document library with the url ""logos"" located in the sitecollection at ""https://yourtenant.sharepoint.com/sites/branding"" as an organizational asset specifying the thumbnail image ""thumbnail.jpg"" residing in the same document library for it and enabling the document library as a public Office 365 CDN source", SortOrder = 2)]
+ [CmdletExample(
+ Code = @"PS:> Add-PnPOrgAssetsLibrary -LibraryUrl https://yourtenant.sharepoint.com/sites/branding/logos -CdnType Private",
+ Remarks = @"Adds the document library with the url ""logos"" located in the sitecollection at ""https://yourtenant.sharepoint.com/sites/branding"" as an organizational asset not specifying a thumbnail image for it and enabling the document library as a private Office 365 CDN source", SortOrder = 3)]
+ public class AddOrgAssetsLibrary : PnPAdminCmdlet
+ {
+ [Parameter(Mandatory = true, HelpMessage = "The full url of the document library to be marked as one of organization's assets sources")]
+ public string LibraryUrl;
+
+ [Parameter(Mandatory = false, HelpMessage = "The full url to an image that should be used as a thumbnail for showing this source. The image must reside in the same site as the document library you specify.")]
+ public string ThumbnailUrl;
+
+ [Parameter(Mandatory = false, HelpMessage = @"Indicates what type of Office 365 CDN source the document library will be added to")]
+ public SPOTenantCdnType CdnType = SPOTenantCdnType.Public;
+
+ protected override void ExecuteCmdlet()
+ {
+ Tenant.AddToOrgAssetsLibAndCdn(CdnType, LibraryUrl, ThumbnailUrl);
+ ClientContext.ExecuteQueryRetry();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Commands/Admin/AddOrgNewsSite.cs b/Commands/Admin/AddOrgNewsSite.cs
new file mode 100644
index 000000000..1e26bcd77
--- /dev/null
+++ b/Commands/Admin/AddOrgNewsSite.cs
@@ -0,0 +1,29 @@
+#if !ONPREMISES
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base;
+using System.Management.Automation;
+using SharePointPnP.PowerShell.Commands.Base.PipeBinds;
+
+namespace SharePointPnP.PowerShell.Commands.Admin
+{
+ [Cmdlet(VerbsCommon.Add, "PnPOrgNewsSite")]
+ [CmdletHelp("Adds the site as an organization news source in your tenant",
+ SupportedPlatform = CmdletSupportedPlatform.Online,
+ Category = CmdletHelpCategory.TenantAdmin)]
+ [CmdletExample(
+ Code = @"PS:> Add-PnPOrgNewsSite -OrgNewsSiteUrl https://yourtenant.sharepoint.com/sites/news",
+ Remarks = @"Adds the site as one of multiple possible tenant's organizational news sites", SortOrder = 1)]
+ public class AddOrgNewsSite : PnPAdminCmdlet
+ {
+ [Parameter(Mandatory = true, HelpMessage = "The url of the site to be marked as one of organization's news sites")]
+ public SitePipeBind OrgNewsSiteUrl;
+
+ protected override void ExecuteCmdlet()
+ {
+ Tenant.SetOrgNewsSite(OrgNewsSiteUrl.Url);
+ ClientContext.ExecuteQueryRetry();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Commands/Admin/GetOrgAssetsLibrary.cs b/Commands/Admin/GetOrgAssetsLibrary.cs
new file mode 100644
index 000000000..a1a2663e5
--- /dev/null
+++ b/Commands/Admin/GetOrgAssetsLibrary.cs
@@ -0,0 +1,30 @@
+#if !ONPREMISES
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base;
+using System.Management.Automation;
+
+namespace SharePointPnP.PowerShell.Commands.Admin
+{
+ [Cmdlet(VerbsCommon.Get, "PnPOrgAssetsLibrary")]
+ [CmdletHelp("Returns the list of all the configured organizational asset libraries",
+ SupportedPlatform = CmdletSupportedPlatform.Online,
+ Category = CmdletHelpCategory.TenantAdmin)]
+ [CmdletExample(
+ Code = @"PS:> Get-PnPOrgAssetsLibrary",
+ Remarks = @"Returns the list of all the configured organizational asset sites", SortOrder = 1)]
+ [CmdletExample(
+ Code = @"PS:> (Get-PnPOrgAssetsLibrary)[0].OrgAssetsLibraries[0].LibraryUrl.DecodedUrl",
+ Remarks = @"Returns the server relative url of the first document library which has been flagged as organizational asset library, i.e. ""sites/branding/logos""", SortOrder = 2)]
+ //
+ public class GetOrgAssetsLibrary : PnPAdminCmdlet
+ {
+ protected override void ExecuteCmdlet()
+ {
+ var results = Tenant.GetOrgAssets();
+ ClientContext.ExecuteQueryRetry();
+ WriteObject(results.Value, true);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Commands/Admin/GetOrgNewsSite.cs b/Commands/Admin/GetOrgNewsSite.cs
new file mode 100644
index 000000000..2a59a3a56
--- /dev/null
+++ b/Commands/Admin/GetOrgNewsSite.cs
@@ -0,0 +1,26 @@
+#if !ONPREMISES
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base;
+using System.Management.Automation;
+
+namespace SharePointPnP.PowerShell.Commands.Admin
+{
+ [Cmdlet(VerbsCommon.Get, "PnPOrgNewsSite")]
+ [CmdletHelp("Returns the list of all the configured organizational news sites.",
+ SupportedPlatform = CmdletSupportedPlatform.Online,
+ Category = CmdletHelpCategory.TenantAdmin)]
+ [CmdletExample(
+ Code = @"PS:> Get-PnPOrgNewsSite",
+ Remarks = @"Returns the list of all the configured organizational news sites.", SortOrder = 1)]
+ public class GetOrgNewsSite : PnPAdminCmdlet
+ {
+ protected override void ExecuteCmdlet()
+ {
+ var results = Tenant.GetOrgNewsSites();
+ ClientContext.ExecuteQueryRetry();
+ WriteObject(results, true);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Commands/Admin/GetTenantId.cs b/Commands/Admin/GetTenantId.cs
index 22346ab3c..4aae4ea86 100644
--- a/Commands/Admin/GetTenantId.cs
+++ b/Commands/Admin/GetTenantId.cs
@@ -47,6 +47,7 @@ protected override void ProcessRecord()
}
catch (Exception ex)
{
+#if !NETSTANDARD2_1
if (ex.InnerException != null)
{
if (ex.InnerException is HttpException)
@@ -64,6 +65,9 @@ protected override void ProcessRecord()
{
throw ex;
}
+#else
+ throw ex;
+#endif
}
}
}
diff --git a/Commands/Admin/RemoveOrgAssetsLibrary.cs b/Commands/Admin/RemoveOrgAssetsLibrary.cs
new file mode 100644
index 000000000..b23985fc5
--- /dev/null
+++ b/Commands/Admin/RemoveOrgAssetsLibrary.cs
@@ -0,0 +1,42 @@
+#if !ONPREMISES
+using Microsoft.Online.SharePoint.TenantAdministration;
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base;
+using System.Management.Automation;
+
+namespace SharePointPnP.PowerShell.Commands.Admin
+{
+ [Cmdlet(VerbsCommon.Remove, "PnPOrgAssetsLibrary")]
+ [CmdletHelp("Removes a given document library as a organizational asset source",
+ DetailedDescription = @"Removes a given document library as a organizational asset source based on its server relative URL in your Sharepoint Online Tenant. It will not remove the document library itself. It may take some time before this change will be reflected in the webinterface.",
+ SupportedPlatform = CmdletSupportedPlatform.Online,
+ Category = CmdletHelpCategory.TenantAdmin)]
+ [CmdletExample(
+ Code = @"PS:> Remove-PnPOrgAssetsLibrary -LibraryUrl ""sites/branding/logos""",
+ Remarks = @"This example removes the document library with the url ""logos"" residing in the sitecollection with the url ""sites/branding/logos"" from the list with organizational assets keeping it as an Office 365 CDN source", SortOrder = 1)]
+ [CmdletExample(
+ Code = @"PS:> Remove-PnPOrgAssetsLibrary -LibraryUrl ""sites/branding/logos"" -ShouldRemoveFromCdn $true",
+ Remarks = @"This example removes the document library with the url ""logos"" residing in the sitecollection with the url ""sites/branding/logos"" from the list with organizational assets also removing it as a Public Office 365 CDN source", SortOrder = 2)]
+ [CmdletExample(
+ Code = @"PS:> Remove-PnPOrgAssetsLibrary -LibraryUrl ""sites/branding/logos"" -ShouldRemoveFromCdn $true -CdnType Private",
+ Remarks = @"This example removes the document library with the url ""logos"" residing in the sitecollection with the url ""sites/branding/logos"" from the list with organizational assets also removing it as a Private Office 365 CDN source", SortOrder = 3)]
+ public class RemoveOrgAssetsLibrary : PnPAdminCmdlet
+ {
+ [Parameter(Mandatory = true, HelpMessage = @"The server relative url of the document library flagged as organizational asset which you want to remove, i.e. ""sites/branding/logos""")]
+ public string LibraryUrl;
+
+ [Parameter(Mandatory = false, HelpMessage = @"Boolean indicating if the document library that will no longer be flagged as an organizational asset also needs to be removed as an Office 365 CDN source")]
+ public bool ShouldRemoveFromCdn = false;
+
+ [Parameter(Mandatory = false, HelpMessage = @"Indicates what type of Office 365 CDN source the document library that will no longer be flagged as an organizational asset was of")]
+ public SPOTenantCdnType CdnType = SPOTenantCdnType.Public;
+
+ protected override void ExecuteCmdlet()
+ {
+ Tenant.RemoveFromOrgAssetsAndCdn(ShouldRemoveFromCdn, CdnType, LibraryUrl);
+ ClientContext.ExecuteQueryRetry();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Commands/Admin/RemoveOrgNewsSite.cs b/Commands/Admin/RemoveOrgNewsSite.cs
new file mode 100644
index 000000000..ffd1247e9
--- /dev/null
+++ b/Commands/Admin/RemoveOrgNewsSite.cs
@@ -0,0 +1,31 @@
+#if !ONPREMISES
+using Microsoft.Online.SharePoint.TenantAdministration;
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base;
+using System.Management.Automation;
+using SharePointPnP.PowerShell.Commands.Base.PipeBinds;
+
+namespace SharePointPnP.PowerShell.Commands.Admin
+{
+ [Cmdlet(VerbsCommon.Remove, "PnPOrgNewsSite")]
+ [CmdletHelp("Removes a given site from the list of organizational news sites.",
+ DetailedDescription = @"Removes a given site from the list of organizational news sites based on its URL in your Sharepoint Online Tenant.",
+ SupportedPlatform = CmdletSupportedPlatform.Online,
+ Category = CmdletHelpCategory.TenantAdmin)]
+ [CmdletExample(
+ Code = @"PS:> Remove-PnPOrgNewsSite -OrgNewsSiteUrl https://tenant.sharepoint.com/sites/mysite",
+ Remarks = @"This example removes the specified site from list of organization's news sites.", SortOrder = 1)]
+ public class RemoveOrgNewsSite : PnPAdminCmdlet
+ {
+ [Parameter(Mandatory = true, HelpMessage = @"The site to be removed from list of organization's news sites")]
+ public SitePipeBind OrgNewsSiteUrl;
+
+ protected override void ExecuteCmdlet()
+ {
+ Tenant.RemoveOrgNewsSite(OrgNewsSiteUrl.Url);
+ ClientContext.ExecuteQueryRetry();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Commands/Admin/RemoveSiteCollectionAppCatalog.cs b/Commands/Admin/RemoveSiteCollectionAppCatalog.cs
index 929a8547e..985284b64 100644
--- a/Commands/Admin/RemoveSiteCollectionAppCatalog.cs
+++ b/Commands/Admin/RemoveSiteCollectionAppCatalog.cs
@@ -16,7 +16,7 @@ namespace SharePointPnP.PowerShell.Commands.Admin
SupportedPlatform = CmdletSupportedPlatform.Online,
Category = CmdletHelpCategory.TenantAdmin)]
[CmdletExample(
- Code = @"PS:> Remove-PnPOffice365GroupToSite -Url ""https://contoso.sharepoint.com/sites/FinanceTeamsite""",
+ Code = @"PS:> Remove-PnPSiteCollectionAppCatalog -Site ""https://contoso.sharepoint.com/sites/FinanceTeamsite""",
Remarks = @"This will remove a SiteCollection app catalog from the specified site", SortOrder = 1)]
public class RemoveSiteCollectionAppCatalog: PnPAdminCmdlet
{
diff --git a/Commands/Apps/AddApplicationCustomizer.cs b/Commands/Apps/AddApplicationCustomizer.cs
new file mode 100644
index 000000000..536fd7cfc
--- /dev/null
+++ b/Commands/Apps/AddApplicationCustomizer.cs
@@ -0,0 +1,66 @@
+#if !SP2013 && !SP2016
+using System.Management.Automation;
+using Microsoft.SharePoint.Client;
+using OfficeDevPnP.Core.Entities;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Enums;
+using SharePointPnP.PowerShell.Commands.Base.PipeBinds;
+
+namespace SharePointPnP.PowerShell.Commands.Branding
+{
+ [Cmdlet(VerbsCommon.Add, "PnPApplicationCustomizer")]
+ [CmdletHelp("Adds a SharePoint Framework client side extension application customizer",
+ "Adds a SharePoint Framework client side extension application customizer by registering a user custom action to a web or sitecollection",
+ Category = CmdletHelpCategory.Apps,
+ SupportedPlatform = CmdletSupportedPlatform.Online | CmdletSupportedPlatform.SP2019)]
+ [CmdletExample(Code = @"Add-PnPApplicationCustomizer -Title ""CollabFooter"" -ClientSideComponentId c0ab3b94-8609-40cf-861e-2a1759170b43 -ClientSideComponentProperties ""{`""sourceTermSet`"":`""PnP-CollabFooter-SharedLinks`"",`""personalItemsStorageProperty`"":`""PnP-CollabFooter-MyLinks`""}",
+ Remarks = @"Adds a new application customizer to the current web. This requires that a SharePoint Framework solution has been deployed containing the application customizer specified in its manifest. Be sure to run Install-PnPApp before trying this cmdlet on a site.",
+ SortOrder = 1)]
+ public class AddApplicationCustomizer : PnPWebCmdlet
+ {
+ [Parameter(Mandatory = false, HelpMessage = "The title of the application customizer")]
+ public string Title = string.Empty;
+
+ [Parameter(Mandatory = false, HelpMessage = "The description of the application customizer")]
+ public string Description = string.Empty;
+
+ [Parameter(Mandatory = false, HelpMessage = "Sequence of this application customizer being injected. Use when you have a specific sequence with which to have multiple application customizers being added to the page.")]
+ public int Sequence = 0;
+
+ [Parameter(Mandatory = false, HelpMessage = "The scope of the CustomAction to add to. Either Web or Site; defaults to Web. 'All' is not valid for this command.")]
+ public CustomActionScope Scope = CustomActionScope.Web;
+
+ [Parameter(Mandatory = true, HelpMessage = "The Client Side Component Id of the SharePoint Framework client side extension application customizer found in the manifest")]
+ public GuidPipeBind ClientSideComponentId;
+
+ [Parameter(Mandatory = false, HelpMessage = "The Client Side Component Properties of the application customizer. Specify values as a json string : \"{Property1 : 'Value1', Property2: 'Value2'}\"")]
+ public string ClientSideComponentProperties;
+
+ protected override void ExecuteCmdlet()
+ {
+ CustomActionEntity ca = new CustomActionEntity()
+ {
+ Title = Title,
+ Location = "ClientSideExtension.ApplicationCustomizer",
+ ClientSideComponentId = ClientSideComponentId.Id,
+ ClientSideComponentProperties = ClientSideComponentProperties
+ };
+
+ switch (Scope)
+ {
+ case CustomActionScope.Web:
+ SelectedWeb.AddCustomAction(ca);
+ break;
+
+ case CustomActionScope.Site:
+ ClientContext.Site.AddCustomAction(ca);
+ break;
+
+ case CustomActionScope.All:
+ WriteWarning("CustomActionScope 'All' is not supported for adding CustomActions");
+ break;
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Commands/Apps/GetApplicationCustomizer.cs b/Commands/Apps/GetApplicationCustomizer.cs
new file mode 100644
index 000000000..fe92f7f74
--- /dev/null
+++ b/Commands/Apps/GetApplicationCustomizer.cs
@@ -0,0 +1,86 @@
+#if !SP2013 && !SP2016
+using System.Management.Automation;
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base.PipeBinds;
+using SharePointPnP.PowerShell.Commands.Enums;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SharePointPnP.PowerShell.Commands.Branding
+{
+ [Cmdlet(VerbsCommon.Get, "PnPApplicationCustomizer", ConfirmImpact = ConfirmImpact.High, SupportsShouldProcess = true)]
+ [CmdletHelp("Returns all SharePoint Framework client side extension application customizers",
+ "Returns all SharePoint Framework client side extension application customizers registered on the current web and/or site",
+ Category = CmdletHelpCategory.Apps,
+ SupportedPlatform = CmdletSupportedPlatform.Online | CmdletSupportedPlatform.SP2019)]
+ [CmdletExample(Code = @"PS:> Get-PnPApplicationCustomizer",
+ Remarks = @"Returns the custom action representing the SharePoint Framework client side extension registrations registered on the current site collection and web.",
+ SortOrder = 1)]
+ [CmdletExample(Code = @"PS:> Get-PnPApplicationCustomizer -Identity aa66f67e-46c0-4474-8a82-42bf467d07f2",
+ Remarks = @"Returns the custom action representing the SharePoint Framework client side extension registration with the id 'aa66f67e-46c0-4474-8a82-42bf467d07f2'.",
+ SortOrder = 2)]
+ [CmdletExample(Code = @"PS:> Get-PnPApplicationCustomizer -ClientSideComponentId aa66f67e-46c0-4474-8a82-42bf467d07f2 -Scope Web",
+ Remarks = @"Returns the custom action(s) being registered for a SharePoint Framework solution having the id 'aa66f67e-46c0-4474-8a82-42bf467d07f2' in its manifest from the current web.",
+ SortOrder = 3)]
+ public class GetApplicationCustomizer : PnPWebRetrievalsCmdlet
+ {
+ private const string ParameterSet_CUSTOMACTIONID = "Custom Action Id";
+ private const string ParameterSet_CLIENTSIDECOMPONENTID = "Client Side Component Id";
+
+ [Parameter(Mandatory = false, HelpMessage = "Identity of the SharePoint Framework client side extension application customizer to return. Omit to return all SharePoint Frameworkclient side extension application customizer.", ParameterSetName = ParameterSet_CUSTOMACTIONID)]
+ public GuidPipeBind Identity;
+
+ [Parameter(Mandatory = true, HelpMessage = "The Client Side Component Id of the SharePoint Framework client side extension application customizer found in the manifest for which existing custom action(s) should be removed", ParameterSetName = ParameterSet_CLIENTSIDECOMPONENTID)]
+ public GuidPipeBind ClientSideComponentId;
+
+ [Parameter(Mandatory = false, HelpMessage = "Scope of the SharePoint Framework client side extension application customizer, either Web, Site or All to return both (all is the default)")]
+ public CustomActionScope Scope = CustomActionScope.All;
+
+ [Parameter(Mandatory = false, HelpMessage = "Switch parameter if an exception should be thrown if the requested SharePoint Frameworkclient side extension application customizer does not exist (true) or if omitted, nothing will be returned in case the SharePoint Framework client side extension application customizer does not exist")]
+ public SwitchParameter ThrowExceptionIfCustomActionNotFound;
+
+ protected override void ExecuteCmdlet()
+ {
+ List actions = new List();
+
+ if (Scope == CustomActionScope.All || Scope == CustomActionScope.Web)
+ {
+ actions.AddRange(SelectedWeb.GetCustomActions(RetrievalExpressions));
+ }
+ if (Scope == CustomActionScope.All || Scope == CustomActionScope.Site)
+ {
+ actions.AddRange(ClientContext.Site.GetCustomActions(RetrievalExpressions));
+ }
+
+ if (Identity != null)
+ {
+ var foundAction = actions.FirstOrDefault(x => x.Id == Identity.Id && x.Location == "ClientSideExtension.ApplicationCustomizer");
+ if (foundAction != null || !ThrowExceptionIfCustomActionNotFound)
+ {
+ WriteObject(foundAction, true);
+ }
+ else
+ {
+ throw new PSArgumentException($"No SharePoint Framework client side extension application customizer found with the Identity '{Identity.Id}' within the scope '{Scope}'", "Identity");
+ }
+ }
+ else
+ {
+ switch (ParameterSetName)
+ {
+ case ParameterSet_CLIENTSIDECOMPONENTID:
+ actions = actions.Where(x => x.Location == "ClientSideExtension.ApplicationCustomizer" & x.ClientSideComponentId == ClientSideComponentId.Id).ToList();
+ break;
+
+ case ParameterSet_CUSTOMACTIONID:
+ actions = actions.Where(x => x.Location == "ClientSideExtension.ApplicationCustomizer").ToList();
+ break;
+ }
+
+ WriteObject(actions, true);
+ }
+ }
+ }
+}
+#endif
diff --git a/Commands/Apps/RemoveApplicationCustomizer.cs b/Commands/Apps/RemoveApplicationCustomizer.cs
new file mode 100644
index 000000000..b5a0b8fff
--- /dev/null
+++ b/Commands/Apps/RemoveApplicationCustomizer.cs
@@ -0,0 +1,102 @@
+#if !SP2013 && !SP2016
+using System.Management.Automation;
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base.PipeBinds;
+using SharePointPnP.PowerShell.Commands.Enums;
+using Resources = SharePointPnP.PowerShell.Commands.Properties.Resources;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SharePointPnP.PowerShell.Commands.Branding
+{
+ [Cmdlet(VerbsCommon.Remove, "PnPApplicationCustomizer", ConfirmImpact = ConfirmImpact.High, SupportsShouldProcess = true)]
+ [CmdletHelp("Removes a SharePoint Framework client side extension application customizer",
+ "Removes a SharePoint Framework client side extension application customizer by removing a user custom action from a web or sitecollection",
+ Category = CmdletHelpCategory.Apps,
+ SupportedPlatform = CmdletSupportedPlatform.Online | CmdletSupportedPlatform.SP2019)]
+ [CmdletExample(Code = @"PS:> Remove-PnPCustomAction -Identity aa66f67e-46c0-4474-8a82-42bf467d07f2",
+ Remarks = @"Removes the custom action representing the client side extension registration with the id 'aa66f67e-46c0-4474-8a82-42bf467d07f2'.",
+ SortOrder = 1)]
+ [CmdletExample(Code = @"PS:> Remove-PnPCustomAction -ClientSideComponentId aa66f67e-46c0-4474-8a82-42bf467d07f2 -Scope web",
+ Remarks = @"Removes the custom action(s) being registered for a SharePoint Framework solution having the id 'aa66f67e-46c0-4474-8a82-42bf467d07f2' in its manifest from the current web.",
+ SortOrder = 2)]
+ public class RemoveApplicationCustomizer : PnPWebCmdlet
+ {
+ private const string ParameterSet_CUSTOMACTIONID = "Custom Action Id";
+ private const string ParameterSet_CLIENTSIDECOMPONENTID = "Client Side Component Id";
+
+ [Parameter(Mandatory = false, Position = 0, ValueFromPipeline = true, HelpMessage = "The id or name of the CustomAction representing the client side extension registration that needs to be removed or a CustomAction instance itself", ParameterSetName = ParameterSet_CUSTOMACTIONID)]
+ public UserCustomActionPipeBind Identity;
+
+ [Parameter(Mandatory = true, HelpMessage = "The Client Side Component Id of the SharePoint Framework client side extension application customizer found in the manifest for which existing custom action(s) should be removed", ParameterSetName = ParameterSet_CLIENTSIDECOMPONENTID)]
+ public GuidPipeBind ClientSideComponentId;
+
+ [Parameter(Mandatory = false, HelpMessage = "Define if the CustomAction representing the client side extension registration is to be found at the web or site collection scope. Specify All to allow deletion from either web or site collection (default).")]
+ public CustomActionScope Scope = CustomActionScope.All;
+
+ [Parameter(Mandatory = false, HelpMessage = "Use the -Force flag to bypass the confirmation question")]
+ public SwitchParameter Force;
+
+ protected override void ExecuteCmdlet()
+ {
+ List actions = new List();
+
+ if (Identity != null && Identity.UserCustomAction != null)
+ {
+ actions.Add(Identity.UserCustomAction);
+ }
+ else
+ {
+ if (Scope == CustomActionScope.All || Scope == CustomActionScope.Web)
+ {
+ actions.AddRange(SelectedWeb.GetCustomActions());
+ }
+ if (Scope == CustomActionScope.All || Scope == CustomActionScope.Site)
+ {
+ actions.AddRange(ClientContext.Site.GetCustomActions());
+ }
+
+ if (Identity != null)
+ {
+ actions = actions.Where(action => Identity.Id.HasValue ? Identity.Id.Value == action.Id : Identity.Name == action.Name).ToList();
+
+ if (!actions.Any())
+ {
+ throw new PSArgumentException($"No CustomAction representing the client side extension registration found with the {(Identity.Id.HasValue ? "Id" : "name")} '{(Identity.Id.HasValue ? Identity.Id.Value.ToString() : Identity.Name)}' within the scope '{Scope}'", "Identity");
+ }
+ }
+ }
+
+ // Only take the customactions which are application customizers
+ actions = actions.Where(a => a.Location == "ClientSideExtension.ApplicationCustomizer").ToList();
+
+ // If a ClientSideComponentId has been provided, only leave those who have a matching client side component id
+ if (ParameterSetName == ParameterSet_CLIENTSIDECOMPONENTID)
+ {
+ actions = actions.Where(a => a.ClientSideComponentId == ClientSideComponentId.Id).ToList();
+ }
+
+ if (!actions.Any())
+ {
+ WriteVerbose($"No CustomAction representing the client side extension registration found within the scope '{Scope}'");
+ return;
+ }
+
+ foreach (var action in actions.Where(action => Force || (MyInvocation.BoundParameters.ContainsKey("Confirm") && !bool.Parse(MyInvocation.BoundParameters["Confirm"].ToString())) || ShouldContinue(string.Format(Resources.RemoveCustomAction, action.Name, action.Id, action.Scope), Resources.Confirm)))
+ {
+ switch (action.Scope)
+ {
+ case UserCustomActionScope.Web:
+ SelectedWeb.DeleteCustomAction(action.Id);
+ break;
+
+ case UserCustomActionScope.Site:
+ ClientContext.Site.DeleteCustomAction(action.Id);
+ break;
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/Commands/Apps/SetApplicationCustomizer.cs b/Commands/Apps/SetApplicationCustomizer.cs
new file mode 100644
index 000000000..ba98bc040
--- /dev/null
+++ b/Commands/Apps/SetApplicationCustomizer.cs
@@ -0,0 +1,126 @@
+#if !SP2013 && !SP2016
+using System.Management.Automation;
+using Microsoft.SharePoint.Client;
+using SharePointPnP.PowerShell.CmdletHelpAttributes;
+using SharePointPnP.PowerShell.Commands.Base.PipeBinds;
+using SharePointPnP.PowerShell.Commands.Enums;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SharePointPnP.PowerShell.Commands.Branding
+{
+ [Cmdlet(VerbsCommon.Set, "PnPApplicationCustomizer", ConfirmImpact = ConfirmImpact.High, SupportsShouldProcess = true)]
+ [CmdletHelp("Updates a SharePoint Framework client side extension application customizer",
+ "Updates a SharePoint Framework client side extension application customizer by updating its custom action. Only the properties that will be provided will be updated. Others will remain as they are.",
+ Category = CmdletHelpCategory.Apps,
+ SupportedPlatform = CmdletSupportedPlatform.Online | CmdletSupportedPlatform.SP2019)]
+ [CmdletExample(Code = @"PS:> Set-PnPCustomAction -Identity aa66f67e-46c0-4474-8a82-42bf467d07f2",
+ Remarks = @"Updates the custom action representing the client side extension registration with the id 'aa66f67e-46c0-4474-8a82-42bf467d07f2'.",
+ SortOrder = 1)]
+ [CmdletExample(Code = @"PS:> Set-PnPCustomAction -ClientSideComponentId aa66f67e-46c0-4474-8a82-42bf467d07f2 -Scope web -ClientSideComponentProperties ""{`""sourceTermSet`"":`""PnP-CollabFooter-SharedLinks`"",`""personalItemsStorageProperty`"":`""PnP-CollabFooter-MyLinks`""}",
+ Remarks = @"Updates the custom action(s) properties being registered for a SharePoint Framework solution having the id 'aa66f67e-46c0-4474-8a82-42bf467d07f2' in its manifest from the current web.",
+ SortOrder = 2)]
+ public class SetApplicationCustomizer : PnPWebCmdlet
+ {
+ private const string ParameterSet_CUSTOMACTIONID = "Custom Action Id";
+ private const string ParameterSet_CLIENTSIDECOMPONENTID = "Client Side Component Id";
+
+ [Parameter(Mandatory = false, Position = 0, ValueFromPipeline = true, HelpMessage = "The id or name of the CustomAction representing the client side extension registration that needs to be updated or a CustomAction instance itself", ParameterSetName = ParameterSet_CUSTOMACTIONID)]
+ public UserCustomActionPipeBind Identity = null;
+
+ [Parameter(Mandatory = false, HelpMessage = "The Client Side Component Id of the SharePoint Framework client side extension application customizer found in the manifest for which existing custom action(s) should be updated", ParameterSetName = ParameterSet_CLIENTSIDECOMPONENTID)]
+ public GuidPipeBind ClientSideComponentId = null;
+
+ [Parameter(Mandatory = false, HelpMessage = "Define if the CustomAction representing the client side extension registration is to be found at the web or site collection scope. Specify All to update the component on both web and site collection level.")]
+ public CustomActionScope Scope = CustomActionScope.Web;
+
+ [Parameter(Mandatory = false, HelpMessage = "The title of the application customizer. Omit to not update this property.")]
+ public string Title = null;
+
+ [Parameter(Mandatory = false, HelpMessage = "The description of the application customizer. Omit to not update this property.")]
+ public string Description = null;
+
+ [Parameter(Mandatory = false, HelpMessage = "Sequence of this application customizer being injected. Use when you have a specific sequence with which to have multiple application customizers being added to the page. Omit to not update this property.")]
+ public int? Sequence = null;
+
+ [Parameter(Mandatory = false, HelpMessage = "The Client Side Component Properties of the application customizer to update. Specify values as a json string : \"{Property1 : 'Value1', Property2: 'Value2'}\". Omit to not update this property.")]
+ public string ClientSideComponentProperties = null;
+
+ protected override void ExecuteCmdlet()
+ {
+ List actions = new List();
+
+ if (Identity != null && Identity.UserCustomAction != null)
+ {
+ actions.Add(Identity.UserCustomAction);
+ }
+ else
+ {
+ if (Scope == CustomActionScope.All || Scope == CustomActionScope.Web)
+ {
+ actions.AddRange(SelectedWeb.GetCustomActions());
+ }
+ if (Scope == CustomActionScope.All || Scope == CustomActionScope.Site)
+ {
+ actions.AddRange(ClientContext.Site.GetCustomActions());
+ }
+
+ if (Identity != null)
+ {
+ actions = actions.Where(action => Identity.Id.HasValue ? Identity.Id.Value == action.Id : Identity.Name == action.Name).ToList();
+
+ if (!actions.Any())
+ {
+ throw new PSArgumentException($"No CustomAction representing the client side extension registration found with the {(Identity.Id.HasValue ? "Id" : "name")} '{(Identity.Id.HasValue ? Identity.Id.Value.ToString() : Identity.Name)}' within the scope '{Scope}'", "Identity");
+ }
+ }
+ }
+
+ // If a ClientSideComponentId has been provided, only leave those who have a matching client side component id
+ if(ParameterSetName == ParameterSet_CLIENTSIDECOMPONENTID)
+ {
+ actions = actions.Where(a => a.ClientSideComponentId == ClientSideComponentId.Id && a.Location == "ClientSideExtension.ApplicationCustomizer").ToList();
+ }
+
+ if (!actions.Any())
+ {
+ WriteVerbose($"No CustomAction representing the client side extension registration found within the scope '{Scope}'");
+ return;
+ }
+
+ // Update each of the matched custom actions
+ foreach (var action in actions)
+ {
+ bool isDirty = false;
+
+ if(Title != null)
+ {
+ action.Title = Title;
+ isDirty = true;
+ }
+ if(Description != null)
+ {
+ action.Description = Description;
+ isDirty = true;
+ }
+ if (Sequence.HasValue)
+ {
+ action.Sequence = Sequence.Value;
+ isDirty = true;
+ }
+ if (ClientSideComponentProperties != null)
+ {
+ action.ClientSideComponentProperties = ClientSideComponentProperties;
+ isDirty = true;
+ }
+
+ if (isDirty)
+ {
+ action.Update();
+ ClientContext.ExecuteQueryRetry();
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/Commands/Base/AddStoredCredential.cs b/Commands/Base/AddStoredCredential.cs
index 1f0e20f96..6f5c6a0f2 100644
--- a/Commands/Base/AddStoredCredential.cs
+++ b/Commands/Base/AddStoredCredential.cs
@@ -7,7 +7,7 @@
namespace SharePointPnP.PowerShell.Commands.Base
{
[Cmdlet(VerbsCommon.Add, "PnPStoredCredential")]
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
[CmdletHelp("Adds a credential to the Windows Credential Manager",
@"Adds an entry to the Windows Credential Manager. If you add an entry in the form of the URL of your tenant/server PnP PowerShell will check if that entry is available when you connect using Connect-PnPOnline. If it finds a matching URL it will use the associated credentials.
@@ -41,7 +41,7 @@ public class AddStoredCredential : PSCmdlet
[Parameter(Mandatory = false, HelpMessage = @"If not specified you will be prompted to enter your password.
If you want to specify this value use ConvertTo-SecureString -String 'YourPassword' -AsPlainText -Force")]
public SecureString Password;
-#if NETSTANDARD2_0
+#if NETSTANDARD2_1
[Parameter(Mandatory = false)]
public SwitchParameter Overwrite;
#endif
@@ -53,7 +53,7 @@ protected override void ProcessRecord()
Password = Host.UI.ReadLineAsSecureString();
}
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
Utilities.CredentialManager.AddCredential(Name, Username, Password);
#else
Utilities.CredentialManager.AddCredential(Name, Username, Password, Overwrite.ToBool());
diff --git a/Commands/Base/ConnectOnline.cs b/Commands/Base/ConnectOnline.cs
index d22bfb160..52e134936 100644
--- a/Commands/Base/ConnectOnline.cs
+++ b/Commands/Base/ConnectOnline.cs
@@ -13,7 +13,8 @@
using System.Reflection;
using System.Security;
using File = System.IO.File;
-#if NETSTANDARD2_0
+using System.Security.Cryptography.X509Certificates;
+#if NETSTANDARD2_1
using System.IdentityModel.Tokens.Jwt;
#endif
#if !ONPREMISES
@@ -51,82 +52,107 @@ namespace SharePointPnP.PowerShell.Commands.Base
Code = @"PS:> Connect-PnPOnline -Url http://yourlocalserver -Credentials (Get-Credential) -UseAdfs",
Remarks = @"This will prompt for username and password and creates a context using ADFS to authenticate.",
SortOrder = 5)]
+#if !NETSTANDARD2_1
+ [CmdletExample(
+ Code = @"PS:> Connect-PnPOnline -Url http://yourlocalserver -UseAdfsCert",
+ Remarks = @"This will enable you to select a certificate to create a context using ADFS to authenticate.",
+ SortOrder = 6)]
+#endif
[CmdletExample(
Code = @"PS:> Connect-PnPOnline -Url https://yourserver -Credentials (Get-Credential) -CreateDrive
PS:> cd SPO:\\
PS:> dir",
Remarks = @"This will prompt you for credentials and creates a context for the other PowerShell commands to use. It will also create a SPO:\\ drive you can use to navigate around the site",
- SortOrder = 6)]
+ SortOrder = 7)]
[CmdletExample(
Code = @"PS:> Connect-PnPOnline -Url https://yourserver -Credentials (Get-Credential) -AuthenticationMode FormsAuthentication",
Remarks = @"This will prompt you for credentials and creates a context for the other PowerShell commands to use. It assumes your server is configured for Forms Based Authentication (FBA)",
- SortOrder = 7)]
+ SortOrder = 8)]
#if !ONPREMISES
[CmdletExample(
Code = @"PS:> Connect-PnPOnline -Url https://contoso.sharepoint.de -AppId 344b8aab-389c-4e4a-8fa1-4c1ae2c0a60d -AppSecret a3f3faf33f3awf3a3sfs3f3ss3f4f4a3fawfas3ffsrrffssfd -AzureEnvironment Germany",
Remarks = @"This will authenticate you to the German Azure environment using the German Azure endpoints for authentication",
- SortOrder = 8)]
+ SortOrder = 9)]
#endif
#if !ONPREMISES
[CmdletExample(
Code = @"PS:> Connect-PnPOnline -Url https://contoso.sharepoint.com -SPOManagementShell",
Remarks = @"This will authenticate you using the SharePoint Online Management Shell application",
- SortOrder = 9)]
+ SortOrder = 10)]
#endif
#if !ONPREMISES
[CmdletExample(
Code = @"PS:> Connect-PnPOnline -Url https://contoso.sharepoint.com -PnPO365ManagementShell",
Remarks = @"This will authenticate you using the PnP O365 Management Shell Multi-Tenant application. A browser window will have to be opened where you have to enter a code that is shown in your PowerShell window.",
- SortOrder = 10)]
+ SortOrder = 11)]
[CmdletExample(
Code = @"PS:> Connect-PnPOnline -Url https://contoso.sharepoint.com -PnPO365ManagementShell -LaunchBrowser",
Remarks = @"This will authenticate you using the PnP O365 Management Shell Multi-Tenant application. A browser window will automatically open and the code you need to enter will be automatically copied to your clipboard.",
- SortOrder = 11)]
+ SortOrder = 12)]
#endif
#if !ONPREMISES
[CmdletExample(
Code = @"PS:> Connect-PnPOnline -Url https://contoso.sharepoint.com -AccessToken $myaccesstoken",
Remarks = @"This will authenticate you using the provided access token",
- SortOrder = 12)]
+ SortOrder = 13)]
#endif
#if !ONPREMISES
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
[CmdletExample(
Code = "PS:> Connect-PnPOnline -Scopes \"Mail.Read\",\"Files.Read\"",
Remarks = "Connects to Azure AD and gets and OAuth 2.0 Access Token to consume the Microsoft Graph API including the declared permission scopes. The available permission scopes are defined at the following URL: https://docs.microsoft.com/en-us/graph/permissions-reference",
- SortOrder = 13)]
+ SortOrder = 14)]
#endif
#endif
#if !ONPREMISES
[CmdletExample(
Code = "PS:> Connect-PnPOnline -AppId '' -AppSecret '' -AADDomain 'contoso.onmicrosoft.com'",
Remarks = "Connects to the Microsoft Graph API using application permissions via an app's declared permission scopes. See https://github.com/SharePoint/PnP-PowerShell/tree/master/Samples/Graph.ConnectUsingAppPermissions for a sample on how to get started.",
- SortOrder = 14)]
+ SortOrder = 15)]
[CmdletExample(
Code = "PS:> Connect-PnPOnline -Url https://contoso.sharepoint.com -ClientId '' -Tenant 'contoso.onmicrosoft.com' -CertificatePath c:\\absolute-path\\to\\pnp.pfx -CertificatePassword ",
Remarks = "Connects to SharePoint using app-only tokens via an app's declared permission scopes. See https://github.com/SharePoint/PnP-PowerShell/tree/master/Samples/SharePoint.ConnectUsingAppPermissions for a sample on how to get started.",
- SortOrder = 15)]
+ SortOrder = 16)]
[CmdletExample(
Code = "PS:> Connect-PnPOnline -Url https://contoso.sharepoint.com -ClientId '' -Tenant 'contoso.onmicrosoft.com' -Thumbprint 34CFAA860E5FB8C44335A38A097C1E41EEA206AA",
Remarks = "Connects to SharePoint using app-only tokens via an app's declared permission scopes. See https://github.com/SharePoint/PnP-PowerShell/tree/master/Samples/SharePoint.ConnectUsingAppPermissions for a sample on how to get started.",
- SortOrder = 16)]
+ SortOrder = 17)]
[CmdletExample(
Code = "PS:> Connect-PnPOnline -Url https://contoso.sharepoint.com -ClientId '' -Tenant 'contoso.onmicrosoft.com' -PEMCertificate -PEMPrivateKey -CertificatePassword ",
Remarks = "Connects to SharePoint using app-only tokens via an app's declared permission scopes. See https://github.com/SharePoint/PnP-PowerShell/tree/master/Samples/SharePoint.ConnectUsingAppPermissions for a sample on how to get started.",
SortOrder = 17)]
+ [CmdletExample(
+ Code = "PS:> Connect-PnPOnline -Url https://contoso.sharepoint.com -ClientId '' -Tenant 'contoso.onmicrosoft.com' -Certificate ",
+ Remarks = "Connects to SharePoint using app-only auth in combination with a certificate. See https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread#using-this-principal-in-your-powershell-script-using-the-pnp-sites-core-library for a sample on how to get started.",
+ SortOrder = 18)]
#endif
#if ONPREMISES
[CmdletExample(
Code = @"PS:> certutil.exe -csp 'Microsoft Enhanced RSA and AES Cryptographic Provider' -v -p 'password' -importpfx -user c:\HighTrust.pfx NoRoot
PS:> Connect-PnPOnline -Url https://yourserver -ClientId -HighTrustCertificate (Get-Item Cert:\CurrentUser\My\)",
Remarks = @"Connect to an on-premises SharePoint environment using a high trust certificate, stored in the Personal certificate store of the current user.",
- SortOrder = 14)]
+ SortOrder = 15)]
[CmdletExample(
Code = @"PS:> Connect-PnPOnline -Url https://yourserver -ClientId 763d5e60-b57e-426e-8e87-b7258f7f8188 -HighTrustCertificatePath c:\HighTrust.pfx -HighTrustCertificatePassword 'password' -HighTrustCertificateIssuerId 6b9534d8-c2c1-49d6-9f4b-cd415620bca8",
Remarks = @"Connect to an on-premises SharePoint environment using a high trust certificate stored in a .PFX file.",
- SortOrder = 15)]
+ SortOrder = 16)]
#endif
- public class ConnectOnline : PSCmdlet
+#if !ONPREMISES
+ [CmdletExample(
+ Code = "PS:> Connect-PnPOnline -ClientId -CertificatePath 'c:\\mycertificate.pfx' -CertificatePassword (ConvertTo-SecureString -AsPlainText 'myprivatekeypassword' -Force) -Url https://contoso.sharepoint.com -Tenant 'contoso.onmicrosoft.com'",
+ Remarks = "Connects using an Azure Active Directory registered application using a locally available certificate containing a private key. See https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread for a sample on how to get started.",
+ SortOrder = 16)]
+ [CmdletExample(
+ Code = "PS:> Connect-PnPOnline -ClientId -CertificateBase64Encoded 'xxxx' -CertificatePassword (ConvertTo-SecureString -AsPlainText 'myprivatekeypassword' -Force) -Url https://contoso.sharepoint.com -Tenant 'contoso.onmicrosoft.com'",
+ Remarks = "Connects using an Azure Active Directory registered application using a certificate containing a private key encoded in base 64 such as received in an Azure Function when using Azure KeyVault. See https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread for a sample on how to get started.",
+ SortOrder = 17)]
+ [CmdletExample(
+ Code = "PS:> Connect-PnPOnline -ClientId -Certificate $cert -CertificatePassword (ConvertTo-SecureString -AsPlainText 'myprivatekeypassword' -Force) -Url https://contoso.sharepoint.com -Tenant 'contoso.onmicrosoft.com'",
+ Remarks = "Connects using an Azure Active Directory registered application using a certificate instance containing a private key. See https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread for a sample on how to get started.",
+ SortOrder = 18)]
+
+#endif
+ public class ConnectOnline : BasePSCmdlet
{
private const string ParameterSet_MAIN = "Main";
private const string ParameterSet_TOKEN = "Token";
@@ -135,12 +161,12 @@ public class ConnectOnline : PSCmdlet
private const string ParameterSet_NATIVEAAD = "Azure Active Directory";
private const string ParameterSet_APPONLYAAD = "App-Only with Azure Active Directory";
private const string ParameterSet_APPONLYAADPEM = "App-Only with Azure Active Directory using certificate as PEM strings";
-
+ private const string ParameterSet_APPONLYAADCER = "App-Only with Azure Active Directory using X502 certificates";
private const string ParameterSet_APPONLYAADThumb = "App-Only with Azure Active Directory using certificate from certificate store by thumbprint";
private const string ParameterSet_SPOMANAGEMENT = "SPO Management Shell Credentials";
private const string ParameterSet_DEVICELOGIN = "PnP O365 Management Shell / DeviceLogin";
private const string ParameterSet_GRAPHDEVICELOGIN = "PnP Office 365 Management Shell to the Microsoft Graph";
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
private const string ParameterSet_GRAPHWITHSCOPE = "Microsoft Graph using Scopes";
#endif
private const string ParameterSet_GRAPHWITHAAD = "Microsoft Graph using Azure Active Directory";
@@ -166,6 +192,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, ValueFromPipeline = true, HelpMessage = "Returns the connection for use with the -Connection parameter on cmdlets.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, ValueFromPipeline = true, HelpMessage = "Returns the connection for use with the -Connection parameter on cmdlets.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, ValueFromPipeline = true, HelpMessage = "Returns the connection for use with the -Connection parameter on cmdlets.")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, ValueFromPipeline = true, HelpMessage = "Returns the connection for use with the -Connection parameter on cmdlets.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, ValueFromPipeline = true, HelpMessage = "Returns the connection for use with the -Connection parameter on cmdlets.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACCESSTOKEN, ValueFromPipeline = true, HelpMessage = "Returns the connection for use with the -Connection parameter on cmdlets.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_DEVICELOGIN, ValueFromPipeline = true, HelpMessage = "Returns the connection for use with the -Connection parameter on cmdlets.")]
@@ -183,7 +210,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_NATIVEAAD, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")]
[Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_APPONLYAAD, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")]
[Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_APPONLYAADPEM, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")]
- [Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_APPONLYAADThumb, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")]
+ [Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_APPONLYAADCER, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")][Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_APPONLYAADThumb, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")]
[Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_SPOMANAGEMENT, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")]
[Parameter(Mandatory = false, Position = 0, ParameterSetName = ParameterSet_ACCESSTOKEN, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")]
[Parameter(Mandatory = true, Position = 0, ParameterSetName = ParameterSet_DEVICELOGIN, ValueFromPipeline = true, HelpMessage = "The Url of the site collection to connect to.")]
@@ -203,6 +230,9 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_MAIN, HelpMessage = "If you want to connect to your on-premises SharePoint farm using ADFS")]
public SwitchParameter UseAdfs;
+ [Parameter(Mandatory = false, ParameterSetName = "Main", HelpMessage = "If you want to connect to your SharePoint farm using ADFS with Certificate Authentication")]
+ public SwitchParameter UseAdfsCert;
+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_MAIN, HelpMessage = "Authenticate using Kerberos to an on-premises ADFS instance.")]
public SwitchParameter Kerberos;
@@ -217,6 +247,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Specifies a minimal server healthscore before any requests are executed.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "Specifies a minimal server healthscore before any requests are executed.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "Specifies a minimal server healthscore before any requests are executed.")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "Specifies a minimal server healthscore before any requests are executed.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "Specifies a minimal server healthscore before any requests are executed.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACCESSTOKEN, HelpMessage = "Specifies a minimal server healthscore before any requests are executed.")]
#endif
@@ -234,6 +265,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Defines how often a retry should be executed if the server healthscore is not sufficient. Default is 10 times.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "Defines how often a retry should be executed if the server healthscore is not sufficient. Default is 10 times.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "Defines how often a retry should be executed if the server healthscore is not sufficient. Default is 10 times.")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "Defines how often a retry should be executed if the server healthscore is not sufficient. Default is 10 times.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "Defines how often a retry should be executed if the server healthscore is not sufficient. Default is 10 times.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACCESSTOKEN, HelpMessage = "Defines how often a retry should be executed if the server healthscore is not sufficient. Default is 10 times.")]
#endif
@@ -251,6 +283,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Defines how many seconds to wait before each retry. Default is 1 second.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "Defines how many seconds to wait before each retry. Default is 1 second.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "Defines how many seconds to wait before each retry. Default is 1 second.")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "Defines how many seconds to wait before each retry. Default is 1 second.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "Defines how many seconds to wait before each retry. Default is 1 second.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACCESSTOKEN, HelpMessage = "Defines how many seconds to wait before each retry. Default is 1 second.")]
#endif
@@ -268,6 +301,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "The request timeout. Default is 1800000")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "The request timeout. Default is 1800000")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "The request timeout. Default is 1800000")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "The request timeout. Default is 180000")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "The request timeout. Default is 1800000")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACCESSTOKEN, HelpMessage = "The request timeout. Default is 1800000")]
#endif
@@ -306,6 +340,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "If you want to create a PSDrive connected to the URL")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "If you want to create a PSDrive connected to the URL")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "If you want to create a PSDrive connected to the URL")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "If you want to create a PSDrive connected to the URL")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "If you want to create a PSDrive connected to the URL")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACCESSTOKEN, HelpMessage = "If you want to create a PSDrive connected to the URL")]
#endif
@@ -323,6 +358,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Name of the PSDrive to create (default: SPO)")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "Name of the PSDrive to create (default: SPO)")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "Name of the PSDrive to create (default: SPO)")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "Name of the PSDrive to create (default: SPO)")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "Name of the PSDrive to create (default: SPO)")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACCESSTOKEN, HelpMessage = "Name of the PSDrive to create (default: SPO)")]
#endif
@@ -370,6 +406,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "The Client ID of the Azure AD Application")]
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "The Client ID of the Azure AD Application")]
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "The Client ID of the Azure AD Application")]
+ [Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "The Client ID of the Azure AD Application")]
#endif
#if ONPREMISES
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_HIGHTRUST_CERT, HelpMessage = "The Client ID of the Add-In Registration in SharePoint. Used as the HighTrustCertificateIssuerId if none is specified.")]
@@ -384,11 +421,18 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "The Azure AD Tenant name,e.g. mycompany.onmicrosoft.com")]
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "The Azure AD Tenant name,e.g. mycompany.onmicrosoft.com")]
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "The Azure AD Tenant name,e.g. mycompany.onmicrosoft.com")]
+ [Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "The Azure AD Tenant name,e.g. mycompany.onmicrosoft.com")]
public string Tenant;
- [Parameter(Mandatory = true, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Path to the certificate (*.pfx)")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Path to the certificate containing the private key (*.pfx)")]
public string CertificatePath;
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Base64 Encoded X509Certificate2 certificate containing the private key to authenticate the requests to SharePoint Online such as retrieved in Azure Functions from Azure KeyVault")]
+ public string CertificateBase64Encoded;
+
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "X509Certificate2 reference containing the private key to authenticate the requests to SharePoint Online")]
+ public System.Security.Cryptography.X509Certificates.X509Certificate2 Certificate;
+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Password to the certificate (*.pfx)")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "Password to the certificate (*.pfx)")]
public SecureString CertificatePassword;
@@ -410,9 +454,10 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "The Azure environment to use for authentication, the defaults to 'Production' which is the main Azure environment.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "The Azure environment to use for authentication, the defaults to 'Production' which is the main Azure environment.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "The Azure environment to use for authentication, the defaults to 'Production' which is the main Azure environment.")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "The Azure environment to use for authentication, the defaults to 'Production' which is the main Azure environment.")]
public AzureEnvironment AzureEnvironment = AzureEnvironment.Production;
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_MAIN, HelpMessage = "The array of permission scopes for the Microsoft Graph API.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOKEN, HelpMessage = "The array of permission scopes for the Microsoft Graph API.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_WEBLOGIN, HelpMessage = "The array of permission scopes for the Microsoft Graph API.")]
@@ -437,6 +482,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "The url to the Tenant Admin site. If not specified, the cmdlets will assume to connect automatically to https://-admin.sharepoint.com where appropriate.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "The url to the Tenant Admin site. If not specified, the cmdlets will assume to connect automatically to https://-admin.sharepoint.com where appropriate.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "The url to the Tenant Admin site. If not specified, the cmdlets will assume to connect automatically to https://-admin.sharepoint.com where appropriate.")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "The url to the Tenant Admin site. If not specified, the cmdlets will assume to connect automatically to https://-admin.sharepoint.com where appropriate.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "The url to the Tenant Admin site. If not specified, the cmdlets will assume to connect automatically to https://-admin.sharepoint.com where appropriate.")]
#endif
#if ONPREMISES
@@ -454,7 +500,7 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Should we skip the check if this site is the Tenant admin site. Default is false")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "Should we skip the check if this site is the Tenant admin site. Default is false")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "Should we skip the check if this site is the Tenant admin site. Default is false")]
- [Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "Should we skip the check if this site is the Tenant admin site. Default is false")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "Should we skip the check if this site is the Tenant admin site. Default is false")][Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "Should we skip the check if this site is the Tenant admin site. Default is false")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_ACCESSTOKEN, HelpMessage = "Should we skip the check if this site is the Tenant admin site. Default is false")]
#endif
#if ONPREMISES
@@ -471,8 +517,11 @@ public class ConnectOnline : PSCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAAD, HelpMessage = "Ignores any SSL errors. To be used i.e. when connecting to a SharePoint farm using self signed certificates or using a certificate authority not trusted by this machine.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADPEM, HelpMessage = "Ignores any SSL errors. To be used i.e. when connecting to a SharePoint farm using self signed certificates or using a certificate authority not trusted by this machine.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADThumb, HelpMessage = "Ignores any SSL errors. To be used i.e. when connecting to a SharePoint farm using self signed certificates or using a certificate authority not trusted by this machine.")]
+ [Parameter(Mandatory = false, ParameterSetName = ParameterSet_APPONLYAADCER, HelpMessage = "Ignores any SSL errors. To be used i.e. when connecting to a SharePoint farm using self signed certificates or using a certificate authority not trusted by this machine.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_GRAPHWITHAAD, HelpMessage = "Ignores any SSL errors. To be used i.e. when connecting through a proxy to the Microsoft Graph API which has SSL interception enabled.")]
+#if !NETSTANDARD2_1
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_GRAPHWITHSCOPE, HelpMessage = "Ignores any SSL errors. To be used i.e. when connecting through a proxy to the Microsoft Graph API which has SSL interception enabled.")]
+#endif
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_GRAPHDEVICELOGIN, HelpMessage = "Ignores any SSL errors. To be used i.e. when connecting through a proxy to the Microsoft Graph API which has SSL interception enabled.")]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_SPOMANAGEMENT, HelpMessage = "Ignores any SSL errors. To be used i.e. when connecting to a SharePoint farm using self signed certificates or using a certificate authority not trusted by this machine.")]
#endif
@@ -535,7 +584,7 @@ protected void Connect()
}
else if (UseWebLogin)
{
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
connection = SPOnlineConnectionHelper.InstantiateWebloginConnection(new Uri(Url), MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, Host, SkipTenantAdminCheck);
#else
WriteWarning(@"-UseWebLogin is not implemented, due to restrictions of the .NET Standard framework.
@@ -551,7 +600,7 @@ protected void Connect()
creds = Host.UI.PromptForCredential(Properties.Resources.EnterYourCredentials, "", "", "");
}
}
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
connection = SPOnlineConnectionHelper.InstantiateAdfsConnection(new Uri(Url),
Kerberos,
creds,
@@ -568,6 +617,22 @@ protected void Connect()
throw new NotImplementedException();
#endif
}
+#if !NETSTANDARD2_1
+ else if (UseAdfsCert)
+ {
+ // Modal Dialog to enable a user to select a certificate to use to authenticate against ADFS
+ X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
+ store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
+ var certs = X509Certificate2UI.SelectFromCollection(store.Certificates, "Select ADFS User Certificate", "Selec the certificate to use to authenticate to ADFS", X509SelectionFlag.SingleSelection);
+
+ if (certs[0] != null)
+ {
+ var serialNumber = certs[0].SerialNumber;
+
+ SPOnlineConnection.CurrentConnection = SPOnlineConnectionHelper.InstantiateAdfsCertificateConnection(new Uri(Url), serialNumber, Host, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, SkipTenantAdminCheck);
+ }
+ }
+#endif
#if !ONPREMISES
else if (ParameterSetName == ParameterSet_SPOMANAGEMENT)
{
@@ -587,16 +652,28 @@ protected void Connect()
}
else if (ParameterSetName == ParameterSet_APPONLYAAD)
{
-#if !NETSTANDARD2_0
- WriteWarning(@"Your certificate is copied by the operating system to c:\ProgramData\Microsoft\Crypto\RSA\MachineKeys. Over time this folder may increase heavily in size. Use Disconnect-PnPOnline in your scripts remove the certificate from this folder to clean up. Consider using -Thumbprint instead of -CertificatePath.");
- connection = SPOnlineConnectionHelper.InitiateAzureADAppOnlyConnection(new Uri(Url), ClientId, Tenant, CertificatePath, CertificatePassword, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, Host, NoTelemetry, SkipTenantAdminCheck, AzureEnvironment);
+#if !NETSTANDARD2_1
+ if (MyInvocation.BoundParameters.ContainsKey("CertificatePath"))
+ {
+ connection = SPOnlineConnectionHelper.InitiateAzureADAppOnlyConnection(new Uri(Url), ClientId, Tenant, CertificatePath, CertificatePassword, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, Host, NoTelemetry, SkipTenantAdminCheck, AzureEnvironment);
+ WriteWarning(@"Your certificate is copied by the operating system to c:\ProgramData\Microsoft\Crypto\RSA\MachineKeys. Over time this folder may increase heavily in size. Use Disconnect-PnPOnline in your scripts remove the certificate from this folder to clean up. Consider using -Thumbprint instead of -CertificatePath.");
+ } else if (MyInvocation.BoundParameters.ContainsKey("Certificate"))
+ {
+ connection = SPOnlineConnectionHelper.InitiateAzureAdAppOnlyConnectionWithCert(new Uri(Url), ClientId, Tenant, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, Host, NoTelemetry, SkipTenantAdminCheck, AzureEnvironment, Certificate);
+ } else if (MyInvocation.BoundParameters.ContainsKey("CertificateBase64Encoded"))
+ {
+ connection = SPOnlineConnectionHelper.InitiateAzureAdAppOnlyConnectionWithCert(new Uri(Url), ClientId, Tenant, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, Host, NoTelemetry, SkipTenantAdminCheck, AzureEnvironment, CertificateBase64Encoded);
+ } else
+ {
+ throw new ArgumentException("You must either provide CertificatePath, Certificate or CertificateBase64Encoded when connecting using an Azure Active Directory registered application");
+ }
#else
throw new NotImplementedException();
#endif
}
else if (ParameterSetName == ParameterSet_APPONLYAADPEM)
{
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
connection = SPOnlineConnectionHelper.InitiateAzureADAppOnlyConnection(new Uri(Url), ClientId, Tenant, PEMCertificate, PEMPrivateKey, CertificatePassword, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, Host, NoTelemetry, SkipTenantAdminCheck, AzureEnvironment);
#else
throw new NotImplementedException();
@@ -604,13 +681,21 @@ protected void Connect()
}
else if (ParameterSetName == ParameterSet_APPONLYAADThumb)
{
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
connection = SPOnlineConnectionHelper.InitiateAzureADAppOnlyConnection(new Uri(Url), ClientId, Tenant, Thumbprint, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, Host, NoTelemetry, SkipTenantAdminCheck, AzureEnvironment);
#else
throw new NotImplementedException();
#endif
}
-#if !NETSTANDARD2_0
+ else if (ParameterSetName == ParameterSet_APPONLYAADCER)
+ {
+#if !NETSTANDARD2_1
+ connection = SPOnlineConnectionHelper.InitiateAzureADAppOnlyConnection(new Uri(Url), ClientId, Tenant, Certificate, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, Host, NoTelemetry, SkipTenantAdminCheck, AzureEnvironment);
+#else
+ throw new NotImplementedException();
+#endif
+ }
+#if !NETSTANDARD2_1
else if (ParameterSetName == ParameterSet_GRAPHWITHSCOPE)
{
ConnectGraphScopes();
@@ -675,7 +760,7 @@ protected void Connect()
connection = SPOnlineConnectionHelper.InstantiateSPOnlineConnection(new Uri(Url), creds, Host, CurrentCredentials, MinimalHealthScore, RetryCount, RetryWait, RequestTimeout, TenantAdminUrl, NoTelemetry, SkipTenantAdminCheck, AuthenticationMode);
}
#if !ONPREMISES
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
if (MyInvocation.BoundParameters.ContainsKey("Scopes") && ParameterSetName != ParameterSet_GRAPHWITHSCOPE)
{
ConnectGraphScopes();
@@ -733,7 +818,7 @@ private SPOnlineConnection ConnectNativeAAD(string clientId, string redirectUrl)
File.Delete(configFile);
}
}
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
return SPOnlineConnectionHelper.InitiateAzureADNativeApplicationConnection(
new Uri(Url), clientId, new Uri(redirectUrl), MinimalHealthScore, RetryCount,
RetryWait, RequestTimeout, TenantAdminUrl, Host, NoTelemetry, SkipTenantAdminCheck, AzureEnvironment);
@@ -742,7 +827,7 @@ private SPOnlineConnection ConnectNativeAAD(string clientId, string redirectUrl)
#endif
}
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
private void ConnectGraphScopes()
{
var clientApplication = new PublicClientApplication(MSALPnPPowerShellClientId);
@@ -841,7 +926,7 @@ private void ConnectGraphAAD()
{
var appCredentials = new ClientCredential(AppSecret);
var authority = new Uri(GraphAADLogin, AADDomain).AbsoluteUri;
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
var clientApplication = new ConfidentialClientApplication(authority, AppId, RedirectUri, appCredentials, null);
var authenticationResult = clientApplication.AcquireTokenForClient(GraphDefaultScope, null).GetAwaiter().GetResult();
SPOnlineConnection.AuthenticationResult = authenticationResult;
diff --git a/Commands/Base/DisablePowerShellTelemetry.cs b/Commands/Base/DisablePowerShellTelemetry.cs
index e052b3a61..d338eff1b 100644
--- a/Commands/Base/DisablePowerShellTelemetry.cs
+++ b/Commands/Base/DisablePowerShellTelemetry.cs
@@ -1,6 +1,6 @@
using SharePointPnP.PowerShell.CmdletHelpAttributes;
using System;
-#if NETSTANDARD2_0
+#if NETSTANDARD2_1
using System.IdentityModel.Tokens.Jwt;
#else
using System.IdentityModel.Tokens;
diff --git a/Commands/Base/DisconnectSPOnline.cs b/Commands/Base/DisconnectSPOnline.cs
index 48c41b733..4c175dc0c 100644
--- a/Commands/Base/DisconnectSPOnline.cs
+++ b/Commands/Base/DisconnectSPOnline.cs
@@ -25,11 +25,13 @@ protected override void ProcessRecord()
#if !ONPREMISES
if(SPOnlineConnection.CurrentConnection.CertFile != null)
{
+#if !NETSTANDARD2_1
SPOnlineConnectionHelper.CleanupCryptoMachineKey(SPOnlineConnection.CurrentConnection.CertFile);
+#endif
SPOnlineConnection.CurrentConnection.CertFile = null;
}
#endif
- var success = false;
+ var success = false;
if (Connection != null)
{
success = DisconnectProvidedService(Connection);
@@ -47,7 +49,7 @@ protected override void ProcessRecord()
if (provider != null)
{
//ImplementingAssembly was introduced in Windows PowerShell 5.0.
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
var drives = Host.Version.Major >= 5 ? provider.Drives.Where(d => d.Provider.Module.ImplementingAssembly.FullName == Assembly.GetExecutingAssembly().FullName) : provider.Drives;
#else
var drives = Host.Version.Major >= 5 ? provider.Drives.Where(d => d.Provider.Module.Name == Assembly.GetExecutingAssembly().FullName) : provider.Drives;
@@ -61,25 +63,37 @@ protected override void ProcessRecord()
internal static bool DisconnectProvidedService(SPOnlineConnection connection)
{
- if (connection == null)
- return false;
connection.AccessToken = string.Empty;
Environment.SetEnvironmentVariable("PNPPSHOST", string.Empty);
Environment.SetEnvironmentVariable("PNPPSSITE", string.Empty);
+ if (connection == null)
+ {
+ return false;
+ }
+
connection.Context = null;
connection = null;
return true;
}
internal static bool DisconnectCurrentService()
- {
- if (SPOnlineConnection.CurrentConnection == null)
- return false;
- SPOnlineConnection.CurrentConnection.AccessToken = string.Empty;
+ {
Environment.SetEnvironmentVariable("PNPPSHOST", string.Empty);
Environment.SetEnvironmentVariable("PNPPSSITE", string.Empty);
- SPOnlineConnection.CurrentConnection.Context = null;
- SPOnlineConnection.CurrentConnection = null;
+ if (SPOnlineConnection.CurrentConnection == null && SPOnlineConnection.AuthenticationResult == null)
+ {
+ return false;
+ }
+ if (SPOnlineConnection.CurrentConnection != null)
+ {
+ SPOnlineConnection.CurrentConnection.AccessToken = string.Empty;
+ SPOnlineConnection.CurrentConnection.Context = null;
+ SPOnlineConnection.CurrentConnection = null;
+ }
+ if (SPOnlineConnection.AuthenticationResult != null)
+ {
+ SPOnlineConnection.AuthenticationResult = null;
+ }
return true;
}
}
diff --git a/Commands/Base/GetAccessToken.cs b/Commands/Base/GetAccessToken.cs
index 455016896..f453e98ac 100644
--- a/Commands/Base/GetAccessToken.cs
+++ b/Commands/Base/GetAccessToken.cs
@@ -1,7 +1,7 @@
using SharePointPnP.PowerShell.CmdletHelpAttributes;
using System;
using System.Collections.Generic;
-#if NETSTANDARD2_0
+#if NETSTANDARD2_1
using System.IdentityModel.Tokens.Jwt;
#else
using System.IdentityModel.Tokens;
diff --git a/Commands/Base/GetHealthScore.cs b/Commands/Base/GetHealthScore.cs
index e7fe32fb2..5848f9297 100644
--- a/Commands/Base/GetHealthScore.cs
+++ b/Commands/Base/GetHealthScore.cs
@@ -6,10 +6,11 @@
namespace SharePointPnP.PowerShell.Commands.Base
{
[Cmdlet(VerbsCommon.Get, "PnPHealthScore")]
- [CmdletHelp("Retrieves the healthscore value.",
- "Retrieves the current X-SharePointHealthScore value of the server, or CPU, on which your SharePoint instance runs. X-SharePointHealthScore is a value between 0 and 10, where 0 indicates the server is idle and 10 indicates the server is very busy. For more information visit https://docs.microsoft.com/office365/enterprise/diagnosing-performance-issues-with-sharepoint-online and https://docs.microsoft.com/openspecs/sharepoint_protocols/ms-wsshp/c60ddeb6-4113-4a73-9e97-26b5c3907d33.",
+ [CmdletHelp("Retrieves the healthscore of the site given in his Url parameter or from the current connection if the Url parameter is not provided",
+ "Retrieves the current X-SharePointHealthScore value of the server, or CPU, on which your SharePoint instance runs. X-SharePointHealthScore is a value between 0 and 10, where 0 indicates the server is idle and 10 indicates the server is very busy. For more information visit https://docs.microsoft.com/office365/enterprise/diagnosing-performance-issues-with-sharepoint-online and https://docs.microsoft.com/openspecs/sharepoint_protocols/ms-wsshp/c60ddeb6-4113-4a73-9e97-26b5c3907d33.",
Category = CmdletHelpCategory.Base,
OutputType=typeof(int),
+ SupportedPlatform = CmdletSupportedPlatform.OnPremises,
OutputTypeDescription = "Returns a int value representing the current health score value of the server.")]
[CmdletExample(
Code = "PS:> Get-PnPHealthScore",
@@ -19,6 +20,9 @@ namespace SharePointPnP.PowerShell.Commands.Base
Code = "PS:> Get-PnPHealthScore -Url https://contoso.sharepoint.com",
Remarks = @"This will retrieve the current health score for the url https://contoso.sharepoint.com.",
SortOrder = 2)]
+#if !ONPREMISES
+ [Obsolete("Get-PnPHealthScore does not return valid data when using SharePoint Online")]
+#endif
public class GetHealthScore : PSCmdlet
{
[Parameter(Mandatory = false, HelpMessage = "The url of the WebApplication to retrieve the health score from", ValueFromPipeline = true)]
diff --git a/Commands/Base/GetStoredCredential.cs b/Commands/Base/GetStoredCredential.cs
index b7ff63465..fbb23dba4 100644
--- a/Commands/Base/GetStoredCredential.cs
+++ b/Commands/Base/GetStoredCredential.cs
@@ -9,7 +9,7 @@ namespace SharePointPnP.PowerShell.Commands.Base
{
[Cmdlet(VerbsCommon.Get, "PnPStoredCredential")]
[CmdletHelp("Get a credential",
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
"Returns a stored credential from the Windows Credential Manager",
#else
"Returns a stored credential from the Windows Credential Manager or the MacOS KeyChain",
@@ -18,7 +18,7 @@ namespace SharePointPnP.PowerShell.Commands.Base
[CmdletExample(Code = "PS:> Get-PnPStoredCredential -Name O365",
Remarks = "Returns the credential associated with the specified identifier",
SortOrder = 1)]
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
[CmdletExample(Code = "PS:> Get-PnPStoredCredential -Name testEnvironment -Type OnPrem",
Remarks = "Gets the credential associated with the specified identifier from the credential manager and then will return a credential that can be used for on-premises authentication",
SortOrder = 2)]
@@ -28,14 +28,14 @@ public class GetStoredCredential : PSCmdlet
[Parameter(Mandatory = true, HelpMessage = "The credential to retrieve.")]
public string Name;
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
[Parameter(Mandatory = false, HelpMessage = "The object type of the credential to return from the Credential Manager. Possible values are 'O365', 'OnPrem' or 'PSCredential'")]
public CredentialType Type = CredentialType.O365;
#endif
protected override void ProcessRecord()
{
-#if !NETSTANDARD2_0
+#if !NETSTANDARD2_1
var cred = Utilities.CredentialManager.GetCredential(Name);
if (cred != null)
{
diff --git a/Commands/Base/InvokeSPRestMethod.cs b/Commands/Base/InvokeSPRestMethod.cs
index 41fe59c5b..0d303adc2 100644
--- a/Commands/Base/InvokeSPRestMethod.cs
+++ b/Commands/Base/InvokeSPRestMethod.cs
@@ -13,7 +13,9 @@
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
+#if !NETSTANDARD2_1
using System.Web.Script.Serialization;
+#endif
namespace SharePointPnP.PowerShell.Commands.Admin
{
@@ -123,7 +125,11 @@ protected override void ExecuteCmdlet()
var responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (responseString != null)
{
+#if NETSTANDARD2_1
+ WriteObject(System.Text.Json.JsonSerializer.Deserialize