简体   繁体   English

根据文件名中的日期戳移动文件

[英]Move Files Based on Date Stamp in File Name

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. 不幸的是,我是PowerShell的新手,我有一些每月想用PowerShell存档的文件。 Each file has a YYYYMM date stamp in the file name. 每个文件的文件名中都有YYYYMM日期戳。 I'd like to move files that have a date stamp older than 24 months. 我想移动日期戳早于24个月的文件。

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

The date parts in the filenames do not have a value for the Day. 文件名中的日期部分没有Day的值。 The format should therefore be yyyyMM , not yyyyMMdd . 因此,格式应为yyyyMM ,而不是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: 由于格式是可排序的字符串,因此您不必转换为DateTime对象,可以继续比较字符串:

$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: 如果确实要比较DateTime对象,则应这样做:

$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
    } 
}

That doesn't look that bad actually. 实际上,那看上去还不错。 ;-) But your -FilterScript block in your Where-Object needs a little tweak: ;-)但是您的Where-Object -FilterScript块需要一些调整:

$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 . 您可以对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. 所以请让我知道。 ;-) ;-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM