PowerShellでは、ファイルで関数を定義して、PowerShellコマンドラインから呼び出すにはどうすればよいですか?


242

カスタム関数を定義する.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
これは、このファイルのコンテンツをソースすることを意味します。bashと同じです。ss64.com/bash/period.html
inquam

2
最初に。\ MyFunctions.ps1を実行して使用可能にしない限り、(少なくともISEからは)うまく機能しないようです。powershell.exeから厳密に実行するかどうかはわかりません。
Mike Cheel、2013

1
ドットソーシングがスクリプトではなくpwdからの相対パスを使用するのは直観に反すると思ったので、代わりにJoeGの答えを見てモジュールを使用するように人々に促します。
Spork 2014年

5
@Spork . "$PSScriptRoot\MyFunctions.ps1"。Availalbeはv3以降、その前にstackoverflow.com/questions/3667238/…を参照してください。それは非常に一般的です。
yzorg 2015

231

あなたが話していることは、ドットソーシングと呼ばれています。そしてそれは悪です。しかし、心配する必要はありません。モジュールを使用してやりたいことをより簡単に行う方法があります(実際よりも恐ろしいように聞こえます)。モジュールを使用する主な利点は、必要に応じてシェルからモジュールをアンロードできることです。これにより、関数内の変数がシェルに侵入しないようにします(関数ファイルをドットソース化したら、変数の1つをシェルで機能すると、私が何を意味するかがわかります)。

したがって、最初に、すべての関数が含まれている.ps1ファイルの名前をMyFunctions.psm1に変更します(モジュールを作成したところです)。モジュールが適切にロードされるようにするには、ファイルに対して特定のことを行う必要があります。最初にImport-Moduleがモジュールを表示するには(このコマンドレットを使用してモジュールをシェルにロードします)、特定の場所にある必要があります。モジュールフォルダーへのデフォルトのパスは$ home \ Documents \ WindowsPowerShell \ Modulesです。

そのフォルダーで、MyFunctionsという名前のフォルダーを作成し、MyFunctions.psm1ファイルをその中に配置します(モジュールファイルは、PSM1ファイルとまったく同じ名前のフォルダーに存在する必要があります)。

それが完了したら、PowerShellを開き、次のコマンドを実行します。

Get-Module -listavailable

MyFunctionsと呼ばれるものが表示された場合、それは正しく行われ、モジュールをロードする準備ができています(これは、これが正しくセットアップされていることを確認するためだけで、これを行う必要があるのは1回だけです)。

モジュールを使用するには、シェルに次のように入力します(または、この行を$ profileに入れるか、スクリプトの最初の行に入れます)。

Import-Module MyFunctions

これで関数を実行できます。これのクールな点は、10から15個の関数が入ったら、カップルの名前を忘れてしまうことです。モジュールにそれらがある場合、次のコマンドを実行して、モジュール内のすべての関数のリストを取得できます。

Get-Command -module MyFunctions

それはかなり甘いです、そして、それを前側に設置するために取るほんの少しの努力はそれだけの価値があります。


6
関数が特定のPowerShellアプリケーションにのみ関連している場合はどうでしょうか?つまり、PS1のパッケージをインストールしてどこかでジョブを実行する場合、プロファイル内のすべての機能が必要になるとは限りませんよね?
Ian Patrick Hughes

3
その場合は、その特定のアプリケーション用のモジュールを作成し、スクリプトを実行する前にそれをロードするか(インタラクティブに機能している場合)、またはスクリプト内でロードします。ただし、一般的に言えば、特定のタスクにのみ固有のコードがある場合は、それらの関数をスクリプトに含める必要があります。個人的には、一般的に1つのことを行う関数のみを記述します。コードの一部が超特化されている場合、それを関数またはモジュールでラップすることは実際には意味がありません(同じコードを使用するスクリプトがいくつかない限り、それは意味があるかもしれません)。
JoeG

16
モジュールファイルがPSM1ファイルとまったく同じ名前のフォルダーにある必要はありません。それは次のように行うことができます Import-Module .\buildsystem\PSUtils.psm1
Michael Freidgeim 2016年

