Skip to content

Commit 0797fa0

Browse files
Copilotrebelinux
andcommitted
Remove Excel support; add AsBuiltReport config file generation wizard to GUI
Co-authored-by: rebelinux <1002783+rebelinux@users.noreply.github.com>
1 parent 3a4f1e5 commit 0797fa0

3 files changed

Lines changed: 280 additions & 17 deletions

File tree

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,17 @@ point-and-click interface:
243243

244244
| Section | Controls |
245245
| ------- | -------- |
246-
| **Report Configuration** | Target, Output Folder (with folder browser), Report Name, Language |
247-
| **Output Formats** | HTML · Word · Text · Excel checkboxes |
246+
| **Report Configuration** | Target, Output Folder (with folder browser), Report Name, Language, AsBuiltReport Config File (optional — browse or generate) |
247+
| **Output Formats** | HTML · Word · Text checkboxes |
248248
| **Options** | Timestamp · HealthCheck · Enable Diagrams · Export Diagrams · Diagram Theme |
249249
| **Info Level** | Per-section selectors (0 = Disabled, 1 = Summary, 2 = Detailed) for Date, TimeZone, Uptime, PSHost, ProcessInfo |
250250
| **Generate** | Progress bar · scrollable log showing live output |
251251

252+
The **Generate Config...** button opens a wizard that mirrors `New-AsBuiltConfig`:
253+
it collects Report Author, Company details (Full Name, Short Name, Contact, Email,
254+
Phone, Address) and optional SMTP/Email settings, then saves a JSON file that is
255+
automatically passed to `New-AsBuiltReport` via `-AsBuiltConfigFilePath`.
256+
252257
Report generation runs on a background thread so the window stays fully responsive.
253258

254259
## :computer: Examples

Src/GUI/Invoke-AsBuiltReportGui.ps1

