SharePoint Hub Sites: Connecting Your Intranet Ecosystem

Introduction

Modern intranets aren't single sitesβ€”they're ecosystems of interconnected content spanning departments, teams, and projects. SharePoint Hub Sites provide the architecture to connect these disparate sites into a cohesive experience with shared navigation, unified branding, aggregated news, and cross-site search.

In this comprehensive guide, you'll master SharePoint Hub Sites from architectural planning to enterprise implementation. You'll learn hub site design patterns, association strategies, governance models, and automation techniques using PnP PowerShell and Microsoft Graph API.

What You'll Learn:

  • Hub site architecture and benefits
  • Planning hub site hierarchy and taxonomy
  • Creating and configuring hub sites
  • Associating sites and managing permissions
  • Implementing shared navigation and branding
  • Aggregating content across associated sites
  • Hub site governance and lifecycle management
  • Automation with PnP PowerShell and Graph API
  • Migration strategies and best practices

Time to Complete: 90-120 minutes
Skill Level: Intermediate to Advanced

Hub Site Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                SharePoint Hub Site Architecture                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                          β”‚
β”‚                          Root Site Collection                            β”‚
β”‚                          (Tenant-wide Home)                              β”‚
β”‚                                  β”‚                                       β”‚
β”‚         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”‚
β”‚         β”‚                        β”‚                         β”‚            β”‚
β”‚         β–Ό                        β–Ό                         β–Ό            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚   HR Hub     β”‚        β”‚  Sales Hub   β”‚        β”‚   IT Hub     β”‚     β”‚
β”‚  β”‚   (/hr)      β”‚        β”‚  (/sales)    β”‚        β”‚   (/it)      β”‚     β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€     β”‚
β”‚  β”‚ Shared:      β”‚        β”‚ Shared:      β”‚        β”‚ Shared:      β”‚     β”‚
β”‚  β”‚ β€’ Navigation β”‚        β”‚ β€’ Navigation β”‚        β”‚ β€’ Navigation β”‚     β”‚
β”‚  β”‚ β€’ Theme      β”‚        β”‚ β€’ Theme      β”‚        β”‚ β€’ Theme      β”‚     β”‚
β”‚  β”‚ β€’ News       β”‚        β”‚ β€’ News       β”‚        β”‚ β€’ News       β”‚     β”‚
β”‚  β”‚ β€’ Search     β”‚        β”‚ β€’ Search     β”‚        β”‚ β€’ Search     β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚         β”‚                       β”‚                        β”‚             β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚   β”‚           β”‚          β”‚           β”‚          β”‚             β”‚      β”‚
β”‚   β–Ό           β–Ό          β–Ό           β–Ό          β–Ό             β–Ό      β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚ β”‚ Bene  β”‚ β”‚Recruitβ”‚  β”‚North β”‚  β”‚South β”‚  β”‚Help    β”‚   β”‚Projects β”‚  β”‚
β”‚ β”‚ fits  β”‚ β”‚ ing   β”‚  β”‚Regionβ”‚  β”‚Regionβ”‚  β”‚Desk    β”‚   β”‚         β”‚  β”‚
β”‚ β”‚ Site  β”‚ β”‚ Site  β”‚  β”‚ Site β”‚  β”‚ Site β”‚  β”‚Site    β”‚   β”‚Site     β”‚  β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                                        β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚               Hub Site Capabilities                              β”‚ β”‚
β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚ β”‚                                                                  β”‚ β”‚
β”‚ β”‚  1. Shared Navigation                                           β”‚ β”‚
β”‚ β”‚     └─ Top nav links appear on all associated sites             β”‚ β”‚
β”‚ β”‚                                                                  β”‚ β”‚
β”‚ β”‚  2. Unified Search Scope                                        β”‚ β”‚
β”‚ β”‚     └─ Search returns results from all associated sites         β”‚ β”‚
β”‚ β”‚                                                                  β”‚ β”‚
β”‚ β”‚  3. News Aggregation                                            β”‚ β”‚
β”‚ β”‚     └─ Hub home displays news from all associated sites         β”‚ β”‚
β”‚ β”‚                                                                  β”‚ β”‚
β”‚ β”‚  4. Consistent Branding                                         β”‚ β”‚
β”‚ β”‚     └─ Theme (colors, logo) inherited by associated sites       β”‚ β”‚
β”‚ β”‚                                                                  β”‚ β”‚
β”‚ β”‚  5. Metadata Inheritance                                        β”‚ β”‚
β”‚ β”‚     └─ Site columns available to associated sites               β”‚ β”‚
β”‚ β”‚                                                                  β”‚ β”‚
β”‚ β”‚  6. Permission Management                                       β”‚ β”‚
β”‚ β”‚     └─ Hub admins manage associations                           β”‚ β”‚
β”‚ β”‚                                                                  β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                                                        β”‚
β”‚  Benefits:                                                             β”‚
β”‚  βœ“ Logical grouping of related sites                                  β”‚
β”‚  βœ“ Consistent user experience across departments                      β”‚
β”‚  βœ“ Easier discovery of related content                                β”‚
β”‚  βœ“ Simplified navigation and branding management                      β”‚
β”‚  βœ“ Cross-site reporting and analytics                                 β”‚
β”‚                                                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Prerequisites

Required Licenses

  • SharePoint Online (included in Microsoft 365 E3/E5)
  • Microsoft 365 account with appropriate permissions

Required Permissions

  • SharePoint Administrator or Global Administrator (to create hub sites)
  • Hub Site Administrator (to manage associations)
  • Site Owner (to associate sites with hub)

Required Tools

  • PnP PowerShell Module
  • SharePoint Online Management Shell
  • Microsoft Graph PowerShell SDK (optional, for advanced automation)

Install Prerequisites

# Install PnP PowerShell (version 2.x - modern)
Install-Module -Name PnP.PowerShell -Scope CurrentUser -Force

# Verify installation
Get-Module PnP.PowerShell -ListAvailable

