Tician Geschrieben 24. Juni 2019 Teilen Geschrieben 24. Juni 2019 Huhu, ich versuch verzweifelt in C# ein Programm zu basteln mit dem man Office 365 Benutzer verwalten kann. Über PowerShell selbst funktioniert das einwandfrei, aber in C# krieg ich einfach keine Rückmeldungen, nichts was ich auslesen könnte das mir sagt was falsch läuft. Code sieht quasi so aus: PSCredential cred = new PSCredential(mail,password); using (PowerShell ps = PowerShell.Create()) { ps.Commands.AddScript("$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $cred -Authentication Basic -AllowRedirection"); ps.Commands.AddScript("Import-PSSession $Session -DisableNameChecking"); ps.Commands.AddScript("Remove-PSSession $Session"); Collection<PSObject> psOutput = ps.Invoke(); ps.Streams.Progress.DataAdded += Progress_DataAdded; /*if (ps.Streams.Error.Count > 0) { }*/ foreach(PSObject outputItem in psOutput) { if (outputItem != null) { //richTextBox1.AppendText(outputItem.BaseObject.GetType().FullName); richTextBox1.AppendText(outputItem.ToString()); } } } Was genau passiert: - Programm läuft durch ohne Fehler - aber auch ohne irgendwelche Meldungen. Kein Output, keine Errors, nichts, die foreach-Schleife wird übersprungen weil nichts drin ist. Auch das versuchte Event (egal ob Streams.Warning, 'Progress' oder 'Information' triggert nicht. Was mir fehlt: - Der Output des PS-Scripts fehlt mir wie gesagt, aber ich tu mich verdammt schwer irgendwas nützliches im Internet zu finden - Das Objekt der Klasse PSCredential mit dem ich in C# die Benutzerdaten abfrage muss irgendwie in den Befehl als PS-Variable rein, auch hier konnte ich noch nicht raus finden wie ich das schreiben muss damit es funktioniert. Könnte mir da jemand helfen? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
el_pollo_diablo Geschrieben 24. Juni 2019 Teilen Geschrieben 24. Juni 2019 Ich oute mich einfach mal als Powershell-Noob, aber fehlt hier nicht "ps.AddParameter(...)"? (siehe z.B. https://blogs.msdn.microsoft.com/kebab/2014/04/28/executing-powershell-scripts-from-c/ ): using (PowerShell PowerShellInstance = PowerShell.Create()) { // use "AddScript" to add the contents of a script file to the end of the execution pipeline. // use "AddCommand" to add individual commands/cmdlets to the end of the execution pipeline. PowerShellInstance.AddScript("param($param1) $d = get-date; $s = 'test string value'; " + "$d; $s; $param1; get-service"); // use "AddParameter" to add a single parameter to the last command/script on the pipeline. PowerShellInstance.AddParameter("param1", "parameter 1 value!"); } Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Tician Geschrieben 28. Juni 2019 Autor Teilen Geschrieben 28. Juni 2019 (bearbeitet) Ich bin auch ein Powershell-Noob, aber ich hab denke ich verstanden was du meinst. Der neue Code sieht so aus: PSCredential cred = new PSCredential(mail,password); using (PowerShell ps = PowerShell.Create()) { //ps.Commands.AddScript("$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $cred -Authentication Basic -AllowRedirection"); ps.AddScript("$Session = New-PSSession") .AddParameter("ConfigurationName", "Microsoft.Exchange") .AddParameter("ConnectionUri", "https://outlook.office365.com/powershell-liveid/") .AddParameter("Credential", cred) .AddParameter("Authentication", "Basic") .AddParameter("AllowRedirection"); ps.AddCommand("Import-PSSession $Session")/*.AddParameter("$Session")*/.AddParameter("DisableNameChecking"); ps.AddCommand("Remove-PSSession").AddParameter("$Session"); ps.Streams.Progress.DataAdded += Progress_DataAdded; ps.Streams.Error.DataAdded += Error_DataAdded; ps.Streams.Information.DataAdded += Information_DataAdded; ps.Streams.Warning.DataAdded += Warning_DataAdded; Collection<PSObject> psOutput = ps.Invoke(); /*if (ps.Streams.Error.Count > 0) { }*/ foreach(PSObject outputItem in psOutput) { if (outputItem != null) { //richTextBox1.AppendText(outputItem.BaseObject.GetType().FullName); richTextBox1.AppendText(outputItem.ToString()); } } } Mein Problem: Bei den letzten 2 Commands krieg ich entweder ein "Kennt kein cmdlet 'Import-PSSession $Session'" oder "Kennt kein Parameter '$Session"' - ich hab keine Ahnung mit was ich meine Variable da ran hängen muss, der Command an sich wäre einfach nur "Import-PSSession $Session". Was ich auch nicht verstehe ist warum meine Ereignisse nicht ziehen, bzw ich immer noch keinen Output bekomme. Alles was passiert ist das das Programm immer in meinen großen Try/Catch geht und mir dort dann den Fehler ausgibt. Noch Ideen? ? PS: Nach einigen weiteren Beispielen ist 'AddScript' sowieso totaler Schwachsinn, aber mit 'AddCommand' funktioniert es ja auch nicht. Dachte ich... ich bin verwirrt, mal schreiben Leute direkt den Befehl rein, mal verweise sie nur auf eine Datei... Bearbeitet 28. Juni 2019 von Tician Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
mylurid Geschrieben 28. Juni 2019 Teilen Geschrieben 28. Juni 2019 Mal ganz blöd gefragt - funktionieren denn die PS Commands Zitat ps.Commands.AddScript("$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $cred -Authentication Basic -AllowRedirection"); ps.Commands.AddScript("Import-PSSession $Session -DisableNameChecking"); ps.Commands.AddScript("Remove-PSSession $Session"); wenn du sie in der PowerShell ISE / Konsole eintippst und wenn ja - was genau bekommst du zurück? Normalerweise brauchst du den .AddParameter nur, wenn du aus C# Argumete oder Parameter an die PowerShell übergibst. Und da du im ersten Befehl schon versuchst $cred zu übergeben, musst du dies auch als Parameter dort anhängen. Normalerweise solltest du dir das New-PSSession -ConnectionUri servername -Credential $cred mal mindestens ne Ausgabe erzeugen, mit der du was anfangen kannst. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
mylurid Geschrieben 28. Juni 2019 Teilen Geschrieben 28. Juni 2019 Vielleicht kannst du auch mit dem CMDlet Invoke-Command was anfangen. Dort lassen sich auch Scriptblöcke remote ausführen und mit Variablen arbeiten Beispiel: Invoke-Command -Session $s -ScriptBlock { param ($computer) Get-ADComputer -Server "Servername.local" -Identity $computer -Properties * } -ArgumentList $computer Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Tician Geschrieben 28. Juni 2019 Autor Teilen Geschrieben 28. Juni 2019 PowerShell direkt sieht so aus und funktioniert auch (Im Anhang). Ich erwarte nicht dass mir das so angezeigt wird, aber auch nicht... nichts. Ich glaub aber auch nicht dass sie Befehle momentan ausgeführt werden, der erste scheint durchzulaufen (ich weiß es nicht, ich rkieg ja keinen Output sondern nur einen Sprung in mein allgemeines Exception bei 'ps.Invoke()' mit einem der beiden oben beschriebenen Fehler. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
mylurid Geschrieben 28. Juni 2019 Teilen Geschrieben 28. Juni 2019 Bei dem ps.Invoke() musst du in Klammern auf jeden Fall das cred übergeben. Also irgnedwie so in die Richtung: var ps = PowerShell.Create(); //Instanz erstellen script.AddScript("New-PSSession -ConnectionUri xxx -Credential cred"); //Script mit Cmdlets hinzufügen var output = script.Invoke(cred); //Befehl ausführen, ggf. eine Liste mit Eingabeparametern übergeben So wie hier beschrieben: https://dotnet-snippets.de/snippet/powershell-cmdlets-aus-net-aufrufen/4911 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Tician Geschrieben 28. Juni 2019 Autor Teilen Geschrieben 28. Juni 2019 OK, ich bin etwas weiter. Jetzt kriege ich Rückmeldung, kann sie aber nicht ausgeben weil mein Steuerelement (textBox) nicht im selben Thread wie mein PowerShell läuft. using (PowerShell ps = PowerShell.Create()) { ps.AddScript("$Session = New-PSSession") .AddParameter("ConfigurationName", "Microsoft.Exchange") .AddParameter("ConnectionUri", "https://outlook.office365.com/powershell-liveid/") .AddParameter("Credential", cred) .AddParameter("Authentication", "Basic") .AddParameter("AllowRedirection"); ps.AddScript("Import-PSSession $Session").AddParameter("DisableNameChecking"); ps.AddScript("Remove-PSSession $Session"); ps.Streams.Progress.DataAdded += Progress_DataAdded; ps.Streams.Error.DataAdded += Error_DataAdded; //rutscht hier rein ps.Streams.Information.DataAdded += Information_DataAdded; ps.Streams.Warning.DataAdded += Warning_DataAdded; Collection<PSObject> psOutput = ps.Invoke(); foreach(PSObject outputItem in psOutput) { if (outputItem != null) { richTextBox1.AppendText(outputItem.ToString()); } } } private void Error_DataAdded(object sender, DataAddedEventArgs e) { richTextBox1.AppendText(Convert.ToString(e)); //InvalidOperationException } "Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement richTextBox1 erfolgte von einem anderen Thread, für den es erstellt wurde" Ich verstehe warum ich das kriege, aber ich hab bisher kein solches Problem gehabt, mal schauen ob ich das irgendwie gelöst kriege... auch wenn ich keine Ahnung habe wie ich etwas zwischen Threads übergebe... oder so... Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
KeeperOfCoffee Geschrieben 28. Juni 2019 Teilen Geschrieben 28. Juni 2019 (bearbeitet) Kommst du mit nem Invoke drauf? richTextBox1.Dispatcher.BeginInvoke(new Action(() => { richTextBox1.AppendText(outputItem.ToString()); })); Bearbeitet 28. Juni 2019 von KeeperOfCoffee Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Tician Geschrieben 28. Juni 2019 Autor Teilen Geschrieben 28. Juni 2019 @KeeperOfCoffee richTextBox1 kennt kein Dispatcher ? Im Microsoft-Doc steht "System.Windows.Threading", was es aber bei mir nicht gibt, ich hätte nur "System.Threading" anzubieten, das scheint es aber nicht zu sein. Muss ich da was hinzufügen? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
KeeperOfCoffee Geschrieben 28. Juni 2019 Teilen Geschrieben 28. Juni 2019 Ok, wusste nicht, dass es WinForms ist, dann versuche mal ob es mit BeginInvoke ghet Anleitung: https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.begininvoke?redirectedfrom=MSDN&view=netframework-4.8#overloads Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Tician Geschrieben 1. Juli 2019 Autor Teilen Geschrieben 1. Juli 2019 Die Anleitung ist irgendwie... unvollständig. Ich hab mir zwar ein wenig über Delegaten und auch Threads durchgelesen, aber ich fürchte es reicht nicht aus um zu verstehen was bei mir eigentlich falsch läuft und warum ich auch im Debug-Modus nicht weiter komme - und irgendwas gewaltig falsch mache und dabei die nächste Exception bekomme. Folgendes hab ich jetzt (auf wesentliches gekürzt): private delegate void InvokeDelegate(string text); using (PowerShell ps = PowerShell.Create()) { ps.Streams.Error.DataAdded += Error_DataAdded; ps.AddScript("..."); Collection<PSObject> psOutput = ps.Invoke(); //geht hier in das Ereignis } private void Error_DataAdded(object sender, DataAddedEventArgs e) { //richTextBox1.AppendText(Convert.ToString(e)); richTextBox1.BeginInvoke(new InvokeDelegate(InvokeMethod)); //Macht 'nichts' //InvokeMethod(Convert.ToString(e)); //InvokeDelegate(Convert.ToString(e)); } public void InvokeMethod(string text) { richTextBox1.AppendText("Bla "); } Was passiert: Sichtbar quasi nichts, die TextBox bleibt leer, der Code läuft ne ganze Weile bis er dann in 'Program.cs' bei folgendem hängen bleibt: Die Dinge die ich nicht verstehe: 'ps.Invoke()' wird in einem anderen Thread ausgeführt, weswegen ich trotz Haltepunkt (das Delegaten-Zeug auskommentiert) direkt die Exception bekomme. Gibt es in VS eine Möglichkeit auch hier irgendwie einen Haltepunkt für andere Threads zu setzen? Im Microsoft-Beispiel wird 'InvokeMethod()' direkt ausgeführt ohne vorher ein Objekt erstellt zu haben anhand dessen man die Methode aufrufen könnte. Ich hab alles versucht irgendwie noch meinen string-Parameter an den Delegaten ran zu packen, aber mir erschließt sich der Aufbau nicht. Ich hab hier nochmal ein Beispiel mit Parameter gefunden: https://www.codeproject.com/Articles/10311/What-s-up-with-BeginInvoke richTextBox1.BeginInvoke(new InvokeDelegate(InvokeMethod),new object[] { e }); Ich schätze also es müsste so aussehen, aber trotzdem läuft irgendwas gewaltig schief, er versucht New Form1() mit dem Parameter aufzurufen, deswegen hier nun die Ausnahme dass Form1 keinen Parameter vom Typ string mag. Aber warum es überhaupt dorthin geht statt zu 'InvokeMethod()' ... keine Ahnung. ? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
KeeperOfCoffee Geschrieben 5. Juli 2019 Teilen Geschrieben 5. Juli 2019 https://stackoverflow.com/questions/519233/writing-to-a-textbox-from-another-thread Vlt hilft dir das. Habe schon ewig nix mehr mit Forms gemacht Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Tician Geschrieben 8. Juli 2019 Autor Teilen Geschrieben 8. Juli 2019 Ich verzweifel. Ich hab aber auch keine AHnung wie man Multi-Threading debuggt. Auf jedenfall hab ich das hier und haufenweise Haltepunkte (weswegen ich zumindest weiß wo mein Programm sich verabschiedet: using (PowerShell ps = PowerShell.Create()) { ps.AddScript("Blabla"); ps.Streams.Error.DataAdded += Error_DataAdded; Collection<PSObject> psOutput = ps.Invoke(); } private void Error_DataAdded(object sender, DataAddedEventArgs e) { InvokeMethod(Convert.ToString(e)); } public void InvokeMethod(string text) { if (InvokeRequired) { this.Invoke(new Action<string>(InvokeMethod), new object[] { text }); //hier passiert nichts mehr return; } richTextBox1.AppendText("Bla "); } Meiner Meinung nach hab ich quasi genau das kopiert was auf stackoverflow stand und ich hab es auch in einem neuen Projekt ausprobiert, da funktioniert es, aber in meinem Projekt passiert ab 'this.Invoke(....)' gar nichts mehr. Ich hab es 5 Minuten laufen lassen bevor es mir zu blöd wurde. Die GUI ist zu dieser Zeit auch nicht ansprechbar (logisch, sie wartet eigentlich darauf dass mein ps.Invoke fertig ist - glaube ich). Ich seh im Debug-Modus das noch kurz der Balken für die Ereignisse 2-3 mal ausschlagen, dann ist tote Hose und mein Programm veravschiedet sich ins Nirvana... macht irgendwas und kommt nicht mehr zurück. Was mach ich nur falsch? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Tician Geschrieben 8. Juli 2019 Autor Teilen Geschrieben 8. Juli 2019 Edit: Mein Gedankengang war, dass ich keinen neuen Thread brauche, weil ps.Invoke ja schon einen neuen Thread erstellt. Jetzt hab ich trotzdem alles mal in einen neuen Thread verschoben und nun funktioniert es auch. Mein Error-Text stimmt zwar nicht, aber das sollte ich jetzt auch noch hinkriegen Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
KeeperOfCoffee Geschrieben 8. Juli 2019 Teilen Geschrieben 8. Juli 2019 Du kannst die DataAddedEventArgs einfach so konvertieren? Soviel ich in msdn sehe, besteht das Ding aus nem Indexwert und der PowershellinstanceId Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Tician Geschrieben 8. Juli 2019 Autor Teilen Geschrieben 8. Juli 2019 (bearbeitet) Exakt. Normalerweise benutz ich die EventArgs und die beinhalten auch meine Fehlermeldungen - was hier wohl nicht der Fall war, ich hatte nur geraten. Ich brauch irgendein Interface von meinem sender, hatte eben noch ein tolles Beispiel... und find es nicht mehr. Wie gesagt, ab hier sollte ich erstmal wieder alleine klar kommen @KeeperOfCoffeeDanke! ❤️ Bearbeitet 8. Juli 2019 von Tician Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.