$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
$threadId = if ($env:CODEX_THREAD_ID) { $env:CODEX_THREAD_ID } else { "local" }
$outDir = Join-Path $root ("outputs\" + $threadId)
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
$outPath = Join-Path $outDir "GL-001_Simulation.xlsx"
if (Test-Path -LiteralPath $outPath) {
$outPath = Join-Path $outDir ("GL-001_Simulation_" + (Get-Date -Format "yyyyMMdd_HHmmss") + ".xlsx")
}
$buildDir = Join-Path $outDir ("_xlsx_build_" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Force -Path $buildDir | Out-Null
function XmlEscape([object]$value) {
if ($null -eq $value) { return "" }
return [System.Security.SecurityElement]::Escape([string]$value)
}
function ColName([int]$index) {
$name = ""
while ($index -gt 0) {
$mod = ($index - 1) % 26
$name = [char](65 + $mod) + $name
$index = [math]::Floor(($index - $mod) / 26)
}
return $name
}
function CellXml([int]$row, [int]$col, [object]$value, [int]$style = 0, [string]$formula = $null) {
$ref = "$(ColName $col)$row"
$s = if ($style -gt 0) { " s=`"$style`"" } else { "" }
if ($formula) {
return "$(XmlEscape $formula)"
}
if ($null -eq $value -or $value -eq "") {
return ""
}
if ($value -is [string] -and $value -match '^\d{4}-\d{2}-\d{2}$') {
$date = [datetime]::ParseExact($value, "yyyy-MM-dd", [Globalization.CultureInfo]::InvariantCulture)
$serial = [int](($date - [datetime]"1899-12-30").TotalDays)
return "$serial"
}
if ($value -is [int] -or $value -is [double] -or $value -is [decimal]) {
return "$value"
}
return "$(XmlEscape $value)"
}
function RowXml([int]$rowNum, [object[]]$values, [int[]]$styles = $null) {
$cells = New-Object System.Collections.Generic.List[string]
for ($i = 0; $i -lt $values.Count; $i++) {
$style = if ($styles -and $i -lt $styles.Count) { $styles[$i] } else { 0 }
$cells.Add((CellXml $rowNum ($i + 1) $values[$i] $style))
}
return "$($cells -join '')
"
}
function Write-Utf8File([string]$path, [string]$content) {
$dir = Split-Path -Parent $path
New-Item -ItemType Directory -Force -Path $dir | Out-Null
[System.IO.File]::WriteAllText($path, $content, [System.Text.UTF8Encoding]::new($false))
}
$accounts = @(
@("1000", "Cash and bank", "Asset", 85000, "Debit"),
@("1100", "Accounts receivable", "Asset", 42000, "Debit"),
@("1200", "Prepaid expenses", "Asset", 12000, "Debit"),
@("2000", "Accounts payable", "Liability", -36500, "Credit"),
@("2200", "VAT payable", "Liability", -8200, "Credit"),
@("3000", "Share capital", "Equity", -100000, "Credit"),
@("4000", "Consulting revenue", "Revenue", 0, "Credit"),
@("5000", "Subcontractor costs", "Expense", 0, "Debit"),
@("6000", "Operating expenses", "Expense", 0, "Debit"),
@("6900", "Bank fees", "Expense", 0, "Debit")
)
$glHeaders = @(
"entity", "account", "account_name", "transaction_currency", "base_currency",
"posting_date", "document_date", "journal", "journal_entry_number", "document_number",
"document_type", "posting_status", "supplier_invoice_number", "counterparty", "voucher_number",
"description", "reference", "payable_qty", "uom",
"debit_transaction_currency", "credit_transaction_currency", "balance_transaction_currency",
"debit_base_currency", "credit_base_currency", "balance_base_currency",
"entered_date", "entered_by", "modified_date", "modified_by"
)
$entries = @(
@("Open Squared SA", "1000", "Cash and bank", "CHF", "CHF", "2026-01-03", "2026-01-03", "BNK", "GL001-0001", "BNK-260103", "BANK", "Posted", "", "UBS", "VCH-260001", "Opening payroll funding transfer", "TRF-260103", "", "", 30000, 0, "", 30000, 0, "", "2026-01-03", "jsmith", "2026-01-03", "jsmith"),
@("Open Squared SA", "1000", "Cash and bank", "CHF", "CHF", "2026-01-20", "2026-01-20", "BNK", "GL001-0004", "PAY-260020", "PAYMENT", "Posted", "", "Partner X", "VCH-260004", "Supplier payment", "PAY-260020", "", "", 0, -18500, "", 0, -18500, "", "2026-01-20", "mdupont", "2026-01-20", "mdupont"),
@("Open Squared SA", "1000", "Cash and bank", "CHF", "CHF", "2026-02-17", "2026-02-17", "BNK", "GL001-0007", "REC-260217", "RECEIPT", "Posted", "", "Client B", "VCH-260007", "Receipt from Client B", "REC-260217", "", "", 48600, 0, "", 48600, 0, "", "2026-02-17", "jsmith", "2026-02-17", "jsmith"),
@("Open Squared SA", "1000", "Cash and bank", "CHF", "CHF", "2026-02-28", "2026-02-28", "BNK", "GL001-0008", "BNK-260228", "BANK", "Posted", "", "UBS", "VCH-260008", "Bank fees paid", "FEE-260228", "", "", 0, -85, "", 0, -85, "", "2026-02-28", "jsmith", "2026-02-28", "jsmith"),
@("Open Squared SA", "1000", "Cash and bank", "CHF", "CHF", "2026-03-22", "2026-03-22", "BNK", "GL001-0011", "PAY-260322", "PAYMENT", "Posted", "", "Microsoft", "VCH-260011", "Payment to Microsoft", "PAY-260322", "", "", 0, -2592, "", 0, -2592, "", "2026-03-22", "mdupont", "2026-03-22", "mdupont"),
@("Open Squared SA", "1000", "Cash and bank", "CHF", "CHF", "2026-03-29", "2026-03-29", "BNK", "GL001-0012", "REC-260329", "RECEIPT", "Posted", "", "Client C", "VCH-260012", "Receipt from Client C", "REC-260329", "", "", 70200, 0, "", 70200, 0, "", "2026-03-29", "jsmith", "2026-03-29", "jsmith"),
@("Open Squared SA", "1100", "Accounts receivable", "CHF", "CHF", "2026-01-03", "2026-01-03", "BNK", "GL001-0001", "BNK-260103", "BANK", "Posted", "", "Client A", "VCH-260001", "Collection of December receivable", "TRF-260103", "", "", 0, -30000, "", 0, -30000, "", "2026-01-03", "jsmith", "2026-01-03", "jsmith"),
@("Open Squared SA", "1100", "Accounts receivable", "CHF", "CHF", "2026-01-09", "2026-01-09", "SAJ", "GL001-0002", "INV-260001", "AR_INV", "Posted", "", "Client B", "VCH-260002", "January consulting invoice", "SOW-OS-001", "", "", 48600, 0, "", 48600, 0, "", "2026-01-09", "akeller", "2026-01-09", "akeller"),
@("Open Squared SA", "1100", "Accounts receivable", "CHF", "CHF", "2026-02-12", "2026-02-12", "SAJ", "GL001-0006", "INV-260019", "AR_INV", "Posted", "", "Client C", "VCH-260006", "February implementation invoice", "SOW-OS-019", "", "", 70200, 0, "", 70200, 0, "", "2026-02-12", "akeller", "2026-02-12", "akeller"),
@("Open Squared SA", "1100", "Accounts receivable", "CHF", "CHF", "2026-02-17", "2026-02-17", "BNK", "GL001-0007", "REC-260217", "RECEIPT", "Posted", "", "Client B", "VCH-260007", "Customer payment", "REC-260217", "", "", 0, -48600, "", 0, -48600, "", "2026-02-17", "jsmith", "2026-02-17", "jsmith"),
@("Open Squared SA", "1100", "Accounts receivable", "CHF", "CHF", "2026-03-15", "2026-03-15", "SAJ", "GL001-0010", "INV-260037", "AR_INV", "Posted", "", "Client A", "VCH-260010", "March advisory invoice", "SOW-OS-037", "", "", 37800, 0, "", 37800, 0, "", "2026-03-15", "akeller", "2026-03-15", "akeller"),
@("Open Squared SA", "1100", "Accounts receivable", "CHF", "CHF", "2026-03-29", "2026-03-29", "BNK", "GL001-0012", "REC-260329", "RECEIPT", "Posted", "", "Client C", "VCH-260012", "Customer payment", "REC-260329", "", "", 0, -70200, "", 0, -70200, "", "2026-03-29", "jsmith", "2026-03-29", "jsmith"),
@("Open Squared SA", "1200", "Prepaid expenses", "CHF", "CHF", "2026-03-04", "2026-03-01", "PUR", "GL001-0009", "BILL-260304", "AP_INV", "Posted", "INS-2026-031", "Insurer", "VCH-260009", "Annual insurance prepayment", "POL-2026", "", "", 9600, 0, "", 9600, 0, "", "2026-03-04", "mdupont", "2026-03-04", "mdupont"),
@("Open Squared SA", "2000", "Accounts payable", "CHF", "CHF", "2026-01-14", "2026-01-12", "PUR", "GL001-0003", "BILL-260014", "AP_INV", "Posted", "PX-2026-014", "Partner X", "VCH-260003", "Supplier payable", "PO-260014", "", "", 0, -18500, "", 0, -18500, "", "2026-01-14", "mdupont", "2026-01-14", "mdupont"),
@("Open Squared SA", "2000", "Accounts payable", "CHF", "CHF", "2026-01-20", "2026-01-20", "BNK", "GL001-0004", "PAY-260020", "PAYMENT", "Posted", "PX-2026-014", "Partner X", "VCH-260004", "Payment to supplier", "PAY-260020", "", "", 18500, 0, "", 18500, 0, "", "2026-01-20", "mdupont", "2026-01-20", "mdupont"),
@("Open Squared SA", "2000", "Accounts payable", "CHF", "CHF", "2026-02-01", "2026-01-31", "PUR", "GL001-0005", "BILL-260201", "AP_INV", "Posted", "MS-2026-002", "Microsoft", "VCH-260005", "Supplier payable", "MS-AZ-260201", "", "", 0, -2592, "", 0, -2592, "", "2026-02-01", "mdupont", "2026-02-01", "mdupont"),
@("Open Squared SA", "2000", "Accounts payable", "CHF", "CHF", "2026-03-04", "2026-03-01", "PUR", "GL001-0009", "BILL-260304", "AP_INV", "Posted", "INS-2026-031", "Insurer", "VCH-260009", "Insurance payable", "POL-2026", "", "", 0, -9600, "", 0, -9600, "", "2026-03-04", "mdupont", "2026-03-04", "mdupont"),
@("Open Squared SA", "2000", "Accounts payable", "CHF", "CHF", "2026-03-22", "2026-03-22", "BNK", "GL001-0011", "PAY-260322", "PAYMENT", "Posted", "MS-2026-002", "Microsoft", "VCH-260011", "Cloud subscriptions paid", "PAY-260322", "", "", 2592, 0, "", 2592, 0, "", "2026-03-22", "mdupont", "2026-03-22", "mdupont"),
@("Open Squared SA", "2200", "VAT payable", "CHF", "CHF", "2026-01-09", "2026-01-09", "SAJ", "GL001-0002", "INV-260001", "TAX", "Posted", "", "Client B", "VCH-260002", "Output VAT", "VAT-OUT", "", "", 0, -3600, "", 0, -3600, "", "2026-01-09", "akeller", "2026-01-09", "akeller"),
@("Open Squared SA", "2200", "VAT payable", "CHF", "CHF", "2026-02-01", "2026-01-31", "PUR", "GL001-0005", "BILL-260201", "TAX", "Posted", "MS-2026-002", "Microsoft", "VCH-260005", "Input VAT", "VAT-IN", "", "", 192, 0, "", 192, 0, "", "2026-02-01", "mdupont", "2026-02-01", "mdupont"),
@("Open Squared SA", "2200", "VAT payable", "CHF", "CHF", "2026-02-12", "2026-02-12", "SAJ", "GL001-0006", "INV-260019", "TAX", "Posted", "", "Client C", "VCH-260006", "Output VAT", "VAT-OUT", "", "", 0, -5200, "", 0, -5200, "", "2026-02-12", "akeller", "2026-02-12", "akeller"),
@("Open Squared SA", "2200", "VAT payable", "CHF", "CHF", "2026-03-15", "2026-03-15", "SAJ", "GL001-0010", "INV-260037", "TAX", "Posted", "", "Client A", "VCH-260010", "Output VAT", "VAT-OUT", "", "", 0, -2800, "", 0, -2800, "", "2026-03-15", "akeller", "2026-03-15", "akeller"),
@("Open Squared SA", "4000", "Consulting revenue", "CHF", "CHF", "2026-01-09", "2026-01-09", "SAJ", "GL001-0002", "INV-260001", "AR_INV", "Posted", "", "Client B", "VCH-260002", "January consulting revenue", "SOW-OS-001", "", "", 0, -45000, "", 0, -45000, "", "2026-01-09", "akeller", "2026-01-09", "akeller"),
@("Open Squared SA", "4000", "Consulting revenue", "CHF", "CHF", "2026-02-12", "2026-02-12", "SAJ", "GL001-0006", "INV-260019", "AR_INV", "Posted", "", "Client C", "VCH-260006", "February implementation revenue", "SOW-OS-019", "", "", 0, -65000, "", 0, -65000, "", "2026-02-12", "akeller", "2026-02-12", "akeller"),
@("Open Squared SA", "4000", "Consulting revenue", "CHF", "CHF", "2026-03-15", "2026-03-15", "SAJ", "GL001-0010", "INV-260037", "AR_INV", "Posted", "", "Client A", "VCH-260010", "March advisory revenue", "SOW-OS-037", "", "", 0, -35000, "", 0, -35000, "", "2026-03-15", "akeller", "2026-03-15", "akeller"),
@("Open Squared SA", "5000", "Subcontractor costs", "CHF", "CHF", "2026-01-14", "2026-01-12", "PUR", "GL001-0003", "BILL-260014", "AP_INV", "Posted", "PX-2026-014", "Partner X", "VCH-260003", "Subcontractor delivery costs", "PO-260014", "", "", 18500, 0, "", 18500, 0, "", "2026-01-14", "mdupont", "2026-01-14", "mdupont"),
@("Open Squared SA", "6000", "Operating expenses", "CHF", "CHF", "2026-02-01", "2026-01-31", "PUR", "GL001-0005", "BILL-260201", "AP_INV", "Posted", "MS-2026-002", "Microsoft", "VCH-260005", "Cloud subscriptions", "MS-AZ-260201", "", "", 2400, 0, "", 2400, 0, "", "2026-02-01", "mdupont", "2026-02-01", "mdupont"),
@("Open Squared SA", "6900", "Bank fees", "CHF", "CHF", "2026-02-28", "2026-02-28", "BNK", "GL001-0008", "BNK-260228", "BANK", "Posted", "", "UBS", "VCH-260008", "Monthly banking charges", "FEE-260228", "", "", 85, 0, "", 85, 0, "", "2026-02-28", "jsmith", "2026-02-28", "jsmith")
)
$styles = @'
'@
function SheetDoc([string]$sheetData, [string]$cols, [string]$merge = "", [string]$autoFilter = "", [string]$pane = "") {
return "$pane$cols$sheetData$autoFilter$merge"
}
$coverRows = @()
$coverRows += "$(CellXml 2 2 'GL-001 - Simulation de sortie du rapport' 1)
"
$coverRows += "$(CellXml 4 2 'Ce classeur simule une sortie GL-001 pour validation de format, de colonnes, de totaux et de contrôles. Les écritures et soldes sont fictifs.' 0)
"
$coverData = @(
@("Entité", "Open Squared SA"),
@("Rapport", "GL-001 - General Ledger Detail"),
@("Période", "2026-01-01 à 2026-03-31"),
@("Devise", "CHF"),
@("Base", "Comptabilité d'exercice"),
@("Statut", "Simulation"),
@("Préparé le", (Get-Date -Format "yyyy-MM-dd"))
)
for ($i = 0; $i -lt $coverData.Count; $i++) { $coverRows += RowXml (6 + $i) @("", $coverData[$i][0], $coverData[$i][1]) @(0,4,4) }
$coverRows += "$(CellXml 14 2 'Structure du classeur' 2)
"
$coverRows += RowXml 15 @("", "00_Cover", "Conventions, statut et navigation") @(0,4,4)
$coverRows += RowXml 16 @("", "01_Parameters", "Paramètres de simulation et soldes d'ouverture") @(0,4,4)
$coverRows += RowXml 17 @("", "02_GL001_Output", "Sortie détaillée simulée du rapport GL-001") @(0,4,4)
$coverRows += RowXml 18 @("", "03_Controls", "Contrôles de balance, complétude et cohérence") @(0,4,4)
$coverCols = ""
$coverMerge = ""
$paramRows = @()
$paramRows += "$(CellXml 1 1 'Paramètres et soldes d''ouverture' 1)
"
$paramInfo = @(
@("Entity", "Open Squared SA"),
@("Report code", "GL-001"),
@("Period start", "2026-01-01"),
@("Period end", "2026-03-31"),
@("Currency", "CHF"),
@("Scenario", "Simulated output")
)
for ($i = 0; $i -lt $paramInfo.Count; $i++) {
$valueStyle = if ((3 + $i) -in @(5, 6)) { 6 } else { 5 }
$paramRows += RowXml (3 + $i) $paramInfo[$i] @(4,$valueStyle)
}
$paramRows += RowXml 10 @("Account", "Account name", "Type", "Opening balance CHF", "Normal sign") @(2,2,2,2,2)
for ($i = 0; $i -lt $accounts.Count; $i++) { $paramRows += RowXml (11 + $i) $accounts[$i] @(4,4,4,3,4) }
$paramCols = ""
$paramMerge = ""
$glRows = @()
$glRows += "$(CellXml 1 1 'GL-001 - General Ledger Detail (simulation)' 1)
"
$glRows += RowXml 3 $glHeaders @(2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2)
for ($i = 0; $i -lt $entries.Count; $i++) {
$r = 4 + $i
$e = $entries[$i]
$stylesRow = @(4,4,4,4,4,6,6,4,4,4,4,4,4,4,4,4,4,3,4,3,3,3,3,3,3,6,4,6,4)
$cells = New-Object System.Collections.Generic.List[string]
for ($c = 1; $c -le $glHeaders.Count; $c++) {
if ($c -eq 22) {
if ($r -eq 4) {
$formula = "INDEX('01_Parameters'!`$D`$11:`$D`$20,MATCH(B4,'01_Parameters'!`$A`$11:`$A`$20,0))+T4+U4"
} else {
$formula = "IF(AND(B$r=B$($r-1),D$r=D$($r-1)),V$($r-1)+T$r+U$r,INDEX('01_Parameters'!`$D`$11:`$D`$20,MATCH(B$r,'01_Parameters'!`$A`$11:`$A`$20,0))+T$r+U$r)"
}
$cells.Add((CellXml $r $c "" 3 $formula))
} elseif ($c -eq 25) {
if ($r -eq 4) {
$formula = "INDEX('01_Parameters'!`$D`$11:`$D`$20,MATCH(B4,'01_Parameters'!`$A`$11:`$A`$20,0))+W4+X4"
} else {
$formula = "IF(AND(B$r=B$($r-1),E$r=E$($r-1)),Y$($r-1)+W$r+X$r,INDEX('01_Parameters'!`$D`$11:`$D`$20,MATCH(B$r,'01_Parameters'!`$A`$11:`$A`$20,0))+W$r+X$r)"
}
$cells.Add((CellXml $r $c "" 3 $formula))
} else {
$cells.Add((CellXml $r $c $e[$c-1] $stylesRow[$c-1]))
}
}
$glRows += "$($cells -join '')
"
}
$lastGlRow = 3 + $entries.Count
$glCols = ""
$glMerge = ""
$glFilter = ""
$glPane = ""
$checkRows = @()
$checkRows += "$(CellXml 1 1 'Contrôles GL-001' 1)
"
$checkRows += RowXml 3 @("Check", "Actual", "Expected", "Difference", "Tolerance", "Status", "Notes") @(2,2,2,2,2,2,2)
$checkLabels = @(
@("Transaction currency movements net to zero", "SUM('02_GL001_Output'!T4:T$lastGlRow)+SUM('02_GL001_Output'!U4:U$lastGlRow)", 0, "B4-C4", 0.01, "IF(ABS(D4)<=E4,`"OK`",`"Review`")", "Credits are displayed as negative amounts per GL-001 sign convention."),
@("Base currency movements net to zero", "SUM('02_GL001_Output'!W4:W$lastGlRow)+SUM('02_GL001_Output'!X4:X$lastGlRow)", 0, "B5-C5", 0.01, "IF(ABS(D5)<=E5,`"OK`",`"Review`")", "Base currency should reconcile to the same balanced journal movements."),
@("No blank account codes", "COUNTBLANK('02_GL001_Output'!B4:B$lastGlRow)", 0, "B6-C6", 0, "IF(D6=0,`"OK`",`"Review`")", "Every transaction line should carry an account code."),
@("All rows posted", "COUNTIF('02_GL001_Output'!L4:L$lastGlRow,`"<>Posted`")", 0, "B7-C7", 0, "IF(D7=0,`"OK`",`"Review`")", "Simulation assumes only posted lines are in scope."),
@("Report period start", "MIN('02_GL001_Output'!F4:F$lastGlRow)", "'01_Parameters'!B5", "B8-C8", 0, "IF(B8>=C8,`"OK`",`"Review`")", "No transaction before selected period start."),
@("Report period end", "MAX('02_GL001_Output'!F4:F$lastGlRow)", "'01_Parameters'!B6", "B9-C9", 0, "IF(B9<=C9,`"OK`",`"Review`")", "No transaction after selected period end."),
@("AP invoices carry supplier invoice number", "COUNTIFS('02_GL001_Output'!K4:K$lastGlRow,`"AP_INV`",'02_GL001_Output'!M4:M$lastGlRow,`"`")", 0, "B10-C10", 0, "IF(D10=0,`"OK`",`"Review`")", "AP-related entries should expose supplier_invoice_number when available.")
)
for ($i = 0; $i -lt $checkLabels.Count; $i++) {
$r = 4 + $i
$item = $checkLabels[$i]
if ($item[2] -is [int]) {
$expectedCell = CellXml $r 3 $item[2] 3
} else {
$expectedCell = CellXml $r 3 "" 3 $item[2]
}
$cells = @(
(CellXml $r 1 $item[0] 4),
(CellXml $r 2 "" 3 $item[1]),
$expectedCell,
(CellXml $r 4 "" 3 $item[3]),
(CellXml $r 5 $item[4] 3),
(CellXml $r 6 "" 4 $item[5]),
(CellXml $r 7 $item[6] 4)
)
$checkRows += "$($cells -join '')
"
}
$checkRows += RowXml 13 @("Account", "Account name", "Currency", "Opening TC", "Debits TC", "Credits TC", "Closing TC", "Debits base", "Credits base", "Closing base") @(2,2,2,2,2,2,2,2,2,2)
for ($i = 0; $i -lt $accounts.Count; $i++) {
$r = 14 + $i
$src = 11 + $i
$cells = @(
(CellXml $r 1 "" 4 "'01_Parameters'!A$src"),
(CellXml $r 2 "" 4 "'01_Parameters'!B$src"),
(CellXml $r 3 "CHF" 4),
(CellXml $r 4 "" 3 "'01_Parameters'!D$src"),
(CellXml $r 5 "" 3 "SUMIFS('02_GL001_Output'!T:T,'02_GL001_Output'!B:B,A$r,'02_GL001_Output'!D:D,C$r)"),
(CellXml $r 6 "" 3 "SUMIFS('02_GL001_Output'!U:U,'02_GL001_Output'!B:B,A$r,'02_GL001_Output'!D:D,C$r)"),
(CellXml $r 7 "" 3 "D$r+E$r+F$r"),
(CellXml $r 8 "" 3 "SUMIFS('02_GL001_Output'!W:W,'02_GL001_Output'!B:B,A$r,'02_GL001_Output'!E:E,C$r)"),
(CellXml $r 9 "" 3 "SUMIFS('02_GL001_Output'!X:X,'02_GL001_Output'!B:B,A$r,'02_GL001_Output'!E:E,C$r)"),
(CellXml $r 10 "" 3 "D$r+H$r+I$r")
)
$checkRows += "$($cells -join '')
"
}
$checkCols = ""
$checkMerge = ""
Write-Utf8File (Join-Path $buildDir "[Content_Types].xml") @'
'@
Write-Utf8File (Join-Path $buildDir "_rels\.rels") @'
'@
Write-Utf8File (Join-Path $buildDir "xl\_rels\workbook.xml.rels") @'
'@
Write-Utf8File (Join-Path $buildDir "xl\workbook.xml") @'
'@
Write-Utf8File (Join-Path $buildDir "xl\styles.xml") $styles
Write-Utf8File (Join-Path $buildDir "xl\worksheets\sheet1.xml") (SheetDoc ($coverRows -join "") $coverCols $coverMerge)
Write-Utf8File (Join-Path $buildDir "xl\worksheets\sheet2.xml") (SheetDoc ($paramRows -join "") $paramCols $paramMerge "")
Write-Utf8File (Join-Path $buildDir "xl\worksheets\sheet3.xml") (SheetDoc ($glRows -join "") $glCols $glMerge $glFilter $glPane)
Write-Utf8File (Join-Path $buildDir "xl\worksheets\sheet4.xml") (SheetDoc ($checkRows -join "") $checkCols $checkMerge)
Add-Type -AssemblyName System.IO.Compression.FileSystem
Add-Type -AssemblyName System.IO.Compression
$zip = [System.IO.Compression.ZipFile]::Open($outPath, [System.IO.Compression.ZipArchiveMode]::Create)
try {
Get-ChildItem -LiteralPath $buildDir -Recurse -File | ForEach-Object {
$relative = $_.FullName.Substring($buildDir.Length + 1).Replace('\', '/')
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $_.FullName, $relative) | Out-Null
}
}
finally {
$zip.Dispose()
}
Remove-Item -LiteralPath $buildDir -Recurse -Force -ErrorAction SilentlyContinue
Write-Output $outPath