Move-Item:不支持给定路径的格式

时间:2015-05-07 00:35:37

标签: windows powershell

所以我正在编写一个脚本来移动给定目录中的重复文件(我们称之为D:\ Pictures)到Duplicates子目录(在这种情况下为D:\ Pictures \ Duplicates) 。

就目前而言,我唯一可见的问题是将文件从源(D:\ Pictures \ [picture])移动到目的地的实际行为(D:\ Pictures \ Duplicates \ [图片])。 Move-Item返回错误为"不支持给定路径的格式"。

用于重复文件的格式是对文件创建日期的简单重命名,例如:D:\ Pictures \ Duplicates \ 5-6-2015 06:34:22 PM.bmp

当我使用直接文件路径时,例如D:\ Pictures \ 001 - Copy.bmp和D:\ Pictures \ Duplicates \ 5-6-2015 06:34:22 PM.bmp它分别工作正常,只返回使用变量时的错误。

到目前为止我所得到的内容如下(包含用于测试复制目的的完整代码):

cls
echo "Duplicate Sorter -- Version 1.0.0 Alpha"
echo "-------------------------------------"
echo "What directory do you want to sort?"
$workingDir = "false"
while ($workingDir -eq "false")
{
    $DIR = Read-Host
    if (($DIR -eq "C:\") -or ($DIR -like "C:\Program Files*") -or ($DIR -like "C:\Program Files(x86)*") -or ($DIR -like "C:\Windows*") -or ($DIR -like "C:\DRIVERS*") -or ($DIR -like "C:\SWTOOLS*") -or ($DIR -like "C:\inetpub*") -or ($DIR -like "C:\PerfLogs*"))
    {
        echo "You can't choose that directory. Choose a different one."   
    } 
    Else
    {
        $workingDir = "true"
    }
}
echo "What file type do you want to sort? (Press the relative number)"
echo "1. Pictures"
echo "2. Movies"
echo "3. GIFs"
echo "4. PNGs"
echo "5. Custom Type"
$workingType = "false"
while ($workingType -eq "false")
{
    $fileType = Read-Host
    if ($fileType -eq 1)
    {
        $fileType = "jpg"
        $workingType = "true"
    } 
    elseif ($fileType -eq 2)
    {
        $fileType = "avi"  
        $workingType = "true"
    }
    elseif ($fileType -eq 3)
    {
        #Pronounced with a hard G, not like Jif. Gifs aren't a brand of peanut butter!
        $fileType = "gif"
        $workingType = "true"
    } 
    elseif ($fileType -eq 4)
    {
        $fileType = "png"
        $workingType = "true"
    }
    elseif ($fileType -eq 5)
    {
        echo "Okay then, Mr. 'I'm special and deserve my own type', enter your custom type."
        $fileType = Read-Host
        $workingType = "true"
    }
    Else
    {
        echo "This is an invalid option. Try again."
    }
}
$mkdups = "$DIR\$fileType Duplicates"
if (!(Test-Path -Path $mkdups))
{
    New-Item $mkdups -ItemType directory  
}
$preList = Get-ChildItem "$DIR" -Recurse
$list = $preList | Where-Object { $_.Extension -eq $fileType }
$list = $list | %{$_.FullName}
$hashedList=New-Object System.Collections.ArrayList
if ($hashedList.Length -gt 1)
{
    $hashedList.Clear()
}
foreach ($i in $list)
{
    $hashedList+=Get-FileHash $i
}
[int]$iterator1=0
foreach ($i in $hashedList)
{
    [int]$iterator2=0
    foreach ($j in $hashedList)
    {
        if(($i.Hash -eq $j.Hash) -and ($iterator2 -gt $iterator1))
        {
            if(Test-Path $j.Path)
            {
                $checkFile=Split-Path $j.Path -Leaf
                $rnd=(Get-ChildItem $j.Path).CreationTime
                $rnd=$rnd -Replace("/","-")
                $checkFile="$rnd$fileType"
                $dirPath=$mkdups
                $j.Path="$dirPath\$checkFile"
                $src=$i.Path
                $dest=$j.Path
                Move-Item -Path $src -Destination $dest #Problem Area
            }
        }
        $iterator2++
    }
    $iterator1++
}

2 个答案:

答案 0 :(得分:3)

您不能在文件名中使用冒号。

使用类似$dest.Replace(':','_')的内容替换下划线。

答案 1 :(得分:3)

Mike Shepard是对的,问题是你的文件名中有冒号,这是不允许的。但我写信是为了帮助你......

ForEach($j in $hashedList)嵌套在ForEach($i in $hashedList)内会让我的大脑受到太大伤害而无法发表评论。我还看到使用Switch cmdlet更好地完成了If / ElseIf / ElseIf / ElseIf / ElseIf。此外,在已经有一个文件之后重新创建一个哈希数组,好吧,只是没有。最后,执行递归文件列表,然后过滤掉您想要的文件是一种浪费。为提供程序提供一个过滤器,以便它只返回您要处理的文件而不是所有文件,然后使PowerShell过滤掉额外的文件。提供程序做了一件事,它处理文件及其信息,并且它比PowerShell更好(通常),因此首选在该级别进行过滤。在这里,请考虑以下替代方案:

让我向您介绍Switch。不,不是威尔史密斯的歌。这个伟大的小cmdlet将允许您定义各种情况,并将相应地执行代码。看看我们可以将你的If / ElseIf块减少到:

while ($workingType -eq "false")
{
    Switch(Read-Host){
        "1" {$fileType = "*.jpg";$workingType = 'true';Continue} 
        "2" {$fileType = "*.avi";$workingType = 'true';Continue}  
        "3" {$fileType = "*.gif";$workingType = 'true';Continue}
        "4" {$fileType = "*.png";$workingType = 'true';Continue}
        "5" {
            "Okay then, Mr. 'I'm special and deserve my own type', enter your custom type."
            $fileType = Read-Host "[Example: *.bat]"
            $workingType = 'true'
            Continue
            }
        default {"This is an invalid option. Try again."}
    }
}

通过将$fileType设置为"*.jpg"而非"jpg",我们也为下一点做好了准备。

不是获取所有文件,而是使用-filter参数获取所需文件。这会将过滤器直接传递给FileSystem提供程序,因此它只返回您想要的文件。不再有$prelist和所有垃圾:

$List = Get-ChildItem "$DIR" -Filter $fileType -Recurse

既然您有一个要查看的文件列表,而不是将其转换为路径列表,请将它们保留为[FileInfo]对象,这样更有用!我们可以直接将Hash作为属性直接添加到每个对象:

$List | ForEach{Add-Member -InputObject $_ -NotePropertyName 'Hash' -NotePropertyValue (Get-FileHash $_.FullName | Select -Expand Hash)}

在那里,现在所有文件的Hash都包含在他们的对象中。现在神奇......没有将ForEach循环嵌套在彼此之内。根据您列表中的对象数量,该练习会呈指数级增长。而是在Group-Object属性上使用Hash。然后过滤掉组中只有一个文件的任何地方,你就得到了重复的文件了!

$List | Group Hash | Where{$_.Count -gt 1}

它显示了您通过文件哈希分割的所有重复项。它返回具有Count属性的分组对象,这是一个自解释的属性,Name属性,它是您分组的任何值(在您的情况下,每个哈希值)和一个{ {1}}属性,它是与Group匹配的所有内容的集合。所以从那里你移动每个组的文件,跳过第一个。类似的东西:

Name

那就在那里取代你的整个$List | Group Hash | Where{$_.Count -gt 1} | ForEach{ $_.Group | Select -Skip 1 | Move-Item -Dest $mkdups } 循环及其中的所有内容。所以现在让我们把它们放在一起:

ForEach($i in $hashlist)

有关我验证目录的说明,请参阅:https://regex101.com/r/jB0yD9/1