marabunta
Goto Top

Powershell Profil in ini speichern

Hallo,

ich habe eine kleine GUI in der ein Profil ausgewählt und geladen werden kann.
Jetzt will ich auch das neue Profile gespeichert werden können bzw. vorhande aktualisiert.
Der Fortschritt bisher ist, dass ein einziges Profil mit fehleder Sektionsbezeichnung immer neu erzeugt wird.
Ich möchte zuerst die Sektion mit eingebaut bekommen und dann herausfinden wie ich die richtigen Stellen updaten kann....

Out-IniFile : https://gallery.technet.microsoft.com/scriptcenter/7d7c867f-026e-4620-bf ...
Funktionierendes Beispiel aus Funktion Out-IniFile
    $Category1 = @{“Key1”=”Value1”;”Key2”=”Value2”}  
    $Category2 = @{“Key1”=”Value1”;”Key2”=”Value2”}  
    $NewINIContent = @{“Category1”=$Category1;”Category2”=$Category2}  
    Out-IniFile -InputObject $NewINIContent -FilePath "C:\MyNewFile.INI"  

Meine Version:
$Auswahl="Profil1"  
$Profile.default.count=12 #Anzahl Checkboxen

Function SaveAuswahl($Auswahl)
{
$Global:CheckboxNewValue=[ordered]@{}
    for($i=1;$i -le $Profile.default.count;$i++)
    {
        Write-Host "Checkbox Nummer $i =" $AllCheckboxStates[$i-1]  
        if($AllCheckboxStates[$i-1] -eq "Checked")  
        {
            $CheckboxName="Checkbox" + "$i"  
            $AuswahlProfil+=[ordered]@{$CheckboxName="checked"}        
        }
        else{
            $CheckboxName="Checkbox" + "$i"  
            $AuswahlProfil+=[ordered]@{$CheckboxName="unchecked"}     
        }   
    }
    $Global:CheckboxNewValue+=[ordered]@{$Auswahl=$AuswahlProfil}
 
Out-IniFile -InputObject $CheckboxNewValue.$Auswahl -FilePath "C:\MyNewFile.INI" -Force  
}

"C:\MyNewFile.INI" IST:  
Checkbox9=unchecked
Checkbox12=unchecked
Checkbox11=unchecked
Checkbox10=unchecked
Checkbox1=checked
Checkbox2=checked
Checkbox3=unchecked
Checkbox4=checked
Checkbox5=unchecked
Checkbox6=unchecked
Checkbox7=unchecked
Checkbox8=unchecked

"C:\MyNewFile.INI" SOLL:  
[Profil1]
Checkbox1=checked
Checkbox2=checked
Checkbox3=unchecked
Checkbox4=checked
Checkbox5=unchecked
Checkbox6=unchecked
Checkbox7=unchecked
Checkbox8=unchecked
Checkbox9=unchecked
Checkbox10=unchecked
Checkbox11=unchecked
Checkbox12=unchecked

#Später auch andere Profile mit frei wählbarem Namen in der selben Datei, also nur das gewünschte Profil überschreiben bzw. neu hinzufügen und die anderen nicht anrühren

[InstallierGanzVielProfil]
Checkbox1=checked
Checkbox2=checked
Checkbox3=unchecked
Checkbox4=checked
Checkbox5=unchecked
Checkbox6=unchecked
Checkbox7=checked
Checkbox8=unchecked
Checkbox9=unchecked
Checkbox10=checked
Checkbox11=checked
Checkbox12=checked

Content-ID: 272411

Url: https://administrator.de/contentid/272411

Ausgedruckt am: 23.11.2024 um 15:11 Uhr

114757
114757 20.05.2015 um 10:17:58 Uhr
Goto Top
Moin,
Ich würde das mit XML machen, da es dazu schon das entsprechende Zugriffsinterface gibt.
Powershell: Werte aus einer XML-Datei auslesen und wieder darin speichern

Gruß jodel32
colinardo
Lösung colinardo 20.05.2015, aktualisiert am 02.06.2015 um 11:07:03 Uhr
Goto Top
Hallo Marabunta,
würde ich persönlich auch via XML bevorzugen. Hier ein Beispiel wie so was aussehen kann:

Zwei Funktionen, eine zum Speichern der Profile und eine zum Laden der Profile
function Save-Profiles{
    param(
        [string]$xmlfile,
        [hashtable]$settings
    )
    $xml = new-Object XML
    $xml.LoadXML('<?xml version="1.0" encoding="utf-8"?><profiles></profiles>')  
    $root = $xml.SelectSingleNode("/profiles")  
    foreach($profile in $settings.GetEnumerator()){
        $profilenode = $xml.CreateElement("profile")  
        $profilenode.SetAttribute("name",$profile.Name)  
        if ($profile.Value -is [hashtable]){
            $profile.Value.getEnumerator() | %{
                $cbNode = $xml.CreateElement($_.Name)
                $cbNode.InnerText = $_.Value
                $profileNode.AppendChild($cbNode) | out-null
            }
        }
        $root.AppendChild($profilenode) | out-null
    }
    $xml.Save($xmlfile)
}
function Read-Profiles{
    param(
        [string]$xmlfile
    )
    $xml = new-Object XML
    $xml.Load($xmlfile)
    $settings = @{}
    foreach ($profile in $xml.SelectNodes("/profiles/profile")){  
        $cbs = @{}
        $profile.ChildNodes | %{$cbs[$_.Name] = $_.innerText}
        $settings[$profile.Name] = $cbs
    }
    return $settings
}
Diese nutzt man nun folgendermaßen:

Man legt sich seine Profile wie gewohnt mit zwei verschachtelten Hashtables an, und speichert sie dann mit der ersten obigen Funktion in einer XML-Datei
$profilesettings1 = @{"checkbox1"="checked";"checkbox2"="checked";"checkbox3"="unchecked"}  
$profilesettings2 = @{"checkbox1"="checked";"checkbox2"="checked";"checkbox3"="unchecked"}  
$profiles = @{"ProfileABC"=$profilesettings1;"ProfileXYZ"=$profilesettings2}  
Save-Profiles "C:\temp\profiles.xml" $profiles  
Zum Laden der Profile nutzt man dann die zweite Funktion:
$profiles = Read-Profiles "C:\temp\profiles.xml"  
Dann hat man alle Profile in der Variablen $profiles genauso in dem Format wie man sie vorher angelegt hat.
Um nun weitere Profile anzulegen oder zu löschen änderst du einfach die Variable $profile, d.h du kannst darin Profile löschen oder neu anlegen.
Zum Schluss schickst du die Variable erneute mit der ersten Funktion Save-Profiles() wieder in die XML-Datei
Save-Profiles "C:\temp\profiles.xml" $profile  
Fertig.

Die Resultierende XML-Datei sieht dann so aus:
<?xml version="1.0" encoding="utf-8"?>  
<profiles>
  <profile name="ProfileABC">  
    <checkbox1>checked</checkbox1>
    <checkbox2>checked</checkbox2>
    <checkbox3>unchecked</checkbox3>
  </profile>
  <profile name="ProfileXYZ">  
    <checkbox1>checked</checkbox1>
    <checkbox2>checked</checkbox2>
    <checkbox3>unchecked</checkbox3>
  </profile>
</profiles>
Finde ich persönlich professioneller als noch mit INIs zu arbeiten face-wink

Grüße Uwe
Marabunta
Marabunta 20.05.2015 um 11:52:40 Uhr
Goto Top
der inhalt der xml ist genau wie im beispiel. weder die 1:1 kopie noch schritt für schritt wie hier funktionieren:
test.xml:
<?xml version="1.0" encoding="utf-8"?> 
<settings>
  <setting name="Einstellung 1">Wert 1</setting> 
  <setting name="Einstellung 2">Wert 2</setting> 
  <setting name="Einstellung 3">Wert 3</setting> 
</settings>

PS H:\> $xmlDoc.Load("C:\test.xml")  
Ausnahme beim Aufrufen von "Load" mit 1 Argument(en):  "'.', hexidezimaler Wert 0x00, ist ein ungültiges Zeichen. Zeile 2, Position 1."  
In Zeile:1 Zeichen:1
+ $xmlDoc.Load("C:\test.xml")  
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) , MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException
aber wieso?
colinardo
colinardo 20.05.2015 aktualisiert um 12:07:27 Uhr
Goto Top
Da muss sich bei dir ein ungültiges Zeichen eingeschlichen haben oder du hast beim Speichern ein unübliches Encoding verwendet. Läuft ja hier einwandfrei face-wink
Marabunta
Marabunta 20.05.2015 um 12:16:25 Uhr
Goto Top
stimmt böses Little Endian...mit ANSI gehts, ich nehme an mit UTF würde es auch gehen
colinardo
colinardo 20.05.2015 aktualisiert um 12:17:58 Uhr
Goto Top
Zitat von @Marabunta:
ich nehme an mit UTF würde es auch gehen
Jup.
Marabunta
Marabunta 01.06.2015, aktualisiert am 02.06.2015 um 10:49:42 Uhr
Goto Top
Hat zwar gedauert aber jetzt bin ich mal wieder dazu gekommen... natürlich war alles schwieriger als Gedacht bzw. ich habs mir vielleicht auch nur schwerer gemacht...

