【问题标题】:Breaking script output from one huge CSV to smaller CSVs将脚本输出从一个巨大的 CSV 转换为更小的 CSV
【发布时间】:2015-10-28 20:25:27
【问题描述】:

目前有一个脚本将运行服务器上的所有用户文件并根据上次访问时间输出它们。客户想要一份关于去年未触及的文件的报告。

问题是,报告太大了。根据我的测试样本集,我估计有超过 200 万行 CSV。因此,不是一个 HUGE 文件,我想将此脚本转换为输出许多较小的报告,按用户细分。

扫描根用户目录,输出包含该用户名的 CSV,然后迭代到下一个用户,然后重复。

$cutOffDate = (Get-Date).addYears(-1)
$arr = @()
$exclusions = @(".lnk",".url",".ini",".odc",".ctx",".upd",".ica")

gci "D:\USER_FILES\company\USERS\Lname, Fname" -Recurse | ? {
  $_.PSIsContainer -eq $False -and
  $_.LastAccessTime -le $cutOffDate -and
  $exclusions -notcontains $_.Extension -and
  $_.length -gt "0" -and
  $_.Directory -notmatch ".*USERS\\.*\\Personal\\sysdata\\cookies"
} | % {
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Directory $_.DirectoryName
  $obj | Add-Member NoteProperty Name $_.Name
  $obj | Add-Member NoteProperty MB ("{0:N3}" -f ($_.Length/1MB))
  $obj | Add-Member NoteProperty created $_.creationtime
  $obj | Add-Member NoteProperty LastAccessed $_.LastAccessTime
  $obj | Add-Member NoteProperty LastMofified $_.LastWriteTime
  $obj | Add-Member NoteProperty Extension $_.Extension
  $arr += $obj
}

$arr | Export-CSV -notypeinformation "C:\Output.csv"

下面是编辑 - 输出到管道而不是数组

$cutOffDate = (Get-Date).addYears(-1)
$exclusions = @(".lnk",".url",".ini",".odc",".ctx",".upd",".ica")

Get-ChildItem 'D:\USER_FILES\company\USERS' | ? { $_.PSIsContainer } | % {
  $name = $_.Name
  Get-ChildItem $_.FullName -Recurse |
    ? {
      $exclusions -notcontains $_.Extension -and
      $_.PSIsContainer -eq $false -and
      $_.LastAccessTime -le $cutOffDate -and
      $_.length -gt "0" -and
      $_.Directory -notmatch '.*USERS\\.*\\Personal\\sysdata\\cookies'
    } |
    select DirectoryName, Name, @{n='MB';e={"{0:N3}" -f ($_.Length/1MB)}},
           CreationTime, LastAccessTime, LastWriteTime, Extension |
    Export-Csv "D:\User-Files-Output\$name.csv" -NoType
}

注意:忽略初始路径,我现在是在diff环境下测试,所以C盘还是D,根路径还是USERS。

【问题讨论】:

  • 如果报告太大,那么总结一下。例如,您可以将 CSV 加载到 Excel 中并在其上运行数据透视表,然后按用户、访问存储桶(1 个月、2 个月、1 年等)、文件大小分析计数。我一直发现这是一个迭代过程。一旦客户看到报告,他们就会想到他们想要的其他东西。给他们一个带有一些有用分组的交叉表(是否有一个有用的用户层次结构,即按部门)可以很快满足这一点

标签: powershell csv output


【解决方案1】:

枚举用户文件夹(假设您的用户文件夹是在D:\USER_FILES\company\USERS 内名为Lastname, Firstname 的文件夹),然后为每个用户递归到它们。另外,不要在循环中追加到数组。只需选择您的属性并将输出通过管道传输到Export-Csv。如果您有 PowerShell v3 或更新版本,您可以使用参数-File-DirectoryGet-ChildItem 的输出分别限制为文件或文件夹。

