it-swarm.com.de

Starten von .ps1 Script aus PowerShell mit Parametern und Anmeldeinformationen und Abrufen der Ausgabe mithilfe von Variablen

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:

  1. Ich muss Anmeldeinformationen übergeben (die Ausführung stellt eine Verbindung zu einer Datenbank her, die einen bestimmten Benutzer hat).
  2. Es müssen einige Parameter benötigt werden
  3. 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 dieses mit diesen 3 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 den Parameter -Credential Nicht übergeben kann.

Vielen Dank im Voraus!

10
Dmytro

Hinweis:

  • Die folgende Lösung funktioniert mit any externem Programm und erfasst die Ausgabe immer als text.

  • Um eine andere PowerShell-Instanz aufzurufen und erfassen Sie deren Ausgabe als Rich-Objekte (mit Einschränkungen), siehe die Variantenlösung im unteren Abschnitt oder betrachten Sie die hilfreiche Antwort von Mathias R. Jessen , die das PowerShell SDK verwendet.

Hier ist ein Proof-of-Concept, der auf direkter Verwendung des System.Diagnostics.Process und System.Diagnostics.ProcessStartInfo .NET-Typen zum Erfassen der Prozessausgabe im Speicher (wie in Ihrer Frage angegeben, Start-Process ist keine Option, da es nur die Erfassung der Ausgabe in Dateien unterstützt, wie in diese Antwort ) gezeigt:

Hinweis:

  • Aufgrund der Ausführung als anderer Benutzer wird dies unter nur Windows (ab .NET Core 3.1) unterstützt, jedoch in beiden PowerShell-Editionen.

  • Aufgrund der Notwendigkeit, als anderer Benutzer ausgeführt zu werden und die Ausgabe zu erfassen, .WindowStyle kann nicht zum Ausführen des Befehls verwendet werden hidden (weil mit .WindowStyle erfordert .UseShellExecute sein $true, was mit diesen Anforderungen nicht vereinbar ist); Da jedoch alle Ausgaben erfasst sind, wird .CreateNoNewWindow bis $true führt effektiv zu einer versteckten Ausführung.

# Get the target user's name and password.
$cred = Get-Credential

# Create a ProcessStartInfo instance
# with the relevant properties.
$psi = [System.Diagnostics.ProcessStartInfo] @{
  # For demo purposes, use a simple `cmd.exe` command that echoes the username. 
  # See the bottom section for a call to `powershell.exe`.
  FileName = 'cmd.exe'
  Arguments = '/c echo %USERNAME%'
  # Set this to a directory that the target user
  # is permitted to access.
  WorkingDirectory = 'C:\'                                                                   #'
  # Ask that output be captured in the
  # .StandardOutput / .StandardError properties of
  # the Process object created later.
  UseShellExecute = $false # must be $false
  RedirectStandardOutput = $true
  RedirectStandardError = $true
  # Uncomment this line if you want the process to run effectively hidden.
  #   CreateNoNewWindow = $true
  # Specify the user identity.
  # Note: If you specify a UPN in .UserName
  # ([email protected]), set .Domain to $null
  Domain = $env:USERDOMAIN
  UserName = $cred.UserName
  Password = $cred.Password
}

# Create (launch) the process...
$ps = [System.Diagnostics.Process]::Start($psi)

# Read the captured standard output.
# By reading to the *end*, this implicitly waits for (near) termination
# of the process.
# Do NOT use $ps.WaitForExit() first, as that can result in a deadlock.
$stdout = $ps.StandardOutput.ReadToEnd()

# Uncomment the following lines to report the process' exit code.
#   $ps.WaitForExit()
#   "Process exit code: $($ps.ExitCode)"

"Running ``cmd /c echo %USERNAME%`` as user $($cred.UserName) yielded:"
$stdout

Das Obige ergibt ungefähr Folgendes, was zeigt, dass der Prozess mit der angegebenen Benutzeridentität erfolgreich ausgeführt wurde:

Running `cmd /c echo %USERNAME%` as user jdoe yielded:
jdoe

Da Sie eine andere PowerShell Instanz aufrufen, möchten Sie möglicherweise die PowerShell) nutzen CLI 's Fähigkeit, die Ausgabe im CLIXML-Format darzustellen, wodurch die Ausgabe in reiche Objekte deserialisiert werden kann, wenn auch mit begrenzter Typentreue , wie in erklärt) diese verwandte Antwort .

# Get the target user's name and password.
$cred = Get-Credential

# Create a ProcessStartInfo instance
# with the relevant properties.
$psi = [System.Diagnostics.ProcessStartInfo] @{
  # Invoke the PowerShell CLI with a simple sample command
  # that calls `Get-Date` to output the current date as a [datetime] instance.
  FileName = 'powershell.exe'
  # `-of xml` asks that the output be returned as CLIXML,
  # a serialization format that allows deserialization into
  # rich objects.
  Arguments = '-of xml -noprofile -c Get-Date'
  # Set this to a directory that the target user
  # is permitted to access.
  WorkingDirectory = 'C:\'                                                                   #'
  # Ask that output be captured in the
  # .StandardOutput / .StandardError properties of
  # the Process object created later.
  UseShellExecute = $false # must be $false
  RedirectStandardOutput = $true
  RedirectStandardError = $true
  # Uncomment this line if you want the process to run effectively hidden.
  #   CreateNoNewWindow = $true
  # Specify the user identity.
  # Note: If you specify a UPN in .UserName
  # ([email protected]), set .Domain to $null
  Domain = $env:USERDOMAIN
  UserName = $cred.UserName
  Password = $cred.Password
}

# Create (launch) the process...
$ps = [System.Diagnostics.Process]::Start($psi)

# Read the captured standard output, in CLIXML format,
# stripping the `#` comment line at the top (`#< CLIXML`)
# which the deserializer doesn't know how to handle.
$stdoutCliXml = $ps.StandardOutput.ReadToEnd() -replace '^#.*\r?\n'

# Uncomment the following lines to report the process' exit code.
#   $ps.WaitForExit()
#   "Process exit code: $($ps.ExitCode)"

# Use PowerShell's deserialization API to 
# "rehydrate" the objects.
$stdoutObjects = [Management.Automation.PSSerializer]::Deserialize($stdoutCliXml)

"Running ``Get-Date`` as user $($cred.UserName) yielded:"
$stdoutObjects
"`nas data type:"
$stdoutObjects.GetType().FullName

Das Obige gibt ungefähr Folgendes aus und zeigt, dass das [datetime] Instanz ( System.DateTime ) Ausgabe von Get-Date wurde als solche deserialisiert:

Running `Get-Date` as user jdoe yielded:

Friday, March 27, 2020 6:26:49 PM

as data type:
System.DateTime
2
mklement0

Was Sie tun können, ist Folgendes, um einen Parameter an ein ps1-Skript zu übergeben.

Das erste Skript kann ein Origin.ps1 sein, in dem wir schreiben:

& C:\scripts\dest.ps1 Pa$$w0rd parameter_a parameter_n

Das Zielskript dest.ps1 kann den folgenden Code zum Erfassen der Variablen enthalten

$var0 = $args[0]
$var1 = $args[1]
$var2 = $args[2]
Write-Host "my args",$var0,",",$var1,",",$var2

Und das Ergebnis wird sein

my args Pa$$w0rd, parameter_a, parameter_n
0
Andy McRae

rcv.ps1

param(
    $username,
    $password
)

"The user is:  $username"
"My super secret password is:  $password"

ausführung von einem anderen Skript:

.\rcv.ps1 'user' 'supersecretpassword'

ausgabe:

The user is:  user
My super secret password is:  supersecretpassword
0
thepip3r