PowerShell-first document automation for Word, Excel, PowerPoint, PDF, RTF, Markdown, CSV, Reader, and Visio, built on top of OfficeIMO.*.
π¦ PowerShell Gallery
π οΈ Project
PSWriteOffice is the PowerShell layer for OfficeIMO.*.
OfficeIMOowns the document engine and low-level file-format behavior.PSWriteOfficeowns the PowerShell cmdlets, DSL aliases, packaging, examples, and scripting ergonomics.- The goal is simple: make Office document automation feel native in PowerShell without requiring Microsoft Office on the machine.
Start here when you want to create polished documents from PowerShell: workbooks with tables, charts, links, images, pivots, and navigation; Word reports with sections, headers, footers, tables, charts, and conversions; PowerPoint decks with reusable slides, notes, sections, themes, and transitions; PDFs with composition, extraction, forms, stamps, and metadata; RTF documents and bridges; Markdown and CSV workflows; Visio diagrams; and unified readback for existing files.
| Area | Status | What it covers now |
|---|---|---|
| Word | Mature | Document creation, readers, bookmarks, content controls, fields, HTML conversion, Markdown conversion |
| Excel | Advanced | Sheets, tables, named ranges, formulas, validation, charts, pivots, comments, TOC/navigation, explicit range readers, chart formatting, smarter links, URL images, summary-sheet linking |
| PowerPoint | Experimental but useful | Slides, titles, text boxes, bullets, notes, layouts, placeholders, sections, text replacement, slide import, slide copy, transitions, sizing |
| Advanced | New PDFs, text, headings, images, tables, panels, bookmarks, metadata, attachments, stamps, watermarks, forms, merge/split/copy/move pages, HTML conversion, text/image/attachment extraction, compliance inspection | |
| RTF | Solid | Create/read/update .rtf, replace text, append paragraphs, edit document properties, convert RTF to Word/HTML/PDF, convert Word/HTML to RTF, and read semantic chunks through Reader |
| Markdown | Solid | Read Markdown, inspect full object trees/headings/front matter/tables, build Markdown with a DSL, render HTML, convert HTML |
| CSV | Solid | Read CSV, emit CSV, object-focused data workflows |
| Reader | New | Unified chunk/document/table/visual/asset/ingest readback over Word, Excel, PowerPoint, Markdown, PDF, RTF, HTML, CSV, JSON, XML, YAML, ZIP, EPUB, Visio, and text-like files through OfficeIMO.Reader |
| Visio | New | DSL diagram creation, built-in and package-backed stencils, create/load/save .vsdx, inspect diagrams, generate galleries, export stencil preview galleries, and export SVG/PNG through OfficeIMO.Visio |
New-OfficeWord -Path .\Report.docx {
WordSection {
WordHeader { WordParagraph -Text 'Quarterly Report' -Style Heading2 }
WordFooter { WordPageNumber }
WordParagraph -Text 'Hello from PSWriteOffice.'
WordList -Style Bulleted {
WordListItem -Text 'Alpha'
WordListItem -Text 'Beta'
}
}
}$chartData = @(
[PSCustomObject]@{ Region = 'NA'; Revenue = 100 }
[PSCustomObject]@{ Region = 'EMEA'; Revenue = 200 }
)
New-OfficeWord -Path .\Charts.docx {
Add-OfficeWordChart -Type Pie -Data $chartData -CategoryProperty Region -SeriesProperty Revenue -Title 'Revenue Mix'
}$data = @(
[PSCustomObject]@{ Region = 'NA'; Revenue = 100 }
[PSCustomObject]@{ Region = 'EMEA'; Revenue = 200 }
)
New-OfficeExcel -Path .\Report.xlsx {
ExcelSheet 'Data' {
ExcelTable -Data $data -TableName 'Sales' -AutoFit
ExcelNamedRange -Name 'SalesData' -Range 'A1:B3'
}
ExcelSheet 'Notes' {
ExcelRow -Row 1 -Values 'Label', 'Value'
ExcelRow -Row 2 -Values 'Generated', (Get-Date -Format 'yyyy-MM-dd')
}
ExcelTableOfContents -IncludeNamedRanges
}New-OfficePowerPoint -Path .\Deck.pptx {
PptSlide {
PptTitle -Title 'Status Update'
PptTextBox -Text 'Generated with PSWriteOffice' -X 80 -Y 150 -Width 360 -Height 60
PptBullets -Bullets 'Wins','Risks','Next Steps' -X 430 -Y 150 -Width 260 -Height 200
PptNotes -Text 'Keep this under five minutes.'
}
}$ppt = Get-OfficePowerPoint -FilePath .\Deck.pptx
Add-OfficePowerPointSection -Presentation $ppt -Name 'Intro' -StartSlideIndex 0
Rename-OfficePowerPointSection -Presentation $ppt -Name 'Intro' -NewName 'Opening'
Update-OfficePowerPointText -Presentation $ppt -OldValue 'FY24' -NewValue 'FY25' -IncludeNotes
Copy-OfficePowerPointSlide -Presentation $ppt -Index 0
Get-OfficePowerPointSlide -Presentation $ppt -Index 0 | Set-OfficePowerPointSlideTransition -Transition Fade
Set-OfficePowerPointSlideSize -Presentation $ppt -Preset Screen16x9
Import-OfficePowerPointSlide -Presentation $ppt -SourcePath .\SourceDeck.pptx -SourceIndex 0$ppt = Get-OfficePowerPoint -FilePath .\Deck.pptx
Set-OfficePowerPointThemeColor -Presentation $ppt -Colors @{ Accent1 = '#C00000'; Accent2 = '#00B0F0' } -AllMasters
Set-OfficePowerPointThemeFonts -Presentation $ppt -MajorLatin 'Aptos' -MinorLatin 'Calibri' -AllMasters
Set-OfficePowerPointThemeName -Presentation $ppt -Name 'Contoso Theme' -AllMasters
Get-OfficePowerPointSlide -Presentation $ppt -Index 0 | Set-OfficePowerPointSlideLayout -LayoutName 'Title and Content'
Get-OfficePowerPointTheme -Presentation $ppt$rows = @(
[PSCustomObject]@{ Area = 'Word'; Status = 'Ready'; Owner = 'Docs' }
[PSCustomObject]@{ Area = 'PDF'; Status = 'Review'; Owner = 'Adapters' }
)
New-OfficePdf -Path .\Status.pdf {
Add-OfficePdfHeading -Text 'Documentation Status' -Level 1
Add-OfficePdfParagraph -Text 'Generated with PSWriteOffice through OfficeIMO.Pdf.'
Add-OfficePdfTable -InputObject $rows -Property Area,Status,Owner -Header 'Area','Status','Owner' -Align Center
Add-OfficePdfBookmark -Name 'Status table'
Set-OfficePdfMetadata -Title 'Documentation Status' -Author 'PSWriteOffice'
}Join-OfficePdf -Path .\Cover.pdf, .\Status.pdf -OutputPath .\Report.pdf
Split-OfficePdf -Path .\Report.pdf -OutputDirectory .\Pages
Get-OfficePdfText -Path .\Report.pdf$chart = Add-OfficeExcelChart -TableName 'Sales' -Row 6 -Column 1 -Type Pie -Title 'Revenue Mix' -PassThru
$chart |
Set-OfficeExcelChartLegend -Position Right |
Set-OfficeExcelChartDataLabels -ShowValue $true -ShowPercent $true -Position OutsideEnd -NumberFormat '0.0%' -SourceLinked:$false |
Set-OfficeExcelChartStyle -StyleId 251 -ColorStyleId 10ExcelSheet 'Data' {
Set-OfficeExcelSmartHyperlink -Address 'A2' -Url 'https://datatracker.ietf.org/doc/html/rfc7208'
Set-OfficeExcelHostHyperlink -Address 'B2' -Url 'https://learn.microsoft.com/office/open-xml/'
Add-OfficeExcelImageFromUrl -Address 'D2' -Url 'https://example.org/logo.png' -WidthPixels 48 -HeightPixels 48
}ExcelSheet 'Summary' {
Set-OfficeExcelInternalLinks -Range 'D2:D10'
Set-OfficeExcelInternalLinksByHeader -Header 'Sheet' -TableName 'SummaryTable' -DisplayScript { param($text) "Open $text" }
}ExcelSheet 'Summary' {
Set-OfficeExcelUrlLinksByHeader -Header 'RFC' -TableName 'LinksTable' -UrlScript { param($text) "https://datatracker.ietf.org/doc/html/$text" } -TitleScript { param($text) "Open $text" }
Set-OfficeExcelUrlLinks -Range 'D2:D10' -UrlScript { param($text) "https://datatracker.ietf.org/doc/html/$text" }
}New-OfficeRtf -OutputPath .\Report.rtf -Text 'Summary', 'Ready for review'
Get-OfficeRtf -Path .\Report.rtf
Update-OfficeRtfText -Path .\Report.rtf -OutputPath .\Report-Updated.rtf -OldText 'review' -NewText 'release'
ConvertFrom-OfficeRtf -Path .\Report-Updated.rtf -As Pdf -OutputPath .\Report.pdf
Get-OfficeDocumentChunk -Path .\Report-Updated.rtfNew-OfficeMarkdown -Path .\README.md {
MarkdownHeading -Level 1 -Text 'Report'
MarkdownParagraph -Text 'Generated by PSWriteOffice.'
}
$data | ConvertTo-OfficeCsv -OutputPath .\export.csvGet-OfficeDocumentCapability
Get-OfficeDocumentChunk -Path .\Report.docx
Get-OfficeDocumentChunk -Path .\Report.rtf
Get-OfficeDocument -Path .\Report.pdf -AsJson -Indented
Get-OfficeDocumentAsset -Path .\Deck.pptx -Kind image -OutputDirectory .\reader-assetsNew-OfficeVisio -Path .\Diagram.vsdx -Title 'Service map' -RequestRecalcOnOpen {
VisioRectangle -Key web -Text 'Web' -X 1.5 -Y 4 -Width 1.5 -Height 0.8 -FillColor LightBlue -LineColor SteelBlue
VisioDiamond -Key decision -Text 'Ready?' -X 4 -Y 4 -Width 1.2 -Height 1 -FillColor '#FFF2CC' -LineColor '#B45309'
VisioRectangle -Key api -Text 'API' -X 6.2 -Y 4 -Width 1.5 -Height 0.8 -FillColor LightGreen -LineColor SeaGreen
VisioConnector -From web -To decision -Kind RightAngle -EndArrow Triangle -Label 'check'
VisioConnector -From decision -To api -Kind RightAngle -EndArrow Triangle -Label 'ship'
}
Get-OfficeVisioInfo -Path .\Diagram.vsdx -AsText
ConvertTo-OfficeVisioSvg -Path .\Diagram.vsdx -OutputPath .\Diagram.svg
ConvertTo-OfficeVisioPng -Path .\Diagram.vsdx -OutputPath .\Diagram.png$flow = Get-OfficeVisioStencilCatalog -BuiltIn Flowchart
Find-OfficeVisioStencil -Catalog $flow -Query process -First 5
New-OfficeVisio -Path .\Flow.vsdx -Title 'Stencil flow' -UseMastersByDefault -RequestRecalcOnOpen {
Import-OfficeVisioStencil -BuiltIn Flowchart -Name Flow -Default
VisioStencil -Catalog Flow -Stencil process -Key intake -Text 'Intake' -X 1.5 -Y 4 -FillColor '#E0F2FE' -LineColor '#0369A1'
VisioStencil -Catalog Flow -Stencil decision -Key review -Text 'Review?' -X 4 -Y 4 -FillColor '#FEF3C7' -LineColor '#B45309'
VisioStencil -Catalog Flow -Stencil data -Key archive -Text 'Archive' -X 6.5 -Y 4 -FillColor '#DCFCE7' -LineColor '#15803D'
VisioConnector -From intake -To review -Kind RightAngle -EndArrow Triangle -Label 'submit'
VisioConnector -From review -To archive -Kind RightAngle -EndArrow Triangle -Label 'store'
}$catalog = Get-OfficeVisioStencilCatalog -Path .\MyShapes.vssx -CatalogName 'Custom Shapes' -IncludeUnsupportedMasters
Find-OfficeVisioStencil -Catalog $catalog -Query server -First 10
New-OfficeVisio -Path .\CustomStencil.vsdx -UseMastersByDefault {
Import-OfficeVisioStencil -Catalog $catalog -Name Custom -Default
VisioStencil -Stencil server -Key server -Text 'Server' -X 2 -Y 4
VisioStencil -Stencil database -Key database -Text 'Database' -X 5 -Y 4
VisioConnector -From server -To database -Kind RightAngle -EndArrow Triangle
}More visual Visio examples live in Examples\Visio. Run .\Examples\Visio\Build-VisioShowcase.ps1 to generate editable .vsdx files plus SVG/PNG previews for stencil flowcharts, architecture maps, network topology, and package-backed stencil loading.
New-OfficeVisioGallery -OutputDirectory .\VisioGallery |
Select-Object Name, FilePath, IsClean
Export-OfficeVisioStencilPreviewGallery -Path .\MyShapes.vssx -OutputDirectory .\StencilGallery -Title 'Custom stencil previews'PSWriteOffice is not only about writing files. The module now has stronger read-back and bridge workflows too.
$data | Export-OfficeExcel -Path .\Report.xlsx -WorksheetName 'Data' -TableName 'Data' -AutoFit -FreezeTopRow
Import-OfficeExcel -Path .\Report.xlsx -WorksheetName 'Data'The benchmark harness in Benchmarks\Compare-ExcelPerformance.ps1 compares
Export-OfficeExcel / Import-OfficeExcel with ImportExcel and ExcelFast
on repeatable local workloads. The table below is a local snapshot, not a
universal performance promise: hardware, PowerShell version, data shape,
formatting, and workbook features all matter.
Run context: PowerShell 7.5.5, AMD Ryzen 9 9950X3D2 16-Core Processor (16 cores / 32 logical processors), 64 GB RAM, Standard suite, median of three runs, measured on 2026-06-22.
| Scenario | Rows | Winner | PSWriteOffice 1.0.3 / OfficeIMO.Excel 0.6.47 | ImportExcel 7.8.10 | ExcelFast 0.0.1-alpha16 | Relative time (winner = 1x) |
|---|---|---|---|---|---|---|
| Export objects default | 1k | PSWriteOffice | 16 ms | 183 ms | 126 ms | PSWriteOffice 1x; ImportExcel 11.44x; ExcelFast 7.88x |
| Export objects default | 10k | PSWriteOffice | 84 ms | 1,287 ms | 153 ms | PSWriteOffice 1x; ImportExcel 15.32x; ExcelFast 1.82x |
| Export objects default | 25k | PSWriteOffice | 199 ms | 3,827 ms | 233 ms | PSWriteOffice 1x; ImportExcel 19.23x; ExcelFast 1.17x |
| Export wide objects default | 1k | PSWriteOffice | 26 ms | 166 ms | 127 ms | PSWriteOffice 1x; ImportExcel 6.38x; ExcelFast 4.88x |
| Export wide objects default | 10k | PSWriteOffice | 256 ms | 1,231 ms | 296 ms | PSWriteOffice 1x; ImportExcel 4.81x; ExcelFast 1.16x |
| Export wide objects default | 25k | PSWriteOffice | 679 ms | 3,832 ms | 1,134 ms | PSWriteOffice 1x; ImportExcel 5.64x; ExcelFast 1.67x |
| Import mixed objects full sheet | 1k | PSWriteOffice | 9 ms | 52 ms | 32 ms | PSWriteOffice 1x; ImportExcel 5.78x; ExcelFast 3.56x |
| Import mixed objects full sheet | 10k | PSWriteOffice | 98 ms | 383 ms | 311 ms | PSWriteOffice 1x; ImportExcel 3.91x; ExcelFast 3.17x |
| Import mixed objects full sheet | 25k | PSWriteOffice | 333 ms | 3,083 ms | 881 ms | PSWriteOffice 1x; ImportExcel 9.26x; ExcelFast 2.65x |
| Report workbook with table, chart, pivot, formatting | 1k | PSWriteOffice | 98 ms | 214 ms | n/a | PSWriteOffice 1x; ImportExcel 2.18x; ExcelFast n/a |
| Report workbook with table, chart, pivot, formatting | 10k | PSWriteOffice | 1,134 ms | 1,560 ms | n/a | PSWriteOffice 1x; ImportExcel 1.38x; ExcelFast n/a |
| Report workbook with table, chart, pivot, formatting | 25k | PSWriteOffice | 3,677 ms | 3,929 ms | n/a | PSWriteOffice 1x; ImportExcel 1.07x; ExcelFast n/a |
| Export regional workbook, one table per sheet | 1k | PSWriteOffice | 105 ms | 248 ms | n/a | PSWriteOffice 1x; ImportExcel 2.36x; ExcelFast n/a |
| Export regional workbook, one table per sheet | 10k | PSWriteOffice | 735 ms | 1,509 ms | n/a | PSWriteOffice 1x; ImportExcel 2.05x; ExcelFast n/a |
| Export regional workbook, one table per sheet | 25k | PSWriteOffice | 2,003 ms | 3,611 ms | n/a | PSWriteOffice 1x; ImportExcel 1.8x; ExcelFast n/a |
| Export title, offset header, frozen top row | 1k | ImportExcel | 251 ms | 222 ms | n/a | PSWriteOffice 1.13x; ImportExcel 1x; ExcelFast n/a |
| Export title, offset header, frozen top row | 10k | PSWriteOffice | 735 ms | 1,370 ms | n/a | PSWriteOffice 1x; ImportExcel 1.86x; ExcelFast n/a |
| Export title, offset header, frozen top row | 25k | PSWriteOffice | 1,828 ms | 3,290 ms | n/a | PSWriteOffice 1x; ImportExcel 1.8x; ExcelFast n/a |
| Export data workbook with summary formulas | 1k | PSWriteOffice | 53 ms | 192 ms | n/a | PSWriteOffice 1x; ImportExcel 3.62x; ExcelFast n/a |
| Export data workbook with summary formulas | 10k | PSWriteOffice | 507 ms | 1,449 ms | n/a | PSWriteOffice 1x; ImportExcel 2.86x; ExcelFast n/a |
| Export data workbook with summary formulas | 25k | PSWriteOffice | 1,531 ms | 3,254 ms | n/a | PSWriteOffice 1x; ImportExcel 2.13x; ExcelFast n/a |
To compare on your machine, run:
pwsh -NoLogo -NoProfile -ExecutionPolicy Bypass -File .\Benchmarks\Compare-ExcelPerformance.ps1 -Suite StandardThe benchmark output also records exact module prerelease versions, machine and
runtime metadata, per-engine support status, file sizes, and memory deltas in
the generated CSV/JSON files. Export scenarios are also opened after generation
and checked with Open XML validation when the validator is available. The full
scenario list includes append, existing-workbook update, many-sheet, named
range, chart-only, pivot-only, and read-focused workloads. See
Benchmarks\README.md for the artifact schema and scenario list.
Get-OfficeExcelData -Path .\Report.xlsx -Sheet 'Data'
Get-OfficeExcelRange -Path .\Report.xlsx -Sheet 'Data' -Range 'A1:B10'
Get-OfficeExcelUsedRange -Path .\Report.xlsx -Sheet 'Data' -AsDataTable
Get-OfficeExcelNamedRange -Path .\Report.xlsx
Get-OfficeExcelPivotTable -Path .\Report.xlsx$markdown = ConvertTo-OfficeWordMarkdown -Path .\Report.docx
ConvertFrom-OfficeWordMarkdown -Markdown $markdown -OutputPath .\Report-Roundtrip.docx
$doc = Get-OfficeWord -Path .\Report.docx
Update-OfficeWordText -Document $doc -OldValue 'FY24' -NewValue 'FY25'
Close-OfficeWord -Document $doc -SaveConvertTo-OfficeRtf -WordPath .\Report.docx -OutputPath .\Report.rtf
ConvertTo-OfficeRtf -HtmlPath .\Report.html -OutputPath .\Report-from-html.rtf
ConvertFrom-OfficeRtf -Path .\Report.rtf -As Word -OutputPath .\Report-from-rtf.docx
ConvertFrom-OfficeRtf -Path .\Report.rtf -As Html -OutputPath .\Report.html -IncludeDefaultCss$doc = New-OfficeWord -Path .\Report.docx
$chart = $doc.AddChart('Revenue Mix')
$chart.AddPie('North America', 125000).
AddPie('EMEA', 98000).
AddPie('APAC', 143000) | Out-Null
Close-OfficeWord -Document $doc -Save$tableData = $data | Select-Object Region, Revenue,
@{ Name = 'RevenueBand'; Expression = { if ($_.Revenue -gt 100000) { 'High' } else { 'Standard' } } }
New-OfficeWord -Path .\Report.docx {
Add-OfficeWordTable -InputObject $tableData -Style 'GridTable1LightAccent1'
}$ppt = Get-OfficePowerPoint -FilePath .\Deck.pptx
Get-OfficePowerPointSlide -Presentation $ppt
Get-OfficePowerPointSlideSummary -Presentation $ppt
Get-OfficePowerPointNotes -Presentation $ppt
Get-OfficePowerPointShape -Presentation $ppt -Index 0- Word to Markdown and Markdown to Word are now surfaced directly through
OfficeIMO.Word.Markdown. - PDF now has first-class creation, composition, merge/split, page movement, metadata, forms, stamping, attachment, extraction, HTML conversion, and compliance inspection cmdlets. Deeper PDF engine features still belong in
OfficeIMO.Pdffirst. - RTF now has create/read/update/replace cmdlets, Word/HTML/PDF bridges, and semantic Reader chunks through the
OfficeIMO.Reader.Rtfadapter. OfficeIMO.Readeris surfaced through chunk, document-envelope, table, visual, asset, ingest, JSON, and capability-discovery cmdlets across the currently registered adapters.OfficeIMO.Visiois surfaced through a first diagram DSL plus built-in and external stencil catalogs, create/load/save, deterministic inspection, reference gallery generation, stencil preview gallery export, and SVG/PNG export cmdlets.- Excel now has
Add-OfficeExcelTableOfContents,Get-OfficeExcelRange, andGet-OfficeExcelUsedRange. - PowerPoint now has section cmdlets, deck-wide text replacement, slide import helpers, slide copy, transitions, slide sizing, theme inspection, theme updates, and layout switching.
- Excel charts can now be finished with
Set-OfficeExcelChartLegend,Set-OfficeExcelChartDataLabels, andSet-OfficeExcelChartStyle. - Excel now has discoverable URL-image insertion plus smarter external hyperlink helpers.
- Excel summary sheets can now auto-link ranges and header-based columns to workbook tabs or external URLs.
- Backlink placement in Excel TOC flows is safer by default, avoiding overwriting active worksheet data.
Use the examples in this README for the first pass, then move to the generated command reference when you need exact parameters and pipeline behavior.
- Docs/Readme.md is the generated cmdlet index.
- Docs contains one generated page per command.
- Examples contains runnable scripts grouped by Word, Excel, PowerPoint, PDF, RTF, Markdown, CSV, Visio, and shared samples.
- Roadmap/PSWriteOffice-CmdletExamplesAndPolishPlan.md tracks the documentation quality bar and the next wrapper-polish priorities.
The generated command pages are built from XML comments in the cmdlet source. Prefer contextual examples there too: small workflow snippets with real input data, generated artifacts, readback/validation where useful, and no fake PowerShell compatibility aliases.
dotnet build .\Sources\PSWriteOffice.sln -c Debug
pwsh -NoLogo -NoProfile -File .\PSWriteOffice.Tests.ps1
pwsh -NoLogo -NoProfile -File .\Build\Validate-PackagedArtefact.ps1Regenerate the module manifest, generated help, packed artifacts, and website API payloads through the build-module lane:
pwsh -NoLogo -NoProfile -File .\Build\Manage-PSWriteOffice.ps1
pwsh -NoLogo -NoProfile -File .\Build\Export-ApiDocsSnapshot.ps1
pwsh -NoLogo -NoProfile -File .\Build\Measure-CmdletXmlExamples.ps1 -RequireExamplesDevelopment loading is handled through PSWriteOffice.psm1, which prefers the local debug build in Sources\PSWriteOffice\bin\Debug\.
MIT