# Install SharePoint Online Management Shell
Install-Module -Name Microsoft.Online.SharePoint.PowerShell -Scope CurrentUser -Force

# Install Microsoft Graph PowerShell (optional)
Install-Module Microsoft.Graph -Scope CurrentUser -Force

# Verify modules
Get-InstalledModule | Where-Object {$_.Name -like "*SharePoint*" -or $_.Name -like "*PnP*"}

Verify Permissions

# Connect to SharePoint Online
$tenantUrl = "https://contoso-admin.sharepoint.com"
Connect-PnPOnline -Url $tenantUrl -Interactive

# Check your roles
Get-PnPTenantSite | Select-Object Url, Owner, Template | Format-Table

# Verify hub site permissions
$currentUser = Get-PnPProperty -ClientObject (Get-PnPWeb) -Property CurrentUser
Write-Host "Current User: $($currentUser.LoginName)" -ForegroundColor Green
Write-Host "User Roles: $($currentUser.Groups)" -ForegroundColor Green

# Check if you can manage hub sites
try {
    Get-PnPHubSite -ErrorAction Stop | Format-Table Title, SiteUrl
    Write-Host "βœ“ You have hub site management permissions" -ForegroundColor Green
} catch {
    Write-Host "βœ— You need SharePoint Administrator role" -ForegroundColor Red
}

Step 1: Plan Your Hub Site Structure

Design Hub Site Hierarchy

Before creating hub sites, plan your information architecture:

Enterprise Hub Site Planning Matrix
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Hub Site       β”‚ Associated Site Types                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Corporate      β”‚ β€’ Company News                                      β”‚
β”‚ (/corporate)   β”‚ β€’ Executive Communications                          β”‚
β”‚                β”‚ β€’ Company Events                                    β”‚
β”‚                β”‚ β€’ Employee Resources                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ HR Hub         β”‚ β€’ Benefits                                          β”‚
β”‚ (/hr)          β”‚ β€’ Recruiting                                        β”‚
β”‚                β”‚ β€’ Learning & Development                            β”‚
β”‚                β”‚ β€’ Employee Handbook                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ IT Hub         β”‚ β€’ Help Desk                                         β”‚
β”‚ (/it)          β”‚ β€’ IT Policies                                       β”‚
β”‚                β”‚ β€’ Software Downloads                                β”‚
β”‚                β”‚ β€’ Project Sites                                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Sales Hub      β”‚ β€’ Regional Sales Sites (North, South, East, West)  β”‚
β”‚ (/sales)       β”‚ β€’ Sales Enablement                                  β”‚
β”‚                β”‚ β€’ Product Catalog                                   β”‚
β”‚                β”‚ β€’ Customer Success                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Finance Hub    β”‚ β€’ Financial Reports                                 β”‚
β”‚ (/finance)     β”‚ β€’ Expense Management                                β”‚
β”‚                β”‚ β€’ Procurement                                       β”‚
β”‚                β”‚ β€’ Budget Planning                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Hub Site Planning Worksheet

Create a planning document:

# Hub Site Planning: HR Department

**Hub Site Name**: Human Resources  
**Hub Site URL**: https://contoso.sharepoint.com/sites/hr  
**Hub Site Owner**: HR Director  
**Hub Site Admins**: HR IT Team  

## Purpose
Central hub for all HR-related sites, resources, and communications

## Associated Sites (Planned)
1. Benefits Site (/sites/hr-benefits)
2. Recruiting Site (/sites/hr-recruiting)
3. Learning & Development (/sites/hr-learning)
4. Employee Handbook (/sites/hr-handbook)
5. Onboarding (/sites/hr-onboarding)

## Shared Navigation Items
- Home
- Benefits
- Careers
- Learning
- Policies
- Contact HR

## Branding
- Primary Color: #0078D4 (Microsoft Blue)
- Secondary Color: #005A9E
- Logo: HR_Logo.png
- Header Background: hr_header_bg.jpg

## Metadata (Site Columns)
- Department (Choice: HR, IT, Finance, Sales)
- Document Type (Choice: Policy, Form, Guide, Report)
- Review Date (Date)
- Owner (Person)

## Governance
- Content Review: Quarterly
- Access Review: Annually
- Site Owners: Must complete training
- Retention: 7 years for policies, 3 years for general content

Step 2: Create Hub Sites

Create Hub Site via PnP PowerShell

# Connect to SharePoint Admin Center
$tenantUrl = "https://contoso-admin.sharepoint.com"
$tenantName = "contoso"  # Your tenant name

Connect-PnPOnline -Url $tenantUrl -Interactive

# Create Communication Site (will become hub)
$hrSiteUrl = "https://$tenantName.sharepoint.com/sites/hr"
$hrSiteParams = @{
    Type                = "CommunicationSite"
    Title               = "Human Resources"
    Url                 = $hrSiteUrl
    Description         = "Central hub for all HR resources and information"
    Owner               = "[email protected]"
    SiteDesignId        = "6142d2a0-63a5-4ba0-aede-d9fefca2c767"  # Topic site design
    Lcid                = 1033  # English
    HubSiteDesignId     = "00000000-0000-0000-0000-000000000000"  # Will be hub
}

Write-Host "Creating HR site..." -ForegroundColor Cyan
New-PnPSite @hrSiteParams

Write-Host "βœ“ Site created: $hrSiteUrl" -ForegroundColor Green

# Wait for site provisioning to complete
Start-Sleep -Seconds 30

# Register site as Hub Site
Write-Host "Registering as Hub Site..." -ForegroundColor Cyan
Register-PnPHubSite -Site $hrSiteUrl

Write-Host "βœ“ Hub Site registered" -ForegroundColor Green

# Verify hub site creation
$hubSite = Get-PnPHubSite -Identity $hrSiteUrl
Write-Host "`nHub Site Details:" -ForegroundColor Yellow
Write-Host "  Title: $($hubSite.Title)"
Write-Host "  URL: $($hubSite.SiteUrl)"
Write-Host "  Hub Site ID: $($hubSite.ID)"

