Search code examples
powershellpowershell-5.0

Constructing a path with the format operator throws a type error


I am trying to use the builtin -f feature of PowerShell, but I keep getting hit with an error of

Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Filter'. Specified method is not supported.

Here is my code, what am I doing incorrectly to be able to do what I am wanting to do?

$beefcakes = @('Homeboy', 'Coldfry', 'Redpearl')
foreach ($bf in $beefcakes) {
  $HomeDir = "C:\Testing\"
  $DestPath = "$HomeDir\$bf\"
  switch ($bf) {
    Homeboy  { $redfern = "1234" }
    Coldfry  { $redfern = "888" }
    Redpearl { $redfern = "0011" }
  }

  if (Test-Path '{0}\{1}_{2}.csv' -f $DestPath, $redfern, $bf) {
    $savefile = '{0}\{1}_{2}.csv' -f $DestPath, $redfern, $bf
  } else {
    $savefile = '{0}\{1}_{2}_Redo.csv' -f $DestPath, $redfern, $bf
  }
}

Solution

  • You need to put the formatting expression in a subexpression or assign it to a variable, otherwise PowerShell will interpret the -f as the abbreviated parameter -Filter for Test-Path, which expects a string argument, not an object array.

    Test-Path       '{0}\{1}_{2}.csv' -f      $DestPath, $redfern, $bf
        ⇕                  ⇕           ⇕                 ⇕
    Test-Path -Path '{0}\{1}_{2}.csv' -Filter $DestPath, $redfern, $bf

    Change this:

    if (Test-Path '{0}\{1}_{2}.csv' -f $DestPath, $redfern, $bf) {
      $savefile = '{0}\{1}_{2}.csv' -f $DestPath, $redfern, $bf
    } else {
      $savefile = '{0}\{1}_{2}_Redo.csv' -f $DestPath, $redfern, $bf
    }
    

    into either this:

    if (Test-Path ('{0}\{1}_{2}.csv' -f $DestPath, $redfern, $bf)) {
      $savefile = '{0}\{1}_{2}.csv' -f $DestPath, $redfern, $bf
    } else {
      $savefile = '{0}\{1}_{2}_Redo.csv' -f $DestPath, $redfern, $bf
    }
    

    or (better) this:

    $savefile = '{0}\{1}_{2}.csv' -f $DestPath, $redfern, $bf
    if (-not (Test-Path $savefile)) {
      $savefile = '{0}\{1}_{2}_Redo.csv' -f $DestPath, $redfern, $bf
    }
    

    On a more general note, it's good practice to avoid repeated assignment of static values inside loops ($HomeDir), and it's also good practice to use the Join-Path cmdlet for building paths (saves you the headache of having to manage backslashes). You don't even need the format operator here. Simply put your variables in double-quoted strings.

    $HomeDir = 'C:\Testing'
    foreach ($bf in $beefcakes) {
      $DestPath = Join-Path $HomeDir $bf
      ...
      $basename = "${redfern}_${bf}"
      $savefile = Join-Path $DestPath "$basename.csv"
      if (-not (Test-Path $savefile)) {
        $savefile = Join-Path $DestPath "${basename}_Redo.csv"
      }
    }