param ( [switch]$Debug, [switch]$Run, [switch]$SkipPreprocessing ) $OFS = "`r`n" $scriptname = "winutil.ps1" $workingdir = $PSScriptRoot $logFilePath = Join-Path $workingdir "compile.log" # Variable to sync between runspaces $sync = [Hashtable]::Synchronized(@{}) $sync.PSScriptRoot = $workingdir $sync.configs = @{} # Dot-source external functions . "$PSScriptRoot\tools\Update-Progress.ps1" # Function to log messages function Log-Message { param([string]$Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Add-Content -Path $logFilePath -Value "$timestamp - $Message" } # Function to encode special characters in JSON function Encode-JsonSpecialChars { param ( [Parameter(Mandatory)] [PSObject]$jsonObject ) foreach ($prop in $jsonObject.PSObject.Properties) { if ($prop.Value -is [string]) { $prop.Value = $prop.Value.Replace('&','&').Replace('“','“').Replace('”','”').Replace("'",''').Replace('<','<').Replace('>','>').Replace('—','—') } } return $jsonObject } $header = @" ################################################################################################################ ### ### ### WARNING: This file is automatically generated DO NOT modify this file directly as it will be overwritten ### ### ### ################################################################################################################ "@ if ($Debug) { Write-Debug "Debug mode enabled" } if (-NOT $SkipPreprocessing) { try { Update-Progress "Pre-req: Running Preprocessor..." 0 $preprocessingFilePath = Join-Path $PSScriptRoot "tools\Invoke-Preprocessing.ps1" . "$preprocessingFilePath" $excludedFiles = @('.\.git\', '.\.gitignore', '.\.gitattributes', '.\.github\CODEOWNERS', '.\LICENSE', "$preprocessingFilePath", '*.png', '*.exe') $msg = "Pre-req: Code Formatting" Invoke-Preprocessing -WorkingDir "$workingdir" -ExcludedFiles $excludedFiles -ProgressStatusMessage $msg } catch { Write-Error "Preprocessing failed: $($_.Exception.Message)" Log-Message "Preprocessing failed: $($_.Exception.Message)" exit 1 } } # Create the script in memory. Update-Progress "Pre-req: Allocating Memory" 0 $script_content = [System.Collections.Generic.List[string]]::new() Update-Progress "Adding: Header" 5 $script_content.Add($header) Update-Progress "Adding: Version" 10 $script_content.Add($(Get-Content "$workingdir\scripts\start.ps1").replace('#{replaceme}',"$(Get-Date -Format yy.MM.dd)")) Update-Progress "Adding: Functions" 20 Get-ChildItem "$workingdir\functions" -Recurse -File | ForEach-Object { $script_content.Add($(Get-Content $psitem.FullName)) } Update-Progress "Adding: Config *.json" 40 Get-ChildItem "$workingdir\config" | Where-Object {$_.extension -eq ".json"} | ForEach-Object { $json = Get-Content -Path $psitem.FullName -Raw $jsonAsObject = $json | ConvertFrom-Json $jsonAsObject = Encode-JsonSpecialChars -jsonObject $jsonAsObject if ($psitem.Name -eq "applications.json") { foreach ($appEntryName in $jsonAsObject.PSObject.Properties.Name) { $appEntryContent = $jsonAsObject.$appEntryName $jsonAsObject.PSObject.Properties.Remove($appEntryName) $jsonAsObject | Add-Member -MemberType NoteProperty -Name "WPFInstall$appEntryName" -Value $appEntryContent } } $json = ($jsonAsObject | ConvertTo-Json -Depth 3).replace('\r\n', "`r`n") $sync.configs.$($psitem.BaseName) = $json | ConvertFrom-Json $script_content.Add("`$sync.configs.$($psitem.BaseName) = '$json' | ConvertFrom-Json") } $xaml = (Get-Content "$workingdir\xaml\inputXML.xaml" -Raw).Replace("'","''") # Dot-source the Get-TabXaml function . "$workingdir\functions\private\Get-TabXaml.ps1" Update-Progress "Building: Xaml" 75 $appXamlContent = Get-TabXaml "applications" 5 $tweaksXamlContent = Get-TabXaml "tweaks" $featuresXamlContent = Get-TabXaml "feature" Update-Progress "Adding: Xaml" 90 $xaml = $xaml -replace "{{InstallPanel_applications}}", $appXamlContent $xaml = $xaml -replace "{{InstallPanel_tweaks}}", $tweaksXamlContent $xaml = $xaml -replace "{{InstallPanel_features}}", $featuresXamlContent $script_content.Add("`$inputXML = '$xaml'") $script_content.Add($(Get-Content "$workingdir\scripts\main.ps1")) if ($Debug) { Update-Progress "Writing debug files" 95 $appXamlContent | Out-File -FilePath "$workingdir\xaml\inputApp.xaml" -Encoding ascii $tweaksXamlContent | Out-File -FilePath "$workingdir\xaml\inputTweaks.xaml" -Encoding ascii $featuresXamlContent | Out-File -FilePath "$workingdir\xaml\inputFeatures.xaml" -Encoding ascii } else { Update-Progress "Removing temporary files" 99 Remove-Item "$workingdir\xaml\inputApp.xaml" -ErrorAction SilentlyContinue Remove-Item "$workingdir\xaml\inputTweaks.xaml" -ErrorAction SilentlyContinue Remove-Item "$workingdir\xaml\inputFeatures.xaml" -ErrorAction SilentlyContinue } Set-Content -Path "$workingdir\$scriptname" -Value ($script_content -join "`r`n") -Encoding ascii Write-Progress -Activity "Compiling" -Completed Update-Progress -Activity "Validating" -StatusMessage "Checking winutil.ps1 Syntax" -Percent 0 try { $null = Get-Command -Syntax ".\winutil.ps1" } catch { Write-Warning "Syntax Validation for 'winutil.ps1' has failed" Write-Host "$($Error[0])" -ForegroundColor Red Log-Message "Syntax Validation failed: $($Error[0])" } Write-Progress -Activity "Validating" -Completed if ($Run) { try { Start-Process -FilePath "pwsh" -ArgumentList "$workingdir\$scriptname" } catch { Start-Process -FilePath "powershell" -ArgumentList "$workingdir\$scriptname" } } Log-Message "Compilation completed"