Create Multiple Hub Sites (Batch)

# Define all hub sites
$hubSites = @(
    @{
        Title       = "Human Resources"
        Url         = "/sites/hr"
        Description = "Central hub for all HR resources and information"
        Owner       = "[email protected]"
    },
    @{
        Title       = "Sales"
        Url         = "/sites/sales"
        Description = "Sales enablement and regional coordination"
        Owner       = "[email protected]"
    },
    @{
        Title       = "Information Technology"
        Url         = "/sites/it"
        Description = "IT services, projects, and documentation"
        Owner       = "[email protected]"
    },
    @{
        Title       = "Finance"
        Url         = "/sites/finance"
        Description = "Financial reporting and budget management"
        Owner       = "[email protected]"
    },
    @{
        Title       = "Marketing"
        Url         = "/sites/marketing"
        Description = "Marketing campaigns and brand resources"
        Owner       = "[email protected]"
    }
)

# Create and register each hub site
foreach ($hub in $hubSites) {
    $fullUrl = "https://$tenantName.sharepoint.com$($hub.Url)"
    
    Write-Host "`n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
    Write-Host "Creating Hub: $($hub.Title)" -ForegroundColor Cyan
    Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
    
    try {
        # Check if site already exists
        $existingSite = Get-PnPTenantSite -Url $fullUrl -ErrorAction SilentlyContinue
        
        if ($existingSite) {
            Write-Host "  ⚠ Site already exists: $fullUrl" -ForegroundColor Yellow
        } else {
            # Create site
            $siteParams = @{
                Type        = "CommunicationSite"
                Title       = $hub.Title
                Url         = $fullUrl
                Description = $hub.Description
                Owner       = $hub.Owner
                Lcid        = 1033
            }
            
            Write-Host "  β†’ Creating site..." -ForegroundColor Gray
            New-PnPSite @siteParams
            Start-Sleep -Seconds 20
            Write-Host "  βœ“ Site created" -ForegroundColor Green
        }
        
        # Check if already registered as hub
        $existingHub = Get-PnPHubSite -Identity $fullUrl -ErrorAction SilentlyContinue
        
        if ($existingHub) {
            Write-Host "  ⚠ Already registered as hub site" -ForegroundColor Yellow
        } else {
            # Register as hub site
            Write-Host "  β†’ Registering as hub site..." -ForegroundColor Gray
            Register-PnPHubSite -Site $fullUrl
            Write-Host "  βœ“ Hub site registered" -ForegroundColor Green
        }
        
    } catch {
        Write-Host "  βœ— Error: $($_.Exception.Message)" -ForegroundColor Red
    }
}

Write-Host "`n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Green
Write-Host "Hub Site Creation Complete!" -ForegroundColor Green
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`n" -ForegroundColor Green

# List all hub sites
Write-Host "All Hub Sites:" -ForegroundColor Yellow
Get-PnPHubSite | Select-Object Title, SiteUrl, ID | Format-Table -AutoSize

Step 3: Configure Hub Site Settings

Set Hub Site Logo and Theme

# Connect to the HR hub site
$hrSiteUrl = "https://contoso.sharepoint.com/sites/hr"
Connect-PnPOnline -Url $hrSiteUrl -Interactive

# Upload logo
$logoPath = "C:\Logos\HR_Logo.png"
$logoFile = Add-PnPFile -Path $logoPath -Folder "SiteAssets" -Publish

Write-Host "βœ“ Logo uploaded: $($logoFile.ServerRelativeUrl)" -ForegroundColor Green

# Set site logo
$web = Get-PnPWeb
Set-PnPWeb -LogoUrl "$($web.ServerRelativeUrl)/SiteAssets/HR_Logo.png"

Write-Host "βœ“ Logo applied to hub site" -ForegroundColor Green

# Define custom theme
$themeJson = @"
{
    "themePrimary": "#0078d4",
    "themeLighterAlt": "#eff6fc",
    "themeLighter": "#deecf9",
    "themeLight": "#c7e0f4",
    "themeTertiary": "#71afe5",
    "themeSecondary": "#2b88d8",
    "themeDarkAlt": "#106ebe",
    "themeDark": "#005a9e",
    "themeDarker": "#004578",
    "neutralLighterAlt": "#faf9f8",
    "neutralLighter": "#f3f2f1",
    "neutralLight": "#edebe9",
    "neutralQuaternaryAlt": "#e1dfdd",
    "neutralQuaternary": "#d0d0d0",
    "neutralTertiaryAlt": "#c8c6c4",
    "neutralTertiary": "#a19f9d",
    "neutralSecondary": "#605e5c",
    "neutralPrimaryAlt": "#3b3a39",
    "neutralPrimary": "#323130",
    "neutralDark": "#201f1e",
    "black": "#000000",
    "white": "#ffffff"
}
"@

# Add custom theme to tenant
Connect-PnPOnline -Url "https://contoso-admin.sharepoint.com" -Interactive

Add-PnPTenantTheme -Identity "HR Theme" -Palette $themeJson -IsInverted $false -Overwrite

Write-Host "βœ“ Custom theme created" -ForegroundColor Green

# Apply theme to hub site
Connect-PnPOnline -Url $hrSiteUrl -Interactive
Set-PnPWebTheme -Theme "HR Theme"

Write-Host "βœ“ Theme applied to hub site" -ForegroundColor Green

Configure Hub Site Navigation

# Connect to hub site
Connect-PnPOnline -Url $hrSiteUrl -Interactive

# Clear existing navigation
Get-PnPNavigationNode -Location TopNavigationBar | Remove-PnPNavigationNode -Force

# Add hub navigation links
$navItems = @(
    @{Title = "Home"; Url = "/sites/hr"},
    @{Title = "Benefits"; Url = "/sites/hr-benefits"},
    @{Title = "Careers"; Url = "/sites/hr-recruiting"},
    @{Title = "Learning"; Url = "/sites/hr-learning"},
    @{Title = "Policies"; Url = "/sites/hr-handbook"},
    @{Title = "Contact HR"; Url = "/sites/hr/Pages/Contact.aspx"}
)

Write-Host "Adding navigation items..." -ForegroundColor Cyan

foreach ($item in $navItems) {
    $fullUrl = "https://contoso.sharepoint.com$($item.Url)"
    
    Add-PnPNavigationNode -Title $item.Title `
                          -Url $fullUrl `
                          -Location TopNavigationBar
    
    Write-Host "  βœ“ Added: $($item.Title)" -ForegroundColor Green
}

Write-Host "`nβœ“ Navigation configured" -ForegroundColor Green

# Verify navigation
Get-PnPNavigationNode -Location TopNavigationBar | 
    Select-Object Title, Url | 
    Format-Table -AutoSize

Set Hub Site Permissions

# Connect to hub site
Connect-PnPOnline -Url $hrSiteUrl -Interactive

# Add hub site administrators
$hubAdmins = @(
    "[email protected]",
    "[email protected]",
    "[email protected]"
)

Write-Host "Adding hub site administrators..." -ForegroundColor Cyan

foreach ($admin in $hubAdmins) {
    try {
        Add-PnPHubSiteAssociation -Site $hrSiteUrl -HubSiteAdmin $admin
        Write-Host "  βœ“ Added: $admin" -ForegroundColor Green
    } catch {
        Write-Host "  βœ— Failed to add: $admin" -ForegroundColor Red
        Write-Host "    Error: $($_.Exception.Message)" -ForegroundColor Red
    }
}

# Grant hub site permissions (for association)
Grant-PnPHubSiteRights -Identity $hrSiteUrl -Principals $hubAdmins -Rights Join

Write-Host "`nβœ“ Hub administrators configured" -ForegroundColor Green

# List hub administrators
$hubSite = Get-PnPHubSite -Identity $hrSiteUrl
Write-Host "`nHub Administrators:" -ForegroundColor Yellow
$hubSite.SiteOwners | Format-Table

Step 4: Create and Associate Child Sites

Create Associated Sites

# Define associated sites for HR hub
$associatedSites = @(
    @{
        Title       = "Benefits"
        Url         = "/sites/hr-benefits"
        Description = "Employee benefits information and enrollment"
        Owner       = "[email protected]"
        Template    = "CommunicationSite"
    },
    @{
        Title       = "Recruiting"
        Url         = "/sites/hr-recruiting"
        Description = "Talent acquisition and recruiting resources"
        Owner       = "[email protected]"
        Template    = "CommunicationSite"
    },
    @{
        Title       = "Learning & Development"
        Url         = "/sites/hr-learning"
        Description = "Employee training and development programs"
        Owner       = "[email protected]"
        Template    = "CommunicationSite"
    },
    @{
        Title       = "Employee Handbook"
        Url         = "/sites/hr-handbook"
        Description = "Company policies and employee guidelines"
        Owner       = "[email protected]"
        Template    = "CommunicationSite"
    }
)

# Connect to tenant
Connect-PnPOnline -Url "https://contoso-admin.sharepoint.com" -Interactive

# Create each associated site
foreach ($site in $associatedSites) {
    $fullUrl = "https://contoso.sharepoint.com$($site.Url)"
    
    Write-Host "`nCreating: $($site.Title)" -ForegroundColor Cyan
    
    try {
        # Check if site exists
        $existingSite = Get-PnPTenantSite -Url $fullUrl -ErrorAction SilentlyContinue
        
        if ($existingSite) {
            Write-Host "  ⚠ Site already exists" -ForegroundColor Yellow
        } else {
            # Create site
            $siteParams = @{
                Type        = $site.Template
                Title       = $site.Title
                Url         = $fullUrl
                Description = $site.Description
                Owner       = $site.Owner
                Lcid        = 1033
            }
            
            New-PnPSite @siteParams
            Write-Host "  βœ“ Site created" -ForegroundColor Green
            
            # Wait for provisioning
            Start-Sleep -Seconds 15
        }
        
    } catch {
        Write-Host "  βœ— Error: $($_.Exception.Message)" -ForegroundColor Red
    }
}

Associate Sites with Hub

# Get hub site ID
$hrHubSite = Get-PnPHubSite -Identity "https://contoso.sharepoint.com/sites/hr"
$hrHubId = $hrHubSite.ID

Write-Host "Hub Site ID: $hrHubId" -ForegroundColor Yellow
Write-Host "`nAssociating sites with HR hub..." -ForegroundColor Cyan

foreach ($site in $associatedSites) {
    $fullUrl = "https://contoso.sharepoint.com$($site.Url)"
    
    try {
        # Connect to the site
        Connect-PnPOnline -Url $fullUrl -Interactive
        
        # Associate with hub
        Add-PnPHubSiteAssociation -Site $fullUrl -HubSite $hrHubId
        
        Write-Host "  βœ“ Associated: $($site.Title)" -ForegroundColor Green
        
    } catch {
        Write-Host "  βœ— Failed: $($site.Title)" -ForegroundColor Red
        Write-Host "    Error: $($_.Exception.Message)" -ForegroundColor Red
    }
}

Write-Host "`nβœ“ All sites associated with hub" -ForegroundColor Green

# Verify associations
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/hr" -Interactive
$associatedSites = Get-PnPHubSiteChild -Identity $hrHubId

Write-Host "`nAssociated Sites:" -ForegroundColor Yellow
$associatedSites | Select-Object Title, Url | Format-Table -AutoSize

Bulk Associate Existing Sites

# Find all sites with specific naming pattern
$sitesToAssociate = Get-PnPTenantSite | Where-Object { 
    $_.Url -like "*/sites/hr-*" -and 
    $_.Template -eq "SITEPAGEPUBLISHING#0"  # Communication site template
}

Write-Host "Found $($sitesToAssociate.Count) sites matching pattern" -ForegroundColor Yellow

