0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
JPPINTO
  • Home
  • Certifications
  • About
  • Contact
  • Gallery
  • Current Setup
Contact

Search

June 23, 2026 / Microsoft 365, PowerShell, SharePoint Online

PowerShell Script to Generate SharePoint PowerPoint Version History with Microsoft Graph

Tags: microsoft 365, microsoft graph, powerpoint, powershell, sharepoint online, version history

This PowerShell script connects to Microsoft Graph, resolves a SharePoint PowerPoint file from a sharing URL, reads the file's version history, and repeatedly restores a previous version until the target version count is reached. It is useful for learning how SharePoint versioning works through Microsoft Graph and for building a controlled test document with many version-history entries.

What It Does

  • Installs and imports the Microsoft Graph authentication module if needed.
  • Connects to Microsoft Graph with file and site read/write scopes.
  • Converts a SharePoint sharing URL into a Microsoft Graph share ID.
  • Resolves the target drive item and reads its current version history.
  • Restores a previous version repeatedly until the configured target version count is met.
  • Retries common transient Microsoft Graph and SharePoint lock errors.

Before running the script, update <tenant>, <site-name>, <document-guid>, and <presentation-file-name> so they point to the PowerPoint file you want to use in your own Microsoft 365 tenant. The SharePoint host should look like https://<tenant>.sharepoint.com.

How to Run the Script

Open PowerShell, change to the folder where you saved the script, and run it with the script path:

.\script_location\scriptname.ps1

For this example, if the script is saved in C:\Scripts, run:

Set-Location C:\Scripts
.\increaseVersions.ps1

If PowerShell blocks the script from running, read Make Sure PowerShell Scripts Can Run on Windows for the execution policy commands that allow local scripts to run.

PowerShell Script

Clear-Host
Push-Location $PSScriptRoot

#region Settings
Write-Host "Configuring settings..."

$SharingUrl = "https://<tenant>.sharepoint.com/:p:/r/sites/<site-name>/_layouts/15/Doc.aspx?sourcedoc=%7B<document-guid>%7D&file=<presentation-file-name>.pptx&action=edit&mobileredirect=true"
$TargetVersionCount = 500
$SleepSeconds = 2

$GraphScopes = @(
    "Files.ReadWrite.All",
    "Sites.ReadWrite.All"
)

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Write-Host "Target version count: $TargetVersionCount"
Write-Host "Sleep seconds between restores: $SleepSeconds"
#endregion Settings

#region Functions
function Install-RequiredGraphModule {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ModuleName
    )

    Write-Host "Checking module: $ModuleName"

    $ExistingModule = Get-Module -ListAvailable -Name $ModuleName |
        Sort-Object Version -Descending |
        Select-Object -First 1

    if ($ExistingModule) {
        Write-Host "Module already installed: $ModuleName"
        Write-Host "Version: $($ExistingModule.Version)"
        Write-Host "Path: $($ExistingModule.ModuleBase)"
        return
    }

    Write-Host "Module not found. Installing: $ModuleName"

    $NuGetProvider = Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue

    if (-not $NuGetProvider) {
        Write-Host "NuGet provider not found. Installing NuGet provider..."
        Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser
        Write-Host "NuGet provider installed."
    }
    else {
        Write-Host "NuGet provider already installed."
    }

    $PowerShellGetModule = Get-Module -ListAvailable -Name PowerShellGet |
        Sort-Object Version -Descending |
        Select-Object -First 1

    if (-not $PowerShellGetModule) {
        throw "PowerShellGet is required but was not found."
    }

    Write-Host "PowerShellGet version: $($PowerShellGetModule.Version)"

    $Gallery = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue

    if (-not $Gallery) {
        throw "PSGallery repository was not found."
    }

    if ($Gallery.InstallationPolicy -ne "Trusted") {
        Write-Host "Setting PSGallery as trusted..."
        Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
        Write-Host "PSGallery is now trusted."
    }
    else {
        Write-Host "PSGallery is already trusted."
    }

    Install-Module -Name $ModuleName -Scope CurrentUser -Force -AllowClobber

    $InstalledModule = Get-Module -ListAvailable -Name $ModuleName |
        Sort-Object Version -Descending |
        Select-Object -First 1

    if (-not $InstalledModule) {
        throw "Failed to install module: $ModuleName"
    }

    Write-Host "Module installed successfully: $ModuleName"
    Write-Host "Version: $($InstalledModule.Version)"
    Write-Host "Path: $($InstalledModule.ModuleBase)"
}

