1

I have a directory A in which containing the sub directories a, b, c, d, each sub-directory contains timestamped folders, example 20230120, and files whose names end with the date and time of day example file-202301200545

What I want is to copy the files whose names end with today's date to the folder with today's date.

Sorry, it's a bit complicated to explain but I hope you understand it.

I wrote a script that performs this action but on the condition that I fix each directory.

$pattern = Get-Date -Format yyyyMMdd

$path = "D:\A\b\"
$Dest = "D:\A\b\\$pattern"
Get-ChildItem -Path $path -Recurse -Filter *$pattern* | Where-Object {$_.PSIsContainer -eq $false} | Move-Item -Destination $Dest

$path = "D:\A\c\"
$Dest = "D:\A\c\\$pattern"
Get-ChildItem -Path $path -Recurse -Filter *$pattern* | Where-Object {$_.PSIsContainer -eq $false} | Move-Item -Destination $Dest

$path = "D:\A\d\"
$Dest = "D:\A\d\\$pattern"
Get-ChildItem -Path $path -Recurse -Filter *$pattern* | Where-Object {$_.PSIsContainer -eq $false} | Move-Item -Destination $Dest

I need help to use a loop or any other techinique that will allow me to do this more easily

1

1 Answer 1

0

Assuming that the target dir. already exists:

Get-ChildItem -Directory -Path D:\A\[a-d] |
  Get-ChildItem -File -Recurse -Filter *$pattern* | 
  Move-Item -Destination { 
    Join-Path ($_.DirectoryName -split '\\')[0..2] $pattern
  } -WhatIf 

Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf and re-execute once you're sure the operation will do what you want.

If you want to create the target dir. on demand, use
New-Item -Type Directory -Force (Join-Path ($_.DirectoryName -split '\\')[0..2] $pattern) - New-Item's -Force switch, when combined with -Type Directory, ensures that a preexisting directory, if any, is returned; otherwise, the directory is created; in either case, a System.IO.DirectoryInfo instance representing the directory is returned, which stringifies to its .FullName property, i.e. to its full, file-system-native path.

Note:

  • The nested Get-ChildItem calls are meant to promote conceptual clarity:

    • The outer call uses a PowerShell wildcard expression in combination with the -Directory switch to match the top-level directories of interest - note the use of character range [a-d] to match directories names a, b, c, or d.

    • The inner call acts on each resulting directory and recursively searches only for files matching the pattern, via the -File switch.

    • This approach avoids the need for your Where-Object {$_.PSIsContainer -eq $false} call, which - incidentally - can be more PowerShell-idiomatically expressed as Where-Object { -not $_.PSIsContainer } and - in PowerShell (Core) 7+ - using simplified syntax, Where-Object -not PSIsContainer.

    • Note: It is tempting to try a single Get-ChildItem call such as
      Get-ChildItem -Path D:\A\[a-d] -File -Recurse -Filter *$pattern*, but that doesn't actually work, because the -File switch is then applied to whatever the D:\A\[a-d] wildcard expression resolves to, and since the results are directories, -File effectively excludes them from further processing, resulting in an effective no-op.

      • That is, -File in combination with -Recurse only works meaningfully for literal input paths, to whose child (descendant) items the -File switch is then applied.
  • The Move-Item call uses a delay-bind script block to dynamically determine the destination directory:

    • $_.DirectoryName contains each input file's full directory path, and (... -split '\\')[0..2] extracts the ancestral path that is composed of 3 components, such as D:\A\c.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.