Automates the creation and updating of a Table of Contents (TOC) article for both the global Knowledge Base (KB) and each company's KB in your Hudu instance. It generates a structured HTML representation of the KB folder hierarchy, linking to all relevant articles within the folders.
Global KB TOC: Generates a TOC for the global KB, listing all articles and folders.
Company-Specific TOC: Generates a TOC for each company's KB, organizing articles within their respective folder structures.
HTML Structure: Produces nested HTML lists for a clear hierarchical view of the documentation.
# Generate_TOC.ps1
# This script automates the creation and updating of a Table of Contents (TOC) article
# for both the global Knowledge Base (KB) and each company's KB in Hudu.
# Usage: ./Generate_TOC.ps1
# -------------------------------------------------------------------------
# User Environment
# -------------------------------------------------------------------------
# Before starting, you'll need to set 3 variables, just below their explanations.
# 1. Set your Azure Key Vault name
# 2. Set the name of your secret (which holds Hudu API key)
# 3. Set the URL of your Hudu instance-
$AzVault_Name = "ENTER YOUR KEY VAULT NAME HERE"
$AzVault_HuduSecretName = "ENTER YOUR KEY VAULT SECRET NAME HERE"
$HuduBaseURL = "HTTPS://YOUR.HUDU.DOMAIN"
# -------------------------------------------------------------------------
# Init Modules and Authenticate
# -------------------------------------------------------------------------
foreach ($module in @('Az.KeyVault', 'HuduAPI')) {
if (Get-Module -ListAvailable -Name $module) {
Write-Host "Importing module, $module...";
Import-Module $module
} else {
Write-Host "Installing and importing module $module...";
Install-Module $module -Force -AllowClobber;
Import-Module $module
}
}
if (-not (Get-AzContext)) {
Connect-AzAccount };
New-HuduAPIKey "$(Get-AzKeyVaultSecret -VaultName "$AzVault_Name" -Name "$AzVault_HuduSecretName" -AsPlainText)"
New-HuduBaseUrl $HuduBaseURL
# -------------------------------------------------------------------------
# Begin Script Logic
# -------------------------------------------------------------------------
# Set the name of the Table of Contents article.
$TOCArticleName = '000 - Table of Contents'
# Define the Get-ProcessedFolder function
function Get-ProcessedFolder {
param (
$FolderParentID, # ID of the parent folder being processed
$FolderName, # Name of the folder
$FolderDepth, # Depth of the folder in the hierarchy (used for HTML heading levels)
$Articles, # Collection of articles to be included in the TOC
$Folders, # Collection of folders to be included in the TOC
$HTML # List object used to accumulate the HTML content
)
# Limit the depth of the folder structure to 6 levels to prevent excessively deep nesting
if ($FolderDepth -gt 6) {
$Depth = 6
} else {
$Depth = $FolderDepth
}
# Add the folder name as a heading if depth is greater than 0, otherwise just open a list
if ($Depth -ne 0) {
$HTML.add("<h$($Depth)>$FolderName</h$Depth><ul>")
} else {
$HTML.add("<ul>")
}
# Add each article within the current folder to the HTML list
foreach ($Article in ($Articles | Where-Object { $FolderParentID -eq $_.folder_id } | Sort-Object name)) {
$HTML.add("<li><a href='$($Article.url)'>$($Article.Name)</a></li>")
}
# Recursively process subfolders
foreach ($Folder in ($Folders | Where-Object { $FolderParentID -eq $_.parent_folder_id } | Sort-Object name)) {
Get-ProcessedFolder -FolderParentID $Folder.id -FolderName $Folder.name -FolderDepth ($FolderDepth + 1) -Articles $Articles -Folders $Folders -HTML $HTML
}
# Close the HTML list
$HTML.add("</ul><br />")
}
# Retrieve all non-archived articles and all folders
$AllArticles = Get-HuduArticles | Where-Object { $_.archived -eq $false }
$Folders = Get-HuduFolders
# Retrieve any existing articles with the specified TOC name
$TableOfContentsArticles = Get-HuduArticles -Name $TOCArticleName
# Process the Global KB First
$GlobalKBs = $AllArticles | Where-Object { $_.company_id -eq $null }
$GlobalFolders = $Folders | Where-Object { $_.company_id -eq $null }
# Initialize an empty list to hold the HTML for the global TOC
[System.Collections.Generic.List[PSCustomObject]]$GlobalHTML = @()
$GlobalHTML.add('<h1 class="align-center">' + $TOCArticleName + '</h1>')
# Generate the HTML for the global KB
Get-ProcessedFolder -FolderParentID $null -FolderName "Top Level Documents" -FolderDepth 0 -Articles $GlobalKBs -Folders $GlobalFolders -HTML $GlobalHTML
# Check if the global TOC article already exists and create or update it as necessary
$KBArticle = $TableOfContentsArticles | Where-Object { $_.company_id -eq $null }
$KBCount = ($KBArticle | Measure-Object).count
if ($KBCount -eq 0) {
# Create a new TOC article if it doesn't exist
New-HuduArticle -Name $TOCArticleName -Content ($GlobalHTML -join '')
Write-Host "Created a new global TOC article." -ForegroundColor Green
} elseif ($KBCount -eq 1) {
# Update the existing TOC article if it exists
Set-HuduArticle -ArticleId $KBArticle.Id -Content ($GlobalHTML -join '') -Name $TOCArticleName
Write-Host "Updated the existing global TOC article." -ForegroundColor Yellow
} else {
# Raise an error if multiple TOC articles with the same name are found
Write-Error "Multiple KB Articles found with the same name."
}
# Generate the TOC for each company
foreach ($CompanyID in ($AllArticles.company_id | Select-Object -Unique)) {
$CompanyArticles = $AllArticles | Where-Object { $_.company_id -eq $CompanyID }
$CompanyFolders = $Folders | Where-Object { $_.company_id -eq $CompanyID }
# Initialize an empty list to hold the HTML for the company's TOC
[System.Collections.Generic.List[PSCustomObject]]$CompanyHTML = @()
$CompanyHTML.add('<h1 class="align-center">' + $TOCArticleName + '</h1>')
# Generate the HTML for the company's KB
Get-ProcessedFolder -FolderParentID $null -FolderName "Top Level Documents" -FolderDepth 0 -Articles $CompanyArticles -Folders $CompanyFolders -HTML $CompanyHTML
# Check if the company's TOC article already exists and create or update it as necessary
$CompanyArticle = $TableOfContentsArticles | Where-Object { $_.company_id -eq $CompanyID }
$CompanyCount = ($CompanyArticle | Measure-Object).count
if ($CompanyCount -eq 0) {
New-HuduArticle -Name $TOCArticleName -Content ($CompanyHTML -join '') -company_id $CompanyID
Write-Host "Created a new TOC article for Company ID $CompanyID." -ForegroundColor Green
} elseif ($CompanyCount -eq 1) {
Set-HuduArticle -ArticleId $CompanyArticle.Id -Content ($CompanyHTML -join '') -Name $TOCArticleName -company_id $CompanyID
Write-Host "Updated the existing TOC article for Company ID $CompanyID." -ForegroundColor Yellow
} else {
Write-Error "Multiple KB Articles found with the same name - Company ID: $CompanyID."
}
}
Remove-HuduAPIKey
Script Data
Language: PowerShell
Run As: Logged In User
Script Timeout Duration: 5 Mins
Prerequisites:
Ensure you have a valid Hudu API key with sufficient permissions to create and update articles.
Customize the TOC article name (
$TOCArticleName
) as needed before running.
Script credit: https://mspp.io/powershell-hudu-table-of-contents/