実行中のスクリプトがどのパスから実行されたかを伝えたいと思います。
多くの場合、これは$ pwdではありません。
私は自分のスクリプトに関連するフォルダー構造にある他のスクリプトを呼び出す必要があり、パスをハードコーディングすることはできますが、「dev」から「test」に昇格しようとすると不快であり、少し苦痛です"製造"。
PowerShellチームの Jeffrey Snover が最初に投稿したユビキタススクリプト( Skylerの答え で指定)、Keith CedircとEBGreenが投稿したバリエーションはすべて深刻な欠点に苦しんでいます。 -コードが期待するものを報告するかどうかは、どこで呼び出すかによって異なります!
以下の私のコードは、parentの代わりにscriptスコープを参照するだけでこの問題を解決します範囲:
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
この問題を説明するために、4つの異なる方法でターゲット式を評価するテストビークルを作成しました。 (括弧で囲まれた用語は、次の結果テーブルのキーです。)
最後の2列は、スクリプトスコープ($ script :)を使用した結果、または親スコープ(-scope 1を使用)を使用した結果を示しています。 「スクリプト」の結果は、呼び出しがスクリプトの場所を正しく報告したことを意味します。 「モジュール」の結果は、呼び出しが、関数を呼び出したスクリプトではなく、関数を含むモジュールの場所を報告したことを意味します。これは、モジュールに関数を配置できないという両方の関数の欠点を示しています。
モジュールの問題を別にすれば、テーブルからの注目すべき観察結果は、親スコープのアプローチを使用するとほとんどの場合失敗することです(実際には、それの2倍の頻度で成功)。
最後に、テスト車両を示します。
function DoubleNested()
{
"=== DOUBLE NESTED ==="
NestCall
}
function NestCall()
{
"=== NESTED ==="
"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path
"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3
}
function Get-ScriptDirectory1
{
Split-Path $script:MyInvocation.MyCommand.Path
# $Invocation = (Get-Variable MyInvocation -Scope 1).Value
# Split-Path $Invocation.MyCommand.Path
}
. .\ScriptDirFinder.ps1
Import-Module ScriptDirFinder -force
"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path
"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3
NestCall
DoubleNested
ScriptDirFinder.ps1の内容:
function Get-ScriptDirectory2
{
Split-Path $script:MyInvocation.MyCommand.Path
# $Invocation = (Get-Variable MyInvocation -Scope 1).Value
# Split-Path $Invocation.MyCommand.Path
}
ScriptDirFinder.psm1の内容:
function Get-ScriptDirectory3
{
Split-Path $script:MyInvocation.MyCommand.Path
# $Invocation = (Get-Variable MyInvocation -Scope 1).Value
# Split-Path $Invocation.MyCommand.Path
}
PowerShell 2で導入された内容についてはよく知りませんが、Jeffrey Snoverが例を公開した時点では、スクリプトスコープがPowerShell 1に存在していなかった可能性が非常に高いです。
彼のコード例がウェブ上で広範に増殖しているのを見つけたのに驚いたが、試してみるとすぐに失敗した!しかし、それはSnoverの例とは異なる方法で使用したためです(スクリプトトップではなく、別の関数の内部から呼び出しました(「ネストされた2回」の例))。
2011.09.12アップデート
Simple-Talk.comで公開されたばかりの記事で、モジュールに関する他のヒントやコツでこれについて読むことができます。 ウサギの穴をさらに下ろす:PowerShellモジュールとカプセル化 。
Powershellバージョン1.0の質問にタグを付けましたが、Powershellバージョン3.0にアクセスできる場合は、$PSCommandPath
そして$PSScriptRoot
これにより、スクリプトパスの取得が少し簡単になります。 詳細については、このページの「その他のスクリプト機能」セクションを参照してください。
数年間、ほとんどのスクリプトで次のようなコードを問題なく使用しています。
#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1
最近同じ問題に遭遇しました。次の記事は、問題の解決に役立ちました。 http://blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx
仕組みに興味がない場合は、記事ごとに必要なすべてのコードを以下に示します。
function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}
そして、次のことを行うだけでパスを取得できます。
$path = Get-ScriptDirectory
を使用して実行中のスクリプトのパスを見つけることができると思います
$MyInvocation.MyCommand.Path
それが役に立てば幸い !
セドリック
これは、PSの(少なくとも私の考えでは)奇妙なことの1つです。それには完璧な理由があると確信していますが、それでも私には奇妙に思えます。そう:
スクリプトを使用しているが関数を使用していない場合、$ myInvocation.InvocationNameはスクリプト名を含む完全なパスを提供します。スクリプト内で関数内にいる場合、$ myInvocation.ScriptNameは同じことを提供します。
ありがとうmsorens!これは、カスタムモジュールで本当に役立ちました。誰かが自分で作ることに興味があるなら、ここに私の構造があります。
MyModule (folder)
- MyModule.psd1 (help New-ModuleManifest)
- MyScriptFile.ps1 (ps1 files are easy to test)
次に、MyModule.psd1でMyScriptFile.ps1を参照します。 NestedModules配列で.ps1を参照すると、関数はグローバルセッション状態ではなくモジュールセッション状態になります。 ( モジュールマニフェストの記述方法 )
NestedModules = @('.\MyScriptFile.ps1','.\MyOtherScriptFile.ps1')
MyScriptFile.ps1のコンテンツ
function Get-ScriptDirectory {
Split-Path $script:MyInvocation.MyCommand.Path
}
try {
Export-ModuleMember -Function "*-*"
}
catch{}
MyScriptFile.ps1を実行すると、try/catchはExport-ModuleMemberからエラーを隠します
MyModuleディレクトリをここにあるパスのいずれかにコピーします$ env:PSModulePath
PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule
CommandType Name ModuleName
----------- ---- ----------
Function Get-ScriptDirectory MyModule