-1

Good morning. How to convert list to a string where all lines separated by any keyword (in this case - [keyword]).

For example:

PS C:\> $data = dir c:\
PS C:\> $data

29.03.2023  08:53    <DIR>          inetpub
29.03.2023  14:39    <DIR>          Program Files
29.03.2023  09:43    <DIR>          Program Files (x86)
21.02.2020  00:17    <DIR>          SOLIDWORKS Data
01.04.2023  17:10    <DIR>          SolidWorks_Flexnet_Server
25.03.2023  15:56    <DIR>          Users
29.03.2023  14:39    <DIR>          Windows

I need output like this line:

29.03.2023  08:53    <DIR>          inetpub[keyword]29.03.2023  14:39    <DIR>          Program Files[keyword]21.02.2020  00:17    <DIR>          SOLIDWORKS Data
  

Also check $data for type (list or not). If the variable is a list, then only in this case is the given handler present.

ValB
  • 19
  • 2

2 Answers2

0

You have fix width data from the DIR command. I've read data into a table which you can use any was you want. Try following :

$data = @"
29.03.2023  08:53    <DIR>          inetpub
29.03.2023  14:39    <DIR>          Program Files
29.03.2023  09:43    <DIR>          Program Files (x86)
21.02.2020  00:17    <DIR>          SOLIDWORKS Data
01.04.2023  17:10    <DIR>          SolidWorks_Flexnet_Server
25.03.2023  15:56    <DIR>          Users
29.03.2023  14:39    <DIR>          Windows
"@
$pattern = "^(?<day>\d{2}).(?<month>\d{2}).(?<year>\d{4})\s+(?<hour>\d{2}):(?<minute>\d{2})\s{4}(?<dir>.{5})(?<size>.{10})(?<name>.*)"
$reader = [IO.StringReader]::new($data)

$table = [System.Collections.ArrayList]::new()

while(($line = $reader.ReadLine()) -ne $null)
{
   $newRow = New-Object -TypeName psobject
   $line -match $pattern | Out-Null
   $date = [DateTime]::new($matches.Year,$matches.Month,$matches.Day,$matches.Hour,$matches.Minute,0)
   $newRow | Add-Member -NotePropertyName Date -NotePropertyValue $date
   $table.Add($newRow) | Out-Null
   $dir = $Matches.Dir
   if($dir -eq "<DIR>")
   {
      $newRow | Add-Member -NotePropertyName DIR -NotePropertyValue "DIR"
   }
   $sizeStr = $Matches.Size.Trim()
   if($size.Count -gt 0)
   {
      $size = [long]$Matches.Size
      $newRow | Add-Member -NotePropertyName Size -NotePropertyValue $size
   }
   $newRow | Add-Member -NotePropertyName Name -NotePropertyValue $Matches.Name
} 
$table

Results

Date                  DIR Name
----                  --- ----
3/29/2023 8:53:00 AM  DIR inetpub
3/29/2023 2:39:00 PM  DIR Program Files
3/29/2023 9:43:00 AM  DIR Program Files (x86)
2/21/2020 12:17:00 AM DIR SOLIDWORKS Data
4/1/2023 5:10:00 PM   DIR SolidWorks_Flexnet_Server
3/25/2023 3:56:00 PM  DIR Users
3/29/2023 2:39:00 PM  DIR Windows
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • 1
    I normally wouldn't bother in leaving a comment but your answer is wrong on so many levels from a powershell perspective – Santiago Squarzon Apr 01 '23 at 21:19
  • @SantiagoSquarzon : Stop making comments on my methods. They work. A program has to be able to be maintained and commented. To put everything in one long instruction according to all my college professors, is wrong. The results is what the user needs. The OP need to group the name and you first have to parse the line and get the name to be able to group the data and space the way op wants. Right now it is not clear how the user want to space the data. But this is the first step. – jdweng Apr 01 '23 at 21:30
  • 1
    @SantiagoSquarzon, I've tried before - to no avail: see the comments exchange at https://stackoverflow.com/a/75348106/45375 (Oops! I just realized that you were part of that exchange - but perhaps others find it useful). – mklement0 Apr 01 '23 at 21:41
  • @jdweng, invoking your college professors in support of your position is a classical logical fallacy: an appeal to authority that is supposed to take the place of actual arguments - which, of course, it doesn't. See https://en.wikipedia.org/wiki/Argument_from_authority – mklement0 Apr 01 '23 at 21:51
0

Thanks to all, solved myself:

$a=cmd /c dir c:\

if ($a -is [System.Array])
{
    foreach($s in $a)
    {
        $e += $s + "[newline]"
    }
    $b = [system.String]::Join("",$e)
}
else
{
    $b = $a + "[_n]")
}

$b
ValB
  • 19
  • 2
  • That your question contains a different input command that wouldn't produce the stated output is probably what prompted someone to down-vote. Also, ``cmd /c dir c:\``, as used in your answer, produces _more_ than the output shown in your question, and you're using a different keyword than in the question, and you've changed the logic from using it as a _separator_ to a _terminator_. The value of this site is in having clearly defined questions with matching answers, so that others can benefit too. – mklement0 Apr 02 '23 at 06:54
  • As for the solution: you can simplify to: `$a= cmd /c dir c:\; $terminator = if ($a.Count -gt 1) { '[newline]' } else { '[_n]' }; $b = ($a -join $terminator) + $terminator` – mklement0 Apr 02 '23 at 06:55