foreach ($site in $sitesToAssociate) {
    Write-Host "`nProcessing: $($site.Url)" -ForegroundColor Cyan
    
    try {
        # Check if already associated
        Connect-PnPOnline -Url $site.Url -Interactive
        $currentHub = (Get-PnPSite).HubSiteId
        
        if ($currentHub -eq $hrHubId) {
            Write-Host "  ⚠ Already associated with HR hub" -ForegroundColor Yellow
        } elseif ($currentHub -ne [guid]::Empty) {
            Write-Host "  ⚠ Already associated with another hub: $currentHub" -ForegroundColor Yellow
        } else {
            # Associate with hub
            Add-PnPHubSiteAssociation -Site $site.Url -HubSite $hrHubId
            Write-Host "  βœ“ Successfully associated" -ForegroundColor Green
        }
        
    } catch {
        Write-Host "  βœ— Error: $($_.Exception.Message)" -ForegroundColor Red
    }
}

Step 5: Configure Aggregated Content

Create News Rollup on Hub Home

# Connect to hub site
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/hr" -Interactive

# Get or create homepage
$homePage = Get-PnPPage -Identity "Home.aspx" -ErrorAction SilentlyContinue

if (-not $homePage) {
    $homePage = Add-PnPPage -Name "Home" -LayoutType Home -Publish
    Write-Host "βœ“ Created homepage" -ForegroundColor Green
}

# Add News web part (aggregates from hub)
Add-PnPPageWebPart -Page $homePage `
                   -Component "News" `
                   -Section 1 `
                   -Column 1 `
                   -WebPartProperties @{
                       "dataProviderId" = "news"
                       "newsDataSourceProp" = 2  # 2 = Hub sites
                       "newsSiteList" = @()  # Empty = all associated sites
                       "layoutId" = "FeaturedNews"  # Featured news layout
                       "dataRowsLimit" = 10
                   }

Write-Host "βœ“ News rollup added to homepage" -ForegroundColor Green

# Add Events web part (aggregates from hub)
Add-PnPPageWebPart -Page $homePage `
                   -Component "Events" `
                   -Section 1 `
                   -Column 2 `
                   -WebPartProperties @{
                       "dataProviderId" = "events"
                       "eventsDataSource" = 2  # 2 = Hub sites
                       "layoutId" = "FilmStrip"
                       "dataRowsLimit" = 5
                   }

Write-Host "βœ“ Events rollup added to homepage" -ForegroundColor Green

# Add Highlighted Content (documents from hub)
Add-PnPPageWebPart -Page $homePage `
                   -Component "HighlightedContent" `
                   -Section 2 `
                   -Column 1 `
                   -WebPartProperties @{
                       "contentSource" = "hub"  # Hub source
                       "queryMode" = "Basic"
                       "query" = @{
                           "contentTypes" = @("Document")
                           "sortBy" = "Modified"
                           "sortOrder" = "desc"
                       }
                       "layoutId" = "Card"
                       "dataRowsLimit" = 12
                   }

Write-Host "βœ“ Highlighted content added to homepage" -ForegroundColor Green

# Publish page
Set-PnPPage -Identity "Home.aspx" -Publish

Write-Host "`nβœ“ Homepage published with aggregated content" -ForegroundColor Green

Create Custom Hub News Page

# Create dedicated news page
$newsPage = Add-PnPPage -Name "News" -LayoutType Article -Publish:$false

# Add page title section
Add-PnPPageTextPart -Page $newsPage -Text "# HR News & Updates" -Section 1 -Column 1

# Add News web part with filters
Add-PnPPageWebPart -Page $newsPage `
                   -Component "News" `
                   -Section 2 `
                   -Column 1 `
                   -WebPartProperties @{
                       "dataProviderId" = "news"
                       "newsDataSourceProp" = 2  # Hub sites
                       "layoutId" = "SideBySize"
                       "dataRowsLimit" = 20
                       "filterBy" = @{
                           "contentType" = "News"
                       }
                   }

# Publish news page
Set-PnPPage -Identity "News.aspx" -Publish

Write-Host "βœ“ Dedicated news page created" -ForegroundColor Green

# Add to navigation
Add-PnPNavigationNode -Title "News" `
                      -Url "/sites/hr/SitePages/News.aspx" `
                      -Location TopNavigationBar

Write-Host "βœ“ News page added to navigation" -ForegroundColor Green

Step 6: Implement Site Search Scope

Configure Hub Search Settings

# Connect to hub site
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/hr" -Interactive

# Create search schema (custom managed properties)
$searchConfig = @"
<SearchConfigurationSettings xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Office.Server.Search.Administration.SearchConfigurationSettings">
    <ManagedProperties>
        <ManagedProperty>
            <Name>HRDocumentType</Name>
            <Type>Text</Type>
            <RefinementFilters>
                <RefinementFilter>Document</RefinementFilter>
                <RefinementFilter>Policy</RefinementFilter>
                <RefinementFilter>Form</RefinementFilter>
                <RefinementFilter>Guide</RefinementFilter>
            </RefinementFilters>
        </ManagedProperty>
        <ManagedProperty>
            <Name>HRDepartment</Name>
            <Type>Text</Type>
            <RefinementFilters>
                <RefinementFilter>Benefits</RefinementFilter>
                <RefinementFilter>Recruiting</RefinementFilter>
                <RefinementFilter>Learning</RefinementFilter>
                <RefinementFilter>Compliance</RefinementFilter>
            </RefinementFilters>
        </ManagedProperty>
    </ManagedProperties>
</SearchConfigurationSettings>
"@

# Import search configuration
Set-PnPSearchConfiguration -Scope Site -Configuration $searchConfig

Write-Host "βœ“ Search configuration imported" -ForegroundColor Green

# Create custom search results page
$searchPage = Add-PnPPage -Name "SearchResults" -LayoutType Article -Publish:$false

