Skip to content

Navigation Menu

Sign in
Sign up

Add Excel XLSX export functionality #23

tpcarman started this conversation in Ideas
Discussion options

Adding an Excel export option to AsBuiltReport is something I've wanted to explore for a long time. The PScribo module currently handles all formatting within the framework, but it appears to no longer be actively maintained (I'll leave that for @iainbrighton to confirm). While I'm familiar with ImportExcel and its capabilities, I've been reluctant to introduce another module dependency into the framework.

AI tooling has now made it practical to revisit this idea. I've been using Claude Code heavily over the past 12 months for code development and have used it to assess the feasibility of adding Excel export to ABR. The plan is to build a proof of concept in two stages. First, use ImportExcel to validate that Excel output can be generated from existing report modules, then develop a native PScribo plugin so that PScribo remains the sole formatting tool.

The plan below was drafted with Claude's assistance. A proof of concept will begin soon and feedback on its requirements and direction is welcomed as it progresses.

Important

This is not a commitment to delivering this functionality. This is purely a discussion to explore the idea.

AsBuiltReport — XLSX Export Feasibility & Implementation Plan

Version: 0.1.0
Date: 2026年06月04日
Scope: Add Excel (.xlsx) export to the AsBuiltReport framework using the ImportExcel PowerShell module, where document sections map to worksheets.
Modules analysed: AsBuiltReport.Core (v1.6.2), PScribo (v0.12.0 dev / v0.11.1 min), and report modules VMware.vSphere, Microsoft.Azure, NetApp.ONTAP, Veeam.VBR.

---

1. Verdict

Adding XLSX export is feasible and low-risk to the existing Word/HTML/Text outputs, because every report already builds a fully-populated, traversable PScribo document object model in memory before export. We can walk that object tree and emit a workbook with ImportExcel without touching any report module.

Worksheet mapping is settled: each Heading2 section becomes its own worksheet. This is the correct rule because every report emits exactly one Heading1 section (the target name — vCenter, tenant, cluster, backup server), while the meaningful "chapters" a user expects as tabs (Clusters, Datastores, VMHosts, Networks, Subscriptions, ...) are Heading2 sections. Heading1 is carried as a workbook title / "Report Info" sheet. Implemented via a configurable WorksheetHeadingLevel defaulting to 2. See §4.

Everything else — table extraction, multi-table stacking, health-check cell colouring — maps cleanly.

---

2. How report generation works today (the integration point)

New-AsBuiltReport (AsBuiltReport.Core/Src/Public/New-AsBuiltReport.ps1) does the following:

  1. Builds the document with PScribo's Document keyword (lines ~524 and ~572). The scriptblock dot-sources the style script and invokes the report module's Invoke-AsBuiltReport.<Module>, which emits Section / Table / Paragraph calls.
  2. The Document { ... } call returns the in-memory document object into $AsBuiltReport.
  3. That object is piped to PScribo's exporter:
# New-AsBuiltReport.ps1 : \~line 622
$Document = $AsBuiltReport | Export-Document -Path $OutputFolderPath -Format $Format -Options @{ TextWidth = 240 } -PassThru

$AsBuiltReport is the hook. It is a fully-built PScribo.Document with a populated .Sections tree before Export-Document runs. We can pass that same object to a new Excel exporter. No report module changes are required, ever.

The -Format parameter is constrained here:

# New-AsBuiltReport.ps1 : line 237
\[ValidateSet('Word', 'HTML', 'Text')]
\[Array] $Format = 'Word',

---

3. Feasibility findings (verified against source)

3.1 The document object model is traversable and complete

Object TypeName Key properties
Root PScribo.Document .Sections (ArrayList of children), .Name, .Options
Section PScribo.Section .Name (heading text), .Level (0 = H1, 1 = H2, 2 = H3...), .Number ("1.2.3"), .Style, .Sections (recursive children)
Table PScribo.Table .Name, .Columns (ordered headers), .Rows (ArrayList of PSCustomObject), .IsList, .IsKeyedList, .ListKey, .Caption
Paragraph PScribo.Paragraph prose / inline runs
Other PScribo.PageBreak, .BlankLine, .LineBreak, .Image, .TOC, .ListReference non-tabular

