Comment passer des arguments de ligne de commande à un fichier PowerShell PS1

90

Pendant des années, j'ai utilisé le cmd/DOS/Windowsshell et transmis des arguments de ligne de commande aux fichiers batch. Par exemple, j'ai un fichier, zuzu.batet ce, accès I %1, %2etc. Maintenant, je veux faire la même chose quand j'appelle un PowerShellscénario when I am in a Cmd.exe shell. J'ai un script xuxu.ps1(et j'ai ajouté PS1 à ma variable PATHEXT et aux fichiers PS1 associés avec PowerShell). Mais quoi que je fasse, il me semble incapable d'obtenir quoi que ce soit de la $argsvariable. Il a toujours la longueur 0.

Si je suis dans un PowerShellshell, au lieu de cmd.exeça, ça marche (bien sûr). Mais je ne suis pas encore assez à l'aise pour vivre dans l'environnement PowerShell à plein temps. Je ne veux pas taper powershell.exe -command xuxu.ps1 p1 p2 p3 p4. Je veux taper xuxu p1 p2 p3 p4.

Est-ce possible, et si oui comment?

L'exemple que je ne peux pas obtenir au travail est trivial, foo.ps1:

Write-Host "Num Args:" $args.Length;
foreach ($arg in $args) {
    Write-Host "Arg: $arg";
}

Les résultats sont toujours comme ceci:

C:\temp> foo
Num Args: 0
C:\temp> foo a b c d
Num Args: 0
c:\temp>
Daniel 'Dang' Griffith
la source

Réponses:

34

Cet article aide. En particulier, cette section:

-Fichier

Exécute le script spécifié dans la portée locale ("dot-sourced"), de sorte que les fonctions et les variables créées par le script soient disponibles dans la session en cours. Entrez le chemin du fichier de script et tous les paramètres. File doit être le dernier paramètre de la commande, car tous les caractères saisis après le nom du paramètre File sont interprétés comme le chemin du fichier de script suivi des paramètres de script.

c'est à dire

powershell.exe -File "C:\myfile.ps1" arg1 arg2 arg3

signifie exécuter le fichier myfile.ps1 et arg1 arg2 & arg3 sont les paramètres du script PowerShell.

Arj
la source
1
Cela n'aide toujours pas avec ce que l'op veut ("Je veux taper xuxu p1 p2 p3 p4").
thdoan
19

Après avoir fouillé dans la documentation PowerShell, j'ai découvert des informations utiles sur ce problème. Vous ne pouvez pas utiliser le $argssi vous avez utilisé le param(...)au début de votre fichier; à la place, vous devrez utiliser $PSBoundParameters. J'ai copié / collé votre code dans un script PowerShell, et cela a fonctionné comme prévu dans PowerShell version 2 (je ne sais pas quelle version vous étiez lorsque vous avez rencontré ce problème).

Si vous utilisez $PSBoundParameters(et cela fonctionne UNIQUEMENT si vous utilisez param(...)au début de votre script), ce n'est pas un tableau, c'est une table de hachage, vous devrez donc le référencer à l'aide de la paire clé / valeur.

param($p1, $p2, $p3, $p4)
$Script:args=""
write-host "Num Args: " $PSBoundParameters.Keys.Count
foreach ($key in $PSBoundParameters.keys) {
    $Script:args+= "`$$key=" + $PSBoundParameters["$key"] + "  "
}
write-host $Script:args

Et lorsqu'il est appelé avec ...

PS> ./foo.ps1 a b c d

Le résultat est...

Num Args:  4
$p1=a  $p2=b  $p3=c  $p4=d
Randall Borck
la source
Cela ne tient pas compte du démarrage par OP de sa ligne de commande avec powershell.exe ou pwsh. Le comportement change lorsque OP fait cela.
Eric Hansen
1
@EricHansen Je ne sais pas ce que vous voulez dire, j'obtiens le même résultat dans les deux cas: `Powershell> powershell.exe. \ ParamTest.ps1 val1 val2 val3 val4 Num Args: 4 $ p1 = val1 $ p2 = val2 $ p3 = val3 $ p4 = val4 `
Randall Borck
@RandallBrock Le comportement des arguments change pour moi. Si je suis dans CMD / batch, et que je fais quelque chose comme pwsh .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4ça, ça n'aime vraiment pas ça. D'un autre côté, si je suis dans PowerShell et .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4que je le fais , cela fonctionne comme je m'y attendais. J'ai entendu dire que c'est ainsi qu'il est censé fonctionner pour des «raisons de sécurité».
Eric Hansen
@EricHansen Je me demande si c'est une version. Pour moi, pwsh lance 6.2.0, mais powershell.exe lance 5.1.17134.858, qui produisent tous les deux les mêmes résultats listés: Powershell>pwsh .\ParamTest.ps1 val1 val2 val3 val4donne:Num Args: 4 $p1=val1 $p2=val2 $p3=val3 $p4=val4
Randall Borck
1
@Timo Je ne sais pas ce que vous faites exactement, mais paramc'est une construction de langage, cependant cela doit être la première chose dans le fichier. Avez-vous déclaré une variable ou autre chose avant? Plus d'informations ici: docs.microsoft.com/en-us/powershell/module/…
Randall Borck
18

OK, donc d'abord, cela brise une fonctionnalité de sécurité de base dans PowerShell. Avec cette compréhension, voici comment vous pouvez le faire:

  1. Ouvrez une fenêtre de l' Explorateur Windows
  2. Outils de menu -> Options des dossiers -> onglet Types de fichiers
  3. Trouvez le type de fichier PS1 et cliquez sur le bouton avancé
  4. Cliquez sur le bouton Nouveau
  5. Pour l'action mettre: Ouvrir
  6. Pour l'application, mettez: "C: \ WINNT \ system32 \ WindowsPowerShell \ v1.0 \ powershell.exe" "-file" "% 1"% *

Vous voudrez peut-être y ajouter un -NoProfileargument en fonction de ce que fait votre profil.

EBGreen
la source
4
Je pense que la clé est dans votre étape 6 où vous passez les paramètres à powershell.exe. Daniel dit qu'il a associé des fichiers PS1 à PowerShell mais que cela ne transmet pas d'arguments sans les spécifications supplémentaires de% 1% *. Notez également que le paramètre -File n'est pas disponible dans V1. C'est nouveau dans V2.
Keith Hill
Bonne prise concernant le paramètre -file, j'avais oublié cela.
EBGreen
Je vais devoir installer V2 avant de pouvoir essayer votre suggestion. Merci. Quand vous dites que cela brise une fonction de sécurité de base, que signifie «ceci»? Vous appelez un script PowerShell depuis Cmd.exe comme s'il s'agissait d'un fichier .com / .bat / .exe? Passer des paramètres au script?
Daniel 'Dang' Griffith
1
Désolé, j'aurais dû être plus clair. L'appel du script sans appeler explicitement powershell.exe. Je ne dis pas que c'est une fonctionnalité de sécurité importante pour vous personnellement et que c'est la sécurité par l'obscurité dont je ne suis pas toujours fan de toute façon.
EBGreen
6
Pour ajouter au commentaire d'EBGreen, le problème de sécurité de base que PowerShell essaie d'éviter est que les gens double-cliquent sur les fichiers PS1 joints à l'e-mail et exécutent le script. C'est pourquoi les fichiers PS1 sont uniquement associés à un éditeur par défaut. Microsoft ne veut vraiment pas d'une version PowerShell du virus ILoveYou, par exemple "LOVE-LETTER-FOR-YOU.TXT.ps1"
Keith Hill
11

Vous pouvez déclarer vos paramètres dans le fichier, comme param:

[string]$para1
[string]$param2

Et puis appelez le fichier PowerShell comme ça .\temp.ps1 para1 para2....para10, etc.

VB
la source
6

Vous pouvez peut-être encapsuler l'invocation PowerShell dans un .batfichier comme ceci:

rem ps.bat
@echo off
powershell.exe -command "%*"

Si vous avez ensuite placé ce fichier dans un dossier de votre PATH, vous pouvez appeler des scripts PowerShell comme celui-ci:

ps foo 1 2 3

Les citations peuvent cependant être un peu compliquées:

ps write-host """hello from cmd!""" -foregroundcolor green
Guillermooo
la source
+1 pour afficher les guillemets triples. cela m'a coincé pendant un moment.
DeanOC
1

Vous ne pouvez pas obtenir "xuxu p1 p2 p3 p4" comme il semble. Mais lorsque vous êtes dans PowerShell et que vous définissez

PS > set-executionpolicy Unrestricted -scope currentuser

Vous pouvez exécuter ces scripts comme ceci:

./xuxu p1 p2 p3 p4

ou

.\xuxu p1 p2 p3 p4

ou

./xuxu.ps1 p1 p2 p3 p4

J'espère que cela vous rend un peu plus à l'aise avec PowerShell.

Atiq Rahman
la source
0

si vous souhaitez appeler des scripts ps1 à partir de cmd et passer des arguments sans appeler le script comme

powershell.exe script.ps1 -c test
script -c test ( wont work )

vous pouvez faire ce qui suit

setx PATHEXT "%PATHEXT%;.PS1;" /m
assoc .ps1=Microsoft.PowerShellScript.1
ftype Microsoft.PowerShellScript.1=powershell.exe "%1" %*

Cela suppose que powershell.exe est sur votre chemin

https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/ftype

ta32
la source
Il convient de noter que cela nécessite d'exécuter l'invite cmd en tant qu'administrateur. De plus, j'ai du mal à le faire fonctionner sur Windows 10 version 1903 (18362.778) - toutes les commandes s'exécutent avec succès mais les arguments ne sont toujours pas transmis. Je pense que l'encapsulation avec un fichier .bat est la solution la plus portable.
David Airapetyan le