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
Assuming that the target dir. already exists:
Note: The
-WhatIfcommon parameter in the command above previews the operation. Remove-WhatIfand 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-Forceswitch, when combined with-Type Directory, ensures that a preexisting directory, if any, is returned; otherwise, the directory is created; in either case, aSystem.IO.DirectoryInfoinstance representing the directory is returned, which stringifies to its.FullNameproperty, i.e. to its full, file-system-native path.Note:
The nested
Get-ChildItemcalls are meant to promote conceptual clarity:The outer call uses a PowerShell wildcard expression in combination with the
-Directoryswitch to match the top-level directories of interest - note the use of character range[a-d]to match directories namesa,b,c, ord.The inner call acts on each resulting directory and recursively searches only for files matching the pattern, via the
-Fileswitch.This approach avoids the need for your
Where-Object {$_.PSIsContainer -eq $false}call, which - incidentally - can be more PowerShell-idiomatically expressed asWhere-Object { -not $_.PSIsContainer }and - in PowerShell (Core) 7+ - using simplified syntax,Where-Object -not PSIsContainer.Note: It is tempting to try a single
Get-ChildItemcall such asGet-ChildItem -Path D:\A\[a-d] -File -Recurse -Filter *$pattern*, but that doesn't actually work, because the-Fileswitch is then applied to whatever theD:\A\[a-d]wildcard expression resolves to, and since the results are directories,-Fileeffectively excludes them from further processing, resulting in an effective no-op.-Filein combination with-Recurseonly works meaningfully for literal input paths, to whose child (descendant) items the-Fileswitch is then applied.The
Move-Itemcall uses a delay-bind script block to dynamically determine the destination directory:$_.DirectoryNamecontains each input file's full directory path, and(... -split '\\')[0..2]extracts the ancestral path that is composed of 3 components, such asD:\A\c.