|
8 | 8 |
|
9 | 9 | Sections of the GUI: |
10 | 10 |
|
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 |
13 | 14 | Options - Timestamp, HealthCheck, Diagrams, Export Diagrams, |
14 | 15 | Diagram Theme |
15 | 16 | Info Level - Per-section detail level (0 = Disabled, 1 = Summary, |
|
18 | 19 | Generate - Progress bar + scrollable log; report runs on a |
19 | 20 | background thread so the UI stays responsive. |
20 | 21 |
|
| 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 | +
|
21 | 27 | .NOTES |
22 | 28 | Requirements: |
23 | 29 | - PowerShell 7.4 or newer (AvaloniaUIShell requirement) |
@@ -207,31 +213,269 @@ $rowLang.Orientation = 'Horizontal'; $rowLang.Spacing = 8 |
207 | 213 | $rowLang.Children.Add($lblLang) |
208 | 214 | $rowLang.Children.Add($cbLang) |
209 | 215 |
|
| 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 | + |
210 | 456 | $panelConfig = [StackPanel]::new(); $panelConfig.Spacing = 6 |
211 | 457 | $panelConfig.Children.Add((Get-SectionHeader 'Report Configuration')) |
212 | 458 | $panelConfig.Children.Add($rowTarget) |
213 | 459 | $panelConfig.Children.Add($rowFolder) |
214 | 460 | $panelConfig.Children.Add($rowName) |
215 | 461 | $panelConfig.Children.Add($rowLang) |
| 462 | +$panelConfig.Children.Add($rowAbrConfig) |
216 | 463 |
|
217 | 464 | # =========================================================================== |
218 | 465 | # -- OUTPUT FORMATS ---------------------------------------------------------- |
219 | 466 | # =========================================================================== |
220 | 467 | $chkHtml = [CheckBox]::new(); $chkHtml.Content = 'HTML'; $chkHtml.IsChecked = $true |
221 | 468 | $chkWord = [CheckBox]::new(); $chkWord.Content = 'Word'; $chkWord.IsChecked = $false |
222 | 469 | $chkText = [CheckBox]::new(); $chkText.Content = 'Text'; $chkText.IsChecked = $false |
223 | | -$chkExcel = [CheckBox]::new(); $chkExcel.Content = 'Excel'; $chkExcel.IsChecked = $false |
224 | 470 | $syncHash.ChkHtml = $chkHtml |
225 | 471 | $syncHash.ChkWord = $chkWord |
226 | 472 | $syncHash.ChkText = $chkText |
227 | | -$syncHash.ChkExcel = $chkExcel |
228 | 473 |
|
229 | 474 | $rowFormats = [StackPanel]::new() |
230 | 475 | $rowFormats.Orientation = 'Horizontal'; $rowFormats.Spacing = 18 |
231 | 476 | $rowFormats.Children.Add($chkHtml) |
232 | 477 | $rowFormats.Children.Add($chkWord) |
233 | 478 | $rowFormats.Children.Add($chkText) |
234 | | -$rowFormats.Children.Add($chkExcel) |
235 | 479 |
|
236 | 480 | $panelFormats = [StackPanel]::new(); $panelFormats.Spacing = 6 |
237 | 481 | $panelFormats.Children.Add((Get-SectionHeader 'Output Formats')) |
@@ -380,7 +624,6 @@ $generateCallback.ScriptBlock = { |
380 | 624 | if ($syncHash.ChkHtml.IsChecked) { $formats += 'Html' } |
381 | 625 | if ($syncHash.ChkWord.IsChecked) { $formats += 'Word' } |
382 | 626 | if ($syncHash.ChkText.IsChecked) { $formats += 'Text' } |
383 | | - if ($syncHash.ChkExcel.IsChecked) { $formats += 'Excel' } |
384 | 627 |
|
385 | 628 | $useTimestamp = [bool]$syncHash.ChkTimestamp.IsChecked |
386 | 629 | $useHealth = [bool]$syncHash.ChkHealth.IsChecked |
@@ -466,16 +709,28 @@ $generateCallback.ScriptBlock = { |
466 | 709 |
|
467 | 710 | # ---- Assemble New-AsBuiltReport parameters ------------------------- |
468 | 711 | $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 |
473 | 716 | 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 | + } |
476 | 733 | } |
477 | | - if ($useTimestamp) { $abrParams['Timestamp'] = $true } |
478 | | - if ($useHealth) { $abrParams['EnableHealthCheck'] = $true } |
479 | 734 |
|
480 | 735 | # ---- Run the report ------------------------------------------------- |
481 | 736 | try { |
|
0 commit comments