2
@MichaelFreidgeimは、.with Import-Moduleを変更して拡張の名前を変更するだけの簡単なものであり、モジュールを特定のフォルダーに配置する必要がない場合、つまり、ドットソースの場合と同じように、任意のディレクトリに配置できます。スコーピングのメリットを考慮して、モジュールでドットソースを作成する理由はありますか?(もちろん、これらのスコープの「問題」があなたの望んでいるものでない限り)
Abdul

2
@アブドゥル、ドットソーシングはよりシンプルで、モジュールははるかに強力です。stackoverflow.com/questions/14882332/…を
Michael Freidgeim

17

. "$PSScriptRoot\MyFunctions.ps1" MyA1Func

v3で使用可能になる前に、「PowerShellスクリプトのファイルシステムの場所を取得するにどうすればよいですか?」を参照してください。それは非常に一般的です。

PS私は「すべてがモジュールである」というルールに同意していません。私のスクリプトはGIT以外の他の開発者が使用しているため、スクリプトを実行する前に、特定の場所にデータを配置したり、システム環境変数を変更したりしたくありません。それは単なるスクリプト(または2つ、または3つ)です。


FWIW、モジュールでスクリプトを実行するために、これらのいずれかを実行する必要はありません。
Nick Cox

@NickCoxいくつかの例を見たいです。あなたがいずれかを持っている?+10例がOSSプロジェクトからのものである場合。具体的には、(PSModulePathではなく、またはPSModulePathをカスタマイズせずに)相対パスを介して読み込まれるPSモジュールの例、および重要な例(つまり、モジュールが通常のスクリプトスコープよりも優れている場合)。
yzorg

FluentMigrator.PowerShellモジュールを相対パスから頻繁にインポートします。これにより、それをソース管理にチェックインして、全員が同じバージョンを使用していることを確認できます。それはうまくいきます。
Nick Cox

モジュールとスクリプトのどちらとしてパッケージ化するかについての相対的な長所と短所についてはわかりません。おそらくそれは作者と話し合うべきものでしょうか?への能力Get-Command -Module FluentMigrator.PowerShellがかなりいいと思いますか?
Nick Cox

@NickCoxそのコマンドでモジュールパスを完全に修飾していません。つまり、モジュールをグローバルモジュールフォルダーにコピーするか、GITフォルダーをグローバル環境変数に追加しない限り、モジュールパスは見つかりません。あなたはちょうど私のポイントを示したと思います。
yzorg

7

スクリプトファイルで関数を定義することは確かにできます(次に、ロード時にPowershellプロファイルを介して関数をロードする傾向があります)。

まず、次のコマンドを実行して、関数がロードされていることを確認する必要があります。

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

そして、それがリストに表示されていることを確認し(1のリストである必要があります!)、取得した出力をお知らせください。


1
PowerShell関数ではディレクトリとして扱われるため、c:\またはd:\と同じです。同様に、バックスラッシュがなくても機能するため、ls関数を使用します。ここで{$ _。Name -eq "A1"}
Jonny

4

次の機能を追加できます。

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

機能が利用できるようになります。


3

ファイルに、呼び出し/公開するメイン関数が1つしかない場合は、次のコマンドでファイルを開始することもできます。

Param($Param1)

その後、たとえば次のように呼び出すことができます。

.\MyFunctions.ps1 -Param1 'value1'

これにより、関数をインポートせずに、その関数だけを簡単に呼び出す場合に非常に便利です。


また、PowerShellが[CmdletBinding()]属性を自動的に追加し、無料で高度な関数にアップグレードすることを(私の同僚が教えてくれた後で)今日発見したことにも注意してください。:-)
bergmeister 2018

1

Function-Dumb()というメソッドを持つDummy-Name.psm1というモジュールファイルがあるとします。

Import-Module "Dummy-Name.psm1";
Get-Command -Module "Function-Dumb";
#
#
Function-Dumb;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.