Come passare gli argomenti della riga di comando a un file PS1 di PowerShell


90

Per anni ho utilizzato la cmd/DOS/Windowsshell e passato gli argomenti della riga di comando ai file batch. Ad esempio, ho un file, zuzu.bate in essa, l'accesso io %1, %2ecc Ora, voglio fare lo stesso quando io chiamo una PowerShellsceneggiatura when I am in a Cmd.exe shell. Ho uno script xuxu.ps1(e ho aggiunto PS1 alla mia variabile PATHEXT e file PS1 associati con PowerShell). Ma non importa quello che faccio, non riesco a ottenere nulla dalla $argsvariabile. Ha sempre lunghezza 0.

Se sono in una PowerShellshell, invece di cmd.exe, funziona (ovviamente). Ma non sono ancora abbastanza a mio agio per vivere a tempo pieno nell'ambiente PowerShell. Non voglio scrivere powershell.exe -command xuxu.ps1 p1 p2 p3 p4. Voglio scrivere xuxu p1 p2 p3 p4.

È possibile e, se sì, come?

L'esempio che non riesco a far funzionare è banale, foo.ps1:

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

I risultati sono sempre così:

C:\temp> foo
Num Args: 0
C:\temp> foo a b c d
Num Args: 0
c:\temp>

Risposte:


34

Questo articolo aiuta. In particolare, questa sezione:

-File

Esegue lo script specificato nell'ambito locale ("dot-sourced"), in modo che le funzioni e le variabili create dallo script siano disponibili nella sessione corrente. Immettere il percorso del file di script e qualsiasi parametro. File deve essere l'ultimo parametro nel comando, poiché tutti i caratteri digitati dopo il nome del parametro File vengono interpretati come il percorso del file di script seguito dai parametri di script.

cioè

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

significa eseguire il file myfile.ps1 e arg1 arg2 e arg3 sono i parametri per lo script di PowerShell.


1
Questo ancora non aiuta con quello che vuole l'operazione ("Voglio scrivere xuxu p1 p2 p3 p4").
thdoan

19

Dopo aver esaminato la documentazione di PowerShell, ho scoperto alcune informazioni utili su questo problema. Non puoi usare $argsse hai usato param(...)all'inizio del tuo file; invece dovrai usare $PSBoundParameters. Ho copiato / incollato il tuo codice in uno script PowerShell e ha funzionato come ti aspetteresti nella versione 2 di PowerShell (non sono sicuro di quale versione eri quando hai riscontrato questo problema).

