PSWriteOffice

June 24, 2026 ยท View on GitHub

PowerShell-first document automation for Word, Excel, PowerPoint, PDF, RTF, Markdown, CSV, Reader, and Visio, built on top of OfficeIMO.*.

๐Ÿ“ฆ PowerShell Gallery

PowerShell Gallery Version PowerShell Gallery Downloads PowerShell Gallery Platforms

๐Ÿ› ๏ธ Project

Test PowerShell Test .NET Libraries License

Why PSWriteOffice โœจ

PSWriteOffice is the PowerShell layer for OfficeIMO.*.

  • OfficeIMO owns the document engine and low-level file-format behavior.
  • PSWriteOffice owns 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.

Platform Areas ๐Ÿงญ

AreaStatusWhat it covers now
WordMatureDocument creation, readers, bookmarks, content controls, fields, HTML conversion, Markdown conversion
ExcelAdvancedSheets, tables, named ranges, formulas, validation, charts, pivots, comments, TOC/navigation, explicit range readers, chart formatting, smarter links, URL images, summary-sheet linking
PowerPointExperimental but usefulSlides, titles, text boxes, bullets, notes, layouts, placeholders, sections, text replacement, slide import, slide copy, transitions, sizing
PDFAdvancedNew 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
RTFSolidCreate/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
MarkdownSolidRead Markdown, inspect full object trees/headings/front matter/tables, build Markdown with a DSL, render HTML, convert HTML
CSVSolidRead CSV, emit CSV, object-focused data workflows
ReaderNewUnified 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
VisioNewDSL 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

Quick Start ๐Ÿš€

Word

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'
}

Excel

$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
}

PowerPoint

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

PowerPoint theme and layout helpers

$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

PDF

$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

Excel chart finishing

$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 10
ExcelSheet '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
}

Excel internal navigation

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" }
}

RTF

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.rtf

Markdown and CSV

New-OfficeMarkdown -Path .\README.md {
    MarkdownHeading -Level 1 -Text 'Report'
    MarkdownParagraph -Text 'Generated by PSWriteOffice.'
}

$data | ConvertTo-OfficeCsv -OutputPath .\export.csv

Reader and Visio

Get-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-assets
New-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'

Read, Inspect, and Convert ๐Ÿ”

PSWriteOffice is not only about writing files. The module now has stronger read-back and bridge workflows too.

Excel import/export fast path

$data | Export-OfficeExcel -Path .\Report.xlsx -WorksheetName 'Data' -TableName 'Data' -AutoFit -FreezeTopRow
Import-OfficeExcel -Path .\Report.xlsx -WorksheetName 'Data'

Excel benchmark snapshot

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.

