Files
CustomBranding/deployment/add-custombranding.ps1
T

229 lines
8.9 KiB
PowerShell

param(
[Parameter(Mandatory = $true)]
[Alias('WebUrl')]
[string]$SiteUrl,
[string]$CssPath = '',
[string[]]$AllowedCssHost = @(),
[switch]$EnableDebug,
[switch]$Disable,
[switch]$ResetConfiguration,
[string]$ClassicScriptUrl = '',
[switch]$RemoveClassicScriptLink,
[string]$Description = 'MSFT-Custom-Solution:CustomBranding'
)
if (-not (Get-Command -Name Get-SPSite -ErrorAction SilentlyContinue)) {
if (Get-Module -ListAvailable -Name Microsoft.SharePoint.PowerShell) {
Import-Module Microsoft.SharePoint.PowerShell -DisableNameChecking
}
elseif (Get-PSSnapin -Registered -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) {
Add-PSSnapin Microsoft.SharePoint.PowerShell
}
else {
throw 'Die SharePoint PowerShell-Komponenten wurden nicht gefunden. Bitte in der SharePoint Management Shell ausfuehren.'
}
}
$componentId = [Guid]'035ba968-6488-4d42-86b3-0470ffcc95b9'
$componentIdText = $componentId.ToString().ToLowerInvariant()
$componentLocation = 'ClientSideExtension.ApplicationCustomizer'
$componentName = 'CustomBranding'
$componentTitle = 'Custom Branding Application Customizer'
$classicActionName = 'CustomBranding.Classic.ScriptLink'
function New-DefaultFooterElements {
return @(@{
type = 'div'
attributes = @{ role = 'contentinfo'; 'aria-label' = 'Portalverwaltung' }
styles = @{
padding = '8px 16px'; 'text-align' = 'right'; width = '100%'; 'box-sizing' = 'border-box'
}
children = @(@{
type = 'a'
attributes = @{ href = '~sitecollection/SitePages/PortalSettings.aspx' }
children = @(
@{
type = 'span'
attributes = @{ class = 'ms-Icon ms-Icon--Settings'; 'aria-hidden' = 'true' }
styles = @{ 'margin-right' = '4px' }
},
@{ type = 'span'; content = 'Portal Settings' }
)
})
})
}
function New-DefaultCustomBrandingConfiguration {
return @{
schemaVersion = 2
portalSettings = @{
providerKey = 'custombranding'
contractVersion = 1
minimumPortalSettingsVersion = '3.0.0'
}
enabled = $true
debug = $false
allowedCssHosts = @()
cssfiles = @()
placeholdertop = @{ elements = @() }
placeholderbottom = @{ elements = @(New-DefaultFooterElements) }
}
}
function ConvertTo-Hashtable {
param([object]$InputObject)
if ($null -eq $InputObject) { return $null }
if ($InputObject -is [System.Collections.IDictionary]) {
$result = @{}
foreach ($key in $InputObject.Keys) { $result[$key] = ConvertTo-Hashtable $InputObject[$key] }
return $result
}
if ($InputObject -is [System.Collections.IEnumerable] -and -not ($InputObject -is [string])) {
return @($InputObject | ForEach-Object { ConvertTo-Hashtable $_ })
}
if ($InputObject.PSObject -and $InputObject.PSObject.Properties.Count -gt 0 -and
-not ($InputObject -is [string]) -and -not ($InputObject.GetType().IsPrimitive)) {
$result = @{}
foreach ($property in $InputObject.PSObject.Properties) { $result[$property.Name] = ConvertTo-Hashtable $property.Value }
return $result
}
return $InputObject
}
function Get-ExistingConfiguration {
param([Microsoft.SharePoint.SPUserCustomAction]$Action)
if ($ResetConfiguration -or -not $Action -or [string]::IsNullOrWhiteSpace($Action.ClientSideComponentProperties)) {
return New-DefaultCustomBrandingConfiguration
}
try {
$parsed = $Action.ClientSideComponentProperties | ConvertFrom-Json
$configuration = ConvertTo-Hashtable $parsed
if (-not $configuration) { return New-DefaultCustomBrandingConfiguration }
return $configuration
}
catch {
Write-Warning 'Vorhandene ClientSideComponentProperties waren ungueltig und werden durch Standardwerte ersetzt.'
return New-DefaultCustomBrandingConfiguration
}
}
function Remove-WebScopedComponentActions {
param([Microsoft.SharePoint.SPSite]$CurrentSite)
$removed = 0
foreach ($web in $CurrentSite.AllWebs) {
try {
$actions = @($web.UserCustomActions | Where-Object {
$_.Location -eq $componentLocation -and
$_.ClientSideComponentId -and
$_.ClientSideComponentId.ToString().ToLowerInvariant() -eq $componentIdText
})
foreach ($action in $actions) {
$action.Delete()
$removed++
}
if ($actions.Count -gt 0) { $web.Update() }
}
finally {
$web.Dispose()
}
}
return $removed
}
$site = Get-SPSite -Identity $SiteUrl
try {
$siteActions = @($site.UserCustomActions | Where-Object {
$_.Location -eq $componentLocation -and
$_.ClientSideComponentId -and
$_.ClientSideComponentId.ToString().ToLowerInvariant() -eq $componentIdText
})
$action = $siteActions | Select-Object -First 1
$configuration = Get-ExistingConfiguration -Action $action
$configuration.schemaVersion = 2
$configuration.portalSettings = @{
providerKey = 'custombranding'
contractVersion = 1
minimumPortalSettingsVersion = '3.0.0'
}
if (-not $configuration.ContainsKey('placeholdertop')) { $configuration.placeholdertop = @{ elements = @() } }
if (-not $configuration.ContainsKey('placeholderbottom')) {
$configuration.placeholderbottom = @{ elements = @(New-DefaultFooterElements) }
}
if (-not $configuration.ContainsKey('cssfiles')) { $configuration.cssfiles = @() }
if (-not $configuration.ContainsKey('allowedCssHosts')) { $configuration.allowedCssHosts = @() }
if ($PSBoundParameters.ContainsKey('EnableDebug')) { $configuration.debug = [bool]$EnableDebug.IsPresent }
if ($PSBoundParameters.ContainsKey('Disable')) { $configuration.enabled = -not [bool]$Disable.IsPresent }
if (-not [string]::IsNullOrWhiteSpace($CssPath)) {
$trimmedPath = $CssPath.Trim()
$existingPaths = @($configuration.cssfiles | ForEach-Object {
if ($_ -is [System.Collections.IDictionary]) { [string]$_['path'] } else { [string]$_.path }
})
if ($existingPaths -notcontains $trimmedPath) {
$configuration.cssfiles = @($configuration.cssfiles) + @(@{ path = $trimmedPath; media = 'all' })
}
}
if ($AllowedCssHost.Count -gt 0) {
$configuration.allowedCssHosts = @($AllowedCssHost | ForEach-Object { $_.Trim().ToLowerInvariant() } | Where-Object { $_ } | Select-Object -Unique)
}
if (-not $action) {
$action = $site.UserCustomActions.Add()
Write-Host 'Erstelle zentrale CustomBranding Site-Collection-Action...' -ForegroundColor Yellow
}
else {
Write-Host 'Aktualisiere zentrale CustomBranding Site-Collection-Action...' -ForegroundColor Yellow
}
$action.Name = $componentName
$action.Title = $componentTitle
$action.Description = $Description
$action.Location = $componentLocation
$action.Sequence = 90
$action.ClientSideComponentId = $componentId
$action.ClientSideComponentProperties = [string]($configuration | ConvertTo-Json -Depth 20 -Compress)
$action.Update()
@($siteActions | Select-Object -Skip 1) | ForEach-Object {
Write-Host ('Entferne doppelte Site-Collection-Action: ' + $_.Id) -ForegroundColor Yellow
$_.Delete()
}
$removedWebActions = Remove-WebScopedComponentActions -CurrentSite $site
$classicActions = @($site.UserCustomActions | Where-Object {
$_.Location -eq 'ScriptLink' -and $_.Name -eq $classicActionName
})
if ($RemoveClassicScriptLink) {
foreach ($classicAction in $classicActions) { $classicAction.Delete() }
Write-Host 'Classic ScriptLink wurde entfernt.' -ForegroundColor Yellow
}
elseif (-not [string]::IsNullOrWhiteSpace($ClassicScriptUrl)) {
$classicAction = $classicActions | Select-Object -First 1
if (-not $classicAction) { $classicAction = $site.UserCustomActions.Add() }
$classicAction.Name = $classicActionName
$classicAction.Title = 'CustomBranding Classic Runtime'
$classicAction.Description = $Description
$classicAction.Location = 'ScriptLink'
$classicAction.Sequence = 101
$classicAction.ScriptSrc = $ClassicScriptUrl.Trim()
$classicAction.Update()
@($classicActions | Select-Object -Skip 1) | ForEach-Object { $_.Delete() }
Write-Host ('Classic ScriptLink: ' + $classicAction.ScriptSrc) -ForegroundColor Green
}
Write-Host 'CustomBranding wurde zentral fuer die Site Collection registriert.' -ForegroundColor Green
Write-Host ('Entfernte web-scoped Actions: ' + $removedWebActions)
Write-Host ('Properties: ' + $action.ClientSideComponentProperties)
}
finally {
if ($site) { $site.Dispose() }
}