首页 > 解决方案 > Powershell 产生不完整的结果。从加入 cmdlet 中删除显示的逗号

问题描述

我对脚本非常陌生,我希望有人可以提供一些建议。

我自己创建了一个对项目管理有用的 PowerShell 脚本。该脚本分析文件路径以确定它是否太长,并检查文件名是否少于 50 个字符。此外,它还确保没有非法字符。所有结果最初都打印到一个文本文件中。

在 PowerShell 脚本中,我最初让步骤 1、2 和 3-9 生成 3 个单独的文档。但最终,我决定将所有步骤写入一个文本文件。在最后一步中,然后导入文本文件以创建 CSV。然后文件路径按字母顺序排序,并合并返回 2 个不同结果的任何文件路径。最终,用户将参考此 CSV,以便在他们的媒体存档之前手动更正任何错误。

以下是我遇到的问题。

  1. 从步骤 1 到 9,生成的文本文件不完整。当我检查文本文件时,它会在写入路径的过程中停止。我还注意到在第 10 步中创建的 CSV 也有不完整的结果。
    在此处输入图像描述

  2. 在第 10 步中,我使用 join cmdlet 将结果合并到 CSV 中。所以,如果一个文件名有两个不同的结果,我想将结果合并到 1 行。我使用逗号作为分隔符,但是当我这样做时,它实际上在 CSV 中显示了多个逗号。有没有办法防止逗号被显示?
    在此处输入图像描述

param(
 # $pathToScan Enter the path to scan for file length
 [Parameter(Mandatory=$True,Position=0)]
 [ValidateNotNull()]
 [string]$pathToScan,
 #Character Limit to be set
 [Parameter(Position=1)] 
 #[ValidateNotNull()] 
 [int]$charLimit = 250
)


# File outputs
#$outputEmptyPath = "C:\temp\EmptyPaths_$(Get-Date -Format yyyyMMdd).csv"
#$outputCharPath = "C:\temp\SpecialChars_$(Get-Date -Format yyyyMMdd).csv"
$outputFilePath = "C:\temp\PathLengths_$(Get-Date -Format yyyyMMdd).txt"

# Use this switch to display to screen.  Can ignore this for now.
$writeToConsoleAsWell = $false   # Writing to the console will be much slower.

# Open a new file stream (nice and fast) and write all the paths and their lengths to it.
$outputFileDirectory = Split-Path $outputFilePath -Parent
if (!(Test-Path $outputFileDirectory)) { New-Item $outputFileDirectory -ItemType Directory }
$streamPath = New-Object System.IO.StreamWriter($outputFilePath, $false)
#$streamChar = New-Object System.IO.StreamWriter($outputFilePath, $false)
#$streamEmpty = New-Object System.IO.StreamWriter($outputFilePath, $false)

# STEP 1 - Check for empty paths.
((Get-ChildItem -Path $pathToScan -Recurse | Where-Object {$_.PSIsContainer -eq $True}) | Where-Object {$_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0}) | ForEach-Object {
      $emptyPaths = $_.FullName

      if ($emptyPaths) {
          $streamPath.WriteLine("$emptyPaths , empty folder")
        }
}

# STEP 2 - Show for long paths. (default=250 characters)
Get-ChildItem -Path $pathToScan -Recurse | Select-Object -Property BaseName, FullName, @{Name="FullNameLength";Expression={($_.FullName.Length)}} | Sort-Object -Property FullNameLength -Descending | ForEach-Object {
    $fileName = $_.BaseName
    $filePath = $_.FullName
    $length = $_.FullNameLength

    if ($length -gt $charLimit) {
        $string = "$length : $filePath"
    
        # Write to the Console.
        if ($writeToConsoleAsWell) { Write-Host $string }

        #Write to the file.
        $streamPath.WriteLine("$filepath ,, file path too long")
    }

    #STEP 3 - Check for special characters. Allowed characters are Alphanumerics, single space, dashes, underscores, periods
    if ($filename -match '[^a-zA-Z0-9 -_.]') {
        $streamPath.WriteLine("$filepath ,,, has special characters")
    }

    #STEP 4 - Check for double spaces, dashes, periods and underscores
    if ($filepath -match '\s{2,}|\-{2,}|\.{2,}|_{2,}') {
        $streamPath.WriteLine("$filepath ,,,, has double spaces/dashes/periods/underscores")
    }
    
    #STEP 5 - check for more than 50 characters
    if ($filename -match '[^\\]{51,}\.[a-zA-Z0-9]{2,7}$') {
        $streamPath.WriteLine("$filepath ,,,,, exceeds 50 characters")
   }

    #STEP 6 - check for empty space at end of file or folder name
    if ($filename -match '(\s+$)|(\s+\\)|(\s+\.)') {
        $streamPath.WriteLine("$filepath ,,,,,, name has space at end")
   }
   
    #STEP 7 - check for zip and other archived files
    if ($filename -match '(?i)\.zip$|(?i)\.tar.gz$|(?i)\.gz$|(?i)__MACOSX$') {
        $streamPath.WriteLine("$filepath ,,,,,,, unzip files before archiving")
   }
      
    #step 8 - check for cache and render files
    if ($filename -match '(?i)\.cfa$|(?i)\.pek$|(?i)\.xmp$') {
        $streamPath.WriteLine("$filepath ,,,,,,,, delete cache and render files")
   }

    #step 9 - check for Windows hidden files
    if ($filename -match '(?i)\._|thumbs.db') {
        $streamPath.WriteLine("$filepath ,,,,,,,,, delete hidden files")
   }
} 
    Start-Sleep -Seconds 30

