Torsten Brendgen
2026-06-27 23:19:38 +02:00
4 changed files with 4168 additions and 92 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,89 +0,0 @@
function Import-OrderedPowerShellDataFile {
param(
[Parameter(Mandatory)]
[string]$Path
)
function ConvertTo-OrderedHashtable {
param(
$HashtableAst
)
# Verwende OrderedDictionary statt [ordered]@{}
$ordered = New-Object System.Collections.Specialized.OrderedDictionary
# Sortiere KeyValuePairs nach ihrer Position im Quelltext
$sortedKvps = $HashtableAst.KeyValuePairs | Sort-Object { $_.Item1.Extent.StartOffset }
foreach ($kvp in $sortedKvps) {
# Schlüssel extrahieren
$key = $kvp.Item1.Extent.Text -replace '[''"]', ''
# Wert verarbeiten
$valueAst = $kvp.Item2
# Suche nach HashtableAst in PipelineAst
$hashtable = $null
if ($valueAst -is [System.Management.Automation.Language.HashtableAst]) {
$hashtable = $valueAst
}
elseif ($valueAst -is [System.Management.Automation.Language.PipelineAst]) {
# Suche HashtableAst innerhalb der Pipeline
$hashtable = $valueAst.Find({
$args[0] -is [System.Management.Automation.Language.HashtableAst]
}, $false)
}
if ($hashtable) {
$value = ConvertTo-OrderedHashtable -HashtableAst $hashtable
}
elseif ($valueAst -is [System.Management.Automation.Language.ArrayLiteralAst]) {
$value = @()
foreach ($element in $valueAst.Elements) {
if ($element -is [System.Management.Automation.Language.HashtableAst]) {
$value += ConvertTo-OrderedHashtable -HashtableAst $element
}
else {
$value += Invoke-Expression $element.Extent.Text
}
}
}
else {
try {
$value = Invoke-Expression $valueAst.Extent.Text
}
catch {
$value = $valueAst.Extent.Text
}
}
$ordered.Add($key, $value)
}
return $ordered
}
# Datei parsen
$errors = $null
$tokens = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile(
$Path,
[ref]$tokens,
[ref]$errors
)
if ($errors) {
throw "Fehler beim Parsen der Datei: $($errors[0].Message)"
}
# Finde die oberste Hashtable
$hashtableAst = $ast.Find({
$args[0] -is [System.Management.Automation.Language.HashtableAst]
}, $true)
if (-not $hashtableAst) {
throw "Keine Hashtable in der Datei gefunden"
}
return ConvertTo-OrderedHashtable -HashtableAst $hashtableAst
}

View File

