PowerShell und INI-Dateien

Aus Windows 16bit-Zeiten können die älteren Leser sicher noch die INI-Dateien (Win.ini, System.ini) und selbst heute gibt es immer noch Programme, die auf diese Weise Einstellungen oder sogar Daten abspeichern. Es gibt leider keine native Unterstützung von INI-Dateien in PowerShell aber da es sich um Textdateien handelt, können diese durchaus per PowerShell gelesen, ausgewertet und geschrieben werden. Ich möchte das Rad hier nicht neu erfinden und einer alten Technik Vorschub leisten aber zumindest "lesen" muss ich solche Dateien doch, wie z.B. das Projekt KlimaLogg Pro wieder gezeigt hat.

Aufbau von INI-Dateien

eine INI-Datei hat schon von immer den gleichen Aufbau und sie können selbst auf einem Windows 7 Desktop immer noch die Datei "C:\Windows\win.ini" finden und öffnen. Abschnitte werden mit "eckigen Klammern" gestartet, und darauf folgen Key und Werte, die durch ein Gleichheitszeichen getrennt sind.

; Kommentar eine Beispiel INI-Datei

[Bereich1]
Key1=Wert1
Key2=Wert2

[Bereich2]
Key1=Wert1
Key2=Wert2

Während Bereiche nur einmal vorkommen sollten, können Key können durchaus mehrfach genutzt werden. Über die Interpretation der Werte muss die Anwendung bestimmen. Kommentare sind durch ein Semikolon einzuleiten.

Windows Bordmittel

Wenn Windows selbst INI-Dateien nutze, dann kann man davon ausgehen, dass es auch entsprechende API-Schnittstellen gibt. Schließlich sind Programmierer auch bequem und das Rad muss ja nicht immer neu erfunden werden. Die entsprechenden Funktionen sind in der MSDN gut beschrieben

Allerdings sind dies "Win32 API"-Funktionen und kein Managed Code für die einfache direkte Nutzung in C# oder PowerShell. Es gibt allenfalls andere Projekte, die eine INI-Verarbeitung nachprogrammiert haben

Andere gehen den Weg und konvertieren eine INI-Datei in einem XML-Struktur, auf die sie dann wie gewohnt zugreifen können.

Mein PowerShell-Ansatz zum Lesen

Nein, ich möchte das Rad nicht neu erfinden und daher auch keine neue Klasse für INI-Dateien erstellen. Ich habe aber bei einem anderen Skript (Siehe KlimaLogg Pro - Servermonitoring) den Bedarf eine INI-Datei auszulesen um die Daten in PRTG einzulesen und das sollte schnell und möglichst ohne Abhängigkeiten gehen. In dem Fall war auch das Formt der INI-Datei bekannt und wurde nicht durch andere Programme verändert. Ich konnte einen ganz einfach Ansatz wählen, mit dem INI-Dateien eingelesen werden können

param (
   $inputfile
)

$inifile = get-content $inputfile

$resulttable=@()
foreach ($line in $inifile) {
   write-host "Processing $line"
   if ($line[0] -eq ";") {
      write-host "Skip comment line"
   }

   elseif ($line[0] -eq "[") {
      $segment = $line.replace("[","").replace("]","")
      write-host "Found new segment: $segment"
   }
   elseif ($line -like "*=*") {
      write-host "Found Keyline"
      $resulttable += New-Object PSObject -Property @{
         segment  = $segment
         Key = $line.split("=")[0]
         value    = $line.split("=")[1]
         }
      }
      else {
         write-host "Skip line"
      }
}
$resulttable

So erhalte ich eine Tabelle aus den Spalten "Segment", "Key" und "Value".

Key                  value                      segment
--------                   -----                      -------
programm_name              KlimaLogg Pro              header
programm_version           1.0                        header
file_format_version        1.0                        header
last_actualisation         "3605771885"               time
deg_C                      "22.9"                     temperature_channel_0
deg_F                      "73.3"                     temperature_channel_0

Und darauf lässt sich vortrefflich mit WHERE filtern.

where {$_.Key -eq "deg_C" -and $_.segment -like "temp*"}

Dieses einfache Script ist natürlich nicht in der Lage, eine INI-Datei auch zu ändern. Es ist "ReadOnly".

INI und XML

Zudem ist der Zugriff über eine Liste elegant aber ein direkter Zugriff geht damit doch nicht so einfach. Daher habe ich mir gedacht, das man eine INI-Datei doch ganz einfach in eine XML-Struktur überführen kann. Und hier das Beispiel:

; Kommentar eine Beispiel INI-Datei
                         <inifile>
[Bereich1]                  <Bereich1>
Key1=Wert1                  <Key1>Wert1</Key1>
Key2=Wert2                  <Key2>Wert2</Key2>
                            </Bereich1>
[Bereich2]                  <Bereich2>
Key1=Wert1                  <Key1>Wert1</Key1>
Key2=Wert2                  <Key2>Wert2</Key2>
                            </Bereich1>
                          </inifile>

So übertragen kann man sehr direkt auf einen Wert zugreifen

$wert = $inixml.bereitname.key

Gesagt, getan und mit wenigen PowerShell-Zeilen dürften die meisten INI-Dateien zu einer XML-Struktur in einer Variable zur weiteren Verwendung werden

$inifile = get-content $inputfile

[string]$resultxml="<inifile>"
[string]$inisection=""
foreach ($line in $inifile) {
   write-host "Processing $line"
   if ($line[0] -eq "[") {
      if ($inisection -ne "") {
         write-host "Closing old inisection: $inisection"
         $resultxml+=("</$inisection>`r`n")
      }
      $inisection = $line.replace("[","").replace("]","")
      write-host "Found new inisection: $inisection"
      $resultxml+=("<$inisection>`r`n")
   }
   elseif ($line -like "*=*") {
      $key=($line.split("=")[0])
      $value=($line.split("=")[1])
      write-host "Found parameterline Key: $key    Value:$value"
      $resultxml+=("<$key>$value</$key>`r`n")
   }
   else {
      write-host "Skip line"
   }
}
$resultxml+=("</$inisection>`r`n")
$resultxml+="</inifile>"
$resultxml

Hier ist natürlich keinerlei Validierung oder Fehlerbehandlung vorhanden.

Und was ist mit Schreiben ?

Ich habe am Anfang gesagt, dass ich nur "Lesen" möchte und das hat auch Gründe. Diese einfachen Routinen lesen die INI-Datei ein, um die Daten in Programmen zu verwenden. Aber Sie lesen nicht alle Informationen ein, So werden Formatierungen, Leerzeilen und Kommentare einfach übersprungen. Würde ich diese Daten einfach schreiben, bestände die Gefahr dass Informationen verloren gehen. Insbesondere, wenn schon beim Lesen etwas vergessen oder falsch interpretiert wurde.

Die Code-Beispiele sind alle ohne Fehlerbehandlung und Berücksichtigung von Sonderfällen und es ist einfach zu gefährlich mit diesem "Einfachcode" auch noch zu schreiben. Zudem sind INI-Dateien sowieso "out" und XML-Daten oder die Registrierung hierfür viel besser geeignet. Mir reicht es die Daten von INI-Dateien zu lesen. Auslöser für diese Seite war ja das Parsen einer INI-Datei von KlimaLogg Pro Aber wen Sie die geniale Routine für INI-Dateien geschrieben haben, dann senden Sie mir einfach einen Link, auf den ich verweisen kann.

Weitere Links