function ConvertTo-GraphShareId {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Url
    )

    Write-Host "Encoding SharePoint URL for Microsoft Graph shares endpoint..."

    $Bytes = [System.Text.Encoding]::UTF8.GetBytes($Url)
    $Base64 = [System.Convert]::ToBase64String($Bytes)
    $Encoded = "u!" + $Base64.TrimEnd("=").Replace("/", "_").Replace("+", "-")

    if (-not $Encoded.StartsWith("u!")) {
        throw "Failed to encode SharePoint URL."
    }

    Write-Host "SharePoint URL encoded successfully."

    return $Encoded
}

function Invoke-GraphRequestWithRetry {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Method,

        [Parameter(Mandatory = $true)]
        [string]$Uri,

        [Parameter(Mandatory = $false)]
        [object]$Body = $null,

        [Parameter(Mandatory = $false)]
        [int]$MaxRetries = 12
    )

    $Attempt = 0

    while ($Attempt -lt $MaxRetries) {
        $Attempt++

        try {
            if ($null -ne $Body) {
                return Invoke-MgGraphRequest -Method $Method -Uri $Uri -Body $Body
            }
            else {
                return Invoke-MgGraphRequest -Method $Method -Uri $Uri
            }
        }
        catch {
            $StatusCode = $null
            $ErrorText = $_.Exception.Message

            if ($_.Exception.Response -and $_.Exception.Response.StatusCode) {
                $StatusCode = [int]$_.Exception.Response.StatusCode
            }

            if ($StatusCode -in @(423, 429, 500, 502, 503, 504) -and $Attempt -lt $MaxRetries) {
                if ($StatusCode -eq 423) {
                    $DelaySeconds = 30
                    Write-Host "File is locked by SharePoint or an Office editing session. Retry $Attempt of $MaxRetries in $DelaySeconds seconds..."
                    Write-Host "Close the file in PowerPoint Online, PowerPoint desktop, Teams, OneDrive sync, and any browser tabs."
                }
                else {
                    $DelaySeconds = [Math]::Min(60, [Math]::Pow(2, $Attempt))
                    Write-Host "Graph request failed with status $StatusCode. Retry $Attempt of $MaxRetries in $DelaySeconds seconds..."
                }

                Start-Sleep -Seconds $DelaySeconds
            }
            else {
                Write-Host "Graph request failed."
                Write-Host "Status code: $StatusCode"
                Write-Host "Method: $Method"
                Write-Host "Uri: $Uri"
                Write-Host "Error: $ErrorText"
                throw
            }
        }
    }

    throw "Graph request failed after $MaxRetries attempts."
}

function Get-GraphCollection {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Uri
    )

    $AllItems = New-Object System.Collections.Generic.List[object]
    $NextUri = $Uri

    while ($NextUri) {
        $Response = Invoke-GraphRequestWithRetry -Method "GET" -Uri $NextUri

        if ($Response.value) {
            foreach ($Item in $Response.value) {
                $AllItems.Add($Item)
            }
        }

        if ($Response.'@odata.nextLink') {
            $NextUri = $Response.'@odata.nextLink'
        }
        else {
            $NextUri = $null
        }
    }

    return $AllItems
}

function Get-CurrentVersionCount {
    param(
        [Parameter(Mandatory = $true)]
        [string]$VersionsUri
    )

    Write-Host "Reading current version history..."

    $Versions = Get-GraphCollection -Uri $VersionsUri
    $VersionCount = $Versions.Count

    Write-Host "Current version count: $VersionCount"

    return @{
        Count    = $VersionCount
        Versions = $Versions
    }
}