@@ -10,10 +10,11 @@ function Merge-Templates {
try {
try {
$TemplateData = Import-OrderedPowerShellDataFile -Path $file -ErrorAction Stop
$TemplateData = [TemplateBuilder]::new($file).Template
}
catch {
$Errors += "Datei konnte nicht importiert werden"
continue
}
$ConfigurationData = Merge-ConfigurationData -Template $ConfigurationData -Deployment $TemplateData
@@ -40,4 +41,4 @@ function Merge-Templates {
else {
return $ConfigurationData
}
}
}

185
README.md Normal file
View File

@@ -0,0 +1,185 @@
# DSC Configuration Compiler
Ein WinForms-basiertes PowerShell-Tool zum Laden, Kombinieren, Anzeigen und Exportieren von DSC-nahen Konfigurationen auf Basis von `psd1`-Dateien.
Der Fokus des Projekts liegt auf einem einfachen Template-Workflow:
- Templates aus Ordnern laden
- mehrere Templates zu einer Zielkonfiguration zusammenfuehren
- Parameter und Variablen aufloesen
- die resultierende Struktur im TreeView pruefen
- die zusammengefuehrte Konfiguration wieder als `psd1` exportieren
## Voraussetzungen
- Windows
- PowerShell mit WinForms-Unterstuetzung
- Schreibzugriff auf `%APPDATA%`
Das Tool speichert Einstellungen und Logs unterhalb von `%APPDATA%\DSC Tool`.
## Start
Das Projekt kann direkt ueber `Compiler.ps1` gestartet werden:
```powershell
powershell -ExecutionPolicy Bypass -File .\Compiler.ps1
```
Alternativ:
```powershell
pwsh -File .\Compiler.ps1
```
## Projektstruktur
```text
.
|-- Compiler.ps1
|-- Functions/
|-- Templates/
`-- Deployments/
```
- `Compiler.ps1`: Hauptanwendung, UI, Parser- und Resolver-Logik
- `Functions/`: zusaetzliche Funktionen fuer Import, Export, Merge und UI-Aktualisierung
- `Templates/`: wiederverwendbare Konfigurationsbausteine
- `Deployments/`: exportierte oder vorbereitete Zielkonfigurationen
## Bedienung
1. Anwendung starten.
2. Falls noetig ueber `Einstellungen -> Ordner waehlen...` den Root-Ordner setzen.
3. Templates aus den Kategorien laden.
4. Gewuenschte Templates per Doppelklick zur Auswahl hinzufuegen.
5. Die Auswahl zusammenfuehren.
6. Das Ergebnis im TreeView pruefen.
7. Die zusammengefuehrte Konfiguration als `psd1` exportieren.
Import und Export werden ueber den Deployment-Ordner abgewickelt.
## Template-Modell
Templates bestehen aus drei optionalen Hauptbereichen:
- `Parameters`
- `Variables`
- `Resources`
Ein vereinfachtes Beispiel:
```powershell
@{
Parameters = @{
DatabasePrefix = @{
Type = 'string'
DefaultValue = 'SP'
}
}
Variables = @{
ConfigDbName = "[concat(parameters('DatabasePrefix'),'_','Farm_Config')]"
}
Resources = @{
NonNodeData = @{
Services = @{
Example = @{
DatabaseName = "[variables('ConfigDbName')]"
}
}
}
}
}
```
## Ausdruckssyntax
Die Auswertung ist ARM-inspiriert. Template-Ausdruecke stehen in eckigen Klammern:
```powershell
"[concat(parameters('Prefix'),'_','Database')]"
```
Unterstuetzte Referenzen:
- `parameters('Name')`
- `variables('Name')`
Zusaetzlich werden aus Rueckwaertskompatibilitaet auch diese Varianten verstanden:
- `Parameter('Name')`
- `Variable('Name')`
Unterstuetzte Funktionen:
- `concat(...)`
- `toLower(...)`
- `toUpper(...)`
- `substring(...)`
- `replace(...)`
- `indexOf(...)`
- `firstIndexOf(...)`
- `lastIndexOf(...)`
Funktionsnamen werden ohne freie PowerShell-Ausfuehrung ausgewertet. Die `psd1`-Dateien werden als Daten geparst, nicht als beliebiger Script-Code interpretiert.
## Aufloesungsreihenfolge
Die Aufloesung erfolgt in dieser Reihenfolge:
1. Parameterwerte und Defaultwerte
2. Variablen
3. Ressourcenwerte
Zirkulaere Variablenreferenzen werden erkannt und als Fehler behandelt.
## Merge-Verhalten
Beim Zusammenfuehren mehrerer Templates werden vorhandene Eintraege rekursiv kombiniert:
- Hashtables werden rekursiv gemerged
- Arrays werden anhand passender Name-Felder zusammengefuehrt
- fehlende Werte aus Templates werden in das Ergebnis uebernommen
Die finale Anzeige im TreeView basiert auf dem zusammengefuehrten und bereits aufgeloesten Modell.
## Export
Der Export schreibt die aktuelle TreeView-Struktur wieder in eine `psd1`-Datei.
Standardziel beim Speichern ist:
```text
Deployments\merged_config.psd1
```
## Hinweise
- Einstellungen werden benutzerbezogen gespeichert.
- Logs werden pro Tag unter `%APPDATA%\DSC Tool\Logs` geschrieben.
- Templates sollten deklarativ bleiben und nur Daten plus Template-Ausdruecke enthalten.
- Fuer neue Templates wird die ARM-aehnliche Syntax mit `parameters()` und `variables()` empfohlen.
## Beispielinhalt
Im Repository ist bereits ein groesseres Beispiel enthalten:
- `Templates\Service\SharePointServer.psd1`
Dieses Template zeigt die Verwendung von:
- Parametern
- Variablen
- verschachtelten Ressourcen
- String-Funktionen wie `concat()` und `substring()`
## Weiterentwicklung
Sinnvolle naechste Schritte fuer das Projekt sind:
- Tests fuer Parser, Resolver und Merge-Verhalten
- typsicherer Export-Roundtrip
- robustere Initialisierung der Pfade und Settings
- weitere Template-Funktionen nach Bedarf