Powershell脚本可在文件中查找文件名并将其移动到其他目录

时间:2019-01-17 14:09:58

标签: powershell parsing

我目前正在编写Powershell脚本。它应该浏览目录中的所有文件,然后根据其内容将它们移动到其他目录。 现在,在某些文件中,例如是相关位图的文件名。 我该怎么做,以便在看到关联文件时将其移动到同一文件夹?

到目前为止,这是我的脚本,它根据文件中是否包含$ pattern1和$ pattern2中给出的单词,将文件分发到2个不同的目录中。

$source = 'Z:\Documents\16_Med._App\Aufträge\RuheEKG_24HBP_Skript\Ursprung_test'
$destination = 'Z:\Documents\16_Med._App\Aufträge\RuheEKG_24HBP_Skript\24BHD'
$toDelete = 'Z:\Documents\16_Med._App\Aufträge\RuheEKG_24HBP_Skript\ToDelete'
$pattern1 = '24BHD'
$pattern2 = 'RuheEKG'

$hans = Get-ChildItem $source  

foreach($item in $hans) {
    if (Select-String -list -pattern $pattern1 -path $item.fullname) {
        Move-Item -Path $item.fullname -Destination $destination}
        Else {
        Move-Item -Path $item.fullname -Destination $toDelete}


}

At the end of line 31, you see the associated Bitmap file.

在第31行的末尾,您将看到关联的位图文件。 我需要脚本将其识别为另一个文件,找到它并将其移动到与包含该文件的文件所在的目录相同的目录。

我们将不胜感激!

3 个答案:

答案 0 :(得分:1)

我的猜测是,在移动文件和关联的位图文件之后,您还希望该文件包含这些引用文件的新文件路径。

此外,由于您的模式不是真正的正则表达式,因此我在-SimpleMatch上使用了Select-String参数。

这段代码应该做到这一点。

$source      = 'Z:\Documents\16_Med._App\Aufträge\RuheEKG_24HBP_Skript\Ursprung_test'
$destination = 'Z:\Documents\16_Med._App\Aufträge\RuheEKG_24HBP_Skript\24BHD'
$toDelete    = 'Z:\Documents\16_Med._App\Aufträge\RuheEKG_24HBP_Skript\ToDelete'
$pattern1    = '24BHD'
$pattern2    = 'RuheEKG'

# create the destination paths if they do not exist
if (!(Test-Path -Path $destination -PathType Container)) {
    Write-Host "Creating folder '$destination'"
    New-Item -Path $destination -ItemType 'Directory' -Force | Out-Null
}
if (!(Test-Path -Path $toDelete -PathType Container)) {
    Write-Host "Creating folder '$toDelete'"
    New-Item -Path $toDelete -ItemType 'Directory' -Force | Out-Null
}

# get an array of full path and filenames.
# if they all have the same extension, it would be wise to add the '-Filter' parameter..
$allFiles = @(Get-ChildItem $source -File | Select-Object -ExpandProperty FullName)

foreach($file in $allFiles) {
    # get the file content as array so we can reuse it and update the line(s) with the new bitmap path(s)
    $content = Get-Content -Path $file

    # first decide on the destination. '-Quit' returns $true or $false
    # if both $pattern1 AND $pattern2 are present, move stuff to $destination
    if (($content | Select-String -Pattern $pattern1 -SimpleMatch -Quiet) -and 
        ($content | Select-String -Pattern $pattern2 -SimpleMatch -Quiet)) {
        $dest = $destination
    }
    else {
        $dest = $toDelete
    }

    # next check if the file contains path(s) for referenced (bitmap) file((s)
    $refCount = 0
    $content | Select-String -Pattern '(^.*)([A-Z]:\\.+$)' -AllMatches | ForEach-Object {
        # each '$_' automatic variable in here holds a MatchInfo object.
        # see: https://docs.microsoft.com/en-us/dotnet/api/microsoft.powershell.commands.matchinfo?view=pscore-6.0.0

        $prefix  = $_.Matches[0].Groups[1].Value   # get the prefix of the line (something like '0619154')
        $refPath = $_.Matches[0].Groups[2].Value   # get the bitmap file path

        if (Test-Path -Path $refPath -PathType Leaf) {
            Write-Host "Moving referenced file '$refPath' to '$dest'"
            Move-Item -Path $refPath -Destination $dest -Force
            # recreate the line to match the new location of the bitmap file
            Write-Host "Updating path in '$file' to '$refPath'"
            $refFile = Split-Path $refPath -Leaf
            $refPath = Join-Path -Path $dest -ChildPath $refFile
            $content[$_.LineNumber -1] = $prefix + $refPath
            $refCount++
        }
        else {
            Write-Warning "Referenced file '$refPath' not found"
        }
        if ($refCount) {
            # we handled referenced files, so write the new content back to the original file
            Set-Content -Path $file -Value $content -Force
        }
    }

    # finally move the file to its new destination
    Write-Host "Moving file '$file' to '$dest'"
    Move-Item -Path $file -Destination $dest -Force
}


编辑


根据您的评论:

我已经像下面这样测试过了。

我在D:驱动器上创建了几个文件夹,并将文件放在其中:

+---Fnkraf
    \---Bitmaps
    |       PIC0053.BMP
    |       PIC0057.BMP
    |       PIC0571.BMP
    |       PIC0572.BMP
    |
    \---MasterFiles
            File1.txt
            File2.txt
            File3.txt

Bitmaps文件夹包含引用的位图文件。
MasterFiles文件夹中,我放置了以下文件:

File1.txt
此文件有效,因为它包含两个关键字模式并且具有两个引用的位图文件。两个引用的文件都存在。这些将转到24BHD文件夹。

24BHD
RuheEKG

01091521
0249153EKG 10 Sekunden
0619154D:\Fnkraf\Bitmaps\PIC0053.BMP
0619155D:\Fnkraf\Bitmaps\PIC0057.BMP
0118410HF

File2.txt
此文件有效,因为它包含两个关键字模式并且具有两个引用的位图文件。其中之一将发出警告,因为找不到警告。这些将转到24BHD文件夹。

24BHD
RuheEKG

01091521
0249153EKG 15 Sekunden
0719154D:\Fnkraf\Bitmaps\PIC0571.BMP
0719157D:\Fnkraf\Bitmaps\DOESNOTEXIST.BMP
0118410HG

File3.txt
此文件无效,因为它仅包含一个关键字模式。它确实有一个可找到的引用位图文件。这些应该转到toDelete文件夹

25BHD
RuheEKG

01091521
0249153EKG 17 Sekunden
0619154D:\Fnkraf\Bitmaps\PIC0572.BMP
0118410HG

运行脚本后,结果如下:

+---Fnkraf
    \---24BHD
    |       File1.txt
    |       File2.txt
    |       PIC0053.BMP
    |       PIC0057.BMP
    |       PIC0571.BMP
    |
    +---Bitmaps
    +---MasterFiles
    \---ToDelete
            File3.txt
            PIC0572.BMP

您可以看到同时创建了目标24BHDtoDelete文件夹,并且主文件File1.txtFile2.txt及其引用的位图文件最终都位于目标中。
File3.txt未能按预期通过模式测试,并再次移至toDelete文件夹中,同时又包含引用的位图文件。

现在,如果打开已移动的文本文件,则可以看到引用的文件路径已更新,以匹配位图的新位置。

File1.txt

24BHD
RuheEKG

01091521
0249153EKG 10 Sekunden
0619154D:\Fnkraf\24BHD\PIC0053.BMP
0619155D:\Fnkraf\24BHD\PIC0057.BMP
0118410HF

对其他文件也是如此。 更新的唯一参考是在 File2.txt 中找不到的位图文件:

24BHD
RuheEKG

01091521
0249153EKG 15 Sekunden
0719154D:\Fnkraf\24BHD\PIC0571.BMP
0719157D:\Fnkraf\Bitmaps\DOESNOTEXIST.BMP
0118410HG

希望能说明一切。

答案 1 :(得分:0)

我想到了很多问题,

  • 文件路径是否总是在行尾?
  • 每个文件有一个文件路径,还是包含路径的更多行?

假设上述问题的答案是肯定的,那么可以从这样的文件中解析文件路径:

foreach($item in $hans) {
    $mat = $item | Select-String -Pattern '.:\\.+'
    foreach($m in $mat) {
        $m.Matches.Value
    }
}

.:\\.+是一个正则表达式,用于搜索驱动器字母,冒号,反斜杠的序列,并在同一行上捕获其后的所有内容。

很多时候,这样的解析脚本在没有错误的情况下会花费一些时间。正则表达式和Select-String是您的朋友,但是要真正了解它们还需要一些时间:-)在https://regex101.com/上检查/编写RegEx,我在编写正则表达式时通常会用到它。

答案 2 :(得分:0)

如果您有一系列要匹配的模式,并且可以保证这些模式将始终匹配且不会意外匹配其他内容,则可以使用带有任意多个模式匹配项和目的地的switch语句。

您可能需要根据源文件名来构建目标,在这种情况下,我仅以示例的方式对目标路径进行了硬编码:

$hans = Get-ChildItem $source

foreach($item in $hans)
{
    switch($item.FullName)
    {
        { $_ -match '24BHD' }        { $destination = 'Z:\24BHD_Destination' }
        { $_ -match 'RuheEKG' }      { $destination = 'Z:\RuheEKG_Destination' }
        { $_ -match 'OtherPattern' } { $destination = 'Z:\OtherCode_Destination' }

        default { Write-Host "Match not found for file $($item.FullName)" }
    }

    Move-Item $item.FullName $destination
}