Powershell 循环每个文件名只有 运行 一次文件,即使文件名存在多个扩展名

Powershell loop is only running once file per filename, even if the filename exists with multiple extensions

我会第一个承认 PowerShell 不是我的强项,但经过一个晚上在 Internet 上的挖掘,我拼凑了以下内容。最终目标是通过 DateTaken 组织大量图像驱动器,以及 sidecar XMP 文件(如果存在)。它可能不是最优雅的代码,但它几乎可以工作。

我无法弄清楚的最后一个问题是 foreach 循环只对每个文件名执行一次,而不管扩展名。例如,只有 DSC00001.arw、DSC00001.xmp、 DSC00001.jpg 会被处理。

如有任何正确方向的建议,我们将不胜感激。

谢谢!

$Folders = (Get-ChildItem -Path F:\ -Recurse -Directory -Force).FullName

$objShell  = New-Object -ComObject Shell.Application
$Folders | % {

    $objFolder = $objShell.namespace($_)
    foreach ($File in $objFolder.items()) { 
            if (($File | Split-Path -Extension) -in ".arw",".gif",".tiff",".jpg",".png",".nef") {
                Write-Host $File.Name`t -NoNewline -ForegroundColor Green
                try {
                    $DateTaken = ($objFolder.getDetailsOf($File,12) -replace [char]8206)  -replace [char]8207
                    $DateTaken = [DateTime]::ParseExact($DateTaken, "g", $null)
                    $Year = $DateTaken.ToString('yyyy')
                    $Date = $DateTaken.ToString('yyyy-MM-dd')
                    Write-Host $Date`t -ForegroundColor Blue -NoNewline
                }
                catch {
                    $Year = 'Other'
                    $Date = 'Other'
                    Write-Host $Date`t -ForegroundColor DarkRed -NoNewline
                }
                finally {
                    $DatePath = (Join-Path (Join-Path F:\ $Year ) $Date)
                }
                write-Host $File.Path -> (Join-Path $DatePath ($File | Split-Path -Leaf))-NoNewline
                #Move-Item $File.Path (Join-Path $DatePath ($File | Split-Path -Leaf))
                Write-Host Completed`n -NoNewline

                if (Test-Path (Join-Path ($File | Split-Path) (($File | Split-Path -LeafBase) + '.xmp'))) {
                    Write-Host XMP:`t -ForegroundColor Magenta -NoNewLine
                    Write-Host (Join-Path ($File | Split-Path) (($File | Split-Path -LeafBase) + '.xmp')) -> (Join-Path ($DatePath) (($File | Split-Path -LeafBase) + '.xmp'))
                    #Move-Item (Join-Path ($File | Split-Path) (($File | Split-Path -LeafBase) + '.xmp')) (Join-Path ($DatePath) (($File | Split-Path -LeafBase) + '.xmp'))
                }
            }else {
                Write-Host $File.Name is not an image `n -NoNewline -ForegroundColor DarkYellow    
            }
    }

}

我不确定为什么 $objFolder.items() 实际上没有 return 所有预期的文件,但我建议使用 PowerShell 的 built-in 文件系统提供程序来发现每个文件中的实际文件文件夹,然后使用 $objFolder.ParseName() 获取可以传递给 GetDetailsOf():

的引用
$Folders = (Get-ChildItem -Path F:\ -Recurse -Directory -Force).FullName

$objShell  = New-Object -ComObject Shell.Application
$Folders | % {

    $objFolder = $objShell.NameSpace($_)

    foreach ($FileInfo in Get-ChildItem -LiteralPath $_ -File -Force) { # <-- trick is right here, use Get-ChildItem to discover the files in the folder
        if($FileInfo.Extension -in ".arw",".gif",".tiff",".jpg",".png",".nef"){
            $File = $objFolder.ParseName($FileInfo.Name)                # <-- here we resolve the corresponding file item with shell app
    
            # ... resolve and parse dateTaken here, just like before

            # *.xmp file path might be easier to construct like this
            $xmpPath = $FileInfo.FullName -replace "$($FileInfo.Extension)`$",'.xmp'
            if(Test-Path -LiteralPath $xmpPath){
                 # ...
            }
        }
    }
}