Home > Software design >  PowerShell script to place files in directories that contain a string within said file’s name
PowerShell script to place files in directories that contain a string within said file’s name

Time:01-19

I have approximately 300 files, named in the format:

November Foo Bar And Stuff [Final Version].pdf

November Foo Bar And Stuff [Draft].pdf

November Lorum Ipsum [Final].pdf

November Lorum Ipsum [Draft].pdf`

They all start with “November “ and end with a bracketed word, but that word will vary slightly.

And I have approximately 150 corresponding directories in the format:

“Foo Bar And Stuff”

“Lorum Ipsum”

I would like to move the files in to folders with their associated names.

In other words,

  1. Search only for the string of text between “November “ and “[“
  2. Match the string in 1 against a list of directories
  3. When a match is found, move the file to the corresponding directory
  4. If no match is found, skip and continue to the next file

When complete, instead of a flat list of files, I should have all of my Foo Bar And Stuff related files in one directory, and my Lorum Ipsum files in another directory.

Let’s suppose that the files are in c:\files and the directories are in c:\directories

I tried moving these by hand in Explorer and it was tedious.

CodePudding user response:

Use Regex :

$filenames = @("November Foo Bar And Stuff [Final Version].pdf", "November Foo Bar And Stuff [Draft].pdf", "November Lorum Ipsum [Final].pdf", "November Lorum Ipsum [Draft].pdf")
$pattern = "(?<filename>November[^\[] )"
foreach($filename in $filenames)
{
   $match = select-string $pattern -inputobject $filename 
   Write-Host '$match.Matches'
   $match.Matches

   Write-Host "filename = " $match.Matches.Value.Trim()
}

CodePudding user response:

You could do something like this:

$destination = 'C:\directories'

# because the files have square brackets in their name, use `-LiteralPath`
Get-ChildItem -LiteralPath 'C:\Files' -Filter 'November*.pdf' -File | ForEach-Object {
    # filter the folder name from the file BaseName
    $folderName   = ($_.BaseName -replace '^November([^\[] ).*', '$1').Trim()
    $targetFolder = Join-Path -Path $destination -ChildPath $folderName
    if (Test-Path -Path $targetFolder -PathType Container) {
        $_ | Move-Item -Destination $targetFolder -Force
    }
}

To speed this up by not testing the existance of the target folder in every iteration, you could also first get a list of target directory names like so:

$destination = 'C:\directories'
$targets     = (Get-ChildItem -Path $destination -Directory).Name
# because the files have square brackets in their name, use `-LiteralPath`
Get-ChildItem -LiteralPath 'C:\Files' -Filter 'November*.pdf' -File | ForEach-Object {
    # filter the folder name from the file BaseName
    $folderName   = ($_.BaseName -replace '^November([^\[] ).*', '$1').Trim()
    if ($targets -contains $folderName) {
        $targetFolder = Join-Path -Path $destination -ChildPath $folderName
        $_ | Move-Item -Destination $targetFolder -Force
    }
}
  • Related