ある時点で属性としてUNCパスを持つアイテムをループし、それらのパスでGet-ChildItem
を使用するPowershellスクリプトを実行するバッチファイルを書いています。最小バージョンでは、これは私のスクリプトで起こっていることです:
Master.bat
powershell -ExecutionPolicy ByPass -File "Slave.ps1"
Slave.ps1
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
# Do things with item
}
私が実行している問題は、Master.batを実行すると、Get-ChildItem
で次の行に沿ってエラーが発生して失敗することです。
get-childitem : Cannot find path '\\remote-server\foothing' because it does not exist.
ただし、Powershellを使用してSlave.ps1ファイルを直接実行すると、問題なく動作するようです。 Master.batファイルが実行されている場合にのみ、これが発生するのはなぜですか?
私が試したもの
FileSystem::
をUNCパスの先頭に追加 http://powershell.org/wp/2014/02/20/powershell-gotcha-unc-paths-and-providers/-literalPath
のプレーン-path
パラメーターの代わりにGet-ChildItem
パラメーターを使用するGet-ChildItem \\remote-server\foothing
を実行し、リモートサーバーへの接続の検証に成功するUNCパスを参照するスクリプトを実行するとこの問題が見つかりましたが、スクリプトのルートがファイルシステム以外の場所に設定されている場合にのみエラーが発生します。例えばPS SQLSEVER \
したがって、以下は同じエラーで失敗します。
cd env:
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
# Do things with item
Write-Host $item
}
したがって、私の解決策は、このコードを実行する前にPSプロンプトがファイルシステムの場所に返されるようにすることでした。例えば.
cd env:
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"
cd c: #THIS IS THE CRITICAL LINE
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
# Do things with item
Write-Host $item
}
これが役立つことを願っています-これがスタックオーバーフローに関する私の最初の答えなので、私は賞金に非常に満足しています。追伸追加するのを忘れた-PSコマンドプロンプトルートは、マシンの構成で自動ロードされたモジュールによって設定される場合があります。 Get-Locationを使用して、FileSystem以外の場所から実際に実行されているかどうかを確認します。
Roryの答え は効果的な回避策を提供しますが、現在の場所を最初にFileSystemプロバイダーの場所に変更する必要のないソリューション:があります。
NCパスの前にFileSystem::
を付けて、現在の場所に関係なく、正しく認識されるようにします。
$foo = @{Name = "Foo"}
$foo.Path = "FileSystem::\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "FileSystem::\\remote-server\barthing"
あるいは、_-Push-Location
とPop-Location
を使用して、Roryの答えを微調整から現在の場所のセッションをグローバルに変更しない(現在の場所を保持するため)です:
try {
# Switch to the *filesystem provider's* current location, whatever it is.
Push-Location (Get-Location -PSProvider FileSystem)
# Process the paths.
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
# Do things with item
}
} finally {
# Restore the previous location.
Pop-Location
}
この素晴らしいブログ記事 根本的な問題を説明しています(強調を追加):
PowerShellはPSUNC上にないため、[UNCパス]を「ルート化された」ものとして認識しません。そのため、PowerShellの現在の場所に関連付けられているプロバイダーはすべて、それらを処理しようとします。
プレフィックスFileSystem::
を追加すると、現在の場所の基になるプロバイダーに関係なく、パスがFileSystemプロバイダーパスであることが明確に識別されます。
この種の問題に対処する Push-Location
および Pop-Location
コマンドについて他の場所を読みました-手動でステップバイステップで質問に行きました-step、スクリプトにプッシュ/ポップがある新しいルーチンをテストしますが、PSウィンドウでそれらを実行するのを忘れていました。 @Roryの答えを確認した後、PS C:\プロンプトではなくPS SQLServer:\にいることに気付きました。
したがって、これを「スレーブ」スクリプトで使用する方法は次のとおりです。
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
Push-Location
# Do things with item
Pop-Location
}
# Do things
の前後にプッシュ/ポップを追加することの考えは、場所を変更するのはこうしたものだと思われるためです。