Lesen der XML funktioniert problemlos, das setzen der neuen Werte hat Kopfschmerzen bereitet und das Schreiben zurück in XML waren qualen und führen noch zu Fehlermeldungen s.u. . Aber das Ergebnis ist erstmal gut

Function Get-CurrentProfile($Auswahl)
{
#[content:208115]
$Global:CheckboxNewValue=[ordered]@{}
$Global:AuswahlProfil=@{}
    for($i=1;$i -le $Profile.default.count;$i++)
    {
        Write-Host "Checkbox Nummer $i =" $AllCheckboxStates[$i-1]  
        if($AllCheckboxStates[$i-1] -eq "Checked")  
        {
            $CheckboxName="Checkbox" + "$i"  
            $Global:AuswahlProfil+=[ordered]@{$CheckboxName="checked"}        
        }
        else{
            $CheckboxName="Checkbox" + "$i"  
            $Global:AuswahlProfil+=[ordered]@{$CheckboxName="unchecked"}     
        }   
    }
SaveAuswahl $AuswahlProfil
}

Function SaveAuswahl($AuswahlProfil){
while($Checkbox_Nummer -le $Profile.default.count)
{
    $Global:Checkbox_Wert='checkbox' + $Checkbox_Nummer  
    [int]$Global:Checkbox_Nummer=1
    $Profile.$Auswahl.keys |  #Das ist Zeile 553
    Where-Object { $_ -eq $Checkbox_Wert } | %{
        $Wert=$_
        Write-Host "Aktuelle Checkbox : $Wert"  
        $Profile.$Auswahl.$Checkbox_Wert=$auswahlprofil.$checkbox_Wert
    }

[int]$Checkbox_Nummer=$Checkbox_Nummer+1
}
Save-Profiles $Profilepath $Profile
}

Fehlermeldung:
Fehler beim Durchlaufen einer Auflistung: Die Auflistung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden..
In C:\PowershellGUI - XML_Load.ps1:553 Zeichen:5
+     $Profile.$Auswahl.keys |
+     ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Collecti...tableEnumerator:HashtableEnumerator) , RuntimeException
    + FullyQualifiedErrorId : BadEnumeration


UPDATE: GELÖST und es war eigentlich einfach
Function Get-CurrentProfile($Auswahl)
{
#[content:208115]
$Global:CheckboxNewValue=[ordered]@{}
$Global:AuswahlProfil=@{}
    for($i=1;$i -le $Profile.default.count;$i++)
    {
        Write-Host "Checkbox Nummer $i =" $AllCheckboxStates[$i-1]  
        if($AllCheckboxStates[$i-1] -eq "Checked")  
        {
            $CheckboxName="Checkbox" + "$i"  
            $Global:AuswahlProfil+=[ordered]@{$CheckboxName="checked"}        
        }
        else{
            $CheckboxName="Checkbox" + "$i"  
            $Global:AuswahlProfil+=[ordered]@{$CheckboxName="unchecked"}     
        }   
    }
    
    #$Global:CheckboxNewValue+=[ordered]@{$Auswahl=$AuswahlProfil.keys}
    #$Global:Profile+=@{$Auswahl=$CheckboxNewValue.Values}

    $Profile.$Auswahl=$auswahlprofil
Save-Profiles $Profilepath $Profile
}
H41mSh1C0R
H41mSh1C0R 13.10.2015 aktualisiert um 16:08:02 Uhr
Goto Top
Zitat von @colinardo:
Diese nutzt man nun folgendermaßen:

Man legt sich seine Profile wie gewohnt mit zwei verschachtelten Hashtables an, und speichert sie dann mit der ersten obigen Funktion in einer XML-Datei
> $profilesettings1 = @{"checkbox1"="checked";"checkbox2"="checked";"checkbox3"="unchecked"}  
> $profilesettings2 = @{"checkbox1"="checked";"checkbox2"="checked";"checkbox3"="unchecked"}  
> $profiles = @{"ProfileABC"=$profilesettings1;"ProfileXYZ"=$profilesettings2}  
> Save-Profiles "C:\temp\profiles.xml" $profiles  
> 

