Hallo Stack Community :)
Ich habe ein einfaches Ziel. Ich möchte ein PowerShell-Skript von einem anderen Powershell-Skript aus starten, aber es gibt drei Bedingungen:
- Ich muss Anmeldeinformationen übergeben (die Ausführung stellt eine Verbindung zu einer Datenbank her, die einen bestimmten Benutzer hat).
- Es müssen einige Parameter benötigt werden
- Ich möchte die Ausgabe an eine Variable übergeben
Es gibt eine ähnliche Frage Link . Die Antwort ist jedoch, Dateien als Kommunikationsmittel zwischen zwei PS-Skripten zu verwenden. Ich möchte nur Zugriffskonflikte vermeiden. @Update: Das Hauptskript startet einige andere Skripte. Daher kann die Lösung mit Dateien schwierig sein, wenn die Ausführung von mehreren Benutzern gleichzeitig ausgeführt wird.
Script1.ps1 ist das Skript, das eine Zeichenfolge als Ausgabe haben sollte. (Nur um klar zu sein, es ist ein fiktives Skript, das echte hat 150 Zeilen, also wollte ich nur ein Beispiel machen)
param(
[String]$DeviceName
)
#Some code that needs special credentials
$a = "Device is: " + $DeviceName
$a
ExecuteScripts.ps1 sollte diese mit den drei oben genannten Bedingungen aufrufen
Ich habe mehrere Lösungen ausprobiert. Dieser zum Beispiel:
$arguments = "C:\..\script1.ps1" + " -ClientName" + $DeviceName
$output = Start-Process powershell -ArgumentList $arguments -Credential $credentials
$output
Ich bekomme keine Ausgabe davon und kann das Skript nicht einfach mit aufrufen
&C:\..\script1.ps1 -ClientName PCPC
Weil ich ihm keinen -Credential
Parameter übergeben kann.
Vielen Dank im Voraus!
quelle
Antworten:
Hinweis:
Die folgende Lösung funktioniert mit jedem externen Programm und erfasst die Ausgabe immer als Text .
Informationen zum Aufrufen einer anderen PowerShell-Instanz und zum Erfassen ihrer Ausgabe als Rich-Objekte (mit Einschränkungen) finden Sie in der Variantenlösung im unteren Abschnitt oder in der hilfreichen Antwort von Mathias R. Jessen , die das PowerShell-SDK verwendet .
Hier ist ein Proof-of-Concept, der auf der direkten Verwendung der Typen
System.Diagnostics.Process
undSystem.Diagnostics.ProcessStartInfo
.NET zum Erfassen der Prozessausgabe im Speicher basiert (wie in Ihrer Frage angegeben,Start-Process
ist keine Option, da nur das Erfassen der Ausgabe in Dateien unterstützt wird , wie in dieser Antwort gezeigt ). ::Hinweis:
Aufgrund der Ausführung als anderer Benutzer wird dies nur unter Windows (ab .NET Core 3.1) unterstützt, jedoch in beiden PowerShell-Editionen.
Da
.WindowStyle
der Befehl als anderer Benutzer ausgeführt werden muss und die Ausgabe erfasst werden muss, kann er nicht zum Ausführen des ausgeblendeten Befehls verwendet werden (da die Verwendung.WindowStyle
erforderlich.UseShellExecute
ist$true
, was mit diesen Anforderungen nicht kompatibel ist). Da jedoch alle Ausgaben erfasst werden , führt die Einstellung.CreateNoNewWindow
auf$true
effektiv zu einer versteckten Ausführung.Das Obige ergibt ungefähr Folgendes, was zeigt, dass der Prozess mit der angegebenen Benutzeridentität erfolgreich ausgeführt wurde:
Da Sie eine andere PowerShell- Instanz aufrufen , möchten Sie möglicherweise die Fähigkeit der PowerShell-CLI nutzen , die Ausgabe im CLIXML-Format darzustellen, wodurch die Ausgabe in umfangreiche Objekte deserialisiert werden kann , wenn auch mit eingeschränkter Typentreue , wie in dieser Antwort erläutert .
Die obigen Ausgaben geben ungefähr Folgendes aus und zeigen, dass die von
[datetime]
(System.DateTime
) ausgegebene Instanz ( )Get-Date
als solche deserialisiert wurde:quelle
Start-Process
Dies wäre meine letzte Wahl, um PowerShell über PowerShell aufzurufen - insbesondere, weil alle E / A zu Zeichenfolgen und nicht zu (deserialisierten) Objekten werden.Zwei Alternativen:
1. Wenn der Benutzer ein lokaler Administrator ist und PSRemoting konfiguriert ist
Wenn eine Remote-Sitzung auf dem lokalen Computer (leider nur für lokale Administratoren möglich) möglich ist, würde ich auf jeden Fall Folgendes wählen
Invoke-Command
:$strings
wird die Ergebnisse enthalten.2. Wenn der Benutzer kein Administrator auf dem Zielsystem ist
Sie können Ihr eigenes "Nur-Lokal
Invoke-Command
" schreiben, indem Sie einen Out-of-Process-Runspace hochfahren, indem Sie:PowerShellProcessInstance
unter einem anderen LoginIch habe eine solche Funktion unten zusammengestellt, siehe Inline-Kommentare für eine Anleitung:
Dann verwenden Sie wie folgt:
quelle
rcv.ps1
Ausführung von einem anderen Skript:
Ausgabe:
quelle
Was Sie tun können, ist Folgendes, um einen Parameter an ein ps1-Skript zu übergeben.
Das erste Skript kann eine origin.ps1 sein, in die wir schreiben:
Das Zielskript dest.ps1 kann den folgenden Code zum Erfassen der Variablen enthalten
Und das Ergebnis wird sein
quelle
-Credential $credentials
Parameter an diese Ausführung übergeben und die Ausgabe davon in eine Variable erhalten. Die ps1. Das Skript, das ausgeführt wird, wirft am Ende eine einzelne Wortfolge. Schauen Sie sich nur an, wie ich es gemacht habe,Start-process
aber diese Funktion generiert keine Ausgabe$output
Variable zuzugreifen , ist sie NULL. Die andere Idee, die von @ mklement0 kam, ist das Speichern der Ausgabe in einer Datei. Aber in meinem Fall wird es eine große Menge von Dateien an einem Ort verursachen. Alle von verschiedenen Benutzern mit verschiedenen Skripten erstellt