Trong PowerShell, làm cách nào để xác định hàm trong tệp và gọi nó từ dòng lệnh PowerShell?


242

Tôi có một tệp .ps1 trong đó tôi muốn xác định các chức năng tùy chỉnh.

Hãy tưởng tượng tệp được gọi là MyFiances.ps1 và nội dung như sau:

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

Để chạy tập lệnh này và theo lý thuyết đăng ký chức năng A1, tôi điều hướng đến thư mục chứa tệp .ps1 và chạy tệp:

.\MyFunctions.ps1

Kết quả này:

Installing functions
Done

Tuy nhiên, khi tôi cố gắng gọi A1, tôi chỉ đơn giản nhận được lỗi thông báo rằng không có lệnh / hàm theo tên đó:

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

Tôi phải hiểu nhầm một số khái niệm PowerShell. Tôi không thể xác định chức năng trong tập tin tập lệnh?

Lưu ý rằng tôi đã đặt chính sách thực thi của mình thành 'RemoteSign'. Và tôi biết để chạy các tệp .ps1 bằng cách sử dụng dấu chấm phía trước tên tệp :. \ MyFile.ps1


Liên kết đẹp về chức năng tải khi khởi động PS: sandfeld.net/powershell-load-your-fifts-at-startup
Andrew

Câu trả lời:


262

Hãy thử điều này trên dòng lệnh PowerShell:

. .\MyFunctions.ps1
A1

Toán tử dấu chấm được sử dụng cho tập lệnh bao gồm.


11
Vâng, nó có nghĩa là "chạy này trong bối cảnh hiện tại thay vì bối cảnh trẻ em."
JasonMArcher

15
Nó có nghĩa là nguồn nội dung của tập tin này. Tương tự như trong bash . ss64.com/bash/apse.html
inquam

2
Nó dường như không hoạt động tốt mặc dù (ít nhất là từ ISE) trừ khi bạn chạy. \ MyFifts.ps1 trước tiên để làm cho nó khả dụng. Tôi không chắc chắn về việc chạy đúng từ powershell.exe.
Mike Cheel

1
Tôi nghĩ thật phản cảm khi nguồn cung cấp chấm sử dụng đường dẫn liên quan đến pwd thay vì tập lệnh, vì vậy tôi sẽ thúc giục mọi người tìm đến câu trả lời của JoeG và sử dụng các mô-đun.
Spork

5
@ Spork . "$PSScriptRoot\MyFunctions.ps1". Có sẵn bắt đầu từ v3, trước đó hãy xem stackoverflow.com/questions/3667238/ . Nó rất phổ biến.
yzorg 5/2/2015

231

Những gì bạn đang nói về được gọi là chấm nguồn . Và đó là xấu xa. Nhưng không phải lo lắng, có một cách tốt hơn và dễ dàng hơn để làm những gì bạn muốn với các mô-đun (nghe có vẻ đáng sợ hơn nó). Lợi ích chính của việc sử dụng các mô-đun là bạn có thể dỡ chúng khỏi shell nếu bạn cần và nó giữ cho các biến trong các hàm không bị lọt vào vỏ (một khi bạn chấm vào nguồn tệp, hãy thử gọi một trong các biến từ hoạt động trong trình bao và bạn sẽ thấy ý tôi là gì).

Vì vậy, trước tiên, đổi tên tệp .ps1 có tất cả các chức năng của bạn trong đó thành MyFifts.psm1 (bạn vừa tạo một mô-đun!). Bây giờ để một mô-đun tải đúng cách, bạn phải thực hiện một số điều cụ thể với tệp. Đầu tiên cho Mô-đun nhập để xem mô-đun (bạn sử dụng lệnh ghép ngắn này để tải mô-đun vào trình bao), nó phải ở một vị trí cụ thể. Đường dẫn mặc định đến thư mục mô-đun là $ home \ Documents \ WindowsPowerShell \ Modules.

