web-dev-qa-db-fra.com

Démarrage du script .ps1 à partir de PowerShell avec des paramètres et des informations d'identification et obtention de la sortie à l'aide d'une variable

Bonjour la communauté Stack :)

J'ai un objectif simple. J'aimerais démarrer un script PowerShell à partir d'un autre script Powershell, mais il y a 3 conditions:

  1. Je dois passer des informations d'identification (l'exécution se connecte à une base de données qui a un utilisateur spécifique)
  2. Il doit prendre quelques paramètres
  3. Je voudrais passer la sortie dans une variable

Il y a une question similaire Lien . Mais la réponse est d'utiliser des fichiers comme moyen de communiquer entre 2 scripts PS. Je voudrais simplement éviter les conflits d'accès. @Update: Le script principal va démarrer quelques autres scripts. donc la solution avec les fichiers peut être délicate, si l'exécution sera effectuée à partir de plusieurs utilisateurs en même temps.

Script1.ps1 est le script qui doit avoir une chaîne en sortie. (Juste pour être clair, c'est un script fictif, le vrai a 150 lignes, donc je voulais juste faire un exemple)

param(  
[String]$DeviceName
)
#Some code that needs special credentials
$a = "Device is: " + $DeviceName
$a

ExecuteScripts.ps1 devrait invoquer celui-là avec les 3 conditions mentionnées ci-dessus

J'ai essayé plusieurs solutions. Celui-ci pour exemple:

$arguments = "C:\..\script1.ps1" + " -ClientName" + $DeviceName
$output = Start-Process powershell -ArgumentList $arguments -Credential $credentials
$output 

Je n'obtiens aucun résultat et je ne peux pas simplement appeler le script avec

&C:\..\script1.ps1 -ClientName PCPC

Parce que je ne peux pas passer -Credential paramètre à lui ..

Merci d'avance!

10
Dmytro

Remarque:

  • La solution suivante fonctionne avec any programme externe , et capture la sortie invariablement comme texte.

  • Pour invoquer une autre instance PowerShell et capturer sa sortie comme objets riches (avec des limitations), voir la variante de solution dans la section du bas ou considérer réponse utile de Mathias R. Jessen , qui utilise le - SDK PowerShell .

Voici une preuve de concept basée sur l'utilisation directe de System.Diagnostics.Process et System.Diagnostics.ProcessStartInfo Types .NET pour capturer la sortie du processus en mémoire (comme indiqué dans votre question, Start-Process n'est pas une option, car il ne prend en charge que la capture de la sortie dans files, comme indiqué dans cette réponse ):

Remarque:

  • En raison de l'exécution en tant qu'utilisateur différent, cela est pris en charge sur Windows uniquement (à partir de .NET Core 3.1), mais dans les deux éditions PowerShell.

  • En raison de la nécessité de s'exécuter en tant qu'utilisateur différent et de capturer la sortie, .WindowStyle ne peut pas être utilisé pour exécuter la commande hidden (car l'utilisation de .WindowStyle a besoin .UseShellExecute être $true, qui est incompatible avec ces exigences); cependant, puisque toute la sortie est capturée, le réglage .CreateNoNewWindow à $true entraîne effectivement une exécution masquée.

# 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

Ce qui précède donne quelque chose comme ce qui suit, montrant que le processus s'est exécuté avec succès avec l'identité d'utilisateur donnée:

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

Puisque vous appelez une autre instance PowerShell, vous pouvez prendre avantage de la capacité de PowerShell CLI à représenter la sortie au format CLIXML, qui permet de désérialiser la sortie en objets riches, mais avec une fidélité de type limitée , comme expliqué dans cette réponse connexe .

# 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

Ce qui précède produit quelque chose comme ce qui suit, montrant que le [datetime] exemple ( System.DateTime ) sortie par Get-Date a été désérialisé comme tel:

Running `Get-Date` as user jdoe yielded:

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

as data type:
System.DateTime
2
mklement0

Ce que vous pouvez faire, procédez comme suit pour transmettre un paramètre à un script ps1.

Le premier script peut être un Origin.ps1 où nous écrivons:

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

Le script de destination dest.ps1 peut avoir le code suivant pour capturer les variables

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

Et le résultat sera

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"

exécution à partir d'un autre script:

.\rcv.ps1 'user' 'supersecretpassword'

production:

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