ScenarioRowsWinnerPSWriteOffice 1.0.3 / OfficeIMO.Excel 0.6.47ImportExcel 7.8.10ExcelFast 0.0.1-alpha16Relative time (winner = 1x)
Export objects default1kPSWriteOffice16 ms183 ms126 msPSWriteOffice 1x; ImportExcel 11.44x; ExcelFast 7.88x
Export objects default10kPSWriteOffice84 ms1,287 ms153 msPSWriteOffice 1x; ImportExcel 15.32x; ExcelFast 1.82x
Export objects default25kPSWriteOffice199 ms3,827 ms233 msPSWriteOffice 1x; ImportExcel 19.23x; ExcelFast 1.17x
Export wide objects default1kPSWriteOffice26 ms166 ms127 msPSWriteOffice 1x; ImportExcel 6.38x; ExcelFast 4.88x
Export wide objects default10kPSWriteOffice256 ms1,231 ms296 msPSWriteOffice 1x; ImportExcel 4.81x; ExcelFast 1.16x
Export wide objects default25kPSWriteOffice679 ms3,832 ms1,134 msPSWriteOffice 1x; ImportExcel 5.64x; ExcelFast 1.67x
Import mixed objects full sheet1kPSWriteOffice9 ms52 ms32 msPSWriteOffice 1x; ImportExcel 5.78x; ExcelFast 3.56x
Import mixed objects full sheet10kPSWriteOffice98 ms383 ms311 msPSWriteOffice 1x; ImportExcel 3.91x; ExcelFast 3.17x
Import mixed objects full sheet25kPSWriteOffice333 ms3,083 ms881 msPSWriteOffice 1x; ImportExcel 9.26x; ExcelFast 2.65x
Report workbook with table, chart, pivot, formatting1kPSWriteOffice98 ms214 msn/aPSWriteOffice 1x; ImportExcel 2.18x; ExcelFast n/a
Report workbook with table, chart, pivot, formatting10kPSWriteOffice1,134 ms1,560 msn/aPSWriteOffice 1x; ImportExcel 1.38x; ExcelFast n/a
Report workbook with table, chart, pivot, formatting25kPSWriteOffice3,677 ms3,929 msn/aPSWriteOffice 1x; ImportExcel 1.07x; ExcelFast n/a
Export regional workbook, one table per sheet1kPSWriteOffice105 ms248 msn/aPSWriteOffice 1x; ImportExcel 2.36x; ExcelFast n/a
Export regional workbook, one table per sheet10kPSWriteOffice735 ms1,509 msn/aPSWriteOffice 1x; ImportExcel 2.05x; ExcelFast n/a
Export regional workbook, one table per sheet25kPSWriteOffice2,003 ms3,611 msn/aPSWriteOffice 1x; ImportExcel 1.8x; ExcelFast n/a
Export title, offset header, frozen top row1kImportExcel251 ms222 msn/aPSWriteOffice 1.13x; ImportExcel 1x; ExcelFast n/a
Export title, offset header, frozen top row10kPSWriteOffice735 ms1,370 msn/aPSWriteOffice 1x; ImportExcel 1.86x; ExcelFast n/a
Export title, offset header, frozen top row25kPSWriteOffice1,828 ms3,290 msn/aPSWriteOffice 1x; ImportExcel 1.8x; ExcelFast n/a
Export data workbook with summary formulas1kPSWriteOffice53 ms192 msn/aPSWriteOffice 1x; ImportExcel 3.62x; ExcelFast n/a
Export data workbook with summary formulas10kPSWriteOffice507 ms1,449 msn/aPSWriteOffice 1x; ImportExcel 2.86x; ExcelFast n/a
Export data workbook with summary formulas25kPSWriteOffice1,531 ms3,254 msn/aPSWriteOffice 1x; ImportExcel 2.13x; ExcelFast n/a

To compare on your machine, run:

pwsh -NoLogo -NoProfile -ExecutionPolicy Bypass -File .\Benchmarks\Compare-ExcelPerformance.ps1 -Suite Standard

The 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.

Excel readers

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

Word bridges

$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 -Save

RTF bridges

ConvertTo-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

Word charts with the current API

$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

Word tables with extra columns

$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'
}

PowerPoint inspection

$ppt = Get-OfficePowerPoint -FilePath .\Deck.pptx
Get-OfficePowerPointSlide -Presentation $ppt
Get-OfficePowerPointSlideSummary -Presentation $ppt
Get-OfficePowerPointNotes -Presentation $ppt
Get-OfficePowerPointShape -Presentation $ppt -Index 0

Recent Highlights ๐Ÿ†•

  • 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.Pdf first.
  • RTF now has create/read/update/replace cmdlets, Word/HTML/PDF bridges, and semantic Reader chunks through the OfficeIMO.Reader.Rtf adapter.
  • OfficeIMO.Reader is surfaced through chunk, document-envelope, table, visual, asset, ingest, JSON, and capability-discovery cmdlets across the currently registered adapters.
  • OfficeIMO.Visio is 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, and Get-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, and Set-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.

Documentation ๐Ÿ“š

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.

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.

Build and Test ๐Ÿงช

dotnet build .\Sources\PSWriteOffice.sln -c Debug
pwsh -NoLogo -NoProfile -File .\PSWriteOffice.Tests.ps1
pwsh -NoLogo -NoProfile -File .\Build\Validate-PackagedArtefact.ps1

Regenerate 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 -RequireExamples

Development loading is handled through PSWriteOffice.psm1, which prefers the local debug build in Sources\PSWriteOffice\bin\Debug\.

License

MIT