Windows Anmeldescript mit C# Programm bearbeiten
-
Hallo erstmal. ich bin zwar nich neu hier, aber schon lange nicht mehr auf der seite gewesen, weshalb ich auch meine alten logindaten verschusselt hab
ich habe gestern ein vbs fertig gestellt das bei einer windowsanmeldung drucker verbindet. den code find ich soweit ganz gut, aber der verwaltungsaufwand ist einfach viel zu riesig. hier also erst mal das script, damit ihr schonmal mehr mit dem anfangen könnt, wo ich eig. hin will.
' Bei Fehler weiter machen On Error Resume Next ' Windows Shell starten Set WshShell = WScript.CreateObject("WScript.Shell") Set WshNetwork = WScript.CreateObject("WScript.Network") ' Computernamen einlesen Dim computer computer = wshShell.ExpandEnvironmentStrings( "%COMPUTERNAME%" ) ' Falls nicht vorhanden den PC mit Case "Computername" eintragen ' Den jeweiligen Computernamen auswählen und die entsprechenden Drucker hinzufügen ' der gewünschte Standarddrucker muss immer an erster Stelle angegeben werden Select Case (computer) Case "C34EDV50" drucker=Array("P34ZEN01TEST","P34ZEN02") Case "C34CTL02" drucker=Array("P34ZEN02","P34ZEN01TEST") Case "HH-EDV-NB11" drucker=Array("P34ZEN02","P34ZEN01TEST") Case "C34EDV26" drucker=Array("P34ZEN02","P34ZEN01TEST") End Select ' Für jeden eingetragenen Drucker läuft die Schleife durch und fügt den Drucker hinzu for x = 0 to (UBound(drucker)) WshNetwork.AddWindowsPrinterConnection ("\\S34PSEDV01\"&(drucker(x))) next ' Der Drucker an der ersten Stelle im Array wird als Standarddrucker gesetzt WshNetwork.setdefaultprinter("\\S34PSEDV01\"&(drucker(0)))
sooo. wie man sehn kann, wird jeder einzelne pc mit CASE ins script eingebunden und ihm dann die drucker zugeteilt.
jetzt kommen wir aber zu dem verwaltungsaufwand. wir haben 1100 computer in der firma und keine ahnung wieviele drucker. das ganze also per hand zu pflegen ist absolut unübersichtlich und kann nur im chaos enden.
ich habe mir also überlegt ein c# prog zu erstellen, welches dann für die pflege und verwaltung sorgen soll. die computer werde ich von hand in das script einfügen. die ganzen computernamen kann ich nämlich aus einer accessdatenbank entnehmen und einfach mit dem notepad++ per suchen/ersetzen rein hämmern.in dem programm werden dann erst mal alle computer eingelesen und auf der linken seite in eine textbox, oder was auch immer geschrieben in der ich später auch suchen kann. wenn ich einen pc auswähle kommt in der mitte eine liste, welche drucker dem pc zugeordnet sind und rechts ist die liste mit allen drucken, so das ich die rechts anklicke und über einen "hinzufügen button" zu der druckerliste hinzufüge. soweit so gut. jetzt zu meinem problem.
beim einlesen des scripts muss ich erst mal alle vorhanden pc's links in die leiste schreiben. die zeilen durch zu gehn und die computernamen hinter dem CASE aus zu schneiden und in ne textbox ein zu fügen bekomm ich grade noch so hin. also mir zumindest dafür den quellcode raus zu googlen. allerdings muss ich ja jetzt in der nächsten zeile die drucker, die dem pc zugeordnet sind auch noch auslesen. realisiere ich das am besten mit einer for-schleife in einem 2-dimensionalem array? und mein größtest problem ist, wie man die einzelnen drucker aus der einen zeile zwischen ("bla","blubb") raus liest und in einzelne zeilen/variablen/arrays packt. das ganze muss nach dem zuordnen im programm natürlich so auch wieder ins script rein geschrieben werden. also quasi einen druckernamen mehr in die zeile drucker=Array("bla","blubb","und der hier soll jetzt da neu rein")
also 1.) kann mir da irgend jemand weiter helfen
oder 2.) macht das keinen sinn mit nem c# programm und jemand hat ne bessere lösung für mein dilemmaich hoffe es meldet sich überhaupt jemand zu dem thema hier und falls ja, schonmal tausend dank für überhaupt irgend eine antwort
€.: loool hahhahaha ich hab mich gewundert warum die [code] funktion im forum nich will bis ich gemerkt hab ich habs mit [/quote] abgeschlossen
-
Na ja, grundsätzlich geht das schon alles.. man muss halt das Script parsen und entsprechend verarbeiten etc.. aber:
Erste Frage: Was bezweckst du mit dem Script?
Zweite Frage: In der Access-DB, in der die Computernamen stehen, warum machst du da nicht eine weitere Tabelle "Drucker"? Und dann noch eine Tabelle "PC_Drucker" in der Zuordnungen stehen?
-
GPC schrieb:
Na ja, grundsätzlich geht das schon alles.. man muss halt das Script parsen und entsprechend verarbeiten etc.. aber:
Erste Frage: Was bezweckst du mit dem Script?
Zweite Frage: In der Access-DB, in der die Computernamen stehen, warum machst du da nicht eine weitere Tabelle "Drucker"? Und dann noch eine Tabelle "PC_Drucker" in der Zuordnungen stehen?[WALL OF TEXT WOZU DAS SCRIPT DIENT]
also das vbscript ist ein anmeldescript in einer windows 2003 domäne. es wird beim anmelden am pc auf jedem rechner gestartet. das ganze ist über eine gruppenrichtlinie geregelt. denn jedem benutzer das script einzeln im ad zu zuteilen wäre viel zu viel arbeit. dafür haben wir echt zu viele mitarbeiter, die auch ständig wechseln.
das script schaut beim anmelden wie der pcname ist und sucht dann im select case modus diesen namen raus. darunter stehen dann die druckernamen, die dem jeweiligen benutzer zugewiesen sind. die ganzen druckernamen werden dann in ein array gepackt und danach springt das script weiter unten in die for-schleife. dort wird dann jeder einzelne drucker über addwindowsprinterconnection an dem pc hinzugefügt. der macht das aber nur, wenn der drucker noch nich vorhanden ist. spart halt zeit. die ganzen drucker sind auf nem printserver installiert und es sind treiber für 32- und 64-bit hinterlegt. durch den befehl werden die drucker verbunden und falls der treiber noch nicht vorhanden ist, wird er automatisch vom server gezogen. das ganze erspart einem dann auch die arbeit, zu jedem pc zu rennen und dort den treiber per hand zu installieren, wenn mal wieder einem benutzer einfällt, dass er auf diesem und jenen pc ja umgedingt auch drucken muss. unsere firma erstreckt sich halt über sehr viele gebäude auf einem 12km² gelände. wir sind in der edv stark unterbesetzt und durch das script wird ne menge arbeit abgenommen. die drucker in der access db zu zuordnen bringt mir ja nicht viel, denn es muss ja in das script rein und nicht in die db ^^ ich weiß, dass es auch die möglichkeit gibt die drucker per gruppenrichtlinie bereit zu stellen. allerdings geht das bei uns halt auch nicht, weil wir so viele gebäude haben und dann für fast jeden pc ein eigenes gruppenrichtlinien objekt erstellen müssten.[/WALL OF TEXT ENDE]
wenn mir wenigstens einer sagen könnte wie ich aus dieser zeile:
drucker=Array("P34ZEN02","P34ZEN01TEST")
nur die druckernamen rausbekommen und auch wieder reinschreiben kann.bsp.aus dem \1:
Case "C34EDV50" drucker=Array("P34ZEN01TEST","P34ZEN02")
jetzt soll in der windowsform der pcname C34EDV50 auswählbar sein und mir dazu in einer textbox (grad nochmal geschaut und ich nehm wohl ne listbox), die beiden drucker P34ZEN01TEST und P34ZEN02 angezeigt werden
jetzt habe ich noch eine listbox in der ALLE drucker stehen.
da steht dann z.b. untereinander natürlich: P34ZEN01TEST P34ZEN02 P34BEISPIEL05 usw.jetzt will ich dem pc C34EDV50 noch den drucker P34BEISPIEL05 zuordnen. und da muss ich dann noch wissen wie ich den drucker im script, in der richtigen zeile, an der richtigen stelle hinzufüge. script sollte dann folgendermaßen aussehen:
Case "C34EDV50" drucker=Array("P34ZEN01TEST","P34ZEN02","[u][b]P34BEISPIEL05[/b][/u]")
das wichtigste wäre wirklich zu wissen, wie ich die drucker für den jeweiligen pc aus dieser zeile in eine textbox bekomme und wie ich sie für einen bestimmten drucker wieder in die zeile rein bekomme.
-
Nun, du hast natürlich mehrere Möglichkeiten.
Das Offensichtliche ist, die Script-Datei (zeilenweise) in einen StringBuilder einzulesen und dort dann mittels den String-Funktionen nach dem Eintrag zu suchen und zu bearbeiten. Man kann dazu auch Regex nehmen. Man muss halt aufpassen, dass man immer an der richtigen Stelle liest und schreibt, geht aber insg. schon.
Alternativ kannst du dir auch ein paar Klassen schreiben, die die jeweils wichtigen Teile der Script-Datei repräsentieren. Dann kannst du die Script-Datei recht komfortabel über diese Klassen manipulieren (vmtl. der Weg, den ich gehen würde).
-
Warum hast du ein VBS Script gemacht um es danach in C# nochmal zu Parsen? Mach es doch direkt in C# und lass dir dann ein Script ausgeben.
Also statt
Script(VBS) -> Parse(C#) -> Modify(C#) -> Save(VBS)
lieber
Create(C#) -> Save(VBS)Parsen würde ich nix.
(Kannst die Access Datenbank wunderbar mit C# Auslesen, und die Drucker inkl der Zuordnung würde ich auch irgendwo abspeichern, wenn du das nicht in die DB packen willst [warum nicht? Finde keine wenn die PC Namen abgelegt werden konnten, können das auch die Drucker mit nem FK auf den PC Namen] dann wenigstens in eine Textdatei die bei dem Tool dann dabei liegt, du sagtest das du die PC Namen und Drucker manuell in das Script einfügen würdest, dann kannst du es auch in die Textdatei einfügen)
alá
foreach (var machineName in machineNames) { var printerName = GetPrinterByMachineName(machineName); var scriptText = GenerateScript(machineName, printerName); SaveToScriptFile(scriptText); } private StringBuilder GenerateScript(string machineName, string printerName) { var scriptText = new StringBuilder(); scriptText.Append("Alles an Text was unverändert ist"); scriptText.Append("drucker=Array(\"" + machineName + "\",\"" + printerName + "\")"); scriptText.Append("Alles an Text was unverändert ist"); return scriptText; }
-
Sry das ich mich bisher nicht melden konnte.
Erst mal danke für den Anderen Lösungsansatz und das Stück Programmcode von dir, hilft mir schonmal ein bischen weiter.
Also das Ganze muss ja am Ende ein vbs Script sein, weil es ja für die Windowsanmeldung benutzt wird und der Chef da keine Exe ausführen lassen will (warum auch immer). Das vbs ist ja im Grunde genommen wie eine Textdatei, weil man es ja öffnen, einlesen und schreiben kann wie eine txt.
Ich habe mir mal noch was Anderes überlegt, wo ich mir im Moment noch den Code am zusammen googlen bin, weil ich mich mit regex und split nicht auskenne.
Ich kann das ganze vbs ja einfach in string[] einlesen. Das hab ich schon gemacht und das komplett einfach mal in eine Listbox geschrieben um zu sehn, ob es funktioniert. Jetzt hab ich ja links meine ganzen Pcnamen schon in einer Listbox drinn. Die werden beim Programmstart alle aus einer txt eingelesen und man kann Sie da auch hinzufügen, oder löschen (das Selbe geht auch mit meiner drucker.txt).
Ich wähle also jetzt rechts einen Pcnamen aus und schreib den selected index in eine Variable. In string[] steht ja jetzt das vbs Zeilenweise drinn (wenn ich das richtig verstanden habe). Jetzt wollte ich eine Schleife machen. foreach Zeile überprüfe ob mein Pcname darin vorkommt. Wenn er in einer Zeile gefunden wurde, freu ich mich schon mal:D. Jetzt weiß ich ja das meine druckerarray Variable direkt eine Zeile unter der, mit dem Pcnamen steht. Also addiere ich im Zähler eine Zeile hinzu und steh dann in der Zeile mit den Druckern. Und hier lese ich dann mit regex, oder split die Druckernamen in meine Listbox die neben den Pcnamen ist.
Man klickt also links einen Pcnamen an und bekommt daneben die Drucker angezeigt, die im Script zugeordnet sind. Wenn ich mich mit split, oder regex auskennen würde, sollte das ja eig. ganz einfach sein. Die Listbox mit den zugeordneten Druckern zu ändern ist ja ein Kinderspiel, aber die zugeordneten Drucker dann wieder in die selbe Zeile im Script zu schreiben schon schwerer.Es gibt aber bestimmt eine Möglichkeit. In der forschleife habe ich ja quasi schon herrausgefunden in welcher Zeile in string[] meine Drucker für den jeweiligen Pc stehn. Jetzt lösch ich diese Zeile raus und schreib genau an die selbe stelle wieder eine Zeile rein mit den neu zugeordneten Druckern aus der Listbox. Man kann ja in einer bestimmten Zeile einfach eine Zeile ersetzen (löschen/hinzufügen).
So hab ich mir das zumindest übers Wochenende überlegt. Ich weiß genau, dass es so funktioniert. Jetzt muss ich mir "nur" noch den nötigen Code zusammen googlen....nur
Falls ich von c# jetzt zuviel erwarte und es das gar nicht kann, dann warnt mich bitte noch, bevor ich mir jetzt ne Woche lang die Haare raufe, weils nich gehtAnsonsten bin ich sehr dankbar für jegliche Hilfe wie man aus
drucker=Array("P34ZEN01TEST","P34ZEN02","P34BEISPIEL05")
die Drucker mit regex, oder split in eine Listbox bekommt. Dabei stehn in dieser Zeile aber auch 0 bis 50 Drucker und nicht immer nur 3 wie in diesem Beispiel.
Ich weiß, das Es echt schwer zu verstehn is, was ich da eig. genau will und mir in meinem Köpfchen so zusammengedacht habe, aber vielleicht blickt ja noch Einer durch€.: Ich hab mal noch einigermaßen Groß- und Kleinschreibung editiert, damit man den langen Text überhaupt richtig lesen kann. Es ist bestimmt immer noch grausam, aber das kommt halt davon wenn man fast nur noch Englisch ließt und schreibt
-
T3h vICE schrieb:
Falls ich von c# jetzt zuviel erwarte und es das gar nicht kann, dann warnt mich bitte noch, bevor ich mir jetzt ne Woche lang die Haare raufe, weils nich geht
C# kann das definitiv stemmen
Ansonsten bin ich sehr dankbar für jegliche Hilfe wie man aus
drucker=Array("P34ZEN01TEST","P34ZEN02","P34BEISPIEL05")
die Drucker mit regex, oder split in eine Listbox bekommt. Dabei stehn in dieser Zeile aber auch 0 bis 50 Drucker und nicht immer nur 3 wie in diesem Beispiel.
Na ja, basierend auf dem, was ich hier so lese, halte ich Regex nicht für das ideale Werkzeug für dich. Ich zeige dir mal, wie das ganz naiv mit den String-Funktionen geht:
string str = "drucker=Array(\"P34ZEN01TEST\",\"P34ZEN02\",\"P34BEISPIEL05\")"; int openingBracket = str.IndexOf('('); int closingBracket = str.IndexOf(')'); if (openingBracket == -1 || closingBracket == -1) //Ungültiger Eintrag return; if (openingBracket + 1 == closingBracket) //Kein Drucker eingetragen return; //+1 damit die öffnende Klammer übersprungen wird und -1, damit die schließende Klammer nicht enthalten ist string printersAsString = str.Substring(openingBracket + 1, closingBracket - openingBracket - 1); string[] printers = printersAsString.Split(',');
Damit hast du die einzelnen Drucker (mit den hochkommata) im Array "printers" gespeichert. In eine Listbox bekommt du es ja dann ganz einfach.
Ich weiß, das Es echt schwer zu verstehn is, was ich da eig. genau will und mir in meinem Köpfchen so zusammengedacht habe, aber vielleicht blickt ja noch Einer durch
Es ist eig. ziemlich easy
Aber du machst nicht den Eindruck, besonders sattelfest in der Programmierung zu sein.
-
Cool vielen dank. Genau das hat mir noch gefehlt um das Programm fertig zu bekommen. Ich konnte mich in der Woche bisher noch nicht melden, weil ich so ne dämliche Schlafepilepsie hab die mal wieder zugeschlagen hat. Ich bin Fachinformatiker für Systemintegration. Wir haben da in der Schule ein bischen Hello World gelernt, aber das wars dann auch schon. Den rest hab ich mir alles selber beigebracht. Das meiste konnte ich immer googeln, aber hier bin jetzt mal nicht weiter gekommen. Delphi konnte ich mal ziehmlich gut, aber das hab ich vor 6 Jahren das letzte mal benutzt. Von der Programmierlogik sitzt noch alles, aber mit der Syntax isses immer so ne Sache. Vor allem, wenn man halt die ganzen tollen Methoden nicht kennt, die jede Sprache so mit sich bringt.
EDIT:
Hmm wie bekomm ich jetzt noch die " weg? Wenn ich das mit in den Split reinschreibe, dann sagt Er mir zu viele Zeichen im Zeichenliteral. Ich fang schon mal an zu googeln. Falls ich es selber finde melde ich mich.EDIT.2:
Habs geschafft. Geht bestimmt auch einfacher, aber Hauptsache es funktioniert ^^
Dein Code funktioniert übrigens SUPER. Echt tausend dank. Das hätte ich selber bestimmt erst in 3-4 Wochen hin bekommen.
Ich hab jetzt einfach folgendes an deinen Code angehangenforeach (string zeile in printers) { string zeileb = zeile; zeileb = zeile.Replace("\"", ""); listBox1.Items.Add(zeileb); }
EDIT.3:
Hier mal noch ein Bild wie weit ich mit dem Programm bisher bin. Da kann man dann auch mal drauf erkennen was das ganze eigentlich soll
Jetzt muss ich nur noch die Drucker wieder in die Zeile rein schreiben, wenn ich welche hinzugefügt, oder gelöscht habe. Ich wette, dass ich Probleme hab hinter dem letzten Drucker das Komma weg zu lassen
http://s7.directupload.net/images/120810/ymyhgvq3.jpg
so 5000x editiert und man kann anscheinend hier kein Bild posten. Darum halt nur der LinkEDIT.4:
So der wichtige Hauptteil des Programms läuft mitlerweile echt gut. Auch wenn es echt ein langer Code ist, werde ich den hier mal posten. Falls irgendwann mal jemand ein ähnliches Problem hat und per google auf diesen Post hier stolpert, dann kann er vielleicht mit dem Ein oder Anderem was anfangen.using System; using System.IO; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Computerliste einlesen string[] linespc = System.IO.File.ReadAllLines(@"D:\Computer.txt", System.Text.Encoding.Default); this.listBoxAlleComputer.Items.AddRange(linespc); // Druckerliste einlesen string[] linesdrucker = System.IO.File.ReadAllLines(@"D:\Drucker.txt", System.Text.Encoding.Default); this.listBoxAlleDrucker.Items.AddRange(linesdrucker); } private void textBoxHinzufuegen_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == (char)13) { Boolean vorhanden = false; foreach(String Item in listBoxAlleComputer.Items) if (System.String.Compare (Item, textBoxHinzufuegen.Text,true) == 0) { MessageBox.Show("Computer schon vorhanden"); vorhanden = true; break; } if (vorhanden == false) { listBoxAlleComputer.Items.Add(textBoxHinzufuegen.Text); textBoxSuche.Text = ""; } } } private void textBoxSuche_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == (char)13) { String suche = textBoxSuche.Text; int index = listBoxAlleComputer.FindString(suche, -1); if (index != -1) { listBoxAlleComputer.SetSelected(index, true); textBoxSuche.Text = ""; } else MessageBox.Show("PC nicht gefunden :("); textBoxSuche.Text = ""; } } private void textBoxAddDrucker_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == (char)13) { Boolean vorhanden = false; foreach (String Item in listBoxAlleDrucker.Items) if (System.String.Compare(Item, textBoxAddDrucker.Text, true) == 0) { MessageBox.Show("Drucker schon vorhanden"); vorhanden = true; break; } if (vorhanden == false) { listBoxAlleDrucker.Items.Add(textBoxAddDrucker.Text); textBoxAddDrucker.Text = ""; } } } private void buttonPcLoeschen_Click(object sender, EventArgs e) { listBoxAlleComputer.Items.Remove(listBoxAlleComputer.SelectedItem); } private void buttonDruckerLoeschen_Click(object sender, EventArgs e) { listBoxAlleDrucker.Items.Remove(listBoxAlleDrucker.SelectedItem); } public class einlesen { public static string[] text = File.ReadAllLines(@"d:\logondrucker.vbs"); } private void listBoxAlleComputer_SelectedIndexChanged(object sender, EventArgs e) { listBox1.Items.Clear(); string pcname = listBoxAlleComputer.SelectedItem.ToString(); for (int i=0; i < einlesen.text.Length; i++) { if (einlesen.text[i].Contains(pcname) == true) { i++; string str = einlesen.text[i]; int openingBracket = str.IndexOf('('); int closingBracket = str.IndexOf(')'); if (openingBracket == -1 || closingBracket == -1) //Ungültiger Eintrag return; if (openingBracket + 1 == closingBracket) //Kein Drucker eingetragen return; //+1 damit die öffnende Klammer übersprungen wird und -1, damit die schließende Klammer nicht enthalten ist string printersAsString = str.Substring(openingBracket + 1, closingBracket - openingBracket - 1); string[] printers = printersAsString.Split(','); foreach (string zeile in printers) { string zeileb = zeile; zeileb = zeile.Replace("\"", ""); listBox1.Items.Add(zeileb); } } } } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { // Pc-Liste abspeichern var newLinesComputer = new List<string>(this.listBoxAlleComputer.Items.Count); foreach (var line in this.listBoxAlleComputer.Items) newLinesComputer.Add(line.ToString()); System.IO.File.WriteAllLines(@"D:\Computer.txt", newLinesComputer.ToArray(), System.Text.Encoding.Default); // Drucker-Liste abspeichern var newLinesDrucker = new List<string>(this.listBoxAlleDrucker.Items.Count); foreach (var line in this.listBoxAlleDrucker.Items) newLinesDrucker.Add(line.ToString()); System.IO.File.WriteAllLines(@"D:\Drucker.txt", newLinesDrucker.ToArray(), System.Text.Encoding.Default); } private void button1_Click(object sender, EventArgs e) { Boolean vorhanden = false; foreach (String Item in listBox1.Items) if (System.String.Compare(Item, listBoxAlleDrucker.SelectedItem.ToString(), true) == 0) { MessageBox.Show("Drucker schon vorhanden"); vorhanden = true; break; } if (vorhanden == false) { listBox1.Items.Add(listBoxAlleDrucker.SelectedItem.ToString()); } } private void button2_Click(object sender, EventArgs e) { listBox1.Items.Remove(listBox1.SelectedItem); } private void button3_Click(object sender, EventArgs e) { String ersetzen = " drucker=Array("; int z = listBox1.Items.Count; int i = 1; foreach (String Item in listBox1.Items) { if (z != i) { ersetzen += "\"" + Item + "\","; } if (z == i) { ersetzen += "\"" + Item + "\""; } i++; } ersetzen += ")"; string pcname = listBoxAlleComputer.SelectedItem.ToString(); for (int b = 0; b < einlesen.text.Length; b++) { if (einlesen.text[b].Contains(pcname) == true) { b++; einlesen.text[b] = einlesen.text[b].Replace(einlesen.text[b], ersetzen); } } File.WriteAllLines(@"d:\logondrucker.vbs", einlesen.text); } } }
Sobald das Programm dann zu 100% fertig ist, werde ich es komplett Kommentieren und dann nochmal neu hier rein stellen. Vielen Dank an alle die mir hierbei geholfen haben. Der Code sieht grausam aus, aber da ich mir das ganze in gerade mal 2 Wochen beigebracht hab, musste ich echt sehr viel basteln.
-
doppelpost löschen