Heading level is derived (Level = Number.Split('.').Count - 1), so a recursive walk can classify any node as H1/H2/H3/... reliably. (Source: PScribo/Src/Private/New-PScriboSection.ps1, Invoke-PScriboSectionLevel.ps1.)

3.2 Table data is fully preserved as objects

Each PScribo.Table.Rows entry is a PSCustomObject whose properties are the column values — i.e. exactly the shape ImportExcel's Export-Excel consumes. We do not need to parse rendered text. Three layouts exist and each needs handling:

  • Standard (IsList = $false): rows ×ばつ columns → direct Export-Excel.
  • List (IsList = $true): vertical key/value (one source object). → emit as a 2-column Property/Value block, or transpose.
  • Keyed list (IsKeyedList = $true, .ListKey): grouped key/value. → group blocks.

(Source: PScribo/Src/Public/Table.ps1, New-PScriboTableRow.ps1, Plugins/Text/Out-TextTable.ps1.)

3.3 Health-check cell styling is available as metadata (verified)

Set-Style -Style Critical/Warning/Info/OK \[-Property Col1,Col2] attaches note-properties to each row object:

  • \_\_Style — row-level style name
  • <ColumnName>\_\_Style — per-cell style name

Confirmed in PScribo/Src/Private/New-PScriboTableRow.ps1 (lines 43–77) and Src/Public/Set-Style.ps1 (lines 44–45). The Word/HTML plugins read these to colour cells; our Excel exporter can read the identical properties and apply background fills via ImportExcel. The Text plugin simply excludes \*\_\_Style columns — we do the same for data, but inspect them for formatting.

The style → colour map already exists in AsBuiltReport.Core/AsBuiltReport.Core.Style.ps1:

Style Hex (background) Excel use
Critical FEDDD7 cell/row fill
Warning FFF4C7 cell/row fill
Info E3F5FC cell/row fill
OK DFF0D0 cell/row fill
TableDefaultHeading fill 072E58, text FAFAFA header row

These hex values can be lifted directly into ImportExcel -BackgroundColor / conditional formatting, giving the spreadsheet the same visual health-check cues as the Word report.

3.4 Content that does NOT map to cells

Roughly 40–60% of report content is tabular; the rest is paragraphs, blank lines, images/diagrams (NetApp & Veeam are diagram-heavy), and the cover page/TOC. These have no spreadsheet representation. Strategy in §4.4.

---

4. Design

4.1 The worksheet-mapping decision (most important)

Because reports have a single H1, choose one of:

Option Worksheets Pros Cons
A. H2 → worksheet (recommended) One tab per major chapter (Clusters, Datastores, VMHosts, Networks...) Matches user mental model; clean tab list; natural for multi-target via prefix H1 (target name) becomes a title/summary sheet, not a tab
B. Literal H1 → worksheet One tab for the whole report Trivial Useless — single tab
C. Configurable depth (WorksheetHeadingLevel, default 2) Author-tunable per report Most flexible; future-proof Slightly more config surface

Recommendation: implement Option C with a default of level 2 (so out-of-the-box behaviour = Option A). This honours the spirit of the brief ("a section per worksheet") while producing a usable workbook, and lets dense reports push to level 3 if desired.

4.1a Multi-system output: one workbook per system (recommended default, not a hard requirement)

Report modules loop over -Target internally and emit one Heading1 section per system within a single document object. Verified in Invoke-AsBuiltReport.VMware.vSphere.ps1:

foreach ($VIServer in $Target) { # line 41
 ...
 Section -Style Heading1 $vCenterServerName { ... } # line 255 — one H1 per system
}

