PowerShellのカレントディレクトリ問題

めったに影響はないんだけどつまりたまに困る系
あとあのこんなん言われなきゃわからんわっていう

PS C:\hoge> cd C:\fuga
PS C:\fuga> pwd

Path
----
C:\fuga

PS C:\fuga> [System.Environment]::CurrentDirectory
C:\hoge

これな…
関数のパラメータに$Pathを取ってデフォルト値をたとえば.にするじゃん
あるいは-Pathに相対パス渡すじゃん
で、関数内で何かに$Path渡すじゃん
するとその何かが想定してないパスにアクセスしたりすることがあるんだよ
なんかこうPowerShell起動時に指定した作業ディレクトリが起点になる

なんでそんなことになってんのかわかんなくて困ってたこともあったんだが今日謎が解けた
よかった

[System.Environment]::CurrentDirectory = pwd

とりあえずこんな感じで回避すれば良いですかね


追記

しゅんさんのコメントにあるように cd を書き換えてゴキゲンなのですが

厳密には、レジストリを指定された場合等の対策が必要ですが、、、。

とあったので厳密にやってみました

function Set-Location2
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory=$false,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName,ParameterSetName='Path')]
        [string] $Path,
        [parameter(Mandatory=$false,ValueFromPipelineByPropertyName,ParameterSetName='PSPath')]
        [string] $LiteralPath,
        [parameter(Mandatory=$false,ValueFromPipelineByPropertyName,ParameterSetName='Stack')]
        [string] $StackName,
        [switch] $PassThru,
        [switch] $UseTransaction
    )
    process
    {
        switch ($PsCmdlet.ParameterSetName)
        {
            'Stack'
            {
                return Set-Location -StackName $StackName -PassThru:$PassThru -UseTransaction:$UseTransaction
            }
            'PSPath'
            {
                return Set-Location -LiteralPath $LiteralPath -PassThru:$PassThru -UseTransaction:$UseTransaction
            }
        }
        $location = Set-Location -Path $Path -PassThru:$PassThru -UseTransaction:$UseTransaction
        if ($(gi $(pwd)).PSProvider.Name -eq 'FileSystem')
        {
            [Environment]::CurrentDirectory = $(pwd)
        }
        return $location
    }
}

なるべくもともとの Set-Location と同じ動作になるようにパラメータは合わせました
しかし副作用があります

PS> md hoge | Set-Location -PassThru

Path
----
Microsoft.PowerShell.Core\FileSystem::C:\hoge

もともとの Set-Location だとこのように、ディレクトリを作って即移動なんてことをするとパスが PSPath になっちゃって気持ち悪かったんですね
Get-Item してパイプした場合なんかも同様でした
しかし

PS> md hoge | Set-Location2 -PassThru

Path
----
C:\hoge

気持ち悪くなりません、やったね!
実はこれ絶対に対応したいなって思ってたんですけど、なんかするまでもなく望み通りになっててラッキーでした
(パイプしてないからなのかな?)

あと、 [Environment]::CurrentDirectory$Path ではなく $(pwd) を代入してるのは

PS> Set-Location2 c: -PassThru

Path
----
C:\Program Files

PS> [System.Environment]::CurrentDirectory
C:\

こうなっちゃうのを防ぐためです
ちなみにこの PSDrive 名を渡したときにその CurrentLocation に飛ぶ便利機能はなんて呼ぶんだ

あとは $PROFILE

Set-Alias -Name cd -Value Set-Location2 -Force -Option AllScope

してやれば cd がいい感じに!

広告

PowerShellのカレントディレクトリ問題」への4件のフィードバック

  1. おおー!
    これ、たまに困るんですよね。
    面倒になって、あちこちフルパスにした記憶が、、、。
    今度困ったらやってみます!

  2. やっぱり引っかかりますよね…
    なんでこんな仕様になっちゃんてるんでしょうね!なにかしら理由があるのかもしれないけれど使ってる方としては想定外すぎて困っちゃう
    もういっそpromptで常に作業フォルダをpwdにしてしまっても良いかもしれませんね

  3. せっかくなので、こうすることにしました。

    Remove-Item -Path alias:cd
    function cd {
    Param(
    [string]$Path
    )

    Set-Location $Path
    [Environment]::CurrentDirectory = $Path
    }

    おかげさまですっきりしました。
    厳密には、レジストリを指定された場合等の対策が必要ですが、、、。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中