Background: I have some locations I'd like to have easier access to. I don't want to mklink, because then something may save the path as the link path and fail later.
Proposed solution: Create some PSDrives. Start with a static array of hashtables, so that they can be imported/exported/filtered easily in the future.
Prep-step:
# Clear out existing drives, empty error stack
Get-PSDrive -name "*-test-*" | Remove-PSDrive
$Error.Clear()
Failed Solution 1: Create array of hashes with parameter KVPs
@(
@{ Name='hasharray-test-control'; Root='C:\Windows\Temp' },
@{ Name='hasharray-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | New-PSDrive -PSProvider FileSystem
Confusing error "The input object cannot be bound to any parameters for the command ..."
Failed Solution 2: Web-grokking shows that the items have to be PSCustomObject, not a hash
@(
[PSCustomObject]@{ Name='array-test-control'; Root='C:\Windows\Temp' },
[PSCustomObject]@{ Name='array-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | New-PSDrive -PSProvider FileSystem
Fails on second item with
New-PSDrive : Cannot bind parameter 'Name' to the target.
Exception setting "Name":
"Cannot process argument because the value of argument "value" is null.
Failed Solution 3: Ok, Maybe powershell is passing the array as one big blob, make it implicit
[PSCustomObject]@{ Name='implicitarray-test-control'; Root='C:\Windows\Temp' },
[PSCustomObject]@{ Name='implicitarray-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" } |
New-PSDrive -PSProvider FileSystem
Fails on second item with same error
Failed solution 4: Insert intermediate variable
$TestDrives = @(
[PSCustomObject]@{ Name='foreach-test-control'; Root='C:\Windows\Temp' }
[PSCustomObject]@{ Name='foreach-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
)
$TestDrives | New-PSDrive -PSProvider FileSystem
Fails on second item with same error
Failed Solution 5: Insert a select to extract properties
@(
[PSCustomObject]@{ Name='select-test-control'; Root='C:\Windows\Temp' },
[PSCustomObject]@{ Name='select-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | Select Name, Root | New-PSDrive -PSProvider FileSystem
Fails on second item with same error
Failed Solution 6: No? Ok, I'll add a foreach to force each item to resolve
$TestDrives = @(
[PSCustomObject]@{ Name='foreachpipe-test-control'; Root='C:\Windows\Temp' },
[PSCustomObject]@{ Name='foreachpipe-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
)
$TestDrives | ForEach-Object { $_ } | New-PSDrive -PSProvider FileSystem
Fails on second item with same error
Failed Solution 7: Still No? Fine, Select each property explicitly inside the foreach
@(
[PSCustomObject]@{ Name='foreachselect-test-control'; Root='C:\Windows\Temp' },
[PSCustomObject]@{ Name='foreachselect-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | ForEach-Object { $_ | Select Name, Root } | New-PSDrive -PSProvider FileSystem
Fails on second item with same error
And just for good measure, let's try only static values:
@(
[PSCustomObject]@{ Name='foreachstatic-test-control'; Root='C:\Windows\Temp' }
[PSCustomObject]@{ Name='foreachstatic-test-control-2'; Root='C:\Windows\Temp' }
) | New-PSDrive -PSProvider FileSystem
Fails on second item with same error
Extra notes:
- I tried both with, and without the commas in the array declaration, results are identical
- I also tried the following as the second item with identical results
[PSCustomObject]@{ Name='test-interp'; Root="$HOME\Temp" }[PSCustomObject]@{ Name='test-interp-command'; Root="$($HOME)\Temp" }[PSCustomObject]@{ Name='test-format'; Root=('{0}\Temp' -f $HOME) }[PSCustomObject]@{ Name='test-format-resolve'; Root=$('{0}\Temp' -f $HOME) }- Set
$tRootoutside hash, and use[PSCustomObject]@{ Name='test-format-resolve'; Root=$tRoot }
Working Solution: Wow, I'm speechless... let's force a foreach around everything
@(
[PSCustomObject]@{ Name='foreach-test-control'; Root='C:\Windows\Temp' },
[PSCustomObject]@{ Name='foreach-test-interp-brace'; Root="${ENV:SystemRoot}\Temp" }
) | ForEach-Object { $_ | New-PSDrive -PSProvider FileSystem }
And now it works, but just feels wrong, since it's already on the pipeline.
And now, the question(s):
Why do I have to explicitly ForEach-Object in this case instead of being able to use the pipeline, when New-PSDrive supports ValueFromPipelineByPropertyName for both Name and Root?
Why does the first item in each array work, while all subsequent items fail?