Як в PowerShell визначити функцію у файлі та викликати її з командної лінії PowerShell?


243

У мене є .ps1 файл, в якому я хочу визначити власні функції.

Уявіть, що файл називається MyFunctions.ps1, а вміст такий:

Write-Host "Installing functions"
function A1
{
    Write-Host "A1 is running!"
}
Write-Host "Done"

Щоб запустити цей скрипт і теоретично зареєструвати функцію A1, я переходжу до папки, в якій знаходиться файл .ps1, і запускаю файл:

.\MyFunctions.ps1

Це виводи:

Installing functions
Done

Тим не менш, коли я намагаюся зателефонувати на A1, я просто отримую помилку, вказуючи, що немає команди та функції під цим ім'ям:

The term 'A1' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling
 of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:3
+ A1 <<<<
    + CategoryInfo          : ObjectNotFound: (A1:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Я повинен неправильно зрозуміти деякі концепції PowerShell. Чи не можу я визначити функції у файлах сценаріїв?

Зауважте, що я вже встановив свою політику виконання на "RemoteSigned". І я знаю запускати .ps1 файли, використовуючи крапку перед іменем файлу:. \ MyFile.ps1


Приємне посилання на функції завантаження при запуску PS: sandfeld.net/powershell-load-your-functions-at-startup
Андрій

Відповіді:


262

Спробуйте це в командному рядку PowerShell:

. .\MyFunctions.ps1
A1

Оператор крапки використовується для сценарію include.


11
Ну, це означає "запустити це в поточному контексті замість дочірнього контексту".
JasonMArcher

15
Це означає джерело вмісту цього файлу. Те саме, що в басі . ss64.com/bash/period.html
запитуйте

2
Здається, він не працює дуже добре (принаймні, від ISE), якщо ви не запустите. \ MyFunctions.ps1 першим, щоб зробити його доступним. Я не впевнений у тому, щоб чітко працювати з powershell.exe.
Майк Чіл

1
Я вважав, що контр-інтуїтивно зрозуміло, що точка-джерело використовує шлях відносно pwd, а не сценарій, тому я закликаю людей шукати замість відповіді JoeG і використовувати модулі.
Spork

5
@Spork . "$PSScriptRoot\MyFunctions.ps1". Наявна починаючи з версії 3, до цього см stackoverflow.com/questions/3667238 / ... . Це ДУЖЕ звичайно.
yzorg

233

Те, про що ви говорите, називається крапковим джерелом . І це зло. Але не хвилюйтесь, є кращий і простіший спосіб зробити те, що ви хочете, з модулями (це звучить набагато страшніше, ніж це). Основна перевага використання модулів полягає в тому, що ви можете вивантажити їх з оболонки, якщо вам потрібно, і це утримує змінні у функціях з повзання в оболонку (як тільки ви отримаєте точку джерела файлу функції, спробуйте викликати одну із змінних з функціонувати в оболонці, і ви побачите, що я маю на увазі).

Отже, спочатку перейменуйте файл .ps1, у якому є всі ваші функції, в MyFunctions.psm1 (ви тільки що створили модуль!). Тепер, щоб модуль належним чином завантажився, потрібно зробити деякі файли з файлом. Спочатку Import-Module побачив модуль (цей командлет ви використовуєте для завантаження модуля в оболонку), він повинен знаходитися в певному місці. Шлях до папки з модулями за замовчуванням - $ home \ Documents \ WindowsPowerShell \ Modules.

У цій папці створіть папку з назвою MyFunctions і помістіть у неї файл MyFunctions.psm1 (файл модуля повинен містити папку з точно такою ж назвою, що і файл PSM1).

Після цього відкрийте PowerShell і запустіть цю команду:

Get-Module -listavailable

Якщо ви бачите один під назвою MyFunctions, ви зробили це правильно, і ваш модуль готовий до завантаження (це просто для того, щоб це було налаштовано правильно, робити це потрібно лише один раз).

Щоб використовувати модуль, введіть у оболонці наступне (або введіть цей рядок у свій профіль $ або поставте це як перший рядок у сценарії):

Import-Module MyFunctions

Тепер ви можете запускати свої функції. Прикольна річ у тому, що як тільки у вас буде 10-15 функцій, ви забудете ім'я пари. Якщо у вас є модуль, ви можете запустити наступну команду, щоб отримати список усіх функцій вашого модуля:

Get-Command -module MyFunctions

Це досить солодко, і крихітний шматочок зусиль, який він потребує, щоб встановити на передній стороні, НАДІЙНО варто.


6
А як бути, якщо ваші функції стосуються лише тієї програми PowerShell? Я маю на увазі, якщо ви встановите пакет PS1, щоб зробити роботу десь, можливо, вам не потрібна кожна функція у вашому профілі, правда?
Ian Patrick Hughes

3
У такому випадку я б створив модуль для цього конкретного додатка і завантажував його перед запуском сценаріїв (якщо він працює в інтерактивному режимі), або завантажував його в сценарій. Але взагалі, якщо у вас є код, специфічний лише для заданої задачі, ви хочете, щоб ці функції були в сценарії. Особисто я пишу лише функції, які загалом роблять одне. Якщо фрагмент коду є гіперспеціалізованим, його насправді не має сенсу включати у функцію чи модуль (якщо не існує декількох скриптів, які використовують той самий код, то це може мати сенс).
JoeG

17
НЕ потрібно, щоб файл модуля знаходився в папці з точно такою ж назвою, що і файл PSM1. Це можна зробити так Import-Module .\buildsystem\PSUtils.psm1
Майкл Фрейджім

2
@MichaelFreidgeim , якщо це так просто , як просто змінюючи .з Import-Moduleі перейменування розширення, і не вимагає модулів , які будуть поміщені в папку конкретного, тобто я можу мати його в будь-який каталог я хочу, так само , як з точки пошуку, є Чи є якась причина навіть робити точковий пошук над модулями, враховуючи переваги, які приносяться для здійснення масштабування? (якщо, звичайно, ці сфери "питань" - це те, що ви хочете)
Абдул

2
@ Abdul, пошук точок простіший, модулі набагато потужніші. Див stackoverflow.com/questions/14882332 / ...
Майкл Freidgeim

17

. "$PSScriptRoot\MyFunctions.ps1" MyA1Func

Availalbe, починаючи з v3, перед цим див. Як я можу отримати розташування файлової системи сценарію PowerShell? . Це ДУЖЕ звичайно.

PS Я не підписуюся на правило "все - це модуль". Мої сценарії використовуються іншими розробниками з GIT, тому мені не подобається розміщувати матеріали в певному місці або змінювати змінні системного середовища до того, як мій сценарій запуститься. Це просто сценарій (або два, або три).


FWIW, вам не потрібно робити жодної з цих речей, щоб запустити скрипт в модулі.
Нік Кокс

@NickCox Я хотів би побачити кілька прикладів цього. Чи є у вас? +10, якщо приклад із проекту OSS. Зокрема, приклад завантаження модуля PS через відносний шлях (не PSModulePath або без налаштування PSModulePath), і нетривіальний приклад (тобто там, де модуль має переваги над звичайним розміщенням сценарію).
yzorg

Я часто імпортую модуль FluentMigrator.PowerShell з відносного шляху. Це дозволяє нам перевірити це на контроль джерел і переконатися, що всі користуються однаковою версією. Це добре працює.
Нік Кокс

Я не впевнений у відносних плюсах і мінусах упаковки його як модуля проти як сценарію: можливо, це одне обговорення з автором? Я здогадуюсь, що придатність до Get-Command -Module FluentMigrator.PowerShellцього досить приємна?
Нік Кокс

@NickCox Ви не повністю кваліфікували шлях модуля в цій команді, а значить, його не буде знайдено, якщо ви не скопіюєте модуль у глобальну папку модуля або додасте папку GIT до глобальної змінної середовища. Я думаю, ти щойно продемонстрував мою думку.
yzorg

7

Ви, звичайно, можете визначати функції у файлах сценаріїв (я тоді схильний завантажувати їх через мій профіль Powershell при завантаженні).

Спочатку потрібно перевірити, щоб переконатися, що функція завантажена запуск:

ls function:\ | where { $_.Name -eq "A1"  }

І переконайтеся, що воно відображається у списку (має бути список 1!), То повідомте нам, який результат ви отримаєте!


1
У PowerShell функція трактується як каталог, так що це те саме, що говорити c: \ або d: \. Так само ви працюєте без нахилу, тому функція ls: | де {$ _. Ім'я -eq "A1"}
Jonny

4

Ви можете додати функцію до:

c:\Users\David\Documents\WindowsPowerShell\profile.ps1

Функція буде доступна.


3

Якщо у вашому файлі є лише одна основна функція, яку ви хочете зателефонувати / відкрити, ви також можете просто запустити файл із:

Param($Param1)

Потім ви можете назвати це, наприклад, наступним чином:

.\MyFunctions.ps1 -Param1 'value1'

Це робить набагато зручнішим, якщо ви хочете легко зателефонувати саме до цієї функції, не потребуючи імпорту функції.


Я також повинен зазначити, що я виявив сьогодні (після того, як мій колега сказав мені), що PowerShell автоматично додає [CmdletBinding()]атрибут і безкоштовно оновить його до розширеної функції. :-)
bergmeister

1

Припустимо, у вас є файл модуля під назвою Dummy-Name.psm1, який має метод під назвою Function-Dumb ()

Import-Module "Dummy-Name.psm1";
Get-Command -Module "Function-Dumb";
#
#
Function-Dumb;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.