In my day to day job I use a fair amount of PowerShell. Some might say the deployment process is mountains of PowerShell glued together by Team Foundation Server. Cruel but accurate. I don’t make any claims to be a PowerShell expert (I really don’t) so I post this not to show my PS brilliance but rather as a way for me to practice and learn. I appreciate this has been written about elsewhere but as I say it’s just practice and I wrote this without peeking at anybody else’s solution (promise)
Standard Call
Within the mountains of PowerShell I use Join-Path quite a bit. It’s fine for two parameters
Join-Path "C:\TestPath1" "TestPath2"
Output
C:\TestPath1\TestPath2
But I’m always mildly surprised it can’t cope with more parameters
Join-Path "C:\TestPath1" "TestPath2" "TestPath3"
Output
Join-Path : A positional parameter cannot be found that accepts argument 'TestPath3'. At line:1 char:1 + Join-Path "C:\TestPath1" "TestPath2" "TestPath3" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Join-Path], ParameterBindingException + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.JoinPathCommand
Boom – unhappy code, unhappy coder.
Piped Call
The most straightforward solution is to pipe the output of one call to a send call and so on. So
Join-Path "C:\TestPath1" "TestPath2" | Join-Path "TestPath3"
Sadly doesn’t work
Join-Path : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input. At line:1 char:40 + Join-Path "C:\TestPath1" "TestPath2" | Join-Path "TestPath3" + ~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (C:\TestPath1\TestPath2:PSObject) [Join-Path], ParameterBindingException + FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Commands.JoinPathCommand
In order to get this to work the second parameter needs to be explicitly named
Join-Path "C:\TestPath1" "TestPath2" | Join-Path -ChildPath "TestPath3" | Join-Path -ChildPath "TestPath4"
Which then works perfectly well
C:\TestPath1\TestPath2\TestPath3\TestPath4
Using parameter array
It feels as if it should/must/ought to be possible to do this without piping – by passing in an array of parameters. Indeed it is. This function will do the trick
function Join-ArrayPath { param([parameter(Mandatory=$true)] [string[]]$PathElements) if ($PathElements.Length -eq "0") { $CombinedPath = "" } else { $CombinedPath = $PathElements[0] for($i=1; $i -lt $PathElements.Length; $i++) { $CombinedPath = Join-Path $CombinedPath $PathElements[$i] } } return $CombinedPath }
To call it it needs to be imported into the shell, There are a number of ways to do this but the easiest is by using the dot operator (dot-sourcing) i.e.
. "C:\PowerShellLib\Join-ArrayPath.ps1"
The function is then available to be called
Join-ArrayPath "c:\TestPath1","TestPath2","TestPath3","TestPath3"
And again works perfectly well
C:\TestPath1\TestPath2\TestPath3\TestPath4
So there you have it, both original and insightful. Sadly the original is not insightful and the insightful is not original. But I enjoyed writing it!
Note on script permissions
When importing the script about you may see this
File C:\PowerShellLib\Join-ArrayPath.ps1 cannot be loaded because running
scripts is disabled on this system. As part of Microsoft Trustworthy Computing initiative PowerShell is secure by default won’t allow scripts to be run. To bypass this run
Set-ExecutionPolicy Unrestricted
This is just for demo purposes though. For production or anything other than quick demos then consider signing scripts (see links below).
Useful Links
Adding functions to Powershell sessions
http://mikepfeiffer.net/2010/06/how-to-add-functions-to-your-powershell-session/
Execution Policies
https://technet.microsoft.com/library/hh847748.aspx
Better ways to work with the PowerShell execution policy
https://technet.microsoft.com/en-us/magazine/2b6812f2-e6e5-41ad-a1c4-6b9e01977cc7
Thanks
Pretty! This has been a really wonderful article.
Thanks for supplying these details.
Can you tell us more about this? I’d like to find out some additional information.