What PowerShell Module To Use?
I wrote about it before, so I invite you to the article:
Which module to choose, SharePoint PowerShell Online or PnP
Action Order
In short, to create a PowerShell site collection from PowerShell:
- Install the appropriate PowerShell module
- Connect to SharePoint
- Create a site collection
- Connect to the newly created collection
- Customize it according to your needs – appearance, content, permissions
- Close connection
Required Permissions
What will we need? You need an account with permissions to perform the planned activities. It does not have to be a Global Administrator, SharePoint PnP allows you to connect in the context of another user, it is important that he has the appropriate permissions to perform the tasks. SharePoint Administrator is enough to create a Site Collection.
Installing the SharePoint PnP module
Module installation:
Install-Module SharePointPnPPowerShellOnline
Upgrading from an earlier version:
Update-Module SharePointPnPPowerShell*
Checking the currently installed version:
Get-Module SharePointPnPPowerShell* -ListAvailable | Select-Object Name,Version | Sort-Object Version -Descending
More information:
GitHub: https://github.com/SharePoint/PnP-PowerShell
MS Doc: https://docs.microsoft.com/en-us/powershell/…
Connection to SharePoint
The basic method for establishing a connection is to run the command:
Connect-PnPOnline –Url https://yoursite.sharepoint.com –Credentials (Get-Credential)
If we use MFA, we can connect using the command:
Connect-PnPOnline -Url https://yoursite.sharepoint.com -UseWebLogin
When we start creating a new collection, we open the first connection to the top-level collection. As a parameter, we give then: https://YOURTENANT.sharepoint.com
Once we create a new collection and make a connection to make changes to it, we’ll connect to the character’s address: https://YOURTENANT.sharepoint.com/sites/NEWSITE
In both cases, we will be redirected to a website where we will have to log in.
In the event that we want to automate the operation of our script and execute it without the need for our interference, we must use a different solution.
We prepare a variable containing our credentials:
$adminLogin = ‘adminroleuser@YOURTENANT.onmicrosoft.com’
$adminPassword = ‘yourtopsecretpassword’
$secstr = New-Object -TypeName System.Security.SecureString
$adminPassword.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$userCredential = new-object -typename System.Management.Automation.PSCredential -argumentlist $adminLogin, $secstr
And we use it to login. The finished fragment of the PowerShell script opening the connection to Sharepoint could look like this:
#config
$sharepointUrl = ‘https://YOURTENANT.sharepoint.com’
$adminLogin = “adminroleuser@yourdomain”
$adminPassword = ‘yourtopsecretpassword’
#prepare user credentials
$secstr = New-Object -TypeName System.Security.SecureString
$adminPassword.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$userCredential = new-object -typename System.Management.Automation.PSCredential -argumentlist $adminLogin, $secstr
#connect
$pnpConnection = Connect-PnPOnline –Url $sharepointUrl -ReturnConnection –Credentials $userCredential
Create a site collection
We create a new collection of sites using the New-PnPSite command. The command syntax is:
$newSiteUrl = New-PnPSite -Type TeamSite -Owner ‘user@yourdomain’ -Title ‘Your Site Title’ -Alias ‘YourSiteAlias’ -Wait
The Type parameter has two values: CommunicationSite and TeamSite.
Good to remember!
For most commands, the Connection parameter is available, which indicates which connection the command applies to. It is especially useful when operating on several open connections.
For a CommunicationSite site, the Url parameter is also required. The command looks like this:
$newSiteUrl = New-PnPSite -Connection $pnpConnection -Type CommunicationSite -Title ‘New Communication Site’ -Url ‘https://YOURTENANT.sharepoint.com/sites/newsitename’ -SiteDesign Showcase
The SiteDesign parameter, available for CommunicationSite sites, allows us to choose a site layout. Available values are: Blank, Showcase and Topic
After creating a new site, we open a connection to it. The whole thing could look like this:
#create new site
$newSiteUrl = New-PnPSite -Connection $pnpConnection -Type TeamSite -Owner ‘user@yourdomain’ -Title ‘Your Site Title’ -Alias ‘YourSiteAlias’ -Wait
#connect to it
$pnpNewConnection = Connect-PnPOnline –Url $newSiteUrl -ReturnConnection –Credentials $userCredential
Customizing layout
Color palette
To modify the site’s color palette, use the command: Set-PnPTheme
The format of the command is:
Set-PnPTheme -Connection $pnpNewConnection -ColorPaletteUrl ‘/_catalogs/theme/15/palette025.spcolor’
Adding And Removing Items From The Menu
Adding items to the menu is done by:
Set-PnPTheme -Connection $pnpNewConnection -ColorPaletteUrl ‘/_catalogs/theme/15/palette025.spcolor’
The Location parameter specifies to which menu we add the parameter and takes the values: TopNavigationBar, SearchNav, QuickLaunch, Footer.
The following parameters are also available:
-First – switch indicating that the link should be placed at the beginning
-Parent – to point to the parent link and build a multi-level menu
The item can be removed from the menu with the command:
Remove-PnPNavigationNode -Connection $pnpNewConnection -Id $linkId -Force
We will get a list of available menu items by following the command:
Get-PnPNavigationNode
As a result, we will get a list of menu items in the form:
Id Title Visible Url
— —– ——- —
1031 Home True /sites/newTeamSite
2002 Conversations True /sites/newTeamSite/_layouts/15/groupstatus.aspx
2003 Documents True /sites/newTeamSite/Shared Documents/Forms/AllItems.aspx
2004 Notebook True /sites/newTeamSite/_layouts/15/groupstatus.aspx?Target=NOTEBOOK
2005 Pages True /sites/newTeamSite/SitePages/Forms/ByAuthor.aspx
1034 Site contents True /sites/newTeamSite/_layouts/15/viewlsts.aspx
For the selected item we can get more detailed information:
Get-PnPNavigationNode -Id 2003|fl
AudienceIds :
Children : {}
Id : 2003
IsDocLib : True
IsExternal : False
IsVisible : True
ListTemplateType : DocumentLibrary
Title : Documents
Url : /sites/newTeamSite/Shared Documents/Forms/AllItems.aspx
Context : OfficeDevPnP.Core.PnPClientContext
Tag :
Path : Microsoft.SharePoint.Client.ObjectPathIdentity
ObjectVersion :
ServerObjectIsNull : False
TypedObject : Microsoft.SharePoint.Client.NavigationNode
To delete the selected link:
Get-PnPNavigationNode| Where-Object {$_.Title -in ‘Pages’,’Site contents’}
And finally, the command would look like this:
Get-PnPNavigationNode -Connection $pnpNewConnection|Where-Object {$_.Title -in 'Pages','Site contents'}|Remove-PnPNavigationNode
-Connection $pnpNewConnection -Force
Adding Lists and Libraries
We create a new list using the command:
New-PnPList -Template Contacts -Title “New List Title” -Url ‘Link to List’ -OnQuickLaunch
Where as parameters we can indicate:
-Title as the name of the new list
-Url as a link to the list that appears in the menu
-OnQuickLaunch as a switch that determines whether the list should be visible in the menu
and
-Template – template by which the list will be created, for example, they can be Contacts or DocumentLibrary
In our case, creating a new document library will look like this:
$newList = New-PnPList -Connection $pnpNewSiteConnection -Template DocumentLibrary -Title “Archive Docs” -Url ‘Archive’ -OnQuickLaunch
Adding Webparts
We customize the site by placing webpages in sections. To understand the logic of operation, it is best to train in the standard SharePoint editor in the web interface and later try to do the same through PowerShell.
To get a list of current page components, use the command:
$page = Get-PnPClientSidePage -Identity ‘Home’
Get-PnPClientSideComponent -Page $page
As a result, we will get a list of page elements:
InstanceId Type Title Section Column Position PropertiesJson
———- —- —– ——- —— ——– ————–
b8246ff8-eb43-4bac-a907-926177278caa ClientSideWebPart News 1 1 1 {“carouselSett…
15737a91-1038-4e68-a9f3-900b85d640fb ClientSideWebPart Events 1 2 1 {“selectedList…
a000c570-f4ce-49c1-bcab-fe081d612352 ClientSideWebPart Planner 2 1 1 {“planId”:””,”…
4522ddff-8754-43d1-9397-1603cb5523c1 ClientSideWebPart List 2 1 2 {“isDocumentLi…
Element PropertiesJson contains the configuration of the given WebPart element. If you do not know what the correct syntax should look like, the solution may be to configure the element through a web editor and then read the correct settings. E.g:
$element = Get-PnPClientSideComponent -Page $page|Where-Object {$_.Title -eq ‘List’}
$element.PropertiesJson
As a result we will get:
{“isDocumentLibrary”:”true”,”filterBy”:{},”title”:”Team Documents”}
And the variable:
$element.Properties
It allows you to get a full list of parameters:
HasValues : False
Type : String
Parent : {}
Root : {isDocumentLibrary, filterBy, title}
Next :
Previous :
Path : isDocumentLibrary
First :
Last :
LineNumber : 1
LinePosition : 27
Type : Object
HasValues : False
First :
Last :
Count : 0
Parent : {{}}
Root : {isDocumentLibrary, filterBy, title}
Next :
Previous :
Path : filterBy
LineNumber : 1
LinePosition : 40
IsReadOnly : False
AllowNew : True
AllowEdit : True
AllowRemove : True
SupportsChangeNotification : True
SupportsSearching : False
SupportsSorting : False
IsSorted : False
SortProperty :
SortDirection : Ascending
IsFixedSize : False
SyncRoot : System.Object
IsSynchronized : False
Keys : {}
HasValues : False
Type : String
Parent : {}
Root : {isDocumentLibrary, filterBy, title}
Next :
Previous :
Path : title
First :
Last :
LineNumber : 1
LinePosition : 69
To compose your own site, you can use the following code snippet. If the page contains any elements, you can use the ClearPage command to clear it. Remember to post your changes: Publish ()
An example below:
$page = Get-PnPClientSidePage -Identity ‘Home’
$page.ClearPage()
Add-PnPClientSidePageSection -Page $page -SectionTemplate TwoColumnLeft -Order 1
Add-PnPClientSidePageSection -Page $page -SectionTemplate OneColumn -Order 2
Add-PnPClientSideWebPart -Page $page -Section 1 -Column 1 -DefaultWebPartType News -WebPartProperties @{layoutId=”FeaturedNews”;title=”Aktualności”}
Add-PnPClientSideWebPart -Page $page -Section 1 -Column 2 -DefaultWebPartType Events -WebPartProperties @{layout=”Compact”;layoutId=”Flex”;dataSource=3;maxItemsPerPage=5;dataProviderId=”Search”;title=”Nadchodzące wydarzenia”}
$element = Get-PnPList -Identity ‘Documents’
Add-PnPClientSideWebPart -Page $page -Section 2 -Column 1 -DefaultWebPartType List -WebPartProperties @{isDocumentLibrary=”true”;title=”Dokumenty Zespołu”;selectedListId = $element.Id}
page.Publish()
Permission Modification
When modifying permissions, please note that default SharePoint groups are created for each site collection. The groups are:
Owners, Members i Visitors
You can change the default permissions for each of these groups. You can create a new group, give it permissions and assign users to it. You can also change the default permission roles such as Reader, Editor or Contributor
The get-PnpGroup command allow getting a list of SharePoint groups defined for a given site
Get-PnPGroup
Id Title LoginName
— —– ———
6 Site Members Site Members
4 Site Owners Site Owners
5 Site Visitors Site Visitors
We change the permissions of the default Members group
$membersGroup = Get-PnPGroup -AssociatedMemberGroup
Get-PnPGroupPermissions -Identity $membersGroup.Id
#Result
#
#Name RoleTypeKind Hidden Order
#—- ———— —— —–
#Contribute Contributor False 64
Set-PnPGroupPermissions -Identity $membersGroup.Id -RemoveRole @(‘Contribute’) -AddRole @(‘Edit’)
Get-PnPGroupPermissions -Identity $membersGroup.Id
#Result after change
#
#Name RoleTypeKind Hidden Order
#—- ———— —— —–
#Edit Editor False 48
Ready Script – Create And Customize
The code of the ready script creating and configuring site collections based on the configuration. For convenience, the script is divided into two parts. Functions and calling code along with the configuration. For the script to work, you must save both parts in one file and start or part with the functions save as a module and import in the calling part. I leave these tasks for independent experiments.
Functions
Connect – open connection to SharePoint
CreateNewSite – creates new site collection and connects to it
CustomizeNewSite – customizes new collection, configuration is reades from a variable
function Connect($_tenant, $_adminLogin, $_adminPassword){ $secstr = New-Object -TypeName System.Security.SecureString $_adminPassword.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)} $Global:userCredential = new-object -typename System.Management.Automation.PSCredential -argumentlist $_adminLogin, $secstr $Global:pnpSPOConnection = Connect-PnPOnline –Url https://$_tenant.sharepoint.com -ReturnConnection –Credentials $Global:userCredential } function CreateNewSite([ref]$config){ #create new site collection $newSiteUrl = New-PnPSite -Type TeamSite -Owner $config.Value.SPOConfiguration.newSiteOwner -Title $config.Value.newTeamName -Alias $config.Value.newTeamAlias -Lcid $config.Value.SPOConfiguration.newSiteLanguage -Wait #connect to it and save connection $Global:pnpNewSiteConnection = Connect-PnPOnline –Url $newSiteUrl -ReturnConnection –Credentials $Global:userCredential #save new site url into config $config.Value.SPOConfiguration += @{ newSiteUrl = $newSiteUrl } $membersGroup = Get-PnPGroup -Connection $Global:pnpNewSiteConnection -AssociatedMemberGroup #get from config permissions to change $removeRoles = $config.Value.SPOConfiguration.newSiteMembersPermissions.removeroles $addRoles = $config.Value.SPOConfiguration.newSiteMembersPermissions.addroles #set new permissions Set-PnPGroupPermissions -Connection $Global:pnpNewSiteConnection -Identity $membersGroup.Id -RemoveRole @($removeRoles) -AddRole @($addRoles) } function CustomizeNewSite($configuration){ $configuration.keys|sort|ForEach-Object{ $config = $($configuration[$_]) if ($_ -eq 'SPOConfiguration'){ $paletteUrl = $config.SPOColorPaletteUrl Set-PnPTheme -Connection $Global:pnpNewSiteConnection -ColorPaletteUrl $paletteUrl } if ($_ -eq 'SPONavigationNodes'){ $config.Keys | ForEach-Object{ if ($($config[$_].op) -eq 'add'){ $ret = Add-PnPNavigationNode -Connection $Global:pnpNewSiteConnection -Title $_ -Url $($config[$_].url) -Location $($config[$_].location) -External } if ($($config[$_].op) -eq 'del'){ Remove-PnPNavigationNode -Connection $Global:pnpNewSiteConnection -Id $($config[$_].id) -Force } } } if ($_ -eq 'SPOLists'){ $config.Keys | ForEach-Object{ $ret = New-PnPList -Connection $Global:pnpNewSiteConnection -Title $($config[$_].title) -Template $($config[$_].template) -Url $($config[$_].url) -OnQuickLaunch:$($config[$_].OnQuickLaunch) } } if ($_ -eq 'SPOWebparts'){ $page = Get-PnPClientSidePage -Connection $Global:pnpNewSiteConnection -Identity "Home" $order=0; $config.Keys|sort|foreach{ $s=1 if ($($config[$_].object) -eq 'section'){ $order++ $ret = Add-PnPClientSidePageSection -Connection $Global:pnpNewSiteConnection -Page $page -SectionTemplate $($config[$_].SectionTemplate) -Order $order -ZoneEmphasis 0 } if ($($config[$_].object) -eq 'webpart'){ if ( $config[$_].ListIdentity.Length -gt 0){ $sharedDocuments = Get-PnPList -Connection $Global:pnpNewSiteConnection -Identity $($config[$_].ListIdentity) $selectedListId = $sharedDocuments.Id $config[$_].wpproperties += @{selectedListId = $selectedListId} } $ret = Add-PnPClientSideWebPart -Connection $Global:pnpNewSiteConnection -Page $page -Section $order -Column $($config[$_].column) -DefaultWebPartType $($config[$_].Type) -WebPartProperties $($config[$_].wpproperties) } } $ret = Set-PnPClientSidePage -Connection $Global:pnpNewSiteConnection -Identity $page -LayoutType Home -Publish } } }
Execution- configuration variable and our 3 functions execution . That’s all, new site collection is ready.
# # New Site Config # $newSiteConfig = @{ 'newTeamName' = 'New Site Name' 'newTeamAlias' = 'NewSiteAlias' 'SPOConfiguration'= @{ newSiteOwner = 'MrNobody@TenantName.OnMicrosoft.com' newSiteLanguage = 1033 # only 1033 and 1045 allowed here newSiteDesign = 'Topic' SPOColorPaletteUrl = '/_catalogs/theme/15/palette025.spcolor' newSiteMembersPermissions = @{ removeroles = 'Edit'; addroles = 'Contribute' } } 'SPONavigationNodes' = @{ 'Pages' = @{ 'op' = 'del'; 'id' = 2005 } 'Site contents' = @{ 'op' = 'del'; 'id' = 1034 } 'Link1' = @{ 'op' = 'add'; url = 'http://site1.com'; location = 'TopNavigationBar' } 'Link2' = @{ 'op' = 'add'; url = 'https://site2.com'; location = 'TopNavigationBar' } } 'SPOLists' = @{ 'iportant contacts1' = @{'title' = 'Important Contacts'; 'template' = 'Contacts'; url = 'Important Contacts'; 'OnQuickLaunch' = $true } 'archive docs' = @{'title' = 'Archive'; 'template' = 'DocumentLibrary'; url = 'Archive Doc'; 'OnQuickLaunch' = $true } } 'SPOWebparts' = @{ 1 = @{ object = 'section'; SectionTemplate = 'TwoColumnLeft'; } 2 = @{ object = 'webpart'; column = '1'; Type = 'News'; wpproperties = @{layoutId='FeaturedNews';title='Corp News'} } 3 = @{ object = 'webpart'; column = '2'; Type = 'Events'; wpproperties = @{layout="Compact";layoutId=”Flex”;dataSource=3;maxItemsPerPage=5;dataProviderId="Search";title=”Upcoming Events”} } 4 = @{ object = 'section'; SectionTemplate = 'OneColumn'; } 5 = @{ object = 'webpart'; column = '1'; Type = 'Planner'; wpproperties = @{plannerViewMode='board';isFullScreen=$false} } 6 = @{ object = 'webpart'; column = '1'; Type = 'List'; wpproperties = @{isDocumentLibrary='true';title='Dokumenty Zespołu'} ; ListIdentity='Documents'} } } # # Credentials # $tenant = 'TenantName' $adminLogin = 'admin@TenantName.onmicrosoft.com' $adminPassword = 'TopSecretPassword' # # Create and customize SharePoint site collection # Connect $tenant $adminLogin $adminPassword CreateNewSite ([ref]$newSiteConfig) CustomizeNewSite $newSiteConfig