Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ public class JoinPathCommand : CoreCommandWithCredentialsBase
[Parameter]
public SwitchParameter Resolve { get; set; }

/// <summary>
/// Gets or sets the extension to use for the resulting path.
Comment thread
yotsuda marked this conversation as resolved.
/// If not specified, the original extension (if any) is preserved.
/// <para>
/// Behavior:
/// - If the path has an existing extension, it will be replaced with the specified extension.
/// - If the path does not have an extension, the specified extension will be added.
/// - If an empty string is provided, any existing extension will be removed.
/// - A leading dot in the extension is optional; if omitted, one will be added automatically.
/// </para>
/// </summary>
[Parameter(ValueFromPipelineByPropertyName = true)]
[ValidateNotNull]
public string Extension { get; set; }
Comment thread
yotsuda marked this conversation as resolved.

#endregion Parameters

#region Command code
Expand Down Expand Up @@ -128,6 +143,12 @@ protected override void ProcessRecord()
continue;
}

// If Extension parameter is present it is not null due to [ValidateNotNull].
if (Extension is not null)
{
Comment thread
iSazonov marked this conversation as resolved.
joinedPath = System.IO.Path.ChangeExtension(joinedPath, Extension.Length == 0 ? null : Extension);
}

if (Resolve)
{
// Resolve the paths. The default API (GetResolvedPSPathFromPSPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,102 @@ Describe "Join-Path cmdlet tests" -Tags "CI" {
$result = Join-Path -Path $Path -ChildPath $ChildPath
$result | Should -BeExactly $ExpectedResult
}
It "should handle extension parameter: <TestName>" -TestCases @(
@{
TestName = "change extension"
ChildPath = "file.txt"
Extension = ".log"
ExpectedChildPath = "file.log"
}
@{
TestName = "add extension to file without extension"
ChildPath = "file"
Extension = ".txt"
ExpectedChildPath = "file.txt"
}
@{
TestName = "extension without leading dot"
ChildPath = "file.txt"
Extension = "log"
ExpectedChildPath = "file.log"
}
@{
TestName = "double extension with dot"
ChildPath = "file.txt"
Extension = ".tar.gz"
ExpectedChildPath = "file.tar.gz"
}
@{
TestName = "double extension without dot"
ChildPath = "file.txt"
Extension = "tar.gz"
ExpectedChildPath = "file.tar.gz"
}
@{
TestName = "remove extension with empty string"
ChildPath = "file.txt"
Extension = ""
ExpectedChildPath = "file"
}
@{
TestName = "preserve dots in base name when removing extension with empty string"
ChildPath = "file...txt"
Extension = ""
ExpectedChildPath = "file.."
}
@{
TestName = "replace only the last extension for files with multiple dots"
ChildPath = "file.backup.txt"
Extension = ".log"
ExpectedChildPath = "file.backup.log"
}
@{
TestName = "preserve dots in base name when changing extension"
ChildPath = "file...txt"
Extension = ".md"
ExpectedChildPath = "file...md"
}
@{
TestName = "add extension to directory-like path"
ChildPath = "subfolder"
Extension = ".log"
ExpectedChildPath = "subfolder.log"
}
) {
param($TestName, $ChildPath, $Extension, $ExpectedChildPath)
$result = Join-Path -Path "folder" -ChildPath $ChildPath -Extension $Extension
$result | Should -BeExactly "folder${SepChar}${ExpectedChildPath}"
}
It "should handle extension parameter with multiple child path segments: <TestName>" -TestCases @(
@{
TestName = "change extension when joining multiple child path segments"
ChildPaths = @("subfolder", "file.txt")
Extension = ".log"
ExpectedPath = "folder${SepChar}subfolder${SepChar}file.log"
}
) {
param($TestName, $ChildPaths, $Extension, $ExpectedPath)
$result = Join-Path -Path "folder" -ChildPath $ChildPaths -Extension $Extension
$result | Should -BeExactly $ExpectedPath
}
It "should change extension for multiple paths" {
$result = Join-Path -Path "folder1", "folder2" -ChildPath "file.txt" -Extension ".log"
$result.Count | Should -Be 2
$result[0] | Should -BeExactly "folder1${SepChar}file.log"
$result[1] | Should -BeExactly "folder2${SepChar}file.log"
}
It "should resolve path when -Extension changes to existing file" {
New-Item -Path TestDrive:\testfile.log -ItemType File -Force | Out-Null
$result = Join-Path -Path TestDrive: -ChildPath "testfile.txt" -Extension ".log" -Resolve
$result | Should -BeLike "*testfile.log"
}
Comment thread
yotsuda marked this conversation as resolved.
It "should throw error when -Extension changes to non-existing file with -Resolve" {
{ Join-Path -Path TestDrive: -ChildPath "testfile.txt" -Extension ".nonexistent" -Resolve -ErrorAction Stop; Throw "Previous statement unexpectedly succeeded..." } |
Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.JoinPathCommand"
}
It "should accept Extension from pipeline by property name" {
$obj = [PSCustomObject]@{ Path = "folder"; ChildPath = "file.txt"; Extension = ".log" }
$result = $obj | Join-Path
$result | Should -BeExactly "folder${SepChar}file.log"
}
}
Loading