So a two-vCenter run yields a document whose .Sections contains two Level 0 sections. Both behaviours are feasible — the choice is cosmetic, not technical:

  • One workbook per system (recommended default). Split on Heading1; each H1 → its own .xlsx, named after that system, with that system's H2 sections as tabs. More logical for per-system analysis and keeps tab lists short.
  • Single combined workbook (alternative). All systems' H2 sections as tabs in one file, tab names prefixed with the system (<System> - <H2>).

Since it isn't a hard requirement, treat this as a switch (e.g. -ExcelPerSystem, default on) so either is trivially available. Note Word/HTML/Text always produce a single combined file (PScribo's model); per-system splitting is Excel-only and lives in Core (§4.5).

File naming (per-system mode):

  • Single system: <FileName>.xlsx — unchanged from today's naming ($ReportConfig.Report.Name, plus -Timestamp suffix if set).
  • Multiple systems: one file each, <FileName> - <SystemName>.xlsx, <SystemName> = sanitised H1 text (invalid filename chars stripped, de-duplicated on collision); -Timestamp still applies per file.

4.2 Heading-level disposition (H1–H6) — how the tree flattens

Report modules use heading levels 1–6. They map to Excel as follows (default WorksheetHeadingLevel = 2):

Level Disposition
H1 File boundary — one .xlsx per H1 (= per system; see §4.1a).
H2 Worksheet boundary — one tab per H2.
H3–H6 In-sheet section bannersnot tabs, not files. Each becomes a heading/label row inside its ancestor H2 worksheet, titling and grouping the table(s) beneath it.

H3–H6 never create new tabs or files; they are flattened into the H2 worksheet. For each H2, the exporter recurses the entire subtree, collects every PScribo.Table descendant in document order, and stacks them vertically down the sheet. Depth (H3 vs H4 vs H5 vs H6) is preserved visually, not structurally:

  • Banner row before each table from the owning sub-section's .Name, prefixed with its .Number (e.g. 1.4.2 SCSI LUN Info, which already encodes full hierarchy).
  • Indentation — banner (and optionally the table) shifts one column right per level (H3→A, H4→B, ...).
  • Style — banner font size/bold/colour mirrors the Style.ps1 heading palette (Heading 3=395879, Heading 4=958026, Heading 5=009684, Heading 6=009683). NO TOC HeadingN variants are treated by their numeric level (the "NO TOC" only affected Word/HTML TOC inclusion).
  • One blank row between stacked tables; freeze each table's header row; auto-size columns; apply an Excel table style per block.
  • Drop \*\_\_Style helper columns from the visible data; use them only for cell fill colour (§3.3).

Example — vSphere Datastores (H2) tab at InfoLevel 3+:

Datastores ← H2 = the worksheet/tab name
 \[ summary table: all datastores ] ← table directly under H2
 datastore-01 ← H3 banner (1.4.1)
 \[ detail list table ]
 SCSI LUN Info ← H4 banner (1.4.1.1)
 \[ LUN table ]
 datastore-02 ← H3 banner (1.4.2)
 \[ detail list table ]

Optional (Phase 3): map heading depth to Excel row outline levels, making H3–H6 bands collapsible/expandable groups — a natural fit for the hierarchy, straightforward with ImportExcel.

If the knob is changed (WorksheetHeadingLevel = N): H1 always remains the file split; level N becomes the tab boundary; levels between H1 and N qualify (prefix) the tab name; levels below N become the in-sheet banners above. At the default N = 2 this reduces to the table above.

This preserves the report's hierarchy as readable bands within a single tab, rather than exploding into dozens of micro-tabs.

4.3 Worksheet naming & sanitisation

Excel tab constraints must be enforced centrally:

  • Max 31 chars; strip \[ ] : \* ? / \\; cannot be blank; must be unique (append (2), (3) on collision); cannot be History.
  • Derive from Section.Name; keep a "section number → tab name" map for an optional index/TOC sheet with hyperlinks.

