Reputation: 3
I'm new to PowerShell unfortunately, and I have a number of files that I would to like to archive with PowerShell on a monthly basis. Each file has a YYYYMM date stamp in the file name. I'd like to move files that have a date stamp older than 24 months.
Example:
file1_201903.txt file2_201902.txt ... file3_201703.txt (this should be archived) file4_201702.txt (this should be archived)
Note that the source files reside in a directory with a number of subfolders. I'd like the script to check all subfolders. The folders do not need to be replicated in the destination.
Here's what I've tried so far:
$SourceDir = 'C:\source'
$DestDir = 'C:\destination'
$YearsAgo = 2
$Then = (Get-Date).AddYears(-$YearsAgo).Date
Get-ChildItem -Path $SourceDir |
Where-Object {
$DatePart = ($_.BaseName -split '_')[1]
$FileDate = [DateTime]::ParseExact($DatePart, 'yyyyMMdd', [CultureInfo]::CurrentCulture)
$FileDate -lt $Then
} |
Move-Item -Destination $DestDir
Upvotes: 0
Views: 963
Reputation: 61068
The date parts in the filenames do not have a value for the Day. The format should therefore be yyyyMM
, not yyyyMMdd
.
Since the format is a sortable string, you do not have to convert to a DateTime object and can go ahead and compare the strings:
$SourceDir = 'C:\source'
$DestDir = 'C:\destination'
$YearsAgo = -2
$Then = '{0:yyyyMM}' -f (Get-Date).AddYears($YearsAgo) # returns a String "201703"
Get-ChildItem -Path $SourceDir | ForEach-Object {
$DatePart = ( $_.BaseName -split '_' )[1]
# comparing sortable date strings
if ($DatePart -lt $Then) {
$_ | Move-Item -Destination $DestDir
}
}
If you do want to compare on DateTime objects, this should do it:
$SourceDir = 'C:\source'
$DestDir = 'C:\destination'
$YearsAgo = -2
$RefDate = ('{0:yyyyMM}' -f (Get-Date).AddYears($YearsAgo)) # returns a String "201703"
# convert this string into a DateTime object
$Then = [DateTime]::ParseExact( $RefDate, 'yyyyMM', [cultureinfo]::CurrentCulture )
Get-ChildItem -Path $SourceDir | ForEach-Object {
$DatePart = ( $_.BaseName -split '_' )[1]
$FileDate = [DateTime]::ParseExact( $DatePart, 'yyyyMM', [cultureinfo]::CurrentCulture )
# comparing DateTime objects
if ($FileDate -lt $Then) {
$_ | Move-Item -Destination $DestDir
}
}
Upvotes: 1
Reputation: 5232
That doesn't look that bad actually. ;-) But your -FilterScript
block in your Where-Object
needs a little tweak:
$SourceDir = 'C:\source'
$DestDir = 'C:\destination'
$YearsAgo = -2
$Then = ( Get-Date ).AddYears( $YearsAgo ).Date
Get-ChildItem -Path $SourceDir -Recurse |
Where-Object {
[datetime]::ParseExact( $(( $_.BaseName -split '_' )[1]), 'yyyyMMdd', [cultureinfo]::CurrentCulture ) -lt $Then
} |
Move-Item -Destination $DestDir
You could use a little more descriptive way with a Foreach-Object
. Sometimes that's easier to read/understand/follow:
Get-ChildItem -Path $SourceDir -Recurse |
ForEach-Object{
$DatePart = ( $_.BaseName -split '_' )[1]
$FileDate = [datetime]::ParseExact( $DatePart, 'yyyyMMdd', [cultureinfo]::CurrentCulture )
if ($FileDate -lt $Then) {
Move-Item -Path $_.FullName -Destination $DestDir
}
}
Unfortunately I cannot test at the moment. So try and let me know please. ;-)
Upvotes: 0