Miek Pool
Miek Pool

Reputation: 55

Multiple variables in path

I am planning on using the following script by looping through a text file to set variables for the location of the source PDF, and designate the path to create a new folder (with week number) to move the source PDF to.

$pdfSource = 'C:\path\in\text\file'
$newFolder = 'C:\path\to\newfolder\in\text\file'
Get-ChildItem $pdfSource '*.pdf' -Recurse | foreach {
    $x = $_.LastWriteTime.ToShortDateString()
    $new_folder_name = Get-Date $x -UFormat %V
    $des_path = "C:\path\to\newfolder\$new_folder_name"

    if (Test-Path $des_path) {
        Move-Item $_.FullName $des_path
    } else {
        New-Item -ItemType Directory -Path $des_path
        Move-Item $_.FullName $des_path
    }
}

I can't seem to figure out the syntax for the line below to include the $newFolder path variable along with the existing $new_folder_name I'm creating.

$des_path = "C:\path\to\newfolder\$new_folder_name"

Upvotes: 1

Views: 3442

Answers (2)

Adam
Adam

Reputation: 4188

Option-1:

$des_path = "${newFolder}\${new_folder_name}"

Option-2:

$des_path = "${0}\${1}" -f $newFolder, $new_folder_name

Option-3:

$des_path = $newFolder + $new_folder_name

Option-4:

$des_path = Join-Path -Path $newFolder -ChildPath $new_folder_name

Upvotes: 5

mklement0
mklement0

Reputation: 440501

There's nothing wrong with your approach to string expansion (interpolation):

$new_folder_name = 'foo' # sample value
$des_path = "C:\path\to\newfolder\$new_folder_name" # use string expansion

yields string literal C:\path\to\newfolder\foo, as expected.

Adam's answer shows you alternatives to constructing file paths, with Join-Path being the most robust and PowerShell-idiomatic, albeit slow.
Another option is to use [IO.Path]::Combine():

[IO.Path]::Combine('C:\path\to\newfolder', $new_folder_name)

The way you calculate the value for $new_folder_name should be problematic if your current culture is not en-US (US-English), but due to a bug actually isn't[1]; either way, it should be simplified:

Instead of:

$x = $_.LastWriteTime.ToShortDateString()
$new_folder_name = Get-Date $x -uformat %V

use:

$new_folder_name = Get-Date $_.LastWriteTime -uformat %V

That is, pass $_.LastWriteTime directly to Get-Date, as a [datetime] instance - no detour via a string representation needed.


[1] .ToShortDateString() returns a culture-sensitive string representation, whereas PowerShell typically uses the invariant culture to ensure cross-culture consistency; therefore, if you pass a string to a parameter that accepts a [datetime] instance, it is the invariant culture's formats that should (only) be recognized, not the current culture's. While that is true for functions written in PowerShell, in compiled cmdlets (typically C#-based), the current culture is unexpectedly applied; while this is a bug, a decision was made not to fix it for the sake of backward compatibility - see this GitHub issue

Upvotes: 2

Related Questions