4.4 Non-tabular content

  • Paragraphs: optionally written as wrapped text rows above the first table of a sheet (off by default to keep sheets data-clean), or skipped.
  • Images/diagrams: skipped (optionally noted as "see Word/HTML report"). Embedding base64 images is a possible later enhancement via Add-ExcelImage-style logic, but out of MVP scope.
  • Cover page / TOC: replaced by a generated "Report Info" first sheet (Author, Company, Version, Date — same data the cover page Table already holds) plus an "Index" sheet linking to each tab.

4.5 Architecture: the exporter lives in Core and uses ImportExcel

A Core-resident exporter that consumes the $AsBuiltReport document object directly and renders with ImportExcel is the right home. It is self-contained, shippable without touching any other repo, and the natural place for AsBuiltReport-specific semantics (H2→worksheet, optional one-workbook-per-system, system-based filenames) that have no equivalent in generic PScribo. This is the basis for the MVP.

**Out of scope:** PScribo *does* support an Out-<Format>Document plugin convention, so a native -Format Excel plugin would be possible **if** PScribo were ever forked into the AsBuiltReport org. That fork is a long-term consideration only — it requires significant changes across all report repos plus ongoing maintenance — and is **not pursued here**. Should it ever happen, the MVP's traversal/render logic could be lifted into such a plugin with the per-system split staying in Core; nothing in this plan depends on it.

---

4.6 Recommended MVP scope

Objective: prove the concept end-to-end — New-AsBuiltReport ... -Format Excel produces a valid, openable .xlsx from a real report run, with sections as worksheets and report data in cells, using ImportExcel. Everything beyond "it demonstrably works" is deferred.

In scope (minimum to prove functionality):

# Item Notes
1 Excel added to the -Format ValidateSet, wired into New-AsBuiltReport §5.2
2 Core-resident Export-AbrExcelDocument rendering with ImportExcel §5.1
3 H2 → worksheet; H3–H6 → in-sheet banners with descendant tables collected in document order and stacked vertically §4.2
4 Standard and List table layouts rendered; \*\_\_Style helper columns dropped from data keyed-list can be rendered as plain rows for MVP
5 One workbook per system (default), single-system → one file; multi-system → <FileName> - <System>.xlsx §4.1a
6 Worksheet-name and filename sanitisation + de-duplication 31-char/illegal-char rules
7 Header row styling, freeze top row, auto-size columns basic readability
8 Soft ImportExcel dependency — load on demand, friendly error if absent when -Format Excel is used avoids forcing the module on Word-only users
9 One smoke test proving a workbook is generated and re-readable see validation target below

Explicitly out of scope for the MVP (deferred to later phases per §7):

  • Health-check cell fill colours from \_\_Style metadata (Phase 2) — the metadata read is proven feasible (§3.3) but not required to demonstrate export.
  • Index and Report Info summary sheets (Phase 2/3).
  • Keyed-list grouping, optional paragraph inclusion, table captions, Excel outline/grouping for collapsible H3–H6 (Phase 3).
  • Images/diagrams (not planned).
  • Hard RequiredModules dependency / version pinning (decision deferred — §8.2).
  • Full localization of new strings across all locales — MVP may ship en-US only and log the rest as follow-up debt.
  • Configurable WorksheetHeadingLevel UI — MVP can hard-default to 2 and expose the knob later.

Acceptance criteria (definition of "proven"):

  1. New-AsBuiltReport -Report <X> -Target <t> -Format Excel writes a .xlsx that opens cleanly in Excel with no repair prompt.
  2. One worksheet per H2, tab names correct/sanitised/unique.
  3. Table headers and row values match the equivalent Word/HTML output for the same run.
  4. A multi-target run produces one file per system (default mode).
  5. -Format Word,Excel works in one run; no regression to Word/HTML/Text.
  6. With ImportExcel absent, -Format Excel fails with a clear, actionable message (not a crash).