# Add Search Results web part
Add-PnPPageWebPart -Page $searchPage `
                   -Component "SearchResults" `
                   -Section 1 `
                   -Column 1 `
                   -WebPartProperties @{
                       "queryText" = "{searchTerms} path:https://contoso.sharepoint.com/sites/hr*"
                       "resultSourceId" = "8413cd39-2156-4e00-b54d-11efd9abdb89"  # Local SharePoint Results
                       "refiners" = @{
                           "HRDocumentType" = @{
                               "displayName" = "Document Type"
                               "displayOrder" = 1
                           }
                           "HRDepartment" = @{
                               "displayName" = "Department"
                               "displayOrder" = 2
                           }
                           "FileType" = @{
                               "displayName" = "File Type"
                               "displayOrder" = 3
                           }
                       }
                   }

Set-PnPPage -Identity "SearchResults.aspx" -Publish

Write-Host "βœ“ Custom search results page created" -ForegroundColor Green

Step 7: Hub Site Governance

Create Hub Site Governance Policy

# Define governance metadata
$governanceMetadata = @{
    "HubSiteOwner" = "[email protected]"
    "HubSiteAdmins" = @("[email protected]", "[email protected]")
    "ReviewFrequency" = "Quarterly"
    "LastReview" = (Get-Date).ToString("yyyy-MM-dd")
    "NextReview" = (Get-Date).AddDays(90).ToString("yyyy-MM-dd")
    "RetentionPolicy" = "7 years for policies, 3 years for general content"
    "AccessReviewFrequency" = "Annually"
    "ComplianceRequirements" = @("GDPR", "SOX", "HIPAA")
}

# Connect to hub site
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/hr" -Interactive

# Store governance metadata as site properties
foreach ($key in $governanceMetadata.Keys) {
    $value = if ($governanceMetadata[$key] -is [array]) {
        $governanceMetadata[$key] -join ";"
    } else {
        $governanceMetadata[$key]
    }
    
    Set-PnPPropertyBagValue -Key "Governance_$key" -Value $value
    Write-Host "βœ“ Set: $key = $value" -ForegroundColor Green
}

Write-Host "`nβœ“ Governance metadata applied" -ForegroundColor Green

Monitor Hub Site Health

# Hub site health check script
function Get-HubSiteHealth {
    param(
        [string]$HubSiteUrl
    )
    
    Write-Host "`n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
    Write-Host "Hub Site Health Check: $HubSiteUrl" -ForegroundColor Cyan
    Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`n" -ForegroundColor Cyan
    
    try {
        # Connect to hub site
        Connect-PnPOnline -Url $HubSiteUrl -Interactive
        
        # Get hub site details
        $hub = Get-PnPHubSite -Identity $HubSiteUrl
        $web = Get-PnPWeb
        $site = Get-PnPSite
        
        # Get associated sites
        $associatedSites = Get-PnPHubSiteChild -Identity $hub.ID
        
        # Calculate metrics
        $metrics = @{
            "Hub Site Title" = $hub.Title
            "Hub Site URL" = $hub.SiteUrl
            "Hub Site ID" = $hub.ID
            "Associated Sites Count" = $associatedSites.Count
            "Storage Used (GB)" = [math]::Round($site.StorageUsageCurrent / 1024, 2)
            "Storage Quota (GB)" = [math]::Round($site.StorageMaximumLevel / 1024, 2)
            "Storage % Used" = [math]::Round(($site.StorageUsageCurrent / $site.StorageMaximumLevel) * 100, 2)
            "Last Modified" = $web.LastItemModifiedDate
            "Site Owners" = ($hub.SiteOwners -join ", ")
        }
        
        # Display metrics
        Write-Host "Hub Site Metrics:" -ForegroundColor Yellow
        foreach ($key in $metrics.Keys) {
            $color = if ($key -like "*% Used*" -and $metrics[$key] -gt 80) { "Red" } else { "White" }
            Write-Host "  $($key): $($metrics[$key])" -ForegroundColor $color
        }
        
        # Check for issues
        Write-Host "`nHealth Checks:" -ForegroundColor Yellow
        
        # Storage check
        $storagePercent = ($site.StorageUsageCurrent / $site.StorageMaximumLevel) * 100
        if ($storagePercent -gt 90) {
            Write-Host "  βœ— CRITICAL: Storage usage > 90%" -ForegroundColor Red
        } elseif ($storagePercent -gt 75) {
            Write-Host "  ⚠ WARNING: Storage usage > 75%" -ForegroundColor Yellow
        } else {
            Write-Host "  βœ“ Storage usage OK" -ForegroundColor Green
        }
        
        # Associated sites check
        if ($associatedSites.Count -eq 0) {
            Write-Host "  ⚠ WARNING: No associated sites" -ForegroundColor Yellow
        } else {
            Write-Host "  βœ“ $($associatedSites.Count) sites associated" -ForegroundColor Green
        }
        
        # Navigation check
        $navNodes = Get-PnPNavigationNode -Location TopNavigationBar
        if ($navNodes.Count -eq 0) {
            Write-Host "  ⚠ WARNING: No navigation configured" -ForegroundColor Yellow
        } else {
            Write-Host "  βœ“ $($navNodes.Count) navigation items configured" -ForegroundColor Green
        }
        
        # List associated sites
        if ($associatedSites.Count -gt 0) {
            Write-Host "`nAssociated Sites:" -ForegroundColor Yellow
            $associatedSites | ForEach-Object {
                Write-Host "  β€’ $($_.Title) ($($_.Url))" -ForegroundColor Gray
            }
        }
        
        # Return metrics
        return $metrics
        
    } catch {
        Write-Host "βœ— Error checking hub site health: $($_.Exception.Message)" -ForegroundColor Red
        return $null
    }
}

# Run health check
$healthMetrics = Get-HubSiteHealth -HubSiteUrl "https://contoso.sharepoint.com/sites/hr"

# Export to CSV for reporting
if ($healthMetrics) {
    $healthMetrics | Export-Csv -Path "HubSiteHealth_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
    Write-Host "`nβœ“ Health metrics exported to CSV" -ForegroundColor Green
}

Audit Hub Site Associations