Lines changed: 269 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
99
Sections of the GUI:
1010
11-
Report Configuration - Target, Output Folder, Report Name, Language
12-
Output Formats - Html / Word / Text / Excel checkboxes
11+
Report Configuration - Target, Output Folder, Report Name, Language,
12+
AsBuiltReport Config File (optional)
13+
Output Formats - Html / Word / Text checkboxes
1314
Options - Timestamp, HealthCheck, Diagrams, Export Diagrams,
1415
Diagram Theme
1516
Info Level - Per-section detail level (0 = Disabled, 1 = Summary,
@@ -18,6 +19,11 @@
1819
Generate - Progress bar + scrollable log; report runs on a
1920
background thread so the UI stays responsive.
2021
22+
An embedded "Generate Config..." wizard mirrors New-AsBuiltConfig: it collects
23+
Report Author, Company details (Full Name, Short Name, Contact, Email, Phone,
24+
Address) and optional SMTP/Email settings, then writes a JSON file that can be
25+
passed to New-AsBuiltReport via -AsBuiltConfigFilePath.
26+
2127
.NOTES
2228
Requirements:
2329
- PowerShell 7.4 or newer (AvaloniaUIShell requirement)
@@ -207,31 +213,269 @@ $rowLang.Orientation = 'Horizontal'; $rowLang.Spacing = 8
207213
$rowLang.Children.Add($lblLang)
208214
$rowLang.Children.Add($cbLang)
209215

216+
# AsBuiltReport Config File (optional - passed via -AsBuiltConfigFilePath)
217+
$lblAbrConfig = [TextBlock]::new(); $lblAbrConfig.Text = 'AsBuiltReport Config:'
218+
$lblAbrConfig.Width = 130; $lblAbrConfig.VerticalAlignment = 'Center'
219+
$txtAbrConfig = [TextBox]::new()
220+
$txtAbrConfig.Width = 220
221+
$txtAbrConfig.Watermark = 'Optional - leave blank to skip'
222+
$syncHash.TxtAbrConfig = $txtAbrConfig
223+
224+
$btnBrowseAbrConfig = [Button]::new()
225+
$btnBrowseAbrConfig.Content = 'Browse'
226+
$btnBrowseAbrConfig.Width = 70
227+
$btnBrowseAbrConfig.AddClick({
228+
if ($IsWindows) {
229+
try {
230+
Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop
231+
$dlg = [System.Windows.Forms.OpenFileDialog]::new()
232+
$dlg.Title = 'Select AsBuiltReport Config File'
233+
$dlg.Filter = 'JSON files (*.json)|*.json|All files (*.*)|*.*'
234+
if ($dlg.ShowDialog() -eq 'OK') {
235+
$syncHash.TxtAbrConfig.Text = $dlg.FileName
236+
}
237+
} catch {
238+
Add-LogLine "File browser unavailable: $_. Please type the path directly."
239+
}
240+
} else {
241+
Add-LogLine 'File browser not available on this platform - type the path directly.'
242+
}
243+
})
244+
245+
# "Generate Config..." button - opens a sub-window wizard (mirrors New-AsBuiltConfig)
246+
$btnGenAbrConfig = [Button]::new()
247+
$btnGenAbrConfig.Content = 'Generate Config...'
248+
$btnGenAbrConfig.Width = 120
249+
$btnGenAbrConfig.AddClick({
250+
# Collect sub-window field values via a synchronized hashtable
251+
$cfgSync = [Hashtable]::Synchronized(@{})
252+
253+
$cfgWin = [Window]::new()
254+
$cfgWin.Title = 'Generate AsBuiltReport Config File'
255+
$cfgWin.Width = 520
256+
$cfgWin.Height = 640
257+
$cfgWin.WindowStartupLocation = 'CenterScreen'
258+
$cfgWin.CanMaximize = $false
259+
260+
# ---- inner helper: label + textbox row ----
261+
$makeCfgRow = {
262+
param([string]$LabelText, [string]$WatermarkText = '', [string]$DefaultValue = '')
263+
$lbl = [TextBlock]::new(); $lbl.Text = $LabelText
264+
$lbl.Width = 130; $lbl.VerticalAlignment = 'Center'
265+
$txt = [TextBox]::new(); $txt.Width = 310
266+
if ($WatermarkText) { $txt.Watermark = $WatermarkText }
267+
if ($DefaultValue) { $txt.Text = $DefaultValue }
268+
$row = [StackPanel]::new()
269+
$row.Orientation = 'Horizontal'; $row.Spacing = 8
270+
$row.Children.Add($lbl) | Out-Null
271+
$row.Children.Add($txt) | Out-Null
272+
return $row, $txt
273+
}
274+
275+
# ---- Report info ----
276+
$rowAuthor, $txtAuthor = & $makeCfgRow 'Report Author:' '' ([System.Environment]::UserName)
277+
$cfgSync.TxtAuthor = $txtAuthor
278+
279+
# ---- Company ----
280+
$rowCompanyFull, $txtCompanyFull = & $makeCfgRow 'Company Full Name:' 'e.g. Acme Corporation'
281+
$rowCompanyShort, $txtCompanyShort = & $makeCfgRow 'Company Short Name:' 'e.g. Acme'
282+
$rowContact, $txtContact = & $makeCfgRow 'Contact Name:'
283+
$rowCompanyEmail, $txtCompanyEmail = & $makeCfgRow 'Contact Email:'
284+
$rowPhone, $txtPhone = & $makeCfgRow 'Phone Number:'
285+
$rowAddress, $txtAddress = & $makeCfgRow 'Address:'
286+
$cfgSync.TxtCompanyFull = $txtCompanyFull
287+
$cfgSync.TxtCompanyShort = $txtCompanyShort
288+
$cfgSync.TxtContact = $txtContact
289+
$cfgSync.TxtCompanyEmail = $txtCompanyEmail
290+
$cfgSync.TxtPhone = $txtPhone
291+
$cfgSync.TxtAddress = $txtAddress
292+
293+
# ---- SMTP / Email (optional) ----
294+
$rowMailServer, $txtMailServer = & $makeCfgRow 'SMTP Server:' 'e.g. smtp.office365.com'
295+
$rowMailPort, $txtMailPort = & $makeCfgRow 'SMTP Port:' '25 or 587' '25'
296+
$rowMailFrom, $txtMailFrom = & $makeCfgRow 'From Address:'
297+
$rowMailTo, $txtMailTo = & $makeCfgRow 'To Address(es):' 'Comma-separated'
298+
$cfgSync.TxtMailServer = $txtMailServer
299+
$cfgSync.TxtMailPort = $txtMailPort
300+
$cfgSync.TxtMailFrom = $txtMailFrom
301+
$cfgSync.TxtMailTo = $txtMailTo
302+
303+
$chkMailSSL = [CheckBox]::new(); $chkMailSSL.Content = 'Use SSL/TLS'
304+
$chkMailCreds = [CheckBox]::new(); $chkMailCreds.Content = 'Requires Credentials'
305+
$cfgSync.ChkMailSSL = $chkMailSSL
306+
$cfgSync.ChkMailCreds = $chkMailCreds
307+
$rowMailChk = [StackPanel]::new()
308+
$rowMailChk.Orientation = 'Horizontal'; $rowMailChk.Spacing = 16
309+
$rowMailChk.Margin = [Thickness]::new(138, 0, 0, 0)
310+
$rowMailChk.Children.Add($chkMailSSL) | Out-Null
311+
$rowMailChk.Children.Add($chkMailCreds) | Out-Null
312+
313+
# ---- Save path ----
314+
$lblSavePath = [TextBlock]::new(); $lblSavePath.Text = 'Save Config To:'
315+
$lblSavePath.Width = 130; $lblSavePath.VerticalAlignment = 'Center'
316+
$defaultConfigDir = Join-Path $HOME 'AsBuiltReport'
317+
$defaultConfigFile = Join-Path $defaultConfigDir 'AsBuiltReport.json'
318+
$txtSavePath = [TextBox]::new(); $txtSavePath.Width = 230; $txtSavePath.Text = $defaultConfigFile
319+
$cfgSync.TxtSavePath = $txtSavePath
320+
321+
$btnBrowseSave = [Button]::new(); $btnBrowseSave.Content = 'Browse'; $btnBrowseSave.Width = 70
322+
$btnBrowseSave.AddClick({
323+
if ($IsWindows) {
324+
try {
325+
Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop
326+
$sfd = [System.Windows.Forms.SaveFileDialog]::new()
327+
$sfd.Title = 'Save AsBuiltReport Config As'
328+
$sfd.Filter = 'JSON files (*.json)|*.json|All files (*.*)|*.*'
329+
$sfd.FileName = 'AsBuiltReport.json'
330+
if ($sfd.ShowDialog() -eq 'OK') {
331+
$cfgSync.TxtSavePath.Text = $sfd.FileName
332+
}
333+
} catch {
334+
Add-LogLine "File browser unavailable. Please type the save path directly."
335+
}
336+
}
337+
})
338+
339+
$rowSavePath = [StackPanel]::new()
340+
$rowSavePath.Orientation = 'Horizontal'; $rowSavePath.Spacing = 8
341+
$rowSavePath.Children.Add($lblSavePath) | Out-Null
342+
$rowSavePath.Children.Add($txtSavePath) | Out-Null
343+
$rowSavePath.Children.Add($btnBrowseSave) | Out-Null
344+
345+
# ---- Status label (inside sub-window) ----
346+
$lblCfgStatus = [TextBlock]::new(); $lblCfgStatus.Text = ''
347+
$lblCfgStatus.Margin = [Thickness]::new(0, 4, 0, 0)
348+
$cfgSync.LblCfgStatus = $lblCfgStatus
349+
350+
# ---- Save button ----
351+
$btnSaveCfg = [Button]::new()
352+
$btnSaveCfg.Content = 'Save Config'
353+
$btnSaveCfg.HorizontalAlignment = 'Stretch'
354+
$btnSaveCfg.HorizontalContentAlignment = 'Center'
355+
$btnSaveCfg.Height = 36
356+
$btnSaveCfg.Classes.Add('accent')
357+
358+
$btnSaveCfg.AddClick({
359+
$savePath = $cfgSync.TxtSavePath.Text.Trim()
360+
if (-not $savePath) {
361+
$cfgSync.LblCfgStatus.Text = '[WARNING] Please specify a save path.'
362+
return
363+
}
364+
365+
# Build the config object matching New-AsBuiltConfig's schema
366+
$toField = $cfgSync.TxtMailTo.Text.Trim()
367+
$toArray = if ($toField) {
368+
$toField -split '\s*,\s*' | Where-Object { $_ -ne '' }
369+
} else { @() }
370+
371+
$portVal = 25
372+
[void][int]::TryParse($cfgSync.TxtMailPort.Text.Trim(), [ref]$portVal)
373+
374+
$cfgObj = [ordered]@{
375+
Report = [ordered]@{
376+
Author = $cfgSync.TxtAuthor.Text.Trim()
377+
}
378+
Company = [ordered]@{
379+
FullName = $cfgSync.TxtCompanyFull.Text.Trim()
380+
ShortName = $cfgSync.TxtCompanyShort.Text.Trim()
381+
Contact = $cfgSync.TxtContact.Text.Trim()
382+
Email = $cfgSync.TxtCompanyEmail.Text.Trim()
383+
Phone = $cfgSync.TxtPhone.Text.Trim()
384+
Address = $cfgSync.TxtAddress.Text.Trim()
385+
}
386+
Email = [ordered]@{
387+
Server = $cfgSync.TxtMailServer.Text.Trim()
388+
Port = $portVal
389+
UseSSL = [bool]$cfgSync.ChkMailSSL.IsChecked
390+
Credentials = [bool]$cfgSync.ChkMailCreds.IsChecked
391+
From = $cfgSync.TxtMailFrom.Text.Trim()
392+
To = $toArray
393+
Body = ''
394+
}
395+
}
396+
397+
try {
398+
$saveDir = Split-Path $savePath -Parent
399+
if ($saveDir -and -not (Test-Path $saveDir)) {
400+
New-Item -Path $saveDir -ItemType Directory -Force | Out-Null
401+
}
402+
$cfgObj | ConvertTo-Json -Depth 10 | Set-Content -Path $savePath -Encoding UTF8
403+
# Propagate path back to the main window's AsBuiltConfig field
404+
$syncHash.TxtAbrConfig.Text = $savePath
405+
$cfgWin.Close()
406+
} catch {
407+
$cfgSync.LblCfgStatus.Text = "ERROR: $_"
408+
}
409+
})
410+
411+
# ---- Sub-window layout ----
412+
$cfgPanel = [StackPanel]::new()
413+
$cfgPanel.Margin = [Thickness]::new(20)
414+
$cfgPanel.Spacing = 6
415+
416+
# Section: Report
417+
$cfgPanel.Children.Add((Get-SectionHeader 'Report Information')) | Out-Null
418+
$cfgPanel.Children.Add($rowAuthor) | Out-Null
419+
420+
# Section: Company
421+
$cfgPanel.Children.Add((Get-SectionHeader 'Company Information')) | Out-Null
422+
$cfgPanel.Children.Add($rowCompanyFull) | Out-Null
423+
$cfgPanel.Children.Add($rowCompanyShort) | Out-Null
424+
$cfgPanel.Children.Add($rowContact) | Out-Null
425+
$cfgPanel.Children.Add($rowCompanyEmail) | Out-Null
426+
$cfgPanel.Children.Add($rowPhone) | Out-Null
427+
$cfgPanel.Children.Add($rowAddress) | Out-Null
428+
429+
# Section: Email/SMTP (optional)
430+
$cfgPanel.Children.Add((Get-SectionHeader 'Email / SMTP Settings (Optional)')) | Out-Null
431+
$cfgPanel.Children.Add($rowMailServer) | Out-Null
432+
$cfgPanel.Children.Add($rowMailPort) | Out-Null
433+
$cfgPanel.Children.Add($rowMailFrom) | Out-Null
434+
$cfgPanel.Children.Add($rowMailTo) | Out-Null
435+
$cfgPanel.Children.Add($rowMailChk) | Out-Null
436+
437+
# Section: Save
438+
$cfgPanel.Children.Add((Get-SectionHeader 'Save Location')) | Out-Null
439+
$cfgPanel.Children.Add($rowSavePath) | Out-Null
440+
$cfgPanel.Children.Add($btnSaveCfg) | Out-Null
441+
$cfgPanel.Children.Add($lblCfgStatus) | Out-Null
442+
443+
$cfgScroll = [ScrollViewer]::new()
444+
$cfgScroll.Content = $cfgPanel
445+
$cfgWin.Content = $cfgScroll
446+
$cfgWin.Show()
447+
})
448+
449+
$rowAbrConfig = [StackPanel]::new()
450+
$rowAbrConfig.Orientation = 'Horizontal'; $rowAbrConfig.Spacing = 8
451+
$rowAbrConfig.Children.Add($lblAbrConfig) | Out-Null
452+
$rowAbrConfig.Children.Add($txtAbrConfig) | Out-Null
453+
$rowAbrConfig.Children.Add($btnBrowseAbrConfig) | Out-Null
454+
$rowAbrConfig.Children.Add($btnGenAbrConfig) | Out-Null
455+
210456
$panelConfig = [StackPanel]::new(); $panelConfig.Spacing = 6
211457
$panelConfig.Children.Add((Get-SectionHeader 'Report Configuration'))
212458
$panelConfig.Children.Add($rowTarget)
213459
$panelConfig.Children.Add($rowFolder)
214460
$panelConfig.Children.Add($rowName)
215461
$panelConfig.Children.Add($rowLang)
462+
$panelConfig.Children.Add($rowAbrConfig)
216463

217464
# ===========================================================================
218465
# -- OUTPUT FORMATS ----------------------------------------------------------
219466
# ===========================================================================
220467
$chkHtml = [CheckBox]::new(); $chkHtml.Content = 'HTML'; $chkHtml.IsChecked = $true
221468
$chkWord = [CheckBox]::new(); $chkWord.Content = 'Word'; $chkWord.IsChecked = $false
222469
$chkText = [CheckBox]::new(); $chkText.Content = 'Text'; $chkText.IsChecked = $false
223-
$chkExcel = [CheckBox]::new(); $chkExcel.Content = 'Excel'; $chkExcel.IsChecked = $false
224470
$syncHash.ChkHtml = $chkHtml
225471
$syncHash.ChkWord = $chkWord
226472
$syncHash.ChkText = $chkText
227-
$syncHash.ChkExcel = $chkExcel
228473

229474
$rowFormats = [StackPanel]::new()
230475
$rowFormats.Orientation = 'Horizontal'; $rowFormats.Spacing = 18
231476
$rowFormats.Children.Add($chkHtml)
232477
$rowFormats.Children.Add($chkWord)
233478
$rowFormats.Children.Add($chkText)
234-
$rowFormats.Children.Add($chkExcel)
235479

236480
$panelFormats = [StackPanel]::new(); $panelFormats.Spacing = 6
237481
$panelFormats.Children.Add((Get-SectionHeader 'Output Formats'))
@@ -380,7 +624,6 @@ $generateCallback.ScriptBlock = {
380624
if ($syncHash.ChkHtml.IsChecked) { $formats += 'Html' }
381625
if ($syncHash.ChkWord.IsChecked) { $formats += 'Word' }
382626
if ($syncHash.ChkText.IsChecked) { $formats += 'Text' }
383-
if ($syncHash.ChkExcel.IsChecked) { $formats += 'Excel' }
384627

385628
$useTimestamp = [bool]$syncHash.ChkTimestamp.IsChecked
386629
$useHealth = [bool]$syncHash.ChkHealth.IsChecked
@@ -466,16 +709,28 @@ $generateCallback.ScriptBlock = {
466709

467710
# ---- Assemble New-AsBuiltReport parameters -------------------------
468711
$abrParams = @{
469-
Report = 'System.Resources'
470-
Target = $target
471-
Format = $formats
472-
OutputFolderPath = $outFolder
712+
Report = 'System.Resources'
713+
Target = $target
714+
Format = $formats
715+
OutputFolderPath = $outFolder
473716
ReportConfigFilePath = $tmpConfig
474-
ReportLanguage = $language
475-
ErrorAction = 'Stop'
717+
ReportLanguage = $language
718+
ErrorAction = 'Stop'
719+
}
720+
if ($useTimestamp) { $abrParams['Timestamp'] = $true }
721+
if ($useHealth) { $abrParams['EnableHealthCheck'] = $true }
722+
723+
$abrConfigPath = $syncHash.TxtAbrConfig.Text.Trim()
724+
if ($abrConfigPath) {
725+
if (Test-Path $abrConfigPath) {
726+
$abrParams['AsBuiltConfigFilePath'] = $abrConfigPath
727+
$ts = (Get-Date).ToString('HH:mm:ss')
728+
$syncHash.LogBox.Text += "[$ts] AsBuiltReport config : $abrConfigPath`n"
729+
} else {
730+
$ts = (Get-Date).ToString('HH:mm:ss')
731+
$syncHash.LogBox.Text += "[$ts] [WARNING] AsBuiltReport config not found, skipping: $abrConfigPath`n"
732+
}
476733
}
477-
if ($useTimestamp) { $abrParams['Timestamp'] = $true }
478-
if ($useHealth) { $abrParams['EnableHealthCheck'] = $true }
479734

480735
# ---- Run the report -------------------------------------------------
481736
try {

Src/Public/Start-AsBuiltReportGui.ps1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ function Start-AsBuiltReportGui {
1313
- Target system name
1414
- Output folder and report name
1515
- Report language
16-
- Output format (Html / Word / Text / Excel)
16+
- Output format (Html / Word / Text)
1717
- Timestamp and HealthCheck toggles
1818
- Diagram options (Enable, Export, Theme)
1919
- Per-section InfoLevel (0-2) for Date, TimeZone, Uptime, PSHost,
2020
and ProcessInfo
21+
- Optional AsBuiltReport Config File (-AsBuiltConfigFilePath), with
22+
a built-in wizard that mirrors New-AsBuiltConfig to collect author,
23+
company and SMTP/email details and save them as a JSON file
2124
2225
Report generation runs on a background thread, so the window stays fully
2326
responsive while the report is being produced.

0 commit comments

Comments
 (0)