function Get-RestoreVersion {
    param(
        [Parameter(Mandatory = $true)]
        [object[]]$Versions
    )

    Write-Host "Selecting previous version to restore..."

    $SortedVersions = $Versions |
        Where-Object { $_.id -match '^\d+(\.\d+)?$' } |
        Sort-Object { [version]$_.id } -Descending

    if (-not $SortedVersions -or $SortedVersions.Count -lt 2) {
        throw "At least two versions are required. Cannot restore the current version."
    }

    $RestoreVersion = $SortedVersions |
        Select-Object -Skip 1 -First 1

    if (-not $RestoreVersion -or -not $RestoreVersion.id) {
        throw "Could not select a previous version to restore."
    }

    Write-Host "Selected previous version: $($RestoreVersion.id)"

    return $RestoreVersion
}
#endregion Functions

#region Module Install And Import
Write-Host "Preparing Microsoft Graph module..."

Install-RequiredGraphModule -ModuleName "Microsoft.Graph.Authentication"

Write-Host "Importing Microsoft.Graph.Authentication..."

Import-Module Microsoft.Graph.Authentication -Force

$GraphModule = Get-Module -ListAvailable -Name Microsoft.Graph.Authentication |
    Sort-Object Version -Descending |
    Select-Object -First 1

if (-not $GraphModule) {
    throw "Microsoft.Graph.Authentication was not found after install."
}

Write-Host "Microsoft.Graph.Authentication is ready."
Write-Host "Version: $($GraphModule.Version)"
#endregion Module Install And Import

#region Authentication
Write-Host "Connecting to Microsoft Graph..."

Connect-MgGraph -Scopes $GraphScopes

$Context = Get-MgContext

if (-not $Context) {
    throw "Microsoft Graph connection failed."
}

Write-Host "Connected to Microsoft Graph."
Write-Host "Tenant/account details omitted from console output."
#endregion Authentication

#region Resolve SharePoint File
Write-Host "Resolving SharePoint file from URL..."

$ShareId = ConvertTo-GraphShareId -Url $SharingUrl
$DriveItemUri = "https://graph.microsoft.com/v1.0/shares/$ShareId/driveItem"

$DriveItem = Invoke-GraphRequestWithRetry -Method "GET" -Uri $DriveItemUri

if (-not $DriveItem.id) {
    throw "Failed to resolve drive item ID."
}

if (-not $DriveItem.parentReference.driveId) {
    throw "Failed to resolve drive ID."
}

$DriveId = $DriveItem.parentReference.driveId
$ItemId = $DriveItem.id

Write-Host "Resolved file: $($DriveItem.name)"
Write-Host "Drive ID: $DriveId"
Write-Host "Item ID: $ItemId"
#endregion Resolve SharePoint File

#region Get Version Information
$VersionsUri = "https://graph.microsoft.com/v1.0/drives/$DriveId/items/$ItemId/versions"

$VersionInfo = Get-CurrentVersionCount -VersionsUri $VersionsUri
$CurrentVersionCount = $VersionInfo.Count
$Versions = $VersionInfo.Versions

if ($CurrentVersionCount -ge $TargetVersionCount) {
    Write-Host "Target already reached. Current version count: $CurrentVersionCount"
    exit
}

if (-not $Versions -or $Versions.Count -eq 0) {
    throw "No versions were returned for this file."
}

$RestoreVersion = Get-RestoreVersion -Versions $Versions

Write-Host "Version selected for repeated restore: $($RestoreVersion.id)"
#endregion Get Version Information

#region Increase Versions
Write-Host "Starting version increase process..."

