Jakiego Modułu PowerShell Używać?
O tym pisałem już wcześniej, zapraszam więc do artykułu:
Jaki moduł wybrać, SharePoint PowerShell Online czy PnP
Kolejność Działań
W skrócie, aby utworzyć z poziomu PowerShell kolekcję witryn SharePoint nalezy:
- Zainstalować odpowiedni moduł PowerShell’a
- Połączyć się z SharePoint’em
- Utworzyć kolekcję witryn
- Połączyć się z nowo utworzoną kolekcją
- Dostosować ją według własnych potrzeb – wygląd, zawartość, uprawnienia
- Zamknąć połączenie
Wymagane Uprawnienia
Co będzie nam potrzebne? Potrzebne jest konto z uprawnieniami do wykonania planowanych czynności. Nie musi to być Global Administrator, SharePoint PnP pozwala na połączenie w kontekście innego użytkownika, ważne aby miał odpowiednie uprawnienia do wykonywanych czynności. SharePoint Administrator w zupełności wystarczy do utworzenia Kolekcji witryn.
Instalacja modułu SharePoint PnP
Instalacja modułu:
Install-Module SharePointPnPPowerShellOnline
Aktualizacja wcześniejszej wersji:
Update-Module SharePointPnPPowerShell*
Sprawdzenie aktualnie zainstalowanej wersji:
Get-Module SharePointPnPPowerShell* -ListAvailable | Select-Object Name,Version | Sort-Object Version -Descending
Więcej informacji:
GitHub: https://github.com/SharePoint/PnP-PowerShell
MS Doc: https://docs.microsoft.com/en-us/powershell/…
Połączenie do SharePoint’a
Podstawową metodą nawiązania połączenia jest wywołanie polecenia:
Connect-PnPOnline –Url https://yoursite.sharepoint.com –Credentials (Get-Credential)
Jeżeli korzystamy z MFA, połączenie możemy nawiązać korzystając z polecenia:
Connect-PnPOnline -Url https://yoursite.sharepoint.com -UseWebLogin
Gdy przystępujemy do tworzenia nowej kolekcji, pierwsze połączenie otwieramy do kolekcji najwyższego poziomu. Jako parametr podajemy wtedy: https://TWOJANAZWA.sharepoint.com
Gdy stworzymy już nową kolekcję i będziemy nawiązywać połączenie aby dokonać w niej zmian, połączymy się do adresu postaci: https://TWOJANAZWA.sharepoint.com/sites/NOWAKOLEKCJA
W obu przypadkach zostaniemy przekierowani do strony WWW, gdzie będziemy musieli się zalogować.
W przypadku, gdy chcemy automatyzować działanie naszego skryptu i wykonywać go bez konieczności naszej ingerencji musimy skorzystać z innego rozwiązania.
Przygotowujemy zmienną zawierającą nasze poświadczenia:
$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
I wykorzystujemy ją do logowania. Gotowy fragment skryptu PowerShell otwierającego połączenie do Sharepointa, mógłby wyglądać następująco:
#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
Utworzenie kolekcji witryn
Nową kolekcję witryn tworzymy poleceniem New-PnPSite. Składnia polecenia wygląda następująco:
$newSiteUrl = New-PnPSite -Type TeamSite -Owner ‘user@yourdomain’ -Title ‘Your Site Title’ -Alias ‘YourSiteAlias’ -Wait
Parametr Type przyjmuje dwie wartości: CommunicationSite i TeamSite.
Warto pamietać!
Dla większości poleceń dostępny jest parametr Connection za pomocą którego wskazujemy, którego połączenia dotyczy polecenie. Jest on szczególnie przydatny w przypadku operowania przy kilku otwartych połączeniach.
Dla witryny typu CommunicationSite wymagany jest również parametr Url. Polecenie wygląda wtedy następująco:
$newSiteUrl = New-PnPSite -Connection $pnpConnection -Type CommunicationSite -Title ‘New Communication Site’ -Url ‘https://YOURTENANT.sharepoint.com/sites/newsitename’ -SiteDesign Showcase
Parametr SiteDesign, dostępny dla witryn typu CommunicationSite, pozwala nam wybrać układ witryny. Dostępne wartości to: Blank, Showcase i Topic
Po utworzeniu nowej witryny, otwieramy do niej połączenie. Całość mogłaby wyglądać tak:
#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
Dostosowanie wyglądu witryny
Paleta kolorów
Do modyfikacji palety kolorów witryny służy polecenie: Set-PnPTheme
Format polecenia wygląda następująco:
Set-PnPTheme -Connection $pnpNewConnection -ColorPaletteUrl ‘/_catalogs/theme/15/palette025.spcolor’
Dodanie i usuniecie elementów z menu
Dodawanie elementów do menu wykonujemy poleceniem:
Set-PnPTheme -Connection $pnpNewConnection -ColorPaletteUrl ‘/_catalogs/theme/15/palette025.spcolor’
Parametr Location określa do którego menu dodajemy parametr i przyjmuje wartości: TopNavigationBar, SearchNav, QuickLaunch, Footer.
Dostępne są również takie parametry jak:
-First – przełącznik, oznaczający, że link ma byc umieszczony na początku
-Parent – aby wskazać link nadrzędny i budować menu wielopoziomowe
Usunięcie elementu z menu wykonamy poleceniem:
Remove-PnPNavigationNode -Connection $pnpNewConnection -Id $linkId -Force
Listę dostępnych pozycji menu otrzymamy wykonując polecenie:
Get-PnPNavigationNode
W wyniku otrzymamy listę elementów menu w postaci:
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
Dla wybranej pozycji możemy uzyskać bardziej szczegółowe informacje:
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
Aby usunąć wybrany link:
Get-PnPNavigationNode| Where-Object {$_.Title -in ‘Pages’,’Site contents’}
I ostatecznie, polecenie mogłoby wyglądać tak:
Get-PnPNavigationNode -Connection $pnpNewConnection|Where-Object {$_.Title -in 'Pages','Site contents'}|Remove-PnPNavigationNode
-Connection $pnpNewConnection -Force
Dodawanie list i Bibliotek
Nową listę tworzymy przy pomocy polecenia:
New-PnPList -Template Contacts -Title “New List Title” -Url ‘Link to List’ -OnQuickLaunch
Gdzie jako parametry możemy wskazać:
-Title jako nazwę nowej listy
-Url jako link do listy, który pojawi się w menu
-OnQuickLaunch jako przełącznik określający czy lista ma być widoczna w menu
oraz
-Template – szablon wg, którego lista zostanie utworzona, dla przykładu mogą to być Contacts czy DocumentLibrary
W naszym wypadku, utworzenie nowej biblioteki dokumentów będzie wyglądać następująco:
$newList = New-PnPList -Connection $pnpNewSiteConnection -Template DocumentLibrary -Title “Archive Docs” -Url ‘Archive’ -OnQuickLaunch
Dodawanie Webpartów
Dostosowanie zawartości witryny wykonujemy poprzez umieszczenie na niej webpartów ułożonych w sekcje. Aby zrozumieć logikę działania najlepiej potrenować w standardowym edytorze SharePointa w interfejsie WWW a dopiero później spróbować poprzez PowerShell.
Aby uzyskać listę aktualnych składników strony należy użyć polecenia:
$page = Get-PnPClientSidePage -Identity ‘Home’
Get-PnPClientSideComponent -Page $page
W wyniku otrzymamy listę elementów strony:
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 zawiera konfigurację danego elementu WebPart. Jeżeli nie wiemy jak powinna wyglądać prawidłowa składnia, rozwiązaniem może być skonfigurowanie elementu poprzez edytor WWW a następnie odczytanie poprawnych ustawień. Na przykład:
$element = Get-PnPClientSideComponent -Page $page|Where-Object {$_.Title -eq ‘List’}
$element.PropertiesJson
W wyniku uzyskamy:
{“isDocumentLibrary”:”true”,”filterBy”:{},”title”:”Team Documents”}
A zmienna:
$element.Properties
Pozwala uzyskać pełną listę parametrów:
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
Aby skomponować własną witrynę można wykorzystać nastepujący fragment kodu.
Jeżeli strona zawiera jakieś elementy mozna uzyć polecenia ClearPage aby ją wyczyścić.
Nalezy pamietać o opublikowaniu zmian: Publish()
Poniżej przykład:
$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()
Modyfikacja uprawnień
Modyfikując uprawnienia należy zwrócić uwagę na to, że dla każdej kolekcji witryn zostają utworzone doyślne grupy SharePoint, które posiadają uprawnienia do kolekcji.
Są to Owners, Members i Visitors
Można zmienić domyślne uprawnienia dla jednej z tych grup. Mozna stworzyć nową grupę, nadać jej uprawnienia i przyposać do niej użytkowników. Mozna również zmienić domyślne role uprawnień takie jak Reader, Editor czy Contributor
Polecenie get-PnpGroup pozwoli nam uzyskać listę grup SharePoint zdefiniowanych dla danej witryny
Get-PnPGroup
Id Title LoginName
— —– ———
6 Site Members Site Members
4 Site Owners Site Owners
5 Site Visitors Site Visitors
Zmieniamy uprawnienia domyślnej grupy Members
$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
Gotowy skrypt – Utwórz i dostosuj
Poniżej zamieszczam kod gotowego skryptu tworzącego i konfigurującego kolekcje witryn na podstawie konfiguracji. Dla ułatwienia skrypt podzieliłem na 2 cześci. Funkcje i kod wywołujący wraz z konfiguracją. Aby skrypt działał należy obie cześci zapisać w jednym pliku i uruchomić lub cześć z funkcjami zapisac w formie modułu i zaimportować w części wywołującej. Te zadania pozostawiam już do samodzielnych eksperymentów.
Funkcje
Connect – połączenie z SharePoint
CreateNewSite – tworzy nową kolekcję i otwiera połączenie do niej
CustomizeNewSite – modyfikuje nową kolekcję na podstawie konfiguracji zapisanej w zmiennej
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
}
}
}
Wykonanie – zmienna konfiguracyjna oraz wywołanie 3 funkcji. To wszystko, nowa kolekcja witryn jest gotowa.
#
# 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