PowerShell'de, bir dosyadaki bir işlevi nasıl tanımlayabilir ve PowerShell komut satırından nasıl çağırabilirim?


243

Özel işlevleri tanımlamak istediğim bir .ps1 dosyası var.

Dosyanın MyFunctions.ps1 olarak adlandırıldığını ve içeriğin aşağıdaki gibi olduğunu düşünün:

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

Bu komut dosyasını çalıştırmak ve A1 işlevini teorik olarak kaydetmek için, .ps1 dosyasının bulunduğu klasöre gidip dosyayı çalıştırın:

.\MyFunctions.ps1

Bu çıktılar:

Installing functions
Done

Yine de, A1'i aramaya çalıştığımda, bu adla komut / işlev olmadığını belirten hatayı alıyorum:

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

Bazı PowerShell kavramlarını yanlış anlamam gerekiyor. Komut dosyalarındaki işlevleri tanımlayamıyorum?

Yürütme ilkemi zaten 'RemoteSigned' olarak ayarladığımı unutmayın . Ve dosya adının önünde bir nokta kullanarak .ps1 dosyalarını çalıştırmayı biliyorum:. \ MyFile.ps1


PS başlangıcında işlevlerin yüklenmesiyle ilgili güzel bir bağlantı: sandfeld.net/powershell-load-your-functions-at-startup
Andrew

Yanıtlar:


262

PowerShell komut satırında bunu deneyin:

. .\MyFunctions.ps1
A1

Nokta işleci, script içerme için kullanılır.


11
Bu, "bunu alt bağlam yerine geçerli bağlamda çalıştır" anlamına gelir.
JasonMArcher

15
Bu dosyanın içeriğini kaynak anlamına gelir . Bash ile aynı . ss64.com/bash/period.html
inquam 2:12

2
Çalıştırmak için önce. \ MyFunctions.ps1 çalıştırmadığınız sürece (en azından ISE'den) çok iyi çalışmıyor gibi görünüyor. Kesinlikle powershell.exe çalışan hakkında emin değilim.
Mike Cheel

1
Ben nokta-kaynak kodunu değil de pwd göre yolu kullandığını karşı sezgisel olduğunu düşündüm, bu yüzden insanları bunun yerine JoeG'nin cevabına bakmak ve modülleri kullanmak için teşvik ediyorum.
Spork

5
@Spork . "$PSScriptRoot\MyFunctions.ps1". Availalbe v3'ten başlayarak bundan önce stackoverflow.com/questions/3667238/… adresine bakın . ÇOK yaygındır.
yzorg

233

Bahsettiğiniz konuya nokta kaynağı denir . Ve bu kötü. Ancak endişelenmenize gerek yok, modüller ile ne yapmak istediğinizi yapmanın daha iyi ve daha kolay bir yolu var (olduğundan daha korkutucu geliyor). Modül kullanmanın en büyük yararı, gerektiğinde bunları kabuktan kaldırabilmenizdir ve işlevlerdeki değişkenlerin kabuğa sürünmesini engeller (bir işlev dosyasını kaynakladıktan sonra, değişkenlerden birini fonksiyonunu ve ne demek istediğimi göreceksiniz).

Bu nedenle, içinde tüm işlevlerinizin bulunduğu .ps1 dosyasını MyFunctions.psm1 olarak yeniden adlandırın (yeni bir modül oluşturdunuz!). Şimdi bir modülün düzgün bir şekilde yüklenmesi için dosya ile ilgili bazı özel şeyler yapmanız gerekir. İçe Aktarma Modülü'nün modülü görmesi için (modülü kabuk içine yüklemek için bu cmdlet'i kullanırsınız), belirli bir konumda olması gerekir. Modüller klasörünün varsayılan yolu $ home \ Documents \ WindowsPowerShell \ Modules şeklindedir.

Bu klasörde, MyFunctions adlı bir klasör oluşturun ve MyFunctions.psm1 dosyasını bu klasöre yerleştirin (modül dosyası PSM1 dosyasıyla tam olarak aynı ada sahip bir klasörde bulunmalıdır).

Bu yapıldıktan sonra PowerShell'i açın ve şu komutu çalıştırın:

Get-Module -listavailable

MyFunctions adında bir tane görürseniz, bunu doğru yaptınız ve modülünüz yüklenmeye hazırdır (bu sadece bunun doğru şekilde ayarlandığından emin olmak içindir, bunu sadece bir kez yapmanız gerekir).

Modülü kullanmak için kabuğa aşağıdakileri yazın (veya bu satırı $ profilinize koyun veya bunu komut dosyasında ilk satır olarak yerleştirin):

Import-Module MyFunctions

Artık işlevlerinizi çalıştırabilirsiniz. Bununla ilgili güzel olan şey, orada 10-15 fonksiyona sahip olduğunuzda, bir çiftin adını unutacağınızdır. Bunları bir modülde varsa, modülünüzdeki tüm işlevlerin bir listesini almak için aşağıdaki komutu çalıştırabilirsiniz:

Get-Command -module MyFunctions

Oldukça tatlı ve ön tarafa kurmak için harcanan küçük çaba buna değer.


6
İşlevleriniz yalnızca verilen PowerShell uygulamasıyla ilgiliyse ne olacak? Yani, bir yere iş yapmak için bir PS1 paketi yüklerseniz, profilinizdeki her işlevi istemeyebilirsiniz, değil mi?
Ian Patrick Hughes

