Skip to main content

Command Palette

Search for a command to run...

Powershell script to download Azure DevOps project wiki

Published
2 min read
Powershell script to download Azure DevOps project wiki

Azure DevOps has two types of wikis:

  1. Code wikis (Git-backed) - which you can clone

  2. Project wikis (non-Git) - stored in Azure DevOps' internal storage

The Azure DevOps UI gives you the URL to clone a code wiki locally, but does not provide a way to download a project wiki. Using Claude, I vibe coded a powershell script to download a project wiki. I’ve tested it only once and although it worked for my wiki, I can’t guarantee it generalises well to all wikis.

It requires a PAT token. You can create these from https://dev.azure.com/{Your_Organization}/_usersSettings/tokens. The only permission necessary is Wiki (Read). When adding a new PAT token, you'll need to click Show All Scopes then scroll to the bottom of the list to find it.

The script

For some reason, Hashnode (the platform which powers this blog) has messed up the formatting of this powershell script and tried to escape lots of characters. There shouldn't be any backslash characters (\) in the script, so if you remove all of them then it should work.

$org = "your-org"
$project = "your-project"
$wikiId = "your-wiki-id"
$pat = "your-personal-access-token"

Write-Host "Starting wiki backup..." -ForegroundColor Green

\(base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":\)pat"))
\(headers = @{Authorization = "Basic \)base64AuthInfo"}

# Get all pages
\(pagesUrl = "https://dev.azure.com/\)org/\(project/_apis/wiki/wikis/\)wikiId/pages?recursionLevel=full&api-version=7.0"
Write-Host "Fetching pages from: $pagesUrl" -ForegroundColor Cyan

try {
    \(result = Invoke-RestMethod -Uri \)pagesUrl -Headers $headers
    Write-Host "Wiki structure retrieved" -ForegroundColor Green
} catch {
    Write-Host "Error fetching pages: $_" -ForegroundColor Red
    exit
}

# Function to recursively process pages
function Process-WikiPage {
    param($page)
    
    # Skip the root page (path = "/")
    if ($page.path -ne "/") {
        Write-Host "Downloading: \((\)page.path)" -ForegroundColor Yellow
        \(pageUrl = "https://dev.azure.com/\)org/\(project/_apis/wiki/wikis/\)wikiId/pages?path=\((\)page.path)&includeContent=true&api-version=7.0"
        
        try {
            \(content = Invoke-RestMethod -Uri \)pageUrl -Headers $headers
            
            # Save to file
            \(filePath = "wiki-backup\)($page.path).md"
            \(directory = Split-Path \)filePath -Parent
            if (\(directory -and !(Test-Path \)directory)) {
                New-Item -Path $directory -ItemType Directory -Force | Out-Null
            }
            \(content.content | Out-File -FilePath \)filePath -Encoding UTF8
            Write-Host "Saved: $filePath" -ForegroundColor Green
        } catch {
            Write-Host "Error downloading \((\)page.path): $_" -ForegroundColor Red
        }
    }
    
    # Process subpages recursively
    if (\(page.subPages -and \)page.subPages.Count -gt 0) {
        foreach (\(subPage in \)page.subPages) {
            Process-WikiPage -page $subPage
        }
    }
}

# Start processing from the root
Process-WikiPage -page $result

Write-Host "Backup complete!" -ForegroundColor Green