Як передати аргументи командного рядка у файл ps1 PowerShell


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

Ця стаття допомагає. Зокрема, цей розділ:

-Файл

Запускає вказаний сценарій у локальній області ("крапковою"), щоб функції та змінні, які створює скрипт, були доступні в поточному сеансі. Введіть шлях до файлу сценарію та будь-які параметри. Файл повинен бути останнім параметром у команді, оскільки всі символи, введені після імені параметра 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 робить це.
Ерік Хансен

1
@EricHansen Я не знаю, що ви маєте на увазі, я отримую той самий результат у будь-якому випадку: `Powershell> powershell.exe. \ ParamTest.ps1 val1 val2 val3 val4 Num Args: 4 $ p1 = val1 $ p2 = val2 $ p3 = val3 $ p4 = val4 `
Рендалл Борк

@RandallBrock Поведінка аргументів у мене змінюється. Якщо я працюю в CMD / batch і роблю щось подібне pwsh .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4, це справді не подобається. З іншого боку, якщо я працюю в PowerShell і працюю .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4, це працює так, як я очікував. Я чув, що саме таким чином він призначений для функціонування з "міркувань безпеки".
Ерік Хансен

@EricHansen Цікаво, чи це версія версії. Для мене pwsh запускає 6.2.0, але powershell.exe запускає 5.1.17134.858, обидва з яких дають однакові перелічені результати: Powershell>pwsh .\ParamTest.ps1 val1 val2 val3 val4Num Args: 4 $p1=val1 $p2=val2 $p3=val3 $p4=val4
yields

1
@Timo Я не знаю, що ти точно робиш, але paramце мовна конструкція, однак це має бути перше, що є у файлі. Ви оголосили змінну чи щось інше перед нею? Більше інформації тут: docs.microsoft.com/en-us/powershell/module/…
Рендалл Борк

18

Добре, отже, спочатку це порушує основну функцію безпеки в PowerShell. З цим розумінням, ось як ви можете це зробити:

  1. Відкрийте вікно Провідника Windows
  2. Інструменти меню -> Параметри папки -> вкладка Типи файлів
  3. Знайдіть тип файлу PS1 і натисніть розширену кнопку
  4. Натисніть кнопку Створити
  5. Для дії поставити: Відкрити
  6. Для програми поставте: "C: \ WINNT \ system32 \ WindowsPowerShell \ v1.0 \ powershell.exe" "-файл" "% 1"% *

Можливо, ви захочете також ввести -NoProfileаргумент, залежно від того, що робить ваш профіль.


4
Я думаю, що ключ є у вашому кроці 6, де ви передаєте параметри до powershell.exe. Даніель каже, що він пов'язав файли PS1 з PowerShell, але це не передає аргументи без зайвих специфікацій% 1% *. Також зверніть увагу, що параметр -File недоступний у V1. Він є новим для V2.
Кіт Хілл

Хороший улов щодо параметра -file, я про це забув.
EBGreen

Мені доведеться встановити V2, перш ніж я зможу спробувати вашу пропозицію. Дякую. Коли ви говорите, що це порушує основну функцію безпеки, що ви маєте на увазі "це"? Виклик сценарію PowerShell із Cmd.exe так, ніби це файл .com / .bat / .exe? Передача параметрів сценарію?
Даніель 'Данг' Гріффіт,

1
Вибачте, я мав бути більш чітким. Виклик сценарію без явного виклику powershell.exe. Я не кажу, що це важлива функція безпеки для вас особисто, і це безпека через невідомість, котру я не завжди шаную.
EBGreen

6
Щоб додати коментар EBGreen, основною проблемою безпеки, яку намагається уникнути PowerShell, є те, що люди двічі клацають на файлах PS1, прикріплених до електронної пошти, і запускають сценарій. Ось чому файли PS1 за замовчуванням асоціюються лише з редактором. Microsoft справді не хоче версії PowerShell вірусу ILoveYou, наприклад "LOVE-LETTER-FOR-YOU.TXT.ps1"
Кіт Хілл,

11

Ви можете оголосити свої параметри у файлі, наприклад 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 є найбільш портативним рішенням.
Девід Айрапетян,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.