📂

バッチ経由で実行しているPSスクリプトのカレントディレクトリ取得方法

2024/05/07に公開

概要

これまで下記のコードで実行中のPowerShellスクリプトが格納されている場所を取得していました。

以前使っていた「$MyInvocation.ScriptName」を使用した取得方法
$currentDirectoryUsingMyInvocation_old = (Split-Path ( & { $MyInvocation.ScriptName } ) -Parent)

より簡潔に取得できる方法を2つ見つけたので紹介します。

この記事のターゲット

  • PowerShellユーザーの方
  • バッチで実行したPowerShellスクリプト内の処理でカレントディレクトリ(自身の格納場所)を取得する方法を知りたい方

カレントディレクトリを取得するシチュエーション

バッチファイル(*.bat)経由でPowerShellスクリプトを実行、かつバッチファイルとPowerShellスクリプトの格納場所が異なる場合、
PowerShellスクリプト内のコードで .\ などの相対パスを使うとバッチファイルから見た相対パスとなり正常動作しません。

たとえば下記のような構成の場合 ...

ディレクトリー(フォルダー)構成
D:\ルートフォルダー
│
├ ExecuteMain.bat
│
└ sourceフォルダー
 └ powershellフォルダー
  ├ Main.ps1
  └ setup.ini

ExecuteMain.batでMain.ps1を実行し、かつMain.ps1内で相対パスでsetup.iniを参照している場合、
PowerShellスクリプト内で .\setup.ini と使用しても「D:\ルートフォルダー\sourceフォルダー\powershellフォルダー\setup.ini」と解釈されません。
実際には起動したバッチファイルが元となる為、「D:\ルートフォルダー\setup.ini」のファイルを参照しようとし、
エラーが発生してしまいます。

上記エラーとなる構成で検証した結果を共有

前述している通りの構成でスクリプトを作成しました。

フォルダー構成
PS C:\> TREE /F .\ルートフォルダー\
フォルダー パスの一覧:  ボリューム OS
ボリューム シリアル番号は 0000XXXX XXXX:XXXX です
C:\ルートフォルダー
│  ExecuteMain.bat
│
└─sourceフォルダー
    └─powershellフォルダー
            Main.ps1
            setup.ini

PS C:\>

下記のバッチファイルでは、PowerShellスクリプトを呼び出しています。

ExecuteMain.bat
@ECHO OFF

@REM メインスクリプト場所を設定
SET PSFILEPATH="%~dp0sourceフォルダー\powershellフォルダー\Main.ps1"

@REM メインスクリプトを実行
powershell -NoProfile -ExecutionPolicy Unrestricted -File %PSFILEPATH%

@REM 自動で終了するバッチを一時停止
ECHO.
ECHO 処理が終了しました。
ECHO いずれかのキーを押すとウィンドウが閉じます。
PAUSE > NUL

下記のPowerShellスクリプトでは、自身のカレントディレクトリでもある「C:\ルートフォルダー\sourceフォルダー\powershellフォルダー」の配下、 setup.ini を参照しようと、
相対パスで.\setup.ini としています。

このコーディングは直接、PowerShellスクリプトを実行するケースではエラーになりませんが、
前述している通り、バッチファイル起動の場合はエラーとなってしまいます。

Main.ps1
# 相対パスでsetup.iniを参照
Get-Item .\setup.ini

設定ファイル(setup.ini)の内容は参照しない為、雑に記載。

setup.ini
# 参照されない中身をいい加減に記述
SettingColumn01="Setting Contents01"
SettingColumn02="Setting Contents02"

上記の構成・ソースによりバッチファイル経由でPowerShellスクリプトを実行すると、
PowerShellスクリプト内 Get-Item .\setup.ini の相対パスがバッチファイルをベースとした「C:\ルートフォルダー\setup.ini」で解釈されてしまいエラーが発生します。

実際のエラーは下記の通り。

実際に実行した結果
Get-Item : パス 'C:\ルートフォルダー\setup.ini' が存在しないため検出できません。
発生場所 C:\ルートフォルダー\sourceフォルダー\powershellフォルダー\Main.ps1:1 文字:1
+ Get-Item .\setup.ini
+ ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\ルートフォルダー\setup.ini:String) [Get-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand


処理が終了しました。
いずれかのキーを押すとウィンドウが閉じます。

エラー事例:バッチ起動のPowerShellスクリプトで相対パスを使用した場合
エラー事例:バッチ起動のPowerShellスクリプトで相対パスを使用した場合

ここまで検証したとおり、バッチファイル経由でPowerShellスクリプトを実行する場合、「.\~」というように相対パスを使用すると、
バッチファイルを起点としたパスとなる為、すこし回りくどい指定が必要となります。

この記事で紹介する方法を使用する事で、PowerShellスクリプトを起点とした相対パスを使用できます!

対応方法

自動変数「$MyInvocation」を使ったカレントディレクトリの取得方法

「$MyInvocation.MyCommand.Path」を使用した取得方法
$currentDirectoryUsingMyInvocation = (Split-Path -Path $MyInvocation.MyCommand.Path -Parent)
参考情報:以前コーディングしていた「$MyInvocation.ScriptName」を使用した取得方法

冒頭にも紹介しましたが私が以前にコーディングしていた下記の取得方法は、回りくどいですね。上記、「$MyInvocation.MyCommand.Path」を使用する方法の方がシンプルでわかりやすいです。

以前コーディングしていた「$MyInvocation.ScriptName」を使用した取得方法
$currentDirectoryUsingMyInvocation_old = (Split-Path ( & { $MyInvocation.ScriptName } ) -Parent)

自動変数「$PSScriptRoot」を使ったカレントディレクトリの取得方法

$PSScriptRoot
$currentDirectoryUsingPSScriptRoot = $PSScriptRoot

まとめ

  • 以前も自動変数$MyInvocationを使いPowerShellスクリプトの相対パスを取得していたが、よりシンプルな2つの方法があった

    • 自動変数$MyInvocation を使った、よりシンプルな取得方法
    • 自動変数$PSScriptRoot を使った、シンプルな取得方法
  • 個人的なオススメの取得方法は、自動変数「$PSScriptRoot」を使った方法
    理由:処理内容と自動変数の名前が紐づきやすく、わかりやすいため

関連記事

https://haretokidoki-blog.com/pasocon_powershell-startup/
https://zenn.dev/haretokidoki/articles/7e6924ff0cc960

GitHubで編集を提案

Discussion