【问题标题】:Trying to iterate through folders and take recursive actions on each file尝试遍历文件夹并对每个文件执行递归操作
【发布时间】:2017-08-09 15:27:50
【问题描述】:

我正在尝试构建一个脚本,可用于根据上次访问日期删除旧文件。作为脚本的一部分,我想查询每个子文件夹,查找过去 X 天内未访问的文件,在找到的文件的同一文件夹中创建一个日志,并在日志中记录文件详细信息,然后删除这些文件。

我认为我需要的是一个嵌套循环,循环 1 将获取每个子文件夹 (Get-ChildItem -Directory -Recurse),然后对于找到的每个文件夹,第二个循环检查所有文件的最后访问日期,如果超出限制,则将文件详细信息附加到文件夹中的日志文件(供用户参考)以及主日志文件(供 IT 管理员)

循环 1 正在按预期工作并获取子文件夹,但我无法让内部循环通过文件夹中的对象递归,我试图在第一个循环中使用 Get-ChildItem,这是正确的方法吗?

下面的代码示例,我添加了伪来演示逻辑,它确实是我需要帮助的循环:

# Set variables
$FolderPath = "E:TEST_G"
$ArchiveLimit = 7
$ArchiveDate = (Get-Date).AddDays(-$ArchiveLimit)
$MasterLogFile = "C:\Temp\ArchiveLog $(Get-Date -f yyyy-MM-dd).csv"

# Loop 1 - Iterate through each subfolder of $FolderPath
Get-ChildItem -Path $FolderPath -Directory -Recurse | ForEach-Object {
    # Loop 2 - Check each file in the Subfolder and if Last Access is past
    # $ArchiveDate take Action
    Get-ChildItem -Path $_.DirectoryName | where {
        $_.LastAccessTime -le $ArchiveDate
    } | ForEach-Object {
        # Check if FolderLogFile Exists, if not create it
        # Append file details to folder Log
        # Append File & Folder Details to Master Log 
    }
}

【问题讨论】:

    标签: powershell recursion filesystems data-management


    【解决方案1】:

    您的嵌套循环不需要递归(外部循环已经处理好了)。只需处理每个文件夹中的文件(确保排除文件夹日志):

    Get-ChildItem -Path $FolderPath -Directory -Recurse | ForEach-Object {
        $FolderLogFile = Join-Path $_.DirectoryName 'FolderLog.log'
        Get-ChildItem -Path $_.DirectoryName -File | Where-Object {
            $_.LastAccessTime -le $ArchiveDate -and
            $_.FullName -ne $FolderLogFile
        } | ForEach-Object {
            'file details' | Add-Content $FolderLogFile
            'file and folder details' | Add-Content $MasterLogFile
            Remove-Item $_.FullName -Force
        }
    }
    

    您无需测试文件夹日志文件是否存在,因为Add-Content 会在丢失时自动创建。

    【讨论】:

    • 感谢您对 Ansgar 的评论和回复,您关于嵌套循环的观点帮助我走上了正轨。
    • @downvoter 想解释一下你认为这个答案有什么问题?
    【解决方案2】:

    我认为你有点过于复杂了:

    #Set Variables
    $FolderPath = "E:\TEST_G"
    $ArchiveLimit = 7
    $ArchiveDate = (Get-Date).AddDays(-$ArchiveLimit)
    $MasterLogFile = "C:\Temp\ArchiveLog $(get-date -f yyyy-MM-dd).csv"
    If (!(Test-Path $MasterLogFile)) {New-Item $MasterLogFile -Force}
    
    Get-ChildItem -Path $FolderPath -File -Recurse |
      Where-Object { $_.LastAccessTime -lt $ArchiveDate -and
                     $_.Extension -ne '.log' } |
      ForEach-Object {
        $FolderLogFile = Join-Path $_.DirectoryName 'name.log'
        Add-Content -Value "details" -Path $FolderLogFile,$MasterLogFile
    
        Try {
          Remove-Item $_ -Force -EA Stop
        } Catch {
          Add-Content -Value "Unable to delete item! [$($_.Exception.GetType().FullName)] $($_.Exception.Message)"`
                      -Path $FolderLogFile,$MasterLogFile
        }
      }
    

    编辑: 多个递归循环是不必要的,因为您已经在管道中执行递归操作。它足够强大,无需采取额外行动即可进行处理。另一个答案中的Add-Content 也是Out-File 的绝佳解决方案,所以我替换了我的。

    但请注意,Add-Content-Force 标志不会像 New-Item 的意愿那样创建文件夹结构。这就是 $MasterLogFile 声明下的行的原因。

    【讨论】:

    • 请解释一下为什么 OPs 代码不正确以及这有什么帮助?
    • 他不需要多次递归循环,只要原生使用管道就足够强大了。
    • 超级。现在将其编辑到您的答案中,这样它就不仅仅是代码转储了。
    • 感谢 TheIncorrigible1,您的解决方案正是我所需要的。
    • 最后一个问题,当我启用 Try 块以删除项目时出现错误,$_ 似乎没有返回目标文件,而是系统正在尝试查找文件在 c:\winodws\stystem32 (默认路径)中。 $_ 丢失对象是否有原因?因为它仍然在 for-each 循环中?我是否需要将其分配给变量($_.Fullname 等)?
    猜你喜欢
    • 2020-10-24
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多