Suggested validation target: AsBuiltReport.System.Resources. This is the best MVP report module because it reports on the local machine — no remote infrastructure, no lab, no real credentials — so it runs fast and repeatably on the developer's own box. Verified structure (Invoke-AsBuiltReport.System.Resources.ps1 + Src/Private):

  • foreach ($System in $Target) { Section -Style Heading1 "$($System.ToUpper())" { ... } } — the standard one H1 per system pattern, so it also exercises the per-system file split with multiple targets.
  • Exactly 5 Heading2 sections — Date, Process Info, PowerShell Host, Time Zone, Uptime — each emitting tables → a predictable, small 5-worksheet workbook that's trivial to eyeball and assert against.
  • No Invoke-Command / CimSession / PSSession / -ComputerName usage — purely local data gathering.

Validate in two layers:

  1. Automated (deterministic, CI-safe): build a small synthetic PScribo.Document fixture in the unit test — one Document → 1–2 H1s → a few H2s, each with a standard table, a list table, and a nested H3 table including \_\_Style cells — then run Export-AbrExcelDocument and re-open the result with Import-Excel/Open-ExcelPackage to assert worksheet count, tab names, headers, and values. Needs no live target (§5.6).
  2. End-to-end: run AsBuiltReport.System.Resources against localhost (single system) and against two hostnames (multi-system) to confirm a real document renders, splits into per-system files, and opens cleanly in Excel.

Effort: ~2–3 days (= Phase 1 in §7).

5. Implementation plan (Core-resident, ImportExcel)

5.1 New private function — the exporter

File: AsBuiltReport.Core/Src/Private/Export-AbrExcelDocument.ps1

function Export-AbrExcelDocument {
 \[CmdletBinding()]
 param (
 \[Parameter(Mandatory)] \[System.Management.Automation.PSObject] $Document, # the PScribo.Document
 \[Parameter(Mandatory)] \[string] $Path,
 \[string] $FileName,
 \[int] $WorksheetHeadingLevel = 2,
 \[switch] $IncludeParagraphs
 )
 # 1. Find all Heading1 sections (Level 0) = one per system. (Skip cover/TOC/title nodes.)
 # 2. FOR EACH H1 (system):
 # a. Compute the per-system output filename:
 # single H1 -> "$FileName.xlsx"
 # multiple -> "$FileName - <sanitised H1 name>.xlsx" (dedupe collisions)
 # b. Resolve worksheet sections WITHIN this H1: recurse its .Sections collecting
 # nodes where Level -eq $WorksheetHeadingLevel (i.e. H2 by default).
 # c. For each worksheet section, recursively gather descendant PScribo.Table nodes
 # (with owning sub-section name/number for banding).
 # d. For each table: project Rows minus \*\_\_Style cols -> Export-Excel
 # -WorksheetName <sanitised> -PassThru; apply header style, freeze top row,
 # autosize, table style; stack multiple tables vertically with banded sub-headers.
 # e. Walk \*\_\_Style metadata -> Set-ExcelRange -BackgroundColor (mapped hex) per cell/row.
 # f. Prepend a "Report Info" sheet (Author/Company/Version/Date for this system) and
 # an "Index" sheet with hyperlinks to each tab.
 # g. Close-ExcelPackage.
 # 3. Return one \[FileInfo] PER system (the caller collects them all).
}

The function returns an array of FileInfo — one per system — so the entry point can report and (optionally) email every generated workbook.

Helpers (private): ConvertTo-AbrExcelWorksheetName (sanitise/dedupe), Get-AbrExcelStyleColor (style name → hex from the Style.ps1 palette), Get-AbrPScriboTableDescendant (recursive table collector).

5.2 Wire -Format Excel into the entry point

File: AsBuiltReport.Core/Src/Public/New-AsBuiltReport.ps1

  • Extend the validation set (line 237):
 \[ValidateSet('Word', 'HTML', 'Text', 'Excel')]
  • After the existing Export-Document call (~line 622), branch: PScribo handles Word/HTML/Text; if Excel is in $Format, call Export-AbrExcelDocument -Document $AsBuiltReport -Path $OutputFolderPath -FileName $FileName, which returns one file per system. Append all returned files to $Document so the existing -SendEmail path attaches every per-system workbook, and emit one OutputFolder success line per file.
  • Keep the original $Format minus Excel for the PScribo call so PScribo never receives an unknown format.

