Your code should work in principle.
(As of this writing, there's confusion over copying vs. moving, and the aspect of matching only select files is missing.)
Below is a streamlined version of your code, which however, does not explain your symptom - you need to provide more information for us to diagnose your problem.
The streamlined code below:
takes advantage of the PSv3+ -File
Get-ChildItem
parameter to limit matching to files (as opposed to directories) - this saves the need for Where-Object { ! $_.PSIsContainer }
.
uses -LiteralPath
to pass the literal $dir
path; while -Path
(which is also the positional default) often works fine too, it's important to note that it interprets is argument as a wildcard expression, which can have unexpected results).
uses -Filter
to provide the file mask (wildcard expression); this is generally preferable to using the -Path
parameter, because it filters at the source (Windows API call) and is therefore faster, which can make a noticeable difference when processing large directories.
Caveat: the wildcard language supported in the -Filter
argument is more limited than PowerShell's and also burdened with legacy quirks; in short: sticking with *
and ?
should be fine; for the full story, see this well-researched answer.
uses -Force
instead of -ErrorAction SilentlyContinue
in order to either create a directory or use a preexisting one.
- Note that
New-Item -ItemType Directory -Force
returns a [System.IO.DirectoryInfo]
instance in both scenarios (either the newly created directory or the preexisting one), which the code takes advantage of.
# Create sample dir. with 2 sample files in it.
$tmpDir = New-Item -Force -Type Directory tmpDir
New-Item -Type File -Force -Path ('N30008xx.txt', 'N30005xx.txt' -replace '^', "$($tmpDir.FullName)/")
$dir = $tmpDir
$fileMask = 'N*.txt'
Get-ChildItem -File -LiteralPath $dir -Filter $fileMask | ForEach-Object {
$newDir = Join-Path $dir $_.LastWriteTime.ToString("yyyy-MM-dd")
$_ | Move-Item -Destination (New-Item -ItemType Directory -Force $newDir)
}
Caveat re generalization of this code:
You're creating the target subdirectories inside the source directory.
If you were to use Get-ChildItem -Recurse
to process the source directory recursively, you'd end up processing matching files twice: first when moving them, and then again when finding them in their moved-to location.
(In this particular case this would only cause an inefficiency, however, because processing the already-moved files attempts to move them into the directory where they already are, which is a quiet no-op.)