Trong thư mục đó, hãy tạo một thư mục có tên MyFifts và đặt tệp MyFifts.psm1 vào đó (tệp mô-đun phải nằm trong một thư mục có cùng tên với tệp PSM1).

Khi đã xong, hãy mở PowerShell và chạy lệnh này:

Get-Module -listavailable

Nếu bạn thấy một cái gọi là MyFifts, bạn đã làm đúng và mô-đun của bạn đã sẵn sàng để được tải (điều này chỉ để đảm bảo rằng điều này được thiết lập đúng, bạn chỉ phải thực hiện điều này một lần).

Để sử dụng mô-đun, hãy nhập dòng sau vào trình bao (hoặc đặt dòng này trong hồ sơ $ của bạn hoặc đặt dòng này làm dòng đầu tiên trong tập lệnh):

Import-Module MyFunctions

Bây giờ bạn có thể chạy các chức năng của bạn. Điều thú vị ở đây là một khi bạn có 10-15 chức năng trong đó, bạn sẽ quên tên của một cặp vợ chồng. Nếu bạn có chúng trong một mô-đun, bạn có thể chạy lệnh sau để có danh sách tất cả các chức năng trong mô-đun của mình:

Get-Command -module MyFunctions

Nó khá ngọt ngào, và một chút nỗ lực cần thiết để thiết lập ở mặt trước là CÁCH xứng đáng.


6
Còn nếu các chức năng của bạn chỉ phù hợp với ứng dụng PowerShell đó thì sao? Ý tôi là, nếu bạn cài đặt một gói PS1 để thực hiện một công việc ở đâu đó, bạn có thể không muốn mọi chức năng trong hồ sơ của mình, phải không?
Ian Patrick Hughes

3
Trong trường hợp đó, tôi sẽ tạo một mô-đun cho ứng dụng cụ thể đó và tải nó trước khi chạy các tập lệnh (nếu hoạt động tương tác) hoặc tải nó trong tập lệnh. Nhưng nói chung, nếu bạn có mã chỉ dành riêng cho một tác vụ nhất định, bạn sẽ muốn các hàm đó trong tập lệnh. Cá nhân tôi chỉ viết các hàm mà thường làm một việc. Nếu một đoạn mã là siêu chuyên biệt, nó không thực sự có ý nghĩa để bọc nó trong một hàm hoặc mô-đun (trừ khi có một số tập lệnh sử dụng cùng mã đó, thì nó có thể có ý nghĩa).
JoeG

16
KHÔNG cần tệp mô-đun nằm trong một thư mục có cùng tên với tệp PSM1. Nó có thể được thực hiện như thế Import-Module .\buildsystem\PSUtils.psm1
Michael Freidgeim

2
@MichaelFreidgeim nếu đơn giản chỉ là thay đổi .bằng Import-Modulevà đổi tên tiện ích mở rộng và không yêu cầu các mô-đun được đặt trong một thư mục cụ thể, tức là tôi có thể có nó trong bất kỳ thư mục nào tôi muốn, giống như với tìm nguồn cung ứng, là Có lý do nào để thậm chí tìm nguồn cung ứng trên các mô-đun, xem xét các lợi ích mang lại cho phạm vi? (tất nhiên trừ khi những "vấn đề" phạm vi đó là những gì bạn muốn)
Abdul

2
@Abdul, tìm nguồn cung ứng đơn giản hơn, các mô-đun mạnh hơn nhiều. Xem stackoverflow.com/questions/14882332/
Mạnh

17

. "$PSScriptRoot\MyFunctions.ps1" MyA1Func

Sẵn có bắt đầu từ v3, trước đó hãy xem Làm cách nào tôi có thể lấy vị trí hệ thống tệp của tập lệnh PowerShell? . Nó rất phổ biến.