# Audit all hub sites and their associations
function Get-HubSiteAudit {
    $tenantUrl = "https://contoso-admin.sharepoint.com"
    Connect-PnPOnline -Url $tenantUrl -Interactive
    
    Write-Host "Auditing all hub sites..." -ForegroundColor Cyan
    
    # Get all hub sites
    $hubSites = Get-PnPHubSite
    
    $auditReport = @()
    
    foreach ($hub in $hubSites) {
        Write-Host "`nProcessing: $($hub.Title)" -ForegroundColor Yellow
        
        # Get associated sites
        $associatedSites = Get-PnPHubSiteChild -Identity $hub.ID
        
        # Get hub admins
        Connect-PnPOnline -Url $hub.SiteUrl -Interactive
        $site = Get-PnPSite
        $owners = $site.Owner
        
        # Create report entry
        $reportEntry = [PSCustomObject]@{
            HubTitle = $hub.Title
            HubUrl = $hub.SiteUrl
            HubID = $hub.ID
            AssociatedSitesCount = $associatedSites.Count
            AssociatedSites = ($associatedSites.Title -join "; ")
            Owners = $owners.Email
            LastModified = $site.LastContentModifiedDate
            Status = if ($associatedSites.Count -eq 0) { "No Associations" } else { "Active" }
        }
        
        $auditReport += $reportEntry
        
        Write-Host "  Sites: $($associatedSites.Count)" -ForegroundColor Gray
    }
    
    # Export audit report
    $reportPath = "HubSiteAudit_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
    $auditReport | Export-Csv -Path $reportPath -NoTypeInformation
    
    Write-Host "`nβœ“ Audit complete: $reportPath" -ForegroundColor Green
    
    # Display summary
    Write-Host "`nAudit Summary:" -ForegroundColor Yellow
    Write-Host "  Total Hub Sites: $($hubSites.Count)" -ForegroundColor White
    Write-Host "  Total Associated Sites: $(($auditReport | Measure-Object -Property AssociatedSitesCount -Sum).Sum)" -ForegroundColor White
    Write-Host "  Active Hubs: $(($auditReport | Where-Object {$_.Status -eq 'Active'}).Count)" -ForegroundColor Green
    Write-Host "  Inactive Hubs: $(($auditReport | Where-Object {$_.Status -eq 'No Associations'}).Count)" -ForegroundColor Yellow
    
    return $auditReport
}

# Run audit
$auditReport = Get-HubSiteAudit
$auditReport | Format-Table -AutoSize

Step 8: Advanced Automation

Automate Hub Site Provisioning (Complete Solution)

# Complete hub site provisioning script
function New-CompleteHubSite {
    param(
        [Parameter(Mandatory=$true)]
        [string]$HubTitle,
        
        [Parameter(Mandatory=$true)]
        [string]$HubUrl,
        
        [Parameter(Mandatory=$true)]
        [string]$Description,
        
        [Parameter(Mandatory=$true)]
        [string]$Owner,
        
        [Parameter(Mandatory=$false)]
        [string]$LogoUrl,
        
        [Parameter(Mandatory=$false)]
        [string]$ThemeName = "Default",
        
        [Parameter(Mandatory=$false)]
        [array]$NavigationItems = @(),
        
        [Parameter(Mandatory=$false)]
        [array]$AssociatedSites = @()
    )
    
    $tenantName = "contoso"
    $fullHubUrl = "https://$tenantName.sharepoint.com$HubUrl"
    
    Write-Host "`n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
    Write-Host "Complete Hub Site Provisioning" -ForegroundColor Cyan
    Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`n" -ForegroundColor Cyan
    
    try {
        # Step 1: Create Communication Site
        Write-Host "Step 1: Creating communication site..." -ForegroundColor Yellow
        Connect-PnPOnline -Url "https://$tenantName-admin.sharepoint.com" -Interactive
        
        $siteParams = @{
            Type = "CommunicationSite"
            Title = $HubTitle
            Url = $fullHubUrl
            Description = $Description
            Owner = $Owner
            Lcid = 1033
        }
        
        New-PnPSite @siteParams
        Write-Host "  βœ“ Site created" -ForegroundColor Green
        Start-Sleep -Seconds 20
        
        # Step 2: Register as Hub Site
        Write-Host "`nStep 2: Registering as hub site..." -ForegroundColor Yellow
        Register-PnPHubSite -Site $fullHubUrl
        Write-Host "  βœ“ Hub site registered" -ForegroundColor Green
        $hubSite = Get-PnPHubSite -Identity $fullHubUrl
        $hubId = $hubSite.ID
        Write-Host "  Hub ID: $hubId" -ForegroundColor Gray
        
        # Step 3: Configure site settings
        Write-Host "`nStep 3: Configuring site settings..." -ForegroundColor Yellow
        Connect-PnPOnline -Url $fullHubUrl -Interactive
        
        # Apply theme
        if ($ThemeName -ne "Default") {
            Set-PnPWebTheme -Theme $ThemeName
            Write-Host "  βœ“ Theme applied: $ThemeName" -ForegroundColor Green
        }
        
        # Set logo
        if ($LogoUrl) {
            Set-PnPWeb -LogoUrl $LogoUrl
            Write-Host "  βœ“ Logo set" -ForegroundColor Green
        }
        
        # Step 4: Configure navigation
        if ($NavigationItems.Count -gt 0) {
            Write-Host "`nStep 4: Configuring navigation..." -ForegroundColor Yellow
            
            # Clear existing navigation
            Get-PnPNavigationNode -Location TopNavigationBar | Remove-PnPNavigationNode -Force
            
            foreach ($navItem in $NavigationItems) {
                Add-PnPNavigationNode -Title $navItem.Title `
                                      -Url $navItem.Url `
                                      -Location TopNavigationBar
                Write-Host "  βœ“ Added: $($navItem.Title)" -ForegroundColor Green
            }
        }
        
        # Step 5: Create homepage with aggregated content
        Write-Host "`nStep 5: Creating homepage..." -ForegroundColor Yellow
        
        $homePage = Add-PnPPage -Name "Home" -LayoutType Home -Publish:$false
        
        # Add hero web part
        Add-PnPPageWebPart -Page $homePage -Component "Hero" -Section 1 -Column 1
        
        # Add news rollup
        Add-PnPPageWebPart -Page $homePage `
                           -Component "News" `
                           -Section 2 `
                           -Column 1 `
                           -WebPartProperties @{
                               "dataProviderId" = "news"
                               "newsDataSourceProp" = 2
                               "layoutId" = "FeaturedNews"
                               "dataRowsLimit" = 6
                           }
        
        Set-PnPPage -Identity "Home.aspx" -Publish
        Write-Host "  βœ“ Homepage created with news rollup" -ForegroundColor Green
        
        # Step 6: Associate sites
        if ($AssociatedSites.Count -gt 0) {
            Write-Host "`nStep 6: Associating sites..." -ForegroundColor Yellow
            
            foreach ($siteUrl in $AssociatedSites) {
                try {
                    Add-PnPHubSiteAssociation -Site $siteUrl -HubSite $hubId
                    Write-Host "  βœ“ Associated: $siteUrl" -ForegroundColor Green
                } catch {
                    Write-Host "  βœ— Failed: $siteUrl - $($_.Exception.Message)" -ForegroundColor Red
                }
            }
        }
        
        Write-Host "`n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Green
        Write-Host "βœ“ Hub Site Provisioning Complete!" -ForegroundColor Green
        Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`n" -ForegroundColor Green
        
        Write-Host "Hub Site Details:" -ForegroundColor Yellow
        Write-Host "  Title: $HubTitle" -ForegroundColor White
        Write-Host "  URL: $fullHubUrl" -ForegroundColor White
        Write-Host "  Hub ID: $hubId" -ForegroundColor White
        Write-Host "  Associated Sites: $($AssociatedSites.Count)" -ForegroundColor White
        
        return @{
            Success = $true
            HubUrl = $fullHubUrl
            HubId = $hubId
        }
        
    } catch {
        Write-Host "`nβœ— Error during provisioning: $($_.Exception.Message)" -ForegroundColor Red
        return @{
            Success = $false
            Error = $_.Exception.Message
        }
    }
}

