実行中のスクリプトのソースパスを見つけるにはどうすればよいですか? [複製]
-
03-07-2019 - |
質問
この質問にはすでに回答があります:
実行中のスクリプトが実行されたパスを確認できるようにします。
多くの場合、これは$ pwdではありません。
自分のスクリプトに関連するフォルダー構造にある他のスクリプトを呼び出す必要があり、パスをハードコーディングできますが、それは不快であり、「dev」から昇格しようとすると首に少し痛みがあります。 「テスト」へ「本番」に。
解決
元々 Jeffrey Snoverによって投稿されたユビキタススクリプトPowerShellチームの<>( Skylerの回答)およびKeith CedircおよびEBGreenによって投稿されたバリエーションはすべて、重大な欠点-コードが期待するものを報告するかどうかは、どこで呼び出すかによって異なります!
以下の私のコードは、親スコープではなく、単にスクリプトスコープを参照することでこの問題を解決します:
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
問題を説明するために、4つの異なる方法でターゲット式を評価するテスト車両を作成しました。 (括弧で囲まれた用語は、次の結果テーブルのキーです。)
- インラインコード[インライン]
- インライン関数、つまりメインプログラムの関数[インライン関数]
- ドットソース関数、つまり、同じ関数が別の.ps1ファイルに移動[ドットソース]
- モジュール関数、つまり同じ関数が別の.psm1ファイルに移動[モジュール]
最後の2列は、スクリプトスコープ(つまり$ script :)または親スコープ(-scope 1)を使用した結果を示しています。 &quot; script&quot;の結果は、呼び出しがスクリプトの場所を正しく報告したことを意味します。 &quot;モジュール&quot;結果は、呼び出しが関数を呼び出したスクリプトではなく、関数を含むモジュールの場所を報告したことを意味しますこれは、モジュールに関数を配置できないという両方の関数の欠点を示しています。
モジュールの問題を別として、テーブルからの注目すべき観察結果は、ほとんどの場合親スコープのアプローチを使用すると失敗することです(実際には、成功の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
and $ PSScriptRoot
があり、スクリプトパスを取得できます。少し簡単です。 &quot;その他のスクリプト機能&quot;を参照してください。詳細については、このページのセクションをご覧ください。
ここ数年、ほとんどのスクリプトでこのようなコードを問題なく使用しています。
#--------------------------------------------------------------------
# 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
お役に立てばと思います!
C&#233; dric
これは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