Get-ChildItem 'D:\USER_FILES\company\USERS' -Directory | % {
  $name = $_.Name
  Get-ChildItem $_.FullName -Recurse -File |
    ? {
      $_.LastAccessTime -le $cutOffDate -and
      $exclusions -notcontains $_.Extension -and
      $_.length -gt "0" -and
      $_.Directory -notmatch '.*USERS\\.*\\Personal\\sysdata\\cookies'
    } |
    select DirectoryName, Name, @{n='MB';e={"{0:N3}" -f ($_.Length/1MB)}},
           CreationTime, LastAccessTime, LastWriteTime, Extension |
    Export-Csv "C:\$name.csv" -NoType
}

如果您受限于 PowerShell v2,请将上述内容更改为:

Get-ChildItem 'D:\USER_FILES\company\USERS' | ? { $_.PSIsContainer } | % {
  $name = $_.Name
  Get-ChildItem $_.FullName -Recurse |
    ? {
      -not $_.PSIsContainer -and
      $_.LastAccessTime -le $cutOffDate -and
      $exclusions -notcontains $_.Extension -and
      $_.length -gt "0" -and
      $_.Directory -notmatch '.*USERS\\.*\\Personal\\sysdata\\cookies'
    } |
    select DirectoryName, Name, @{n='MB';e={"{0:N3}" -f ($_.Length/1MB)}},
           CreationTime, LastAccessTime, LastWriteTime, Extension |
    Export-Csv "C:\$name.csv" -NoType
}

【讨论】:

  • 收到此错误,但不知道原因。 ',' 后缺少表达式。在 C:\Users\me\Desktop\agedFiles.ps1:12 char:74 + 选择 DirectoryName, Name, @{n='MB';e={"{0:N3}" -f ($_.Length/ 1MB)},
  • @soMuch2Learn 计算的属性缺少右大括号。固定。
  • 复制那个。谢谢。
  • 遇到-not $_.PSIsContainer 条件问题。使用调试器,它永远不会通过这个条件。使用 PowerGUI 调试器,它会迭代,但任何是文件的东西,它都会跳过并导致输出空的 CSV 文件。有任何想法吗?尝试了!$_.PSIsContainer 和 `$_.PSIsContainer -eq $false' 但它没有在遇到文件时将此布尔值评估为 $true。
  • 事实上,我放置“过滤器”的顺序并不重要。它永远不会通过第一个,只会吐出空的 CSV。
【解决方案2】:

移动你最后一行的逻辑:

 $arr | Export-CSV -notypeinformation "C:\Output.csv"

进入最后的ForEach-Object 脚本块:

$obj | Export-Csv -NoTypeInformation -Path ("C:\{0}.csv" -f $user)

您需要从每个项目的路径中获取用户名,例如

$_.FullName -match 'D:\\USER_FILES\\company\\USERS\\([^\\]+)\\' | Out-Null
$user = $Matches[1]

所以,您最终的 ForEach-Object 脚本块如下所示:

$_.FullName -match 'D:\\USER_FILES\\company\\USERS\\([^\\]+)\\' | Out-Null
$user = $Matches[1]    
New-Object PSObject |
    Add-Member NoteProperty Directory $_.DirectoryName -PassThru |
    Add-Member NoteProperty Name $_.Name -PassThru |
    Add-Member NoteProperty MB ("{0:N3}" -f ($_.Length/1MB)) -PassThru |
    Add-Member NoteProperty created $_.creationtime -PassThru |
    Add-Member NoteProperty LastAccessed $_.LastAccessTime -PassThru |
    Add-Member NoteProperty LastMofified $_.LastWriteTime -PassThru |
    Add-Member NoteProperty Extension $_.Extension -PassThru |
    Export-Csv -NoTypeInformation -Path ('C:\{0}.csv' -f $user)

【讨论】:

    猜你喜欢
    • 2022-12-04
    • 1970-01-01
    • 2018-01-07
    • 2014-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-31
    相关资源
    最近更新 更多