# Example: Provision complete HR hub
$hrHubConfig = @{
    HubTitle = "Human Resources"
    HubUrl = "/sites/hr"
    Description = "Central hub for all HR resources and information"
    Owner = "[email protected]"
    LogoUrl = "/sites/hr/SiteAssets/HR_Logo.png"
    ThemeName = "HR Theme"
    NavigationItems = @(
        @{Title = "Home"; Url = "/sites/hr"},
        @{Title = "Benefits"; Url = "/sites/hr-benefits"},
        @{Title = "Careers"; Url = "/sites/hr-recruiting"},
        @{Title = "Learning"; Url = "/sites/hr-learning"},
        @{Title = "Policies"; Url = "/sites/hr-handbook"}
    )
    AssociatedSites = @(
        "https://contoso.sharepoint.com/sites/hr-benefits",
        "https://contoso.sharepoint.com/sites/hr-recruiting",
        "https://contoso.sharepoint.com/sites/hr-learning",
        "https://contoso.sharepoint.com/sites/hr-handbook"
    )
}

$result = New-CompleteHubSite @hrHubConfig

if ($result.Success) {
    Write-Host "`nβœ“ Hub site ready: $($result.HubUrl)" -ForegroundColor Green
} else {
    Write-Host "`nβœ— Provisioning failed: $($result.Error)" -ForegroundColor Red
}

Best Practices Summary

DO:

  1. βœ… Plan hub site hierarchy before implementation
  2. βœ… Use semantic URLs (/sites/department-name)
  3. βœ… Limit hub sites (5-15 per tenant typically)
  4. βœ… Apply consistent branding across hubs
  5. βœ… Configure shared navigation early
  6. βœ… Set up news aggregation on hub homes
  7. βœ… Document governance and ownership
  8. βœ… Monitor hub site health regularly
  9. βœ… Train site owners on hub concepts
  10. βœ… Use PnP PowerShell for automation

DON'T:

  1. ❌ Create too many hub sites (causes confusion)
  2. ❌ Associate sites with multiple hubs
  3. ❌ Skip permission planning
  4. ❌ Forget to configure search scope
  5. ❌ Ignore governance and lifecycle management
  6. ❌ Over-nest hub hierarchies (keep flat)
  7. ❌ Use hub sites for temporary projects
  8. ❌ Skip training for site owners
  9. ❌ Neglect regular audits
  10. ❌ Hard-code URLs in navigation

Key Takeaways

  1. Hub sites connect your intranet - Unified navigation, search, and branding across related sites
  2. Planning is critical - Map your org structure to hub architecture before building
  3. Governance ensures success - Define ownership, review cycles, and compliance requirements
  4. Automation scales deployment - PnP PowerShell enables enterprise-wide provisioning
  5. Aggregated content drives engagement - News rollups and events keep users informed
  6. Permissions matter - Hub admins control associations, site owners manage content
  7. Monitoring prevents issues - Regular health checks identify problems early
  8. Search scope unifies discovery - Users find content across all associated sites
  9. Branding creates consistency - Shared themes and navigation improve UX
  10. Documentation drives adoption - Clear governance and training accelerate usage

Additional Resources

Next Steps

  1. Assess current structure: Map existing sites to logical hubs
  2. Create pilot hub: Start with one department (e.g., HR or IT)
  3. Define governance: Document policies, owners, and review cycles
  4. Automate provisioning: Build PowerShell scripts for consistency
  5. Train site owners: Conduct workshops on hub site concepts
  6. Roll out incrementally: Deploy one hub at a time, gather feedback
  7. Monitor and optimize: Use health checks and audits to improve
  8. Scale across organization: Apply learnings to remaining departments

Ready to unify your SharePoint environment? Start with a pilot hub site for your most mature departmentβ€”you'll immediately see the benefits of connected navigation and aggregated content!