วิธีส่งอาร์กิวเมนต์บรรทัดคำสั่งไปยังไฟล์ PowerShell ps1


90

เป็นเวลาหลายปีแล้วที่ฉันใช้cmd/DOS/Windowsเชลล์และส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่งไปยังไฟล์แบตช์ ตัวอย่างเช่นผมมีไฟล์zuzu.batและในนั้นเข้าถึงฉัน%1, %2ฯลฯ ตอนนี้ผมต้องการที่จะทำเช่นเดียวกันเมื่อผมเรียกสคริปต์PowerShell when I am in a Cmd.exe shellฉันมีสคริปต์xuxu.ps1(และฉันได้เพิ่ม PS1 ลงในตัวแปร PATHEXT และไฟล์ PS1 ที่เชื่อมโยงกับ PowerShell) แต่ไม่ว่าฉันจะทำยังไงฉันก็ไม่สามารถรับอะไรจาก$argsตัวแปรได้เลย มันมีความยาวเป็น 0 เสมอ

ถ้าฉันอยู่ในPowerShellเปลือกหอยแทนที่จะcmd.exeได้ผล (แน่นอน) แต่ฉันยังไม่สบายใจพอที่จะอยู่ในสภาพแวดล้อม PowerShell แบบเต็มเวลา powershell.exe -command xuxu.ps1 p1 p2 p3 p4ฉันไม่ต้องการที่จะพิมพ์ xuxu p1 p2 p3 p4ฉันต้องการที่จะพิมพ์

เป็นไปได้หรือไม่และถ้าเป็นเช่นนั้นได้อย่างไร

ตัวอย่างที่ฉันไม่สามารถไปทำงานได้นั้นไม่สำคัญ foo.ps1:

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

ผลลัพธ์มักจะเป็นเช่นนี้:

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

คำตอบ:


34

บทความนี้ช่วยได้ โดยเฉพาะอย่างยิ่งส่วนนี้:

-ไฟล์

รันสคริปต์ที่ระบุในขอบเขตโลคัล ("dot-sourced") เพื่อให้ฟังก์ชันและตัวแปรที่สคริปต์สร้างขึ้นพร้อมใช้งานในเซสชันปัจจุบัน ป้อนพา ธ ไฟล์สคริปต์และพารามิเตอร์ใด ๆ ไฟล์ต้องเป็นพารามิเตอร์สุดท้ายในคำสั่งเนื่องจากอักขระทั้งหมดที่พิมพ์หลังชื่อพารามิเตอร์ File ถูกตีความว่าเป็นพา ธ ไฟล์สคริปต์ตามด้วยพารามิเตอร์สคริปต์

กล่าวคือ

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

หมายถึงเรียกใช้ไฟล์ myfile.ps1 และ arg1 arg2 & arg3 เป็นพารามิเตอร์สำหรับสคริปต์ PowerShell


1
สิ่งนี้ยังไม่ช่วยในสิ่งที่ฝ่ายปฏิบัติการต้องการ ("ฉันต้องการพิมพ์xuxu p1 p2 p3 p4")
thdoan

19

หลังจากอ่านเอกสาร PowerShell ฉันพบข้อมูลที่เป็นประโยชน์เกี่ยวกับปัญหานี้ คุณไม่สามารถใช้$argsถ้าคุณใช้param(...)ที่จุดเริ่มต้นของไฟล์ของคุณ คุณจะต้องใช้$PSBoundParametersแทน ฉันคัดลอก / วางโค้ดของคุณลงในสคริปต์ PowerShell และทำงานได้ตามที่คุณคาดหวังใน PowerShell เวอร์ชัน 2 (ฉันไม่แน่ใจว่าคุณใช้เวอร์ชันใดเมื่อคุณพบปัญหานี้)

หากคุณกำลังใช้$PSBoundParameters(และใช้ได้เฉพาะเมื่อคุณใช้param(...)ที่จุดเริ่มต้นของสคริปต์ของคุณ) แสดงว่าไม่ใช่อาร์เรย์ แต่เป็นตารางแฮชดังนั้นคุณจะต้องอ้างอิงโดยใช้คู่คีย์ / ค่า

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

และเมื่อเรียกด้วย ...

PS> ./foo.ps1 a b c d

ผลลัพธ์คือ ...

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

สิ่งนี้ไม่ได้คำนึงถึง OP ที่เริ่มต้นบรรทัดคำสั่งด้วย powershell.exe หรือ pwsh พฤติกรรมจะเปลี่ยนไปเมื่อ OP ทำเช่นนั้น
Eric Hansen

1
@EricHansen ฉันไม่รู้ว่าคุณหมายถึงอะไรฉันได้ผลลัพธ์เดียวกันไม่ว่าจะด้วยวิธีใดก็ตาม: `` Powershell> powershell.exe. \ ParamTest.ps1 val1 val2 val3 val4 Num Args: 4 $ p1 = val1 $ p2 = val2 $ p3 = val3 $ p4 = val4 `
Randall Borck

@RandallBrock พฤติกรรมของอาร์กิวเมนต์เปลี่ยนไปสำหรับฉัน ถ้าฉันอยู่ใน CMD / batch และฉันทำอะไรแบบpwsh .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4นั้นมันจะไม่เป็นอย่างนั้นจริงๆ ในทางกลับกันถ้าฉันอยู่ใน PowerShell และทำได้ก็จะได้.\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4ผลอย่างที่ฉันคาดหวัง ฉันได้ยินมาว่านี่เป็นวิธีการทำงานเนื่องจาก "เหตุผลด้านความปลอดภัย"
Eric Hansen

@EricHansen ฉันสงสัยว่ามันเป็นสิ่งที่รุ่น สำหรับฉัน pwsh เปิดตัว 6.2.0 แต่ powershell.exe เปิดตัว 5.1.17134.858 ซึ่งทั้งสองอย่างให้ผลลัพธ์เดียวกัน: Powershell>pwsh .\ParamTest.ps1 val1 val2 val3 val4อัตราผลตอบแทน:Num Args: 4 $p1=val1 $p2=val2 $p3=val3 $p4=val4
Randall Borck

1
@Timo ฉันไม่รู้ว่าคุณกำลังทำอะไรกันแน่ แต่paramเป็นการสร้างภาษาอย่างไรก็ตามมันต้องเป็นสิ่งแรกในไฟล์ คุณได้ประกาศตัวแปรหรืออย่างอื่นก่อนหน้านี้หรือไม่? ข้อมูลเพิ่มเติมที่นี่: docs.microsoft.com/en-us/powershell/module/…
Randall Borck

18

ตกลงก่อนอื่นนี่เป็นการทำลายคุณสมบัติความปลอดภัยขั้นพื้นฐานใน PowerShell ด้วยความเข้าใจดังกล่าวคุณสามารถทำได้ดังนี้:

  1. เปิดหน้าต่างWindows Explorer
  2. เครื่องมือเมนู-> ตัวเลือกโฟลเดอร์ -> ประเภทไฟล์แท็บ
  3. ค้นหาประเภทไฟล์ PS1 และคลิกปุ่มขั้นสูง
  4. คลิกปุ่มใหม่
  5. สำหรับ Action put: เปิด
  6. สำหรับแอปพลิเคชันให้ใส่: "C: \ WINNT \ system32 \ WindowsPowerShell \ v1.0 \ powershell.exe" "-file" "% 1"% *

คุณอาจต้องการ-NoProfileโต้แย้งด้วยขึ้นอยู่กับว่าโปรไฟล์ของคุณทำอะไร


4
ฉันคิดว่ากุญแจอยู่ในขั้นตอนที่ 6 ของคุณซึ่งคุณส่งผ่านพารามิเตอร์ไปยัง powershell.exe Daniel กล่าวว่าเขาได้เชื่อมโยงไฟล์ PS1 กับ PowerShell แต่ไม่ได้ส่งผ่านข้อโต้แย้งที่ไม่มีข้อกำหนดพิเศษ% 1% * โปรดทราบว่าพารามิเตอร์ -File ไม่พร้อมใช้งานใน V1 เป็นเรื่องใหม่สำหรับ V2
Keith Hill

สิ่งที่ดีเกี่ยวกับพารามิเตอร์ -file ฉันลืมไปแล้ว
EBGreen

ฉันจะต้องติดตั้ง V2 ก่อนจึงจะลองทำตามคำแนะนำของคุณได้ ขอบคุณ. เมื่อคุณบอกว่านี่เป็นการทำลายคุณลักษณะด้านความปลอดภัยขั้นพื้นฐานคุณหมายความว่าอย่างไร เรียกสคริปต์ PowerShell จาก Cmd.exe ราวกับว่าเป็นไฟล์. com / .bat / .exe? ส่งผ่านพารามิเตอร์ไปยังสคริปต์?
Daniel 'Dang' Griffith

1
ขอโทษฉันควรจะชัดเจนกว่านี้ การเรียกสคริปต์โดยไม่เรียก powershell.exe อย่างชัดเจน ฉันไม่ได้บอกว่ามันเป็นคุณสมบัติการรักษาความปลอดภัยที่สำคัญสำหรับคุณเป็นการส่วนตัวและเป็นการรักษาความปลอดภัยผ่านความคลุมเครือซึ่งฉันก็ไม่ได้เป็นแฟนคลับเสมอไป
EBGreen

6
หากต้องการเพิ่มความคิดเห็นของ EBGreen ปัญหาด้านความปลอดภัยขั้นพื้นฐานที่ PowerShell พยายามหลีกเลี่ยงคือการดับเบิลคลิกที่ไฟล์ PS1 ที่แนบมากับอีเมลและเรียกใช้สคริปต์ นั่นเป็นเหตุผลที่ไฟล์ PS1 เชื่อมโยงกับโปรแกรมแก้ไขตามค่าเริ่มต้นเท่านั้น Microsoft ไม่ต้องการไวรัส ILoveYou เวอร์ชัน PowerShell เช่น "LOVE-LETTER-FOR-YOU.TXT.ps1"
Keith Hill

12

คุณสามารถประกาศพารามิเตอร์ของคุณในไฟล์เช่น param:

[string]$para1
[string]$param2

แล้วเรียกไฟล์ PowerShell เช่นนั้น.\temp.ps1 para1 para2....para10เป็นต้น


6

บางทีคุณสามารถรวมการเรียกใช้ PowerShell ใน.batไฟล์ดังนี้:

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

หากคุณวางไฟล์นี้ไว้ในโฟลเดอร์ในโฟลเดอร์ของPATHคุณคุณสามารถเรียกสคริปต์ PowerShell ดังนี้:

ps foo 1 2 3

การอ้างอิงอาจทำให้ยุ่งเล็กน้อยแม้ว่า:

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

+1 สำหรับแสดงเครื่องหมายคำพูดสามคำ ที่ทำให้ฉันติดอยู่ชั่วขณะ
DeanOC

1

คุณอาจไม่ได้รับ "xuxu p1 p2 p3 p4" อย่างที่คิด แต่เมื่อคุณอยู่ใน PowerShell และคุณตั้งค่า

PS > set-executionpolicy Unrestricted -scope currentuser

คุณสามารถเรียกใช้สคริปต์เหล่านั้นได้ดังนี้:

./xuxu p1 p2 p3 p4

หรือ

.\xuxu p1 p2 p3 p4

หรือ

./xuxu.ps1 p1 p2 p3 p4

ฉันหวังว่าจะทำให้คุณสบายใจขึ้นเล็กน้อยกับ PowerShell


0

หากคุณต้องการเรียกใช้สคริปต์ ps1 จาก cmd และส่งผ่านอาร์กิวเมนต์โดยไม่เรียกใช้สคริปต์เช่น

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

คุณสามารถทำสิ่งต่อไปนี้

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

นี่ถือว่า powershell.exe อยู่ในเส้นทางของคุณ

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


น่าสังเกตว่าสิ่งนี้ต้องใช้พรอมต์ cmd ในฐานะผู้ดูแลระบบ นอกจากนี้ฉันกำลังดิ้นรนที่จะทำให้มันใช้งานได้จริงบน Windows 10 เวอร์ชัน 1903 (18362.778) - คำสั่งทั้งหมดทำงานได้สำเร็จ แต่อาร์กิวเมนต์ยังไม่ได้รับการส่งผ่านฉันคิดว่าการตัดไฟล์. bat เป็นวิธีที่พกพาได้ง่ายที่สุด
David Airapetyan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.