Se stai usando $PSBoundParameters(e funziona SOLO se stai usando param(...)all'inizio dello script), allora non è un array, è una tabella hash, quindi dovrai fare riferimento ad esso usando la coppia chiave / valore.

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

E quando viene chiamato con ...

PS> ./foo.ps1 a b c d

Il risultato è ...

Num Args:  4
$p1=a  $p2=b  $p3=c  $p4=d

Questo non tiene conto dell'avvio della riga di comando da parte di OP con powershell.exe o pwsh. Il comportamento cambia quando OP lo fa.
Eric Hansen

1
@EricHansen Non so cosa intendi, ottengo lo stesso risultato in entrambi i casi: `Powershell> powershell.exe. \ ParamTest.ps1 val1 val2 val3 val4 Num Args: 4 $ p1 = val1 $ p2 = val2 $ p3 = val3 $ p4 = val4 `
Randall Borck

@RandallBrock Il comportamento degli argomenti cambia per me. Se sono in CMD / batch e faccio qualcosa del genere pwsh .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4, non mi piace davvero. D'altra parte, se sono in PowerShell e lo faccio .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4, funziona come mi aspetterei. Ho sentito che è così che dovrebbe funzionare per "motivi di sicurezza".
Eric Hansen

@EricHansen mi chiedo se sia una cosa di versione. Per me, pwsh lancia 6.2.0, ma powershell.exe lancia 5.1.17134.858, entrambi producono gli stessi risultati elencati: Powershell>pwsh .\ParamTest.ps1 val1 val2 val3 val4produce:Num Args: 4 $p1=val1 $p2=val2 $p3=val3 $p4=val4
Randall Borck

1
@Timo Non so cosa stai facendo esattamente, ma paramè un costrutto di linguaggio, tuttavia deve essere la prima cosa nel file. Hai dichiarato una variabile o qualcos'altro prima di essa? Maggiori informazioni qui: docs.microsoft.com/en-us/powershell/module/…
Randall Borck

18

OK, quindi per prima cosa si tratta di rompere una funzionalità di sicurezza di base in PowerShell. Con questa comprensione, ecco come puoi farlo:

  1. Apri una finestra di Esplora risorse di Windows
  2. Menu Strumenti -> Opzioni cartella -> scheda Tipi di file
  3. Trova il tipo di file PS1 e fai clic sul pulsante avanzato
  4. Fare clic sul pulsante Nuovo
  5. Per l'azione metti: Apri
  6. Per l'applicazione mettere: "C: \ WINNT \ system32 \ WindowsPowerShell \ v1.0 \ powershell.exe" "-file" "% 1"% *

Potresti anche voler inserire un -NoProfileargomento a seconda di ciò che fa il tuo profilo.


4
Penso che la chiave sia nel passaggio 6 in cui si passano i parametri a powershell.exe. Daniel dice di aver associato i file PS1 a PowerShell ma questo non passa argomenti senza le specifiche% 1% * extra. Notare inoltre che il parametro -File non è disponibile in V1. È nuovo per V2.
Keith Hill,

Buona presa riguardo al parametro -file, l'avevo dimenticato.
EBGreen

Dovrò installare V2 prima di poter provare il tuo suggerimento. Grazie. Quando dici che questo sta violando una funzionalità di sicurezza di base, cosa significa "questo"? Chiamare uno script PowerShell da Cmd.exe come se fosse un file .com / .bat / .exe? Passando parametri allo script?
Daniel 'Dang' Griffith

1
Scusa, avrei dovuto essere più chiaro. La chiamata allo script senza chiamare in modo esplicito powershell.exe. Non sto dicendo che sia una caratteristica di sicurezza significativa per te personalmente ed è la sicurezza attraverso l'oscurità di cui comunque non sono sempre un fan.
EBGreen

6
Per aggiungere al commento di EBGreen, il problema di sicurezza di base che PowerShell cerca di evitare è che la gente fa doppio clic sui file PS1 allegati all'e-mail e fa eseguire lo script. Ecco perché i file PS1 sono associati solo a un editor per impostazione predefinita. Microsoft non vuole davvero una versione PowerShell del virus ILoveYou, ad esempio "LOVE-LETTER-FOR-YOU.TXT.ps1"
Keith Hill

11

Puoi dichiarare i tuoi parametri nel file, come param:

[string]$para1
[string]$param2

E poi chiama il file PowerShell in questo modo .\temp.ps1 para1 para2....para10, ecc.


6

Forse puoi racchiudere l'invocazione di PowerShell in un .batfile in questo modo:

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

Se poi hai inserito questo file in una cartella nel tuo PATH, puoi chiamare gli script di PowerShell come questo:

ps foo 1 2 3

La citazione può diventare un po 'complicata, però:

ps write-host """hello from cmd!""" -foregroundcolor green

+1 per mostrare le virgolette triple. che mi ha bloccato per un po '.
DeanOC

1

Potresti non ottenere "xuxu p1 p2 p3 p4" come sembra. Ma quando sei in PowerShell e imposti

PS > set-executionpolicy Unrestricted -scope currentuser

Puoi eseguire quegli script in questo modo:

./xuxu p1 p2 p3 p4

o

.\xuxu p1 p2 p3 p4

o

./xuxu.ps1 p1 p2 p3 p4

Spero che questo ti metta un po 'più a tuo agio con PowerShell.


0

se si desidera richiamare gli script ps1 da cmd e passare argomenti senza richiamare lo script come

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

puoi fare quanto segue

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

Questo presuppone che powershell.exe sia nel tuo percorso

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


Vale la pena notare che ciò richiede l'esecuzione del prompt di cmd come amministratore. Inoltre, sto lottando per farlo funzionare effettivamente su Windows 10 versione 1903 (18362.778): tutti i comandi vengono eseguiti correttamente ma gli argomenti continuano a non essere passati. Penso che il wrapping con un file .bat sia la soluzione più portatile.
David Airapetyan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.