Cara meneruskan argumen baris perintah ke file ps1 PowerShell

90

Selama bertahun-tahun, saya telah menggunakan cmd/DOS/Windowsshell dan memberikan argumen baris perintah ke file batch. Sebagai contoh, saya memiliki sebuah file, zuzu.batdan di dalamnya, akses saya %1, %2, dll Sekarang, saya ingin melakukan hal yang sama ketika saya sebut PowerShellnaskah when I am in a Cmd.exe shell. Saya memiliki skrip, xuxu.ps1(dan saya telah menambahkan PS1 ke variabel PATHEXT saya dan file PS1 terkait dengan PowerShell). Tapi apa pun yang saya lakukan, saya sepertinya tidak bisa mendapatkan apa pun dari $argsvariabel. Itu selalu memiliki panjang 0.

Jika saya berada di PowerShellshell, bukannya cmd.exe, itu berfungsi (tentu saja). Tapi saya belum cukup nyaman untuk hidup di lingkungan PowerShell secara penuh. Saya tidak ingin mengetik powershell.exe -command xuxu.ps1 p1 p2 p3 p4. Saya ingin mengetik xuxu p1 p2 p3 p4.

Apakah ini mungkin dan jika iya, bagaimana?

Sampel yang saya tidak bisa mulai bekerja itu sepele, foo.ps1:

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

Hasilnya selalu seperti ini:

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

Jawaban:

34

Artikel ini membantu. Secara khusus, bagian ini:

-Mengajukan

Menjalankan skrip yang ditentukan dalam cakupan lokal ("dot-source"), sehingga fungsi dan variabel yang dibuat skrip tersedia di sesi saat ini. Masukkan jalur file skrip dan parameter apa pun. File harus menjadi parameter terakhir dalam perintah, karena semua karakter yang diketik setelah nama parameter File diinterpretasikan sebagai jalur file skrip yang diikuti oleh parameter skrip.

yaitu

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

berarti menjalankan file myfile.ps1 dan arg1 arg2 & arg3 adalah parameter untuk skrip PowerShell.

Arj
sumber
1
Ini masih tidak membantu dengan apa yang diinginkan operasi ("Saya ingin mengetik xuxu p1 p2 p3 p4").
thdoan
19

Setelah menggali dokumentasi PowerShell, saya menemukan beberapa informasi berguna tentang masalah ini. Anda tidak dapat menggunakan $argsjika Anda menggunakan param(...)di awal file Anda; sebagai gantinya, Anda harus menggunakan $PSBoundParameters. Saya menyalin / menempelkan kode Anda ke dalam skrip PowerShell, dan berfungsi seperti yang Anda harapkan di PowerShell versi 2 (Saya tidak yakin versi apa yang Anda gunakan saat mengalami masalah ini).

Jika Anda menggunakan $PSBoundParameters(dan ini HANYA berfungsi jika Anda menggunakan param(...)di awal skrip Anda), maka itu bukan array, ini adalah tabel hash, jadi Anda perlu mereferensikannya menggunakan pasangan kunci / nilai.

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

Dan saat dipanggil dengan ...

PS> ./foo.ps1 a b c d

Hasilnya adalah...

Num Args:  4
$p1=a  $p2=b  $p3=c  $p4=d
Randall Borck
sumber
Ini tidak memperhitungkan OP memulai baris perintahnya dengan powershell.exe atau pwsh. Perilaku berubah ketika OP melakukan itu.
Eric Hansen
1
@EricHansen Saya tidak tahu apa yang Anda maksud, saya mendapatkan hasil yang sama: `Powershell> powershell.exe. \ ParamTest.ps1 val1 val2 val3 val4 Num Args: 4 $ p1 = val1 $ p2 = val2 $ p3 = val3 $ p4 = val4 `
Randall Borck
@RandallBrock Perilaku argumen berubah untuk saya. Jika saya dalam CMD / batch, dan saya melakukan sesuatu seperti pwsh .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4itu, sebenarnya tidak seperti itu. Di sisi lain, jika saya menggunakan PowerShell dan melakukannya .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4, itu berfungsi seperti yang saya harapkan. Saya pernah mendengar bahwa ini dimaksudkan untuk berfungsi karena "alasan keamanan."
Eric Hansen
@EricHansen Saya ingin tahu apakah itu adalah hal versi. Bagi saya, pwsh meluncurkan 6.2.0, tetapi powershell.exe meluncurkan 5.1.17134.858, keduanya menghasilkan hasil yang sama terdaftar: Powershell>pwsh .\ParamTest.ps1 val1 val2 val3 val4hasil:Num Args: 4 $p1=val1 $p2=val2 $p3=val3 $p4=val4
Randall Borck
1
@Timo Saya tidak tahu persis apa yang Anda lakukan, tetapi parammerupakan konstruksi bahasa, namun itu harus menjadi hal pertama dalam file. Apakah Anda mendeklarasikan variabel atau sesuatu yang lain sebelumnya? Info lebih lanjut di sini: docs.microsoft.com/en-us/powershell/module/…
Randall Borck
18