5.3 Declare the dependency — soft / load-on-demand (decided for MVP)

ImportExcel is a soft dependency for the MVP: it is not added to AsBuiltReport.Core.psd1's RequiredModules, so users who never produce Excel are unaffected. Instead, it is loaded only when needed:

  • In New-AsBuiltReport (or at the top of Export-AbrExcelDocument), when Excel is in $Format, attempt to load it and fail clearly if absent:
 if ($Format -contains 'Excel') {
 if (-not (Get-Module -ListAvailable -Name ImportExcel)) {
 Write-Error "The 'Excel' output format requires the ImportExcel module. Install it with: Install-Module ImportExcel -Scope CurrentUser" -ErrorAction Stop
 }
 Import-Module ImportExcel -ErrorAction Stop
 }
  • Mention ImportExcel in the README/user-guide as an optional module required only for -Format Excel.

**Deferred to release (not MVP):** whether to promote ImportExcel to a hard RequiredModules entry (with a pinned minimum version, e.g. 7.x) once Excel is a first-class supported format. Revisit at GA — see §8.2.

5.4 Module loading

AsBuiltReport.Core.psm1 already dot-sources everything in Src/Private/, so the new function loads automatically. No psm1 change unless we choose to promote it to global scope (not needed — it's only called from Core).

5.5 Localization

Add strings (export progress, "Excel module not found", sheet-name truncation warning) to all locale files under Language/\*/New-AsBuiltReport.psd1 (minimum en-US), per the project's localization rule.

5.6 Tests

  • Tests/Unit/Export-AbrExcelDocument.Tests.ps1: build a small synthetic PScribo.Document (Document → ×ばつH1 → ×ばつH2, each with a table incl. \_\_Style cells), run the exporter, then re-open with Import-Excel/Open-ExcelPackage and assert: worksheet count = H2 count, tab names sanitised/unique, header row present, data values intact, \_\_Style cells got the expected fill.
  • Tests/Unit/New-AsBuiltReport.Tests.ps1: assert Excel is now a valid -Format value.
  • Tests/Quality: ensure new file is UTF-8, has comment-based help, passes PSScriptAnalyzer, uses approved verbs (Export- ✓).
  • Gate Excel tests on ImportExcel being available (skip with message otherwise) so CI without the module still passes.

5.7 Docs & changelog

  • CHANGELOG.md: ### Added — Excel (XLSX) export via -Format Excel (ImportExcel). Branch off dev; PR targets dev.
  • README / user-guide: new format, the WorksheetHeadingLevel knob, and the "what doesn't export" note (images/prose).

---

6. Worked example — what the user gets

Run: New-AsBuiltReport -Report VMware.vSphere -Target vcenter01 -Credential $c -Format Word,Excel -EnableHealthCheck

Produces one Word doc plus VMware vSphere As Built Report.xlsx with tabs:

\[Report Info] \[Index] \[vCenter] \[Clusters] \[Resource Pools] \[Hosts]
\[Network] \[vSAN] \[Datastores] \[Virtual Machines] \[Update Manager]

Multi-system run: ... -Target vcenter01,vcenter02 -Format Word,Excel produces one combined Word doc (both vCenters as chapters) but two workbooks:

VMware vSphere As Built Report - vcenter01.xlsx
VMware vSphere As Built Report - vcenter02.xlsx

each containing only that vCenter's worksheet tabs.

  • Datastores tab: top band = all-datastores summary table; below it, one banded block per datastore (detail list table + any "SCSI LUN Info" table), in document order.
  • Cells where datastore usage ≥ 90% are filled FEDDD7 (Critical), 75–90% FFF4C7 (Warning) — identical thresholds to the Word health check, read from the \_\_Style metadata.

---

7. Effort & phasing

Phase Work Est.
1 — MVP -Format Excel, one workbook per Heading1/system, H2→worksheet (level configurable), standard + list tables, header styling, freeze/autosize, sheet-name + filename sanitisation, Report Info sheet, manifest dependency 2–3 days
2 — Health checks Read \_\_Style metadata → cell/row fills + Index sheet with hyperlinks 1 day
3 — Polish Keyed-list tables, optional paragraph inclusion, Excel table styles, captions 1–2 days
4 — Tests/docs/CI Pester unit tests, quality tests, changelog, README/user-guide, localization strings 1–2 days
(Optional later) Refactor into upstream PScribo Out-ExcelDocument plugin separate

Total MVP→shippable: ~1 working week.

---

8. Risks, edge cases & decisions for you

  1. H1-vs-H2 mapping — ✅ DECIDED: Heading2 → worksheet. Implemented as Option C (configurable WorksheetHeadingLevel) with the default set to level 2, so out-of-the-box each H2 becomes its own tab and H1 (the target name) is carried as the title / "Report Info" sheet.
  2. Hard vs. soft ImportExcel dependency — ✅ DECIDED for MVP: soft / load-on-demand. ImportExcel is loaded only when -Format Excel is requested, with a clear actionable error if missing; it is not added to RequiredModules, so Word-only users are unaffected (§5.3). Promotion to a hard, version-pinned RequiredModules entry is deferred to GA.
  3. Duplicate / >31-char tab names — handled by central sanitiser; long names truncated with a logged warning.
    3a. Per-system filenames — system (H1) names used in <FileName> - <System>.xlsx must be stripped of invalid path chars (\\ / : \* ? " < > |) and de-duplicated on collision; guard against over-long paths. Single-system runs keep the plain filename.
  4. Wide tables — many report tables have 8–15+ columns; fine in Excel (auto-size + freeze), better than Word in fact.
  5. Array-valued cells (e.g. tags joined with newlines) — flatten to a single string per cell, mirroring what the Text plugin does.
  6. InfoLevel variance — the workbook's tab set depends on the report config JSON; that's expected and self-consistent (we export whatever sections were rendered). No pre-introspection needed since we read the built object.
  7. Images/diagrams not exported — documented limitation; Word/HTML remain the "rich" formats. Excel is the data/analysis format.
  8. PScribo unmaintained — PScribo is no longer actively maintained (a possible long-term org fork is noted in §4.5 but explicitly out of scope). This poses no risk to the Excel feature: the Core-resident exporter only reads stable, long-standing public properties (.Sections, .Level, .Rows, .Columns, .IsList, \*\_\_Style) of the already-built document object, and adds nothing to PScribo itself.

---

9. Bottom line

  • Feasible and clean — the in-memory PScribo document gives us structured sections, object-shaped table rows, and per-cell health-check metadata, all of which ImportExcel consumes naturally.
  • Self-contained — implement as a Core private function (Export-AbrExcelDocument) invoked from New-AsBuiltReport; zero changes to any report module and no fork of PScribo.
  • One design correction — map Heading2 → worksheet (configurable, default), because reports have only one Heading1. Confirm this and the dependency model (§8.1–8.2) and Phase 1 can begin.
You must be logged in to vote

Replies: 1 comment

Comment options

While it's not fully finished you can probably use PSWriteOffice and/or OfficeIMO if you prefer the C# route.

It's not yet fully announced on PowerShell community but PSWriteOffice can do Word, Excel, PowerPoint, PDF, Markdown or even ODF/RTF/HTML/CSV/Visio and all other things you can imagine doing. It's also materially faster than ImportExcel and a lot more functional.

I'm still finalizing the shape of pswriteoffice, and doing some changes but effectively one module to rule them all. I'm open on feedback on pswriteoffice shape if something is missing. OfficeIMO is 96 projects or so, and PSWriteOffice can use all that.

Maybe this will solve your dependency problem and will give you Word development and huge featureset with ability to save as pdf, markdown and excel, csv etc

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Ideas
Labels
change request New feature or request

AltStyle によって変換されたページ (->オリジナル) /