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