#!/usr/bin/env pwsh # https://docs.sheetjs.com/docs/demos/cli/nodesea $oldDir = Get-Location $tempDir = Join-Path -Path $env:TEMP -ChildPath "sheetjs-sea" if (Test-Path -Path $tempDir) { Remove-Item -Path $tempDir -Recurse -Force } New-Item -ItemType Directory -Path $tempDir | Out-Null Set-Location -Path $tempDir # NOTE: This effectuates "Native Tools Command Prompt" $vsVersions = @("2022\Community", "2022\Professional", "2022\Enterprise", "2019\Community") foreach ($vsVersion in $vsVersions) { $vcbasePath = "${env:ProgramFiles}\Microsoft Visual Studio\$vsVersion" $vcvarsPath = "${env:ProgramFiles}\Microsoft Visual Studio\$vsVersion\VC\Auxiliary\Build\vcvars64.bat" if (Test-Path -Path $vcvarsPath) { break } } $tempEnvFile = [System.IO.Path]::GetTempFileName() Push-Location "$vcbasePath" cmd.exe /c "`"$vcvarsPath`" && set > `"$tempEnvFile`"" Pop-Location Get-Content "$tempEnvFile" | ForEach-Object { if ($_ -match '^([^=]+)=(.*)$') { $name = $matches[1] $value = $matches[2] if ($name -ne 'PATH') { Set-Item -Path "Env:$name" -Value $value } else { $env:PATH = "$value;$env:PATH" } } } Remove-Item "$tempEnvFile" -Force -ErrorAction SilentlyContinue node --version npm init -y @' // For NodeJS SEA, the CommonJS `require` must be used const { createRequire } = require('node:module'); require = createRequire(__filename); const { readFile, utils } = require("xlsx"); // argv[2] is the first argument to the script const filename = process.argv[2]; // read file const wb = readFile(filename); // generate CSV of first sheet const ws = wb.Sheets[wb.SheetNames[0]]; const csv = utils.sheet_to_csv(ws); // print to terminal console.log(csv); '@ | Out-File -FilePath "sheet2csv.js" -Encoding utf8 npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz ### Script Test Invoke-WebRequest -Uri "https://docs.sheetjs.com/pres.numbers" -OutFile "pres.numbers" node sheet2csv.js pres.numbers ### SEA Bundle @' { "main": "sheet2csv.js", "output": "sheet2csv.blob" } '@ | Out-File -FilePath "sheet2csv.json" -Encoding utf8 node --experimental-sea-config sheet2csv.json # Local Copy $nodePath = (Get-Command node).Source Copy-Item $nodePath "sheet2csv.exe" # Remove the code signature # (windows) signtool remove /s .\sheet2csv.exe # Inject the SEA bundle ## NOTE: npx -y postject seemed to fail in windows :( npm i -g postject postject --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 sheet2csv.exe NODE_SEA_BLOB sheet2csv.blob # Resign the binary $cert = New-SelfSignedCertificate -Type CodeSigning -DnsName "www.onlyspans.net" -CertStoreLocation Cert:\CurrentUser\My $pass = ConvertTo-SecureString -String "hunter2" -Force -AsPlainText Export-PfxCertificate -Cert "cert:\CurrentUser\My\$($cert.Thumbprint)" -FilePath "mycert.pfx" -Password $pass ## NOTE: if self-signed cert is not trusted, verify will show an error $cert | Export-Certificate -FilePath "mycert.cer" Import-Certificate -FilePath "mycert.cer" -CertStoreLocation Cert:\CurrentUser\Root | Out-Null signtool sign /v /f mycert.pfx /p hunter2 /fd SHA256 sheet2csv.exe ### Standalone Test .\sheet2csv.exe pres.numbers # Validate the signature signtool verify /v /pa sheet2csv.exe Set-Location $oldDir Remove-Item -Path $tempDir -Recurse -Force