Hi Uwe,

ich bastel ja immernoch an meinem Grid rum und lese eine Verzeichnisstruktur ein und wollte erst alles in eine ini schreiben bis Jodel hierher verwiesen hat.

		$row = @("Start", "leer", "leer", $array[$i], $Version, "Download", "Upload")  
		$dataGridView1.Rows.Add($row)
	
		$Pfad_LokaleAblage 	                = $datagridview1.Rows.Cells[1].value
		$Pfad_LokaleAblageSoftware	= $datagridview1.Rows.Cells[2].value
		
		$profilesettings = @{ "Pfad_LokaleAblage" = $Pfad_LokaleAblage; "Pfad_LokaleAblageSoftware" = $Pfad_LokaleAblageSoftware; "Pfad_Ablage" = $array[$i]; "Pfad_AblageVersion" = $Version}  
		$profiles += @{ "Eintrag_$i" = $profilesettings }  
				
		Save-Profiles "C:\temp\profiles.xml" $profiles  

Er schreibt mir auch ins XML file, allerdings in der Reihenfolge:

1
3

2

und sollte ein Eintrag bereits existieren wirft er einen Fehler für jeden doppelten Eintrag:

MainForm.psf (46): ERROR: At Line: 46 char: 15
ERROR: +             $profiles += <<<<  @{ "Eintrag_$i" = $profilesettings }  
ERROR:     + CategoryInfo          : InvalidOperation: (System.Collections.Hashtable:Hashtable) , RuntimeException
ERROR:     + FullyQualifiedErrorId : OperatorFailed

Wenn ich dein Beispiel nochmal hernehme und folgenden code Ausführe:
$profilesettings1 = @{"Quelle1"="C:\Quelle\1";"Ziel1"="C:\Ziel\1"}  
$profilesettings2 = @{"Quelle2"="C:\Quelle\2";"Ziel2"="C:\Ziel\2"}  
$profilesettings3 = @{"Quelle3"="C:\Quelle\3";"Ziel3"="C:\Ziel\3"}  
$profiles = @{"Eintrag_0"=$profilesettings1;"Eintrag_1"=$profilesettings2; "Eintrag_2"=$profilesettings3}  
Save-Profiles "C:\temp\profiles.xml" $profiles  

schaut mein XML so aus:

<?xml version="1.0" encoding="utf-8"?>  
<profiles>
  <profile name="Eintrag_0">  
    <Ziel1>C:\Ziel\1</Ziel1>
    <Quelle1>C:\Quelle\1</Quelle1>
  </profile>
  <profile name="Eintrag_2">  
    <Ziel3>C:\Ziel\3</Ziel3>
    <Quelle3>C:\Quelle\3</Quelle3>
  </profile>
  <profile name="Eintrag_1">  
    <Quelle2>C:\Quelle\2</Quelle2>
    <Ziel2>C:\Ziel\2</Ziel2>
  </profile>
</profiles>

Also ebenfalls mit verkehrter Reihenfolge. Woran kann das liegen?

PS C:\> Read-Profiles "C:\temp\profiles.xml"  

Name                           Value                                 
----                                  -----      
Eintrag_0                      {Ziel1, Quelle1}                                              
Eintrag_2                      {Ziel3, Quelle3}                                              
Eintrag_1                      {Quelle2, Ziel2}     

Irgendwie hat er auch noch die Values durcheinander. *am kopf kratz*


Gruß
colinardo
colinardo 13.10.2015 aktualisiert um 16:09:36 Uhr
Goto Top
Moin H41mSh1C0R,
das kommt deshalb weil Hashtables sich nicht an die Reihenfolge halten weil eine Hashtable ja primär für eine Key->Value Kombination vorgesehen ist bei der man die Werte anhand des Keys abfragt. Du kannst aber auch die Einträge einer Hashtable anhand ihrer Namen sortieren, und zwar folgendermaßen:
$profiles.GetEnumerator() | sort Name
Grüße Uwe
H41mSh1C0R
H41mSh1C0R 13.10.2015 um 16:18:23 Uhr
Goto Top
Hi Uwe,

die Einträge sortiert er mir nun auch, aber trotzdem stimmt was mit den Values nicht:

PS C:\> $profilesettings1 = @{"Quelle1"="C:\Quelle\1";"Ziel1"="C:\Ziel\1"}  
$profilesettings2 = @{"Quelle2"="C:\Quelle\2";"Ziel2"="C:\Ziel\2"}  
$profilesettings3 = @{"Quelle3"="C:\Quelle\3";"Ziel3"="C:\Ziel\3"}  
$profilesettings4 = @{"Quelle4"="C:\Quelle\4";"Ziel4"="C:\Ziel\4"}  
$profilesettings5 = @{"Quelle5"="C:\Quelle\5";"Ziel5"="C:\Ziel\5"}  
$profilesettings6 = @{"Quelle6"="C:\Quelle\6";"Ziel6"="C:\Ziel\6"}  
$profiles = @{"Eintrag_1"=$profilesettings1;"Eintrag_2"=$profilesettings2; "Eintrag_3"=$profilesettings3; "Eintrag_4"=$profilesettings4; "Eintrag_5"=$profilesettings5; "Eintrag_6"=$profilesettings6}  
$profiles.GetEnumerator() | sort Name
Save-Profiles "C:\temp\profiles.xml" $profiles  

Name                           Value           
----                           -----           
Eintrag_1                      {Ziel1, Quelle1}
Eintrag_2                      {Quelle2, Ziel2}
Eintrag_3                      {Ziel3, Quelle3}
Eintrag_4                      {Ziel4, Quelle4}
Eintrag_5                      {Ziel5, Quelle5}
Eintrag_6                      {Quelle6, Ziel6}

PS C:\> $profiles = Read-Profiles "C:\temp\profiles.xml"  
$profiles.GetEnumerator() | sort Name

Name                           Value           
----                           -----           
Eintrag_1                      {Ziel1, Quelle1}
Eintrag_2                      {Quelle2, Ziel2}
Eintrag_3                      {Ziel3, Quelle3}
Eintrag_4                      {Ziel4, Quelle4}
Eintrag_5                      {Ziel5, Quelle5}
Eintrag_6                      {Quelle6, Ziel6}

Gruß
colinardo
colinardo 13.10.2015 aktualisiert um 16:26:43 Uhr
Goto Top
Zitat von @H41mSh1C0R:
die Einträge sortiert er mir nun auch, aber trotzdem stimmt was mit den Values nicht:
Doch das ist in Ordnung so, der Grund die Hashtables sind verschachtelt !! Der Wert bei dir z.B. von Eintrag_1 ist eine weitere Hashtable mit zwei Keys und dazugehörigen zwei Werten @{"Quelle2"="C:\Quelle\2";"Ziel2"="C:\Ziel\2"} !!
Also alles im Lot. Willst du das nicht darf dein Wert keine Hashtable sondern ein Plain String sein.

Einfach mal die Doku zur Hashtable Klasse lesen ... Hashtable-Klasse
Dann musst du nicht immer rumraten !
H41mSh1C0R
H41mSh1C0R 13.10.2015 aktualisiert um 17:07:15 Uhr
Goto Top
Zitat von @colinardo:
Einfach mal die Doku zur Hashtable Klasse lesen ... Hashtable-Klasse
Dann musst du nicht immer rumraten !

Das Problem ist die Zeit für die Umsetzung. Die ist chronisch zu kurz. Von mir aus könnte der Tag 40h haben + Nacht dann wäre Zeit vorhanden für sooviele Dinge. ;( Hashtables im Detail ist nun ein Punkt mehr auf der Learning ToDo Liste.

Trotzalledem wenn ich dein Beispiel nehme und erweitere auf 5-6 profilesettings mit gleichem Inhalt ist die Sortierung immer gleich.
Egal ob in der Reihenfolge .

Was habe ich verändert. statt "Checkbox" und "checked" heißen die Elemente bei mir anders. Somit wundert es schon wieso wenn ich dein Beispiel erweitere bei mir 1-2 Profile anders sortiert sind als der Rest. Die Struktur ist ja gleich.

Ich werde das jetzt erstmal so umsetzen das es nicht ganz so dynamisch ist, da die Anzahl an unterschiedlichen Grideinträgen begrenzt ist.

Trotzdem fettes Danke an deine Unterstützung.

Gruß


EDIT:

Wenn ich Quelle und Ziel pro Profil nicht mit einer Zahl versehe sortiert er mir alles korrekt. =)