Powershell дает неполные результаты. Удаление отображаемых запятых из командлета соединения - PullRequest
0 голосов
/ 11 июля 2020

Я новичок в написании сценариев и надеюсь, что кто-нибудь может дать какой-нибудь совет.

Я взял на себя ответственность создать сценарий PowerShell, который будет полезен для управления проектами. Сценарий анализирует путь к файлу, чтобы определить, не слишком ли он длинный, и проверяет, не превышает ли имя файла 50 символов. Кроме того, он следит за тем, чтобы среди прочего не было запрещенных символов. Все результаты изначально печатаются в текстовый файл.

В сценарии PowerShell у меня изначально были шаги 1, 2 и 3–9 для создания трех отдельных документов. Но в конечном итоге я решил записать все шаги в один текстовый файл. На последнем этапе текстовый файл импортируется для создания CSV. Затем пути к файлам сортируются в алфавитном порядке, и он объединяет любые пути к файлам, которые вернули 2 разных результата. В конечном итоге именно на этот CSV-файл будут ссылаться пользователи, чтобы вручную исправить любые ошибки до того, как их носители будут заархивированы.

Вот проблемы, с которыми я сталкиваюсь.

  1. From шаги 1–9, создаваемый текстовый файл является неполным. Когда я проверяю текстовый файл, он останавливается на середине записи пути. Я также заметил, что CSV, созданный на шаге 10, также имеет неполные результаты. введите здесь описание изображения

  2. На шаге 10 я использовал командлет соединения, чтобы объединить результаты в CSV. Итак, если имя файла дает два разных результата, я хотел бы объединить результаты в одну строку. Я использовал запятую в качестве разделителя, но когда я это делаю, он фактически отображает несколько запятых в 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

1 Ответ

1 голос
/ 11 июля 2020

Вам не следует создавать такой временный файл 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) в регулярном выражении -match, потому что по умолчанию регистр не учитывается.
  • перемещает - на передний план в регулярных выражениях, таких как [^-a-z0-9 _.], потому что в противном случае он будет интерпретироваться как диапазон регулярных выражений вместо сам символ минус
  • поменял тест на скрытые файлы
...