PowerShell Script to Generate a Large PowerPoint PPTX Test File
This PowerShell script builds a large PowerPoint .pptx file from scratch by writing the Open XML presentation package directly into a ZIP archive. It creates hundreds of slides, adds generated bitmap payloads, and validates the final file size, making it useful when testing Microsoft 365, SharePoint, OneDrive, upload, sync, storage, or version-history behavior.
What It Does
- Creates a valid PowerPoint Open XML package without needing PowerPoint installed.
- Generates presentation, slide, relationship, theme, metadata, and content-type XML.
- Adds random bitmap data to each slide to reach a target file size.
- Removes an existing output file before generating a fresh test file.
- Validates that the generated
.pptxexists and is within the expected size range.
Adjust $TargetSizeMB, $SlideCount, and $OutputPptx to generate the file size and slide count you need for your own test case.
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 .\genpptx.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 References
# Open XML Presentation structure:
# https://learn.microsoft.com/en-us/office/open-xml/presentation/structure-of-a-presentationml-document
# .NET ZipArchive:
# https://learn.microsoft.com/en-us/dotnet/api/system.io.compression.ziparchive
# RandomNumberGenerator:
# https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator
#endregion
#region Settings
$OutputPptx = Join-Path $PSScriptRoot "Generated-170MB-Test.pptx"
$TargetSizeMB = 180
$SlideCount = 300
$TargetBytes = $TargetSizeMB * 1024 * 1024
$ApproxBytesPerImage = [Math]::Floor(($TargetBytes - 1024KB) / $SlideCount)
Write-Host "Target PPTX size: $TargetSizeMB MB"
Write-Host "Slide count: $SlideCount"
Write-Host "Approx image bytes per slide: $ApproxBytesPerImage"
#endregion
#region Load Assemblies
Write-Host "Loading .NET ZIP assemblies..."
try {
Add-Type -AssemblyName System.IO.Compression -ErrorAction Stop
Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop
Write-Host "Assemblies loaded successfully."
}
catch {
Write-Host "Failed to load required .NET assemblies."
throw
}
#endregion
#region Helper Functions
function Add-ZipTextEntry {
param (
[Parameter(Mandatory = $true)]
[System.IO.Compression.ZipArchive]$Zip,
[Parameter(Mandatory = $true)]
[string]$Path,
[Parameter(Mandatory = $true)]
[string]$Text
)
Write-Host "Adding XML entry: $Path"
$Entry = $Zip.CreateEntry($Path, [System.IO.Compression.CompressionLevel]::Optimal)
$Stream = $Entry.Open()
$Writer = New-Object System.IO.StreamWriter($Stream, [System.Text.UTF8Encoding]::new($false))
try {
$Writer.Write($Text)
$Writer.Flush()
Write-Host "Added XML entry successfully: $Path"
}
finally {
$Writer.Dispose()
$Stream.Dispose()
}
}
function Add-RandomBmpEntry {
param (
[Parameter(Mandatory = $true)]
[System.IO.Compression.ZipArchive]$Zip,
[Parameter(Mandatory = $true)]
[string]$Path,
[Parameter(Mandatory = $true)]
[int]$ApproxPayloadBytes
)
Write-Host "Adding random BMP entry: $Path"
$Width = 1920
$BitsPerPixel = 24
$RowStride = [Math]::Floor((($BitsPerPixel * $Width + 31) / 32)) * 4
$Height = [Math]::Max(1, [Math]::Floor($ApproxPayloadBytes / $RowStride))
$PixelDataSize = $RowStride * $Height
$FileSize = 54 + $PixelDataSize
Write-Host "BMP dimensions: $Width x $Height"
Write-Host "BMP file size before ZIP: $([Math]::Round($FileSize / 1MB, 2)) MB"
$Entry = $Zip.CreateEntry($Path, [System.IO.Compression.CompressionLevel]::NoCompression)
$Stream = $Entry.Open()
try {
$Header = New-Object byte[] 54
$Header[0] = 0x42
$Header[1] = 0x4D
[BitConverter]::GetBytes([int]$FileSize).CopyTo($Header, 2)
[BitConverter]::GetBytes([int]54).CopyTo($Header, 10)
[BitConverter]::GetBytes([int]40).CopyTo($Header, 14)
[BitConverter]::GetBytes([int]$Width).CopyTo($Header, 18)
[BitConverter]::GetBytes([int]$Height).CopyTo($Header, 22)
[BitConverter]::GetBytes([short]1).CopyTo($Header, 26)
[BitConverter]::GetBytes([short]$BitsPerPixel).CopyTo($Header, 28)
[BitConverter]::GetBytes([int]0).CopyTo($Header, 30)
[BitConverter]::GetBytes([int]$PixelDataSize).CopyTo($Header, 34)
[BitConverter]::GetBytes([int]2835).CopyTo($Header, 38)
[BitConverter]::GetBytes([int]2835).CopyTo($Header, 42)
$Stream.Write($Header, 0, $Header.Length)
$BufferSize = 1024 * 1024
$Buffer = New-Object byte[] $BufferSize
$Rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$Remaining = $PixelDataSize
while ($Remaining -gt 0) {
$BytesToWrite = [Math]::Min($BufferSize, $Remaining)
$Rng.GetBytes($Buffer)
$Stream.Write($Buffer, 0, $BytesToWrite)
$Remaining -= $BytesToWrite
}
$Rng.Dispose()
Write-Host "Added BMP entry successfully: $Path"
}
finally {
$Stream.Dispose()
}
}
function Get-SlideXml {
param (
[Parameter(Mandatory = $true)]
[int]$SlideNumber
)
@"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
<p:cSld>
<p:spTree>
<p:nvGrpSpPr>
<p:cNvPr id="1" name=""/>
<p:cNvGrpSpPr/>
<p:nvPr/>
</p:nvGrpSpPr>
<p:grpSpPr>
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="0" cy="0"/>
<a:chOff x="0" y="0"/>
<a:chExt cx="0" cy="0"/>
</a:xfrm>
</p:grpSpPr>
<p:pic>
<p:nvPicPr>
<p:cNvPr id="2" name="Generated image $SlideNumber"/>
<p:cNvPicPr/>
<p:nvPr/>
</p:nvPicPr>
<p:blipFill>
<a:blip r:embed="rIdImage$SlideNumber"/>
<a:stretch>
<a:fillRect/>
</a:stretch>
</p:blipFill>
<p:spPr>
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="12192000" cy="6858000"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</p:spPr>
</p:pic>
</p:spTree>
</p:cSld>
<p:clrMapOvr>
<a:masterClrMapping/>
</p:clrMapOvr>
</p:sld>
"@
}
function Get-SlideRelXml {
param (
[Parameter(Mandatory = $true)]
[int]$SlideNumber
)
@"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rIdImage$SlideNumber" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image$SlideNumber.bmp"/>
<Relationship Id="rIdLayout" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout1.xml"/>
</Relationships>
"@
}
#endregion
#region Remove Existing File
Write-Host "Checking for existing output file..."
try {
if (Test-Path $OutputPptx) {
Remove-Item $OutputPptx -Force -ErrorAction Stop
Write-Host "Existing file removed: $OutputPptx"
}
else {
Write-Host "No existing output file found."
}
}
catch {
Write-Host "Failed to remove existing output file."
throw
}
#endregion
#region Build Presentation XML
Write-Host "Building presentation XML..."
$SlideIdList = New-Object System.Text.StringBuilder
$PresentationRels = New-Object System.Text.StringBuilder
$ContentOverrides = New-Object System.Text.StringBuilder
for ($i = 1; $i -le $SlideCount; $i++) {
$SlideId = 255 + $i
[void]$SlideIdList.AppendLine(" <p:sldId id=`"$SlideId`" r:id=`"rIdSlide$i`"/>")
[void]$PresentationRels.AppendLine(" <Relationship Id=`"rIdSlide$i`" Type=`"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide`" Target=`"slides/slide$i.xml`"/>")
[void]$ContentOverrides.AppendLine(" <Override PartName=`"/ppt/slides/slide$i.xml`" ContentType=`"application/vnd.openxmlformats-officedocument.presentationml.slide+xml`"/>")
}
$ContentTypesXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Default Extension="xml" ContentType="application/xml"/>
<Default Extension="bmp" ContentType="image/bmp"/>
<Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/>
<Override PartName="/ppt/slideMasters/slideMaster1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"/>
<Override PartName="/ppt/slideLayouts/slideLayout1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/>
<Override PartName="/ppt/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/>
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
$($ContentOverrides.ToString().TrimEnd())
</Types>
"@
$RootRelsXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="ppt/presentation.xml"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
</Relationships>
"@
$PresentationXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<p:presentation xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
<p:sldMasterIdLst>
<p:sldMasterId id="2147483648" r:id="rIdMaster1"/>
</p:sldMasterIdLst>
<p:sldIdLst>
$($SlideIdList.ToString().TrimEnd())
</p:sldIdLst>
<p:sldSz cx="12192000" cy="6858000" type="wide"/>
<p:notesSz cx="6858000" cy="9144000"/>
</p:presentation>
"@
$PresentationRelsXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
$($PresentationRels.ToString().TrimEnd())
<Relationship Id="rIdMaster1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="slideMasters/slideMaster1.xml"/>
<Relationship Id="rIdTheme1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
</Relationships>
"@
$SlideMasterXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<p:sldMaster xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
<p:cSld>
<p:bg>
<p:bgPr>
<a:solidFill>
<a:srgbClr val="FFFFFF"/>
</a:solidFill>
</p:bgPr>
</p:bg>
<p:spTree>
<p:nvGrpSpPr>
<p:cNvPr id="1" name=""/>
<p:cNvGrpSpPr/>
<p:nvPr/>
</p:nvGrpSpPr>
<p:grpSpPr/>
</p:spTree>
</p:cSld>
<p:sldLayoutIdLst>
<p:sldLayoutId id="2147483649" r:id="rIdLayout1"/>
</p:sldLayoutIdLst>
<p:txStyles>
<p:titleStyle/>
<p:bodyStyle/>
<p:otherStyle/>
</p:txStyles>
</p:sldMaster>
"@
$SlideMasterRelsXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rIdLayout1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout1.xml"/>
<Relationship Id="rIdTheme1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="../theme/theme1.xml"/>
</Relationships>
"@
$SlideLayoutXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<p:sldLayout xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" type="blank" preserve="1">
<p:cSld name="Blank">
<p:spTree>
<p:nvGrpSpPr>
<p:cNvPr id="1" name=""/>
<p:cNvGrpSpPr/>
<p:nvPr/>
</p:nvGrpSpPr>
<p:grpSpPr/>
</p:spTree>
</p:cSld>
<p:clrMapOvr>
<a:masterClrMapping/>
</p:clrMapOvr>
</p:sldLayout>
"@
$SlideLayoutRelsXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rIdMaster1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="../slideMasters/slideMaster1.xml"/>
</Relationships>
"@
$ThemeXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Generated Theme">
<a:themeElements>
<a:clrScheme name="Generated">
<a:dk1><a:srgbClr val="000000"/></a:dk1>
<a:lt1><a:srgbClr val="FFFFFF"/></a:lt1>
<a:dk2><a:srgbClr val="1F1F1F"/></a:dk2>
<a:lt2><a:srgbClr val="EEEEEE"/></a:lt2>
<a:accent1><a:srgbClr val="4472C4"/></a:accent1>
<a:accent2><a:srgbClr val="ED7D31"/></a:accent2>
<a:accent3><a:srgbClr val="A5A5A5"/></a:accent3>
<a:accent4><a:srgbClr val="FFC000"/></a:accent4>
<a:accent5><a:srgbClr val="5B9BD5"/></a:accent5>
<a:accent6><a:srgbClr val="70AD47"/></a:accent6>
<a:hlink><a:srgbClr val="0563C1"/></a:hlink>
<a:folHlink><a:srgbClr val="954F72"/></a:folHlink>
</a:clrScheme>
<a:fontScheme name="Generated">
<a:majorFont><a:latin typeface="Aptos Display"/></a:majorFont>
<a:minorFont><a:latin typeface="Aptos"/></a:minorFont>
</a:fontScheme>
<a:fmtScheme name="Generated">
<a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:fillStyleLst>
<a:lnStyleLst><a:ln w="9525"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:ln></a:lnStyleLst>
<a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle></a:effectStyleLst>
<a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:bgFillStyleLst>
</a:fmtScheme>
</a:themeElements>
</a:theme>
"@
$CoreXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dc:title>Generated 170MB Test PPTX</dc:title>
<dc:creator>PowerShell</dc:creator>
</cp:coreProperties>
"@
$AppXml = @"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
<Application>PowerShell</Application>
<PresentationFormat>Widescreen</PresentationFormat>
<Slides>$SlideCount</Slides>
</Properties>
"@
Write-Host "Presentation XML built successfully."
#endregion
#region Create PPTX
Write-Host "Creating PPTX: $OutputPptx"
try {
$FileStream = [System.IO.File]::Open($OutputPptx, [System.IO.FileMode]::CreateNew)
$Zip = New-Object System.IO.Compression.ZipArchive($FileStream, [System.IO.Compression.ZipArchiveMode]::Create)
try {
Add-ZipTextEntry -Zip $Zip -Path "[Content_Types].xml" -Text $ContentTypesXml
Add-ZipTextEntry -Zip $Zip -Path "_rels/.rels" -Text $RootRelsXml
Add-ZipTextEntry -Zip $Zip -Path "docProps/core.xml" -Text $CoreXml
Add-ZipTextEntry -Zip $Zip -Path "docProps/app.xml" -Text $AppXml
Add-ZipTextEntry -Zip $Zip -Path "ppt/presentation.xml" -Text $PresentationXml
Add-ZipTextEntry -Zip $Zip -Path "ppt/_rels/presentation.xml.rels" -Text $PresentationRelsXml
Add-ZipTextEntry -Zip $Zip -Path "ppt/slideMasters/slideMaster1.xml" -Text $SlideMasterXml
Add-ZipTextEntry -Zip $Zip -Path "ppt/slideMasters/_rels/slideMaster1.xml.rels" -Text $SlideMasterRelsXml
Add-ZipTextEntry -Zip $Zip -Path "ppt/slideLayouts/slideLayout1.xml" -Text $SlideLayoutXml
Add-ZipTextEntry -Zip $Zip -Path "ppt/slideLayouts/_rels/slideLayout1.xml.rels" -Text $SlideLayoutRelsXml
Add-ZipTextEntry -Zip $Zip -Path "ppt/theme/theme1.xml" -Text $ThemeXml
for ($i = 1; $i -le $SlideCount; $i++) {
Add-ZipTextEntry -Zip $Zip -Path "ppt/slides/slide$i.xml" -Text (Get-SlideXml -SlideNumber $i)
Add-ZipTextEntry -Zip $Zip -Path "ppt/slides/_rels/slide$i.xml.rels" -Text (Get-SlideRelXml -SlideNumber $i)
Add-RandomBmpEntry -Zip $Zip -Path "ppt/media/image$i.bmp" -ApproxPayloadBytes $ApproxBytesPerImage
}
Write-Host "PPTX ZIP package created successfully."
}
finally {
$Zip.Dispose()
$FileStream.Dispose()
}
}
catch {
Write-Host "Failed to create PPTX."
throw
}
#endregion
#region Validate Output
Write-Host "Validating generated PPTX..."
try {
if (-not (Test-Path $OutputPptx)) {
throw "Output file was not created."
}
$FileInfo = Get-Item $OutputPptx
$ActualMB = [Math]::Round($FileInfo.Length / 1MB, 2)
Write-Host "Generated file: $($FileInfo.FullName)"
Write-Host "Generated size: $ActualMB MB"
if ($FileInfo.Length -lt ($TargetBytes * 0.95)) {
Write-Host "Warning: File is smaller than expected."
}
elseif ($FileInfo.Length -gt ($TargetBytes * 1.10)) {
Write-Host "Warning: File is larger than expected."
}
else {
Write-Host "File size is within expected range."
}
Write-Host "Done."
}
catch {
Write-Host "Validation failed."
throw
}
#endregion
.posts/2026.06.23/genpptx.ps1