ใน 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
Andrew

คำตอบ:


262

ลองสิ่งนี้ในบรรทัดคำสั่ง PowerShell:

. .\MyFunctions.ps1
A1

ตัวดำเนินการจุดใช้สำหรับการรวมสคริปต์


11
มันหมายถึง "ใช้สิ่งนี้ในบริบทปัจจุบันแทนที่จะเป็นบริบทลูก"
JasonMArcher

15
มันหมายถึงแหล่งเนื้อหาของไฟล์นี้ เช่นเดียวกับในทุบตี ss64.com/bash/period.html
Askam

2
ดูเหมือนว่าจะทำงานได้ไม่ดีนัก (อย่างน้อยก็จาก ISE) เว้นแต่คุณจะเรียกใช้ \ MyFunctions.ps1 ก่อนเพื่อให้พร้อมใช้งาน ฉันไม่แน่ใจเกี่ยวกับการทำงานอย่างเคร่งครัดจาก powershell.exe
Mike Cheel

1
ฉันคิดว่ามันตอบโต้ได้ง่าย ๆ ว่า dot-sourcing ใช้พา ธ ที่สัมพันธ์กับ pwd มากกว่าสคริปต์ดังนั้นฉันอยากให้คนดูคำตอบของ JoeG แทนและใช้โมดูล
Spork

5
. "$PSScriptRoot\MyFunctions.ps1"@Spork availalbe เริ่มต้นใน v3 ก่อนที่จะเห็นว่าstackoverflow.com/questions/3667238/... เป็นเรื่องธรรมดามาก
yzorg

233

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

ดังนั้นก่อนอื่นให้เปลี่ยนชื่อไฟล์. ps1 ที่มีฟังก์ชั่นทั้งหมดของคุณเป็น MyFunctions.psm1 (คุณเพิ่งสร้างโมดูล!) ตอนนี้สำหรับโมดูลที่จะโหลดอย่างถูกต้องคุณต้องทำสิ่งที่เฉพาะเจาะจงกับไฟล์ ก่อนอื่นให้นำเข้าโมดูลเพื่อดูโมดูล (คุณใช้ cmdlet นี้เพื่อโหลดโมดูลลงในเชลล์) จะต้องอยู่ในตำแหน่งที่ระบุ เส้นทางเริ่มต้นไปยังโฟลเดอร์โมดูลคือ $ 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
Michael Freidgeim

2
@MichaelFreidgeim ถ้ามันง่ายเพียงแค่เปลี่ยน.ด้วยImport-Moduleและเปลี่ยนชื่อนามสกุลและไม่ต้องการให้โมดูลถูกวางไว้ในโฟลเดอร์เฉพาะเช่นฉันสามารถมีมันในไดเรกทอรีใด ๆ ที่ฉันต้องการเช่นเดียวกับ dot sourcing คือ มีเหตุผลใดที่จะทำการจัดหาดอทผ่านโมดูลโดยคำนึงถึงประโยชน์ที่ได้จากการกำหนดขอบเขต (เว้นแต่ของหลักสูตรที่ผู้ขอบเขต "ปัญหา" คือสิ่งที่คุณต้องการ)
อับดุล

2
@Abdul, dot sourcing นั้นง่ายกว่า, โมดูลมีประสิทธิภาพมากกว่า ดูstackoverflow.com/questions/14882332/…
Michael Freidgeim

17

. "$PSScriptRoot\MyFunctions.ps1" MyA1Func

Availalbe เริ่มต้นใน v3 ก่อนหน้านั้นดูฉันจะหาตำแหน่งระบบไฟล์ของสคริปต์ PowerShell ได้อย่างไร . เป็นเรื่องธรรมดามาก

ป.ล. ฉันไม่สมัครสมาชิกกฎ 'ทุกอย่างเป็นโมดูล' นักพัฒนาซอฟต์แวร์อื่นของฉันใช้สคริปต์ของฉันออกมาจาก GIT ดังนั้นฉันจึงไม่ชอบที่จะวางสิ่งของไว้ในที่เฉพาะเจาะจงหรือปรับเปลี่ยนตัวแปรสภาพแวดล้อมของระบบก่อนที่สคริปต์ของฉันจะทำงาน เป็นเพียงสคริปต์ (หรือสองหรือสาม)


FWIW คุณไม่ต้องทำอย่างใดอย่างหนึ่งเพื่อเรียกใช้สคริปต์ในโมดูล
Nick Cox

@NickCox ฉันชอบที่จะเห็นตัวอย่างบางส่วนของที่ คุณมีอะไรบ้าง +10 ถ้าตัวอย่างมาจากโครงการ OSS โดยเฉพาะตัวอย่างของโมดูล PS ที่ถูกโหลดผ่านเส้นทางสัมพัทธ์ (ไม่ใช่ PSModulePath หรือไม่มีการกำหนด PSModulePath เอง) และตัวอย่างที่ไม่น่าสนใจ (เช่นที่โมดูลมีประโยชน์มากกว่าการกำหนดขอบเขตสคริปต์ปกติ)
yzorg

ฉันมักจะนำเข้าโมดูลFluentMigrator.PowerShellจากเส้นทางสัมพัทธ์ ที่ช่วยให้เราตรวจสอบลงในการควบคุมแหล่งที่มาและให้แน่ใจว่าทุกคนใช้เวอร์ชันเดียวกัน มันใช้งานได้ดี
นิคค็อกซ์

ฉันไม่แน่ใจเกี่ยวกับข้อดีข้อเสียของการบรรจุเป็นโมดูลเทียบกับสคริปต์: บางทีนี่อาจเป็นการสนทนากับผู้แต่ง ฉันเดาว่าความสามารถที่Get-Command -Module FluentMigrator.PowerShellจะค่อนข้างดี?
Nick Cox

@NickCox คุณไม่ได้ผ่านการรับรองโมดูลพา ธ ในคำสั่งนั้นอย่างเต็มที่ซึ่งหมายความว่าจะไม่พบเว้นแต่คุณจะคัดลอกโมดูลไปยังโฟลเดอร์โมดูลส่วนกลางหรือเพิ่มโฟลเดอร์ GIT ของคุณลงในตัวแปรสภาพแวดล้อมโกลบอล ฉันคิดว่าคุณแค่แสดงให้เห็นถึงจุดของฉัน
yzorg

7

แน่นอนคุณสามารถกำหนดฟังก์ชั่นในไฟล์สคริปต์ (จากนั้นฉันมักจะโหลดผ่านโปรไฟล์ Powershell ของฉันในการโหลด)

ก่อนอื่นคุณต้องตรวจสอบเพื่อให้แน่ใจว่าฟังก์ชั่นโหลดโดยการใช้งาน:

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

และตรวจสอบว่ามันปรากฏในรายการ (ควรเป็นรายการ 1!) จากนั้นแจ้งให้เราทราบว่าผลลัพธ์ที่คุณได้รับ!


1
ในฟังก์ชั่น PowerShell จะถือว่าเป็นไดเรกทอรีดังนั้นมันจึงเหมือนกับการบอกว่า c: \ or d: \ คุณจะใช้งานได้โดยไม่ต้องใช้แบ็กสแลชดังนั้น ls จะทำงาน: | โดยที่ {$ _. ชื่อ -eq "A1"}
Jonny


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;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.