52

I have an array of file names in Powershell, and I would like to prepend a path to each of them and get the result in a new array.

In C# I could do this using Linq...

var files = new string[] { "file1.txt", "file2.txt" };
var path = @"c:\temp\";
var filesWithPath = files.Select(f => path + f).ToArray();

But what is the idiomatic way to do this in Powershell? It looks like there is a foreach syntax I could use, but I figure there must be a more concise, functional way to do it.

Connor Low
  • 5,900
  • 3
  • 31
  • 52
Jon Rimmer
  • 12,064
  • 2
  • 19
  • 19

3 Answers3

89

An array in Powershell is declared with @() syntax. % is shorthand for foreach-object. Let's declare an array with all the file names and loop through it with foreach. join-path combines a path and a child path into a single path.

$files = @("file1.txt", "file2.txt")
$pFiles = $files | % {join-path "c:\temp" $_ }
$pFiles

Output:

c:\temp\file1.txt
c:\temp\file2.txt

NB: if the input consists of single an element, foreach will not return a collection. If an array is desired, either use explicit type or wrap the results. Like so,

[array]$pFiles = $files | % {join-path "c:\temp" $_ }
$pFiles = @($files | % {join-path "c:\temp" $_ })
vonPryz
  • 22,996
  • 7
  • 54
  • 65
  • Thanks a lot, I hadn't seen anything about that % shorthand. – Jon Rimmer Jan 18 '12 at 11:32
  • 3
    This is good it looks like if the source array only has 1 element than the result will not be an array...is this your understanding? – chosenbreed37 Jan 06 '16 at 15:43
  • @chosenbreed37 This is about four years old a question. Please post a new one, so that you'll get more attention from the community. – vonPryz Jan 06 '16 at 16:02
  • 4
    @vonPryz This question is the top Google result for _powershell map array_, and yours is the topvoted and accepted answer. If your suggested approach behaves differently when the input is of length 1 (and it seems that it does), then I think that's the kind of thing you should mention in your answer, not brush off to another question. – JLRishe Feb 06 '19 at 09:05
4

Like this:

$a = @("file1.txt","file2.txt")
$b = "c:\temp\"
$c = $a | % { $b + $_ }

I can't figure this w/o a foreach. Sorry

Using the great job from Josh Einstein LINQ for Powershell

you can write this:

$a = @("file1.txt","file2.txt")
$b = "c:\temp\"
$c = $a | Linq-Select -Selector {$b + $_ }

having same results in a LINQ manner but not using a foreach (%).

CB.
  • 58,865
  • 9
  • 159
  • 159
  • 4
    w/o `foreach` it will be `$c = $a | .{process{ $b + $_ }}`. It is basically the same but works faster. – Roman Kuzmin Jan 18 '12 at 11:28
  • @RomanKuzmin thank for this, never use this kind of 'foreach' ! Have you some percent value in faster excecution respect a %? thank you – CB. Jan 18 '12 at 11:35
  • 2
    This is very nice. I have never seen this syntax before. Can you please explain a little about the . in front of the {? Is this dot sourcing or something else? – Matthew MacFarland Jul 18 '16 at 21:00
4

You could also use the replace operator:

PS> 'file1.txt','file2.txt','file3.txt' -replace '(^.+$)','C:\temp\$1'

C:\temp\file1.txt
C:\temp\file2.txt
C:\temp\file3.txt
Shay Levy
  • 121,444
  • 32
  • 184
  • 206