Note: As your error message reveals, mv is a built-in alias of PowerShell's Move-Item cmdlet (albeit only on Windows) - see the bottom section for why this is problematic and why it's better to use the mi alias.
Mathias R. Jessen provided the crucial pointer in a comment:
Multiple source paths must be passed as an array to Move-Item's -Path or -LiteralPath parameter, which with directly specified paths requires separating them with ,:
# Note the "," separating the source file names.
Move-Item -LiteralPath test.txt, test2.txt -Destination test-files
I've used named arguments above, i.e. I've preceded the arguments with the names of their target parameters.
PowerShell also supports positional parameter binding:
Move-Item test.txt, test2.txt test-files
This works, but note that it isn't fully equivalent to the above, because the first positional argument - test.txt, test2.txt binds to the -Path parameter, not -LiteralPath:
- It doesn't make a difference here, because the file names at hand contain no wildcard characters.
- However, if your literal file names happen to contain
[ (e.g., test[2].txt), binding to -Path wouldn't work as expected.
Discovery of whether a cmdlet's parameters support arrays:
You can discover whether a given parameter supports arrays by looking at its syntax diagrams, which are part of the brief help that is displayed when you pass the standard -? switch; you can also display them in isolation with Get-Command -Syntax Move-Item, for instance.
Using Get-Help, you can even ask for details about specific parameters, using -Path as an example:
PS> Get-Help Move-Item -Parameter Path
-Path <System.String[]>
Specifies the path to the current location of the items. The default is the current directory. Wildcard characters are permitted.
Required? true
Position? 0
Default value Current directory
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? true
<System.String[]> denotes the parameter's type, which in this case is an array ([] of System.String ([string]) instances. In other words: [] following a parameter type implies that arrays are supported.
However, a given cmdlet can choose to also support passing multiple arguments individually to an array-typed parameter (of necessity only one parameter can support this per cmdlet), declared with a [Parameter()] attribute whose ValueFromRemainingArguments property is set to $true:
An example is Write-Output, whose (one and only positional) -InputObject parameter is typed System.Management.Automation.PSObject[], but also has ValueFromRemainingArguments set, so that the following two calls are equivalent:[1]
# Single array argument that directly binds to -InputObject
Write-Output 1, 2, 3
# Multiple arguments that implicitly bind collected in an array to -InputObject
Write-Output 1 2 3
Note:
Unfortunately, the help does not reveal the presence of ValueFromRemainingArguments - neither in the parameter's detailed view with Get-Help ... -Parameter ..., nor, typically, in a parameter's description.
While programmatic discovery is possible, it is nontrivial:
# -> 'InputObject'
(Get-Command Write-Output).Parameters.Values.
Where({ $_.Attributes.ValueFromRemainingArguments -contains $true }).Name
Another example is Write-Host, whose -Object parameter behaves the same way. However, what is unusual about this parameter is that its type is -Object <System.Object>, i.e. it doesn't explicitly reveal that it accepts arrays; however, it does; technically, this possible due to System.Object being capable of storing any data type, including arrays (collections). It is only the plural in the parameter's description that hints at the fact that -Object accepts arrays: "Objects to display in the host."
Alias-naming considerations:
That mv is a built-in alias for Move-Item (on Windows only)[2] is problematic. More broadly, all aliases named for internal commands of a different shell (e.g., cmd.exe's dir) or, as in this case, for external programs (possibly a different platform's) are problematic, because the syntax of these commands / programs usually differs fundamentally from PowerShell's syntax.
- Case in point: the
mv command in your question would work with the Unix-platform /bin/mv utility.
It is better to use PowerShell own aliases, whose names are formed methodically from the approved verb part of the command being aliased, with each approved verb having its official abbreviation, e.g., m for Move-. The abbreviation for the noun part isn't standardized, but using the initial letter stands to reason, e.g. i for Item.
- In PowerShell (Core) 7+, you can discover the verb abbreviation via
Get-Verb (output column AliasPrefix), e.g., Get-Verb Move; in Windows PowerShell you'll need to consult the "approved verb" link above.
And, indeed, mi is another built-in alias for Move-Item, as the following discovery command based on Get-Alias reveals:
PS> Get-Alias -Definition Move-Item
CommandType Name Version Source
----------- ---- ------- ------
Alias mi -> Move-Item
Alias move -> Move-Item
Alias mv -> Move-Item # WINDOWS ONLY
The big advantage of such aliases - aside from not pretending to be something they're not - is that their methodic naming makes it easier to remember and possibly even guess their names; e.g., gc for Get-Content and, as Get-Alias -Definition Get-Alias reveals, gal for Get-Alias.
Name conflicts with external programs can still occur, but are less likely. E.g. sc for Set-Content shadows the native sc.exe utility (for controlling services), which is the reason it was - somewhat controversially - removed from PowerShell (Core).
[1] Due to the bug described in GitHub issue #5122, the commands aren't fully equivalent if you also use Write-Output's -NoEnumerate switch in PowerShell (Core) 7+, though the difference will rarely matter in practice: Write-Output -NoEnumerate 1, 2, 3 emits a single [object[]] instance, as expected, whereas Write-Output -NoEnumerate 1 2 3 unexpectedly outputs a [System.Collections.Generic[object]] instance. In Windows PowerShell, there is a different, more severe bug: Only the form Write-Output -NoEnumerate 1, 2, 3 produces an [object[]] array as a single output object, as expected; by contrast, the forms Write-Output -NoEnumerate 1 2 3 and even Write-Output -NoEnumerate -InputObject 1, 2, 3 effectively ignore the -NoEnumerate switch and therefore output the elements one by one.
[2] On Unix-like platforms, the mv alias isn't defined, so as not to shadow the external, platform-native /bin/mv program.