Tái bút: Tôi không đăng ký quy tắc 'mọi thứ đều là mô-đun'. Các tập lệnh của tôi được các nhà phát triển khác sử dụng ngoài GIT, vì vậy tôi không muốn đặt nội dung vào một vị trí cụ thể hoặc sửa đổi các biến môi trường hệ thống trước khi tập lệnh của tôi chạy. Nó chỉ là một kịch bản (hoặc hai hoặc ba).


FWIW, bạn không phải thực hiện một trong những điều đó để chạy tập lệnh trong một mô-đun.
Nick Cox

@NickCox Tôi muốn xem một số ví dụ về điều đó. Bạn có cái nào không +10 nếu ví dụ là từ một dự án OSS. Cụ thể, một ví dụ về mô-đun PS được tải thông qua một đường dẫn tương đối (không phải PSModulePath hoặc không tùy chỉnh PSModulePath) và ví dụ không tầm thường (nghĩa là mô-đun có lợi ích so với phạm vi tập lệnh thông thường).
yzorg

Tôi thường nhập mô-đun FluentMigrator.PowerShell từ một đường dẫn tương đối. Điều đó cho phép chúng tôi kiểm tra nó trong kiểm soát nguồn và đảm bảo rằng mọi người đều sử dụng cùng một phiên bản. Nó hoạt động tốt.
Nick Cox

Tôi không chắc chắn về những ưu và nhược điểm tương đối của việc đóng gói nó như một mô-đun so với kịch bản: có lẽ đó là một vấn đề để thảo luận với tác giả? Tôi đoán khả năng Get-Command -Module FluentMigrator.PowerShelllà khá tốt?
Nick Cox

@NickCox Bạn không đủ điều kiện đường dẫn mô-đun trong lệnh đó, điều đó có nghĩa là nó sẽ không được tìm thấy trừ khi bạn sao chép mô-đun vào thư mục mô-đun toàn cầu hoặc thêm thư mục GIT của bạn vào biến môi trường toàn cầu. Tôi nghĩ rằng bạn chỉ chứng minh quan điểm của tôi.
yzorg

7

Bạn chắc chắn có thể xác định các chức năng trong các tệp script (sau đó tôi có xu hướng tải chúng thông qua hồ sơ Powershell của tôi khi tải).

Trước tiên, bạn cần kiểm tra để đảm bảo chức năng được tải bằng cách chạy:

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

Và kiểm tra xem nó có xuất hiện trong danh sách không (nên là danh sách 1!), Sau đó cho chúng tôi biết sản lượng bạn nhận được!


1
Trong PowerShell, hàm được coi là một thư mục, vì vậy nó giống như nói c: \ hoặc d: \. Tương tự, bạn sẽ làm việc mà không có dấu gạch chéo ngược nên hàm ls: | trong đó {$ _. Tên -eq "A1"}
Jonny

4

Bạn có thể thêm chức năng vào:

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

Một chức năng sẽ có sẵn.


3

Nếu tệp của bạn chỉ có một chức năng chính mà bạn muốn gọi / hiển thị, thì bạn cũng có thể chỉ cần bắt đầu tệp với:

Param($Param1)

Sau đó, bạn có thể gọi nó như sau:

.\MyFunctions.ps1 -Param1 'value1'

Điều này làm cho nó thuận tiện hơn nhiều nếu bạn muốn dễ dàng gọi chỉ chức năng đó mà không phải nhập chức năng.


Tôi cũng nên lưu ý rằng tôi đã phát hiện ra ngày hôm nay (sau khi một đồng nghiệp của tôi nói với tôi) rằng PowerShell tự động thêm [CmdletBinding()]thuộc tính và nâng cấp nó miễn phí lên một chức năng nâng cao. :-)
bergmeister

1

Giả sử bạn có một tệp mô-đun có tên Dummy-Name.psm1 có một phương thức gọi là Function-Dumb ()

Import-Module "Dummy-Name.psm1";
Get-Command -Module "Function-Dumb";
#
#
Function-Dumb;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.