#step 10 - Merge and sort results
Import-Csv -Path "C:\temp\PathLengths_$(Get-Date -Format yyyyMMdd).txt" -Header 'Path', 'Empty Folder', 'Long File Path', 'Special Characters', 'Double Spaces, Dashes, Periods and Underscores', 'Exceeds 50 Characters', 'Name Has Space at End', 'Zip File', 'Cache and Render Files', 'Windows Hidden Files' | sort 'Path' | Group-Object 'Path' | ForEach-Object {
    [PsCustomObject]@{
        'Path' = $_.Name
        'Empty Folder' = $_.Group.'Empty Folder' -join ',' 
        'Long File Path' = $_.Group.'XMP File' -join ',,'
        'Special Characters' = $_.Group.'Special Characters' -join ',,,'
        'Double Spaces, Dashes, Periods and Underscores' = $_.Group.'Double Spaces, Dashes, Periods and Underscores' -join ',,,,'
        'Exceeds 50 Characters' = $_.Group.'Exceeds 50 Characters' -join ',,,,,'
        'Name Has Space at End' = $_.Group.'Name Has Space at End' -join ',,,,,,'
        'Zip File' = $_.Group.'Zip File' -join ',,,,,,,'
        'Cache and Render Files' = $_.Group.'Cache and Render Files' -join ',,,,,,,,'
        'Windows Hidden Files' = $_.Group.'Windows Hidden Files' -join ',,,,,,,,,'        
    }
} | Export-Csv "C:\temp\PathLengths_$(Get-Date -Format yyyyMMdd)-SORTED_FINAL.csv" -Delimiter ',' -NoTypeInformation

标签: powershellcsvjoinfilepathdelimiter

解决方案


您不应该像这样创建一个临时 csv 文件,然后将其转换为 CSV,您可以使用 PSCustomObject 和 Export-Csv 立即执行此操作。
创建类似 csv 的临时文件的方式很容易弄乱逗号的数量,从而导致字段未对齐。

另外,我建议不要在 CSV 标头中使用逗号(也可以缩短它们,但这取决于您)。

尝试:

param(
 # $pathToScan Enter the path to scan for file length
 [Parameter(Mandatory = $true, Position = 0)]
 [ValidateScript({ Test-Path -Path $_ -PathType Container })]
 [string]$pathToScan,

 #Character Limit to be set
 [int]$charLimit = 250
)

# File output
$outputFile = "C:\temp\PathLengths_$(Get-Date -Format yyyyMMdd).csv"

# collect custom objects
$result = Get-ChildItem -Path $pathToScan -Recurse -Force | ForEach-Object {
    # create the output object.
    $obj = [PsCustomObject]@{
        'Path'                                     = $_.FullName
        'ObjectType'                               = if ($_.PSIsContainer) {'Folder'} else {'File'}
        'Empty Folder'                             = $null
        'Long File Path'                           = $null
        'Special Characters'                       = $null
        'Double Spaces_Dashes_Periods_Underscores' = $null
        'Exceeds 50 Characters'                    = $null
        'Name Has Space at End'                    = $null
        'Zip File'                                 = $null
        'Cache and Render Files'                   = $null
        'Windows Hidden Files'                     = $null
    }
    # STEP 1 - Check for empty paths.
    if ($_.PSIsContainer -and $_.GetFileSystemInfos().Count -eq 0) { $obj.'Empty Folder' = 'empty folder' }

    # STEP 2 - Show for long paths. (default=250 characters)
    if ($_.FullName.Length -gt $charLimit) { $obj.'Long File Path' = 'path too long' }

    #STEP 3 - Check for special characters. Allowed characters are Alphanumerics, single space, dashes, underscores, periods
    if ($_.BaseName -match '[^-a-z0-9 _.]') { $obj.'Special Characters' = 'has special characters' }

    #STEP 4 - Check for double spaces, dashes, periods and underscores
    if ($_.BaseName -match '[-\s._]{2,}') { $obj.'Double Spaces_Dashes_Periods_Underscores' = 'has double spaces/dashes/periods/underscores' }

    #STEP 5 - check for more than 50 characters
    # This is a weird check.. Why not simply if ($_.Name.Length -gt 50) ???
    if ($_.Name -match '[^\\]{51,}\.[a-z0-9]{2,7}$') { $obj.'Exceeds 50 Characters' = 'exceeds 50 characters' }

    #STEP 6 - check for empty space at end of file or folder name
    if ($_.Name -match '\s$') { $obj.'Name Has Space at End' = 'name ends in whitespace' }
    
    # these are for files only:
    if (!$_.PSIsContainer) {
        #STEP 7 - check for zip and other archived files
        if ($_.Name -match '\.zip$|\.tar|\.gz$|__MACOSX$') { $obj.'Zip File' = 'unzip files before archiving' }
  
        #STEP 8 - check for cache and render files
        if ('.cfa', '.pek', '.xmp' -contains $_.Extension) { $obj.'Cache and Render Files' = 'delete cache and render files' }

        #STEP 9 - check for Windows hidden files
        if ($_.Attributes -band [System.IO.FileAttributes]::Hidden) { $obj.'Windows Hidden Files' = 'delete hidden files' }
    }

    # output the object, only if there is some value of interest
    # (the first two properties 'Path' and 'ObjectType' are general info, so we disregard those here)
    if (($obj.PsObject.Properties | Select-Object -Skip 2).Value -join '' -ne '') {
        $obj
    }
}

if ($result) { $result | Export-Csv -Path $outputFile -NoTypeInformation }

如您所见,我更改了一些测试:

  • (?i)在 regex 上删除-match,因为默认情况下不区分大小写
  • 在正则表达式中将移到-前面[^-a-z0-9 _.],因为否则它将被解释为正则表达式范围而不是减号字符本身
  • 更改了隐藏文件的测试

推荐阅读