3
Bu durumda, söz konusu uygulama için bir modül oluşturur ve komut dosyalarını çalıştırmadan önce (etkileşimli olarak çalışıyorsa) veya komut dosyasına yüklerim. Ancak genel olarak, yalnızca belirli bir göreve özgü kodunuz varsa, komut dosyasında bu işlevleri kullanmak istersiniz. Şahsen ben sadece genel olarak bir şey yapan fonksiyonlar yazıyorum. Bir kod parçası hiper uzmanlaşmışsa, bir işlev veya modüle sarmak gerçekten mantıklı değildir (aynı kodu kullanan birkaç komut dosyası yoksa, o zaman mantıklı olabilir).
JoeG

17
Modül dosyasının PSM1 dosyasıyla tam olarak aynı ada sahip bir klasörde olması GEREKMEZ. Böyle yapılabilir Import-Module .\buildsystem\PSUtils.psm1
Michael Freidgeim

2
@MichaelFreidgeim sadece değiştirme gibi basit olarak ise .ile Import-Module, yani sadece nokta kaynak ile olduğu gibi, istediğim herhangi bir dizine sahip olabilir, ve dahili adını ve modüller belirli bir klasör yerleştirilmesine gerektirmez kapsam için faydaları göz önünde bulundurarak, modüller üzerinden nokta kaynağı yapmak için herhangi bir neden var mı? (tabii ki bu kapsam "konular" istediğiniz sürece)
Abdul

2
@Abdul, nokta kaynağı daha basit, modüller çok daha güçlü. Bkz. Stackoverflow.com/questions/14882332/…
Michael Freidgeim

17

. "$PSScriptRoot\MyFunctions.ps1" MyA1Func

Availalbe v3'ten başlayarak bundan önce bkz . PowerShell betiğinin dosya sistemi konumunu nasıl alabilirim? . ÇOK yaygındır.

PS: 'Her şey bir modül' kuralına abone değilim. Betiklerim GIT dışındaki diğer geliştiriciler tarafından kullanılıyor, bu yüzden betiğimin çalışması için belirli bir yere malzeme koymak veya sistem ortamı değişkenlerini değiştirmek istemiyorum. Bu sadece bir senaryo (ya da iki ya da üç).


FWIW, bir modülde komut dosyası çalıştırmak için bunlardan hiçbirini yapmanız gerekmez.
Nick Cox

@NickCox Bunun bazı örneklerini görmek isterim. Sende hiç var mı? Örnek bir OSS projesindeyse +10. Özellikle, göreceli bir yolla yüklenen PS modülünün bir örneği (PSModulePath değil veya PSModulePath özelleştirilmeden) ve önemsiz olmayan bir örnek (yani modülün normal komut dosyası kapsamlandırmaya göre avantajları olduğu durumlarda).
yzorg

FluentMigrator.PowerShell modülünü sık sık göreceli bir yoldan içe aktarıyorum . Bu, onu kaynak kontrolüne kontrol etmemize ve herkesin aynı sürümü kullandığından emin olmamıza izin verir. İyi çalışıyor.
Nick Cox

Ben bir modül vs bir komut dosyası olarak ambalaj göreli artıları ve eksileri emin değilim: belki de bu yazar ile tartışmak için bir? Bence Get-Command -Module FluentMigrator.PowerShelloldukça güzel bir olasılık mı?
Nick Cox

@NickCox Bu komutta modül yolunu tam olarak nitelendirmediniz. Bu, modülü genel bir modül klasörüne kopyalamazsanız veya GIT klasörünüzü bir global ortam değişkenine eklemezseniz bulunamayacağı anlamına gelir. Sanırım benim açımı gösterdin.
yzorg

7

Komut dosyalarındaki işlevleri kesinlikle tanımlayabilirsiniz (daha sonra bunları yükümdeki Powershell profilimden yükleme eğilimindeyim).

İlk önce çalıştırarak işlevin yüklendiğinden emin olmanız gerekir:

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

Ve listede göründüğünü kontrol edin (1 listesi olmalı!), Sonra hangi çıktıyı aldığınızı bize bildirin!


1
PowerShell işlevinde bir dizin olarak kabul edilir, bu yüzden c: \ veya d: \ demekle aynıdır. Aynı şekilde ters eğik çizgi olmadan çalışır böylece ls işlevi: | burada {$ _. Name -eq "A1"}
Jonny

4

Aşağıdakilere işlev ekleyebilirsiniz:

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

Bir fonksiyon mevcut olacaktır.


3

Dosyanızda aramak / göstermek istediğiniz tek bir ana işlev varsa, dosyayı şu şekilde de başlatabilirsiniz:

Param($Param1)

Daha sonra örneğin şu şekilde arayabilirsiniz:

.\MyFunctions.ps1 -Param1 'value1'

Bu, fonksiyonu içe aktarmak zorunda kalmadan kolayca bu fonksiyonu çağırmak istiyorsanız çok daha kolay hale getirir.


Ayrıca bugün keşfettim (bir meslektaşım bana söyledikten sonra) PowerShell'in otomatik olarak özelliği eklediğini [CmdletBinding()]ve gelişmiş bir işleve ücretsiz olarak yükselttiğini fark ettim. :-)
bergmeister

1

İşlev-Dumb () adında bir yöntemi olan Dummy-Name.psm1 adlı bir modül dosyanız olduğunu varsayarsak

Import-Module "Dummy-Name.psm1";
Get-Command -Module "Function-Dumb";
#
#
Function-Dumb;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.