Running Get-ChildItem on UNC path works in Powershell but not in Powershell run in batch file

こ雲淡風輕ζ 提交于 2019-12-02 20:28:07

I have found this issue when running scripts referring to UNC paths - but the error only occurs when the root of the script is set to a non file system location. e.g. PS SQLSEVER\

So the following fails with the same error:

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
}

So my resolution was to ensure that the PS prompt was returned to a file system location before executing this code. e.g.

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
}

I hope this helps - I would be very happy with the bounty as this is my first answer on stack overflow. P.S. I forgot to add - the PS command prompt root may be set by auto loaded modules in the configuration of your machine. I would check with Get-Location to see if you are actually executng from a non FileSystem location.

Rory's answer provides an effective workaround, but there's a solution that doesn't require changing the current location to a FileSystem provider location first:

Prefix your UNC paths with FileSystem:: to ensure that they are recognized correctly, irrespective of the current location:

$foo = @{Name = "Foo"}
$foo.Path = "FileSystem::\\remote-server\foothing"

$bar = @{Name = "Bar"}
$bar.Path = "FileSystem::\\remote-server\barthing"

Alternatively, here is a tweak to Rory's answer to avoid changing the current location session-globally (to preserve whatever the current location is), using Push-Location and Pop-Location:

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
}

Optional background information

This excellent blog post explains the underlying problem (emphasis added):

PowerShell doesn't recognize [UNC paths] as "rooted" because they're not on a PSDrive; as such, whatever provider is associated with PowerShell's current location will attempt to handle them.

Adding prefix FileSystem:: unambiguously identifies the path as being a FileSystem provider path, irrespective of the provider underlying the current location.

I read somewhere else about the Push-Location and Pop-Location commands to counter this kind of problem - I landed on your question while manually, step-by-step, testing a new routine where the script has push/pop, but I forgot to do them on my PS window. After checking @Rory's answer I noticed I was on PS SQLServer:\ instead of PS C:\ prompt.

So a way to use this on your "slave" script would be:

$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
}

Thought of adding the Push/Pop before and after the # Do things because it seems that it's those things that change the location.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!