Oke, pertama-tama ini melanggar fitur keamanan dasar di PowerShell. Dengan pemahaman tersebut, berikut adalah cara Anda melakukannya:

  1. Buka jendela Windows Explorer
  2. Alat Menu -> Opsi Folder -> tab Jenis File
  3. Temukan jenis file PS1 dan klik tombol lanjutan
  4. Klik tombol Baru
  5. Untuk Action put: Open
  6. Untuk Aplikasi, letakkan: "C: \ WINNT \ system32 \ WindowsPowerShell \ v1.0 \ powershell.exe" "-file" "% 1"% *

Anda mungkin ingin memberikan -NoProfileargumen di sana juga tergantung pada apa yang dilakukan profil Anda.

EBGreen
sumber
4
Saya pikir kuncinya ada di langkah 6 Anda di mana Anda meneruskan parameter ke powershell.exe. Daniel mengatakan dia telah mengaitkan file PS1 dengan PowerShell tetapi itu tidak memberikan argumen tanpa spesifikasi tambahan% 1% *. Perhatikan juga bahwa parameter -File tidak tersedia di V1. Ini baru untuk V2.
Keith Hill
Penangkapan yang bagus tentang parameter -file. Saya lupa itu.
EBGreen
Saya harus menginstal V2 sebelum saya dapat mencoba saran Anda. Terima kasih. Ketika Anda mengatakan ini melanggar fitur keamanan dasar, apa yang Anda maksud dengan "ini"? Memanggil skrip PowerShell dari Cmd.exe seolah-olah itu adalah file .com / .bat / .exe? Meneruskan parameter ke skrip?
Daniel 'Dang' Griffith
1
Maaf saya seharusnya lebih jelas. Memanggil skrip tanpa secara eksplisit memanggil PowerShell.exe. Saya tidak mengatakan ini adalah fitur keamanan yang signifikan untuk Anda secara pribadi dan keamanan melalui ketidakjelasan yang saya tidak selalu menjadi penggemar.
EBGreen
6
Untuk menambah komentar EBGreen, masalah keamanan dasar yang coba dihindari PowerShell adalah orang-orang mengklik dua kali pada file PS1 yang dilampirkan ke email dan menjalankan skrip. Itu sebabnya file PS1 hanya dikaitkan dengan editor secara default. Microsoft benar-benar tidak menginginkan versi PowerShell dari virus ILoveYou misalnya "LOVE-LETTER-FOR-YOU.TXT.ps1"
Keith Hill
11

Anda bisa mendeklarasikan parameter Anda di file, seperti param:

[string]$para1
[string]$param2

Dan kemudian panggil file PowerShell seperti itu .\temp.ps1 para1 para2....para10, dll.

VB
sumber
6

Mungkin Anda bisa membungkus pemanggilan PowerShell dalam .batfile seperti ini:

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

Jika Anda kemudian menempatkan file ini di bawah folder di Anda PATH, Anda dapat memanggil skrip PowerShell seperti ini:

ps foo 1 2 3

Namun, mengutip bisa sedikit berantakan:

ps write-host """hello from cmd!""" -foregroundcolor green
guillermooo
sumber
1 untuk menampilkan tanda kutip tiga. yang membuat saya mandek untuk sementara waktu.
DeanOC
1

Anda mungkin tidak mendapatkan "xuxu p1 p2 p3 p4" seperti yang terlihat. Tetapi ketika Anda berada di PowerShell dan Anda mengatur

PS > set-executionpolicy Unrestricted -scope currentuser

Anda dapat menjalankan skrip tersebut seperti ini:

./xuxu p1 p2 p3 p4

atau

.\xuxu p1 p2 p3 p4

atau

./xuxu.ps1 p1 p2 p3 p4

Saya harap itu membuat Anda sedikit lebih nyaman dengan PowerShell.

Atiq Rahman
sumber
0

jika Anda ingin memanggil skrip ps1 dari cmd dan meneruskan argumen tanpa menjalankan skrip seperti itu

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

Anda dapat melakukan hal berikut

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

Ini dengan asumsi powershell.exe ada di jalur Anda

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

ta32
sumber
Perlu dicatat bahwa ini memerlukan menjalankan prompt cmd sebagai Administrator. Juga, saya berjuang untuk benar-benar membuatnya bekerja pada Windows 10 versi 1903 (18362.778) - semua perintah berjalan dengan sukses tetapi argumen masih tidak bisa diteruskan. Saya pikir membungkus dengan file bat adalah solusi yang paling portabel.
David Airapetyan