while ($CurrentVersionCount -lt $TargetVersionCount) {
    $RestoreUri = "https://graph.microsoft.com/v1.0/drives/$DriveId/items/$ItemId/versions/$($RestoreVersion.id)/restoreVersion"

    Write-Host "Restoring version $($RestoreVersion.id). Current count: $CurrentVersionCount / $TargetVersionCount"

    Invoke-GraphRequestWithRetry -Method "POST" -Uri $RestoreUri -Body "{}" | Out-Null

    Write-Host "Restore request completed."

    Start-Sleep -Seconds $SleepSeconds

    $VersionInfo = Get-CurrentVersionCount -VersionsUri $VersionsUri
    $NewVersionCount = $VersionInfo.Count
    $Versions = $VersionInfo.Versions

    if ($NewVersionCount -le $CurrentVersionCount) {
        Write-Host "Version count did not increase. Previous count: $CurrentVersionCount. New count: $NewVersionCount."
        Write-Host "Stopping to avoid endless loop."
        break
    }

    $CurrentVersionCount = $NewVersionCount
    $RestoreVersion = Get-RestoreVersion -Versions $Versions

    Write-Host "Next restore version selected: $($RestoreVersion.id)"

    if ($CurrentVersionCount -ge $TargetVersionCount) {
        Write-Host "Target reached. Current version count: $CurrentVersionCount"
        break
    }
}

Write-Host "Version increase process completed."
Write-Host "Final version count: $CurrentVersionCount"
#endregion Increase Versions
.posts/2026.06.23/increaseVersions.ps1
Post Views: 11
<- PowerShell Script to Generate a Large PowerPoint PPTX Test File
Make Sure PowerShell Scripts Can Run on Windows ->

Categories

  • Active Directory (5)
  • AI (1)
  • Amazon Cloud Services (1)
  • Blazor (1)
  • C# (C-Sharp) (3)
  • CI/CD Pipelines (1)
  • Containers (4)
  • Deployment (2)
  • Development (3)
  • Docker (3)
  • General (5)
  • IIS 6.0 (4)
  • IIS 7.0 (10)
  • IIS 8.0 (1)
  • Infrastructure as Code (IaC) (1)
  • Kubernetes (3)
  • Microsoft 365 (2)
  • MySQL (1)
  • Office 2010 (1)
  • PHP (1)
  • PowerShell (6)
  • SharePoint 2007 (8)
  • SharePoint 2010 (19)
  • SharePoint 2013 (2)
  • SharePoint Online (1)
  • SMTP (4)
  • SQL Server 2008 (1)
  • SQL Server 2008 R2 (1)
  • SQL Server 2012 (2)
  • SQL Server 2019 (1)
  • Uncategorized (1)
  • URL Rewrite (2)
  • Visual Studio 2019 (1)
  • Visual Studio Code (1)
  • Windows 10 (4)
  • Windows 2003 (9)
  • Windows 2008 (18)
  • Windows 2012 (6)
  • Windows 7 (3)
  • Windows Firewall (1)
  • Windows Vista (1)
  • WordPress (4)
  • WP-CLI (3)

Recent Posts

  • Use AGENTS.md, CLAUDE.md, Cursor Rules, and Prompt Logs to Keep AI Coding Bots in Context
  • Copy WordPress Plugin Settings from Dev to Production with WP-CLI
  • Move WordPress Articles from Dev to Production with WP-CLI
  • Install WP-CLI on Windows and Run Basic WordPress Commands
  • Make Sure PowerShell Scripts Can Run on Windows

Advertisement

Tags

backconnectionhostnames custom column dev to production disable shutdown event tracker error opening exe exe permissions externalize blob externalize sharepoint data filezilla server firewall rules filazilla full installation http redirect https https redirect IIS iis7 iis 7 installation IIS installation index server configuration installing cumulative updates load balance central administration microsoft 365 moss advanced search nlb no default gateway powerpoint powershell redirect http to https search column sharepoint 2010 cumulative updates sharepoint 2010 farm build sharepoint 2010 farm configuration sharepoint 2010 farm installation sharepoint data externalization shutdown event tracker shutdown tracker SMTP storagepoint Windows 7 windows firewall configuration windows server 2008 wlbs wordpress wp-cli x86
© 2026 JPPinto.com – Tech Blog. All rights reserved.