ratanmalko
ratanmalko

Reputation: 471

PowerShell format text file

I get the below output from a PowerShell query. I don't have access to the server to run the query, so I have no option to influence the output format.

Example:

Name          : folderC
FullName      : D:\folderA\folderB\folderC
Length        :
CreationTime  : 2/8/2014 11:12:58 AM
LastAccessTime: 2/8/2014 11:12:58 AM

Name          : filename.txt
FullName      : D:\folderA\folderB\filename.txt
Length        : 71560192
CreationTime  : 11/25/2015 3:10:43 PM
LastAccessTime: 11/25/2015 3:10:43 PM

How can I format above content to get something more usable, maybe like a table format like so:

Name|FullName|Length|CreationTime|LastAccessTime

Upvotes: 5

Views: 1316

Answers (2)

mklement0
mklement0

Reputation: 437448

As @alroc notes in a comment on the question, it is possible that objects are available to the OP, given that they state that the output is "from a Powershell query" - if so, simple reformatting of the object array using the usual cmdlets is an option.
By contrast, this answer assumes that only a text representation, as printed in the question, is available.

Dave Sexton's answer is a simpler and more elegant choice, if:

  • the input has no empty values (the OP's sample input does).
  • the input file is small enough to be read into memory as a whole.

Consider the approach below to avoid the issues above and/or if you want more control over how the input is converted into custom objects, notably with respect to creating properties with types other than [string]: extend the toObj() function below (as written, all properties are also just strings).


Get-Content File | % `
  -begin {
    function toObj([string[]] $lines) {
      $keysAndValues = $lines -split '(?<=^[^ :]+)\s*: '
      $htProps = @{}
      for ($i = 0; $i -lt $keysAndValues.Count; $i += 2) {
        $htProps.($keysAndValues[$i]) = $keysAndValues[$i+1]
      }
      return [PSCustomObject] $htProps
    }
    $lines = @()
  } `
  -process {
    if ($_.trim() -ne '') { 
      $lines += $_
    } else {
      if ($lines) { toObj $lines }
      $lines = @()
    }
  } `
  -end {
    if ($lines) { toObj $lines }
  } | Format-Table

Explanation:

  • Uses ForEach-Object (%) with separate begin, process, and end blocks.

  • The -begin, executed once at the beginning:

    • Defines helper function toObj() that converts a block of contiguous nonempty input lines to a single custom object.

      • toObj() splits an array of lines into an array of contiguous key-value elements, converts that array to a hashtable, which is then converted to a custom object.
    • Initializes array $lines, which will store the lines of a single block of contiguous nonempty input lines

  • The -process block, executed for each input line:

    • If the input line at hand is nonempty: Adds it to the current block of contiguous nonempty input lines stored in array $lines.

    • Otherwise: Submits the current block to toObj() for conversion to a custom object, and then resets the $lines array to start the next block. In effect, toObj() is invoked for each paragraph (run of nonempty lines).

  • The -end block, executed once at the end:

    • Submits the last paragraph to toObj() for conversion to a custom object.
  • Finally, the resulting array of custom objects is passed to Format-Table.

Upvotes: 3

Dave Sexton
Dave Sexton

Reputation: 11188

I think you need to split the text into records, replace the colons with equals so that you can use the ConvertFrom-StringData to turn each record into a hash which you can then feed into New-Object to convert into an object. Outputting the the object into pipe separated data can then be done with the ConvertTo-Csv. Something like so:

$x = @"
Name           : folderC
FullName       : D:\folderA\folderB\folderC
Length         : 0
CreationTime   : 2/8/2014 11:12:58 AM
LastAccessTime : 2/8/2014 11:12:58 AM

Name           : filename.txt
FullName       : D:\folderA\folderB\filename.txt
Length         : 71560192
CreationTime   : 11/25/2015 3:10:43 PM
LastAccessTime : 11/25/2015 3:10:43 PM
"@

($x -split '[\r\n]+(?=Name)') | % {
  $_ -replace '\s+:\s+', '='
} | % {
  $_ | ConvertFrom-StringData
} | % {
  New-Object psobject -Property $_
}  | ConvertTo-Csv -Delimiter '|' -NoTypeInformation

Upvotes: 4

Related Questions