Skip to content
Draft
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 @@ -2984,21 +2984,49 @@ private Collection<PathInfo> GetResolvedPaths(string path)
/// </summary>
protected override void ProcessRecord()
{
foreach (string path in Path)
// When moving multiple items with wildcards to a non-existent destination,
// we need to create the destination directory first to ensure all items
// preserve their directory structure. Otherwise, the first directory gets
// renamed to the destination, and subsequent items are moved into it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please remove the extra line.

if (!base.SuppressWildcardExpansion)
{
if (base.SuppressWildcardExpansion)
{
MoveItem(path, literalPath: true);
}
else
// First, collect all resolved paths to determine if we're moving multiple items
var allResolvedPaths = new List<string>();
foreach (string path in Path)
{
Collection<PathInfo> resolvedPaths = GetResolvedPaths(path);

foreach (PathInfo resolvedPathInfo in resolvedPaths)
{
string resolvedPath = resolvedPathInfo.Path;
MoveItem(resolvedPath, literalPath: true);
allResolvedPaths.Add(resolvedPathInfo.Path);
}
}

// If moving multiple items and destination doesn't exist, create it first
if (allResolvedPaths.Count > 1 && !InvokeProvider.Item.Exists(Destination))
{
try
{
InvokeProvider.Item.New(Destination, null, "Directory", null, CmdletProviderContext);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please use named arguments for null-s.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please address my request.

}
catch (Exception)
{
// If creation fails, continue anyway - the move operation will handle the error
}
}

// Now proceed with the moves
foreach (string resolvedPath in allResolvedPaths)
{
MoveItem(resolvedPath, literalPath: true);
}
}
else
{
// Literal path mode - process each path directly
foreach (string path in Path)
{
MoveItem(path, literalPath: true);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,39 @@ Describe "Move-Item tests" -Tag "CI" {
$renameToPath | Should -FileContentMatchExactly $booContent
}
}

Context "Move-Item with wildcard source and non-existent destination" {
BeforeEach {
$sourcePath = "$TESTDRIVE/install"
$destPath = "$TESTDRIVE/copy"

# Setup directory structure
New-Item -ItemType Directory -Path "$sourcePath/bin" -Force | Out-Null
New-Item -ItemType File -Path "$sourcePath/bin/test.dll" | Out-Null
New-Item -ItemType Directory -Path "$sourcePath/lib" | Out-Null
New-Item -ItemType File -Path "$sourcePath/ReadMe.md" -Value "readme content" | Out-Null
New-Item -ItemType Directory -Path $destPath | Out-Null
}

AfterEach {
Remove-Item "$TESTDRIVE/install" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item "$TESTDRIVE/copy" -Recurse -Force -ErrorAction SilentlyContinue
}

It "Should preserve directory structure when moving with wildcard to non-existent destination" {
Move-Item -Path "$sourcePath/*" -Destination "$destPath/app" -Verbose

# Verify all items were moved
"$sourcePath/bin" | Should -Not -Exist
"$sourcePath/lib" | Should -Not -Exist
"$sourcePath/ReadMe.md" | Should -Not -Exist

# Verify directory structure is preserved (bin should not be flattened)
"$destPath/app/bin" | Should -Exist
"$destPath/app/bin/test.dll" | Should -Exist
"$destPath/app/lib" | Should -Exist
"$destPath/app/ReadMe.md" | Should -Exist
"$destPath/app/ReadMe.md" | Should -FileContentMatchExactly "readme content"
}
}
}
Loading