1

I made a function that creates a file name.

The function breaks when sent a drive letter that doesn’t exist.

I have have changed the function to not use join-path but I am wondering if there is another way?

The try / catch is not working as expected.

Perhaps the best answer is not using join-path ?

$fullPath = join-path -path $DirectoryName  -childpath ((Get-Date).ToString('yyyy_MM_ddThhmmss-') + ($ReportName + $Extension)) -ErrorAction SilentlyContinue
dcaz
  • 847
  • 6
  • 15
  • 2
    `[System.IO.Path]::Combine()` perhaps? Show your code so we can help wit it, – Theo Jul 04 '21 at 14:53
  • I added a line of code. The forum would not allow me to add my entire function. – dcaz Jul 04 '21 at 16:09
  • `code` $fullPath = $DirectoryName + '\' + ((Get-Date).ToUniversalTime().ToString('yyyy_MM_ddThhmmss-') + ($ReportName + $Extension)) `code` This is how I did it without the join-path and I was wondering if there is a better way? – dcaz Jul 04 '21 at 16:12

2 Answers2

3

To emulate Join-Path's behavior without the - surprising and vexing - requirement that a drive spec. (e.g., N:) refer to an existing drive (even though no other components are required to exist):

Pragmatically speaking, you can simply use string concatenation / interpolation to join your path components:

$dir = 'N:\foo'; $file = 'bar'

# String concatenation
$joinedPath = $dir + '\' + $file

# String interpolation
$joinedPath = "$dir\$file"

# With an open-ended number of path components.
$components = $dir, 'sub', $file
$joinedPath = $components -join '\'

While, depending on the input components, this can result in accidentally duplicated path separators (e.g., N:\foo\\bar), this is usually not a problem, because the file-system APIs treat such duplicates as a single separator; that is, N:\foo\\bar is treated the same as N:\foo\bar.

If you want to avoid duplicated separators, see the solution in the next section.


To more fully emulate Join-Path, which involves removing accidentally duplicated separators and normalizing them to the platform-native form (e.g., on Windows, / -> \), use the following:

$dir = 'N:\foo'; $file = 'bar.txt'
$components = $dir, $file

$joinedPath = 
  ($components -join '\') -replace '(?!^)([\\/])+', [IO.Path]::DirectorySeparatorChar

To wrap this up in a (very simple) function, join-AnyPath:

function join-AnyPath {
  ($args -join '\') -replace '(?!^)([\\/])+', [IO.Path]::DirectorySeparatorChar
}

# Sample call
join-AnyPath N:\dir\ /foo/ bar.txt

The above yields N:\dir\foo\bar.txt (on Windows).


Note: Theo points out that there's also the [IO.Path]::Combine() .NET method, but while it doesn't require that a drive exist either, its behavior differs from Join-Path with respect to how \-prefixed components are handled, which can lead to surprising results: see this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
1

With thanks to this answer from x0n I use the Combine() method from the type System.Management.Automation.PathIntrinsics.

It also works with PSDrives and doesn't have the drawback of the .NET [IO.Path]::Combine() method:

$ExecutionContext.SessionState.Path.Combine('C:\test1', 'test2')

Output:

C:\test1\test2

Sample with custom PSDrive:

New-PSDrive -Name Temp -PSProvider filesystem -Root F:\Temp\
$ExecutionContext.SessionState.Path.Combine('Temp:\test1', 'test2')
$ExecutionContext.SessionState.Path.Combine('Temp:\test1', '\test2')

Output:

Temp:\test1\test2
Temp:\test1\test2
Eelco L.
  • 714
  • 7
  • 7