Log file with columns

Hi folks,

I am learning PowerShell and this is my first post. Looked up on the search engines and couldn’t locate relevant information.

I have a simple script that logs custom objects. Every time it logs, it adds the column headers. I am wondering if someone can guide me on how to keep the column headers and just append the rows.

Here is the sample of what I am using:

$props = @{'CacheTotalSize' = 'row1'
                        'CacheFreeSize' = 'row2'
                                      
}

$obj = New-Object -TypeName PSObject -Property $props

$obj | Out-File c:\test.log -Append

test.log looks like this after running the above script thrice:
CacheFreeSize CacheTotalSize
row 2 row1

CacheFreeSize CacheTotalSize
row 2 row1

CacheFreeSize CacheTotalSize
row 2 row1

 

I want to achieve something like this:
CacheFreeSize CacheTotalSize
row 2 row1
row2 row1
row2 row1

Thank you in advance.

You can t skip headers when printing customobjects. You will have to populate all the values then print it at the end. So you will have to move the Out-File out side the loop.

[quote quote=262436]You can t skip headers when printing customobjects. You will have to populate all the values then print it at the end. So you will have to move the Out-File out side the loop.

[/quote]
Thank you for this.

Could you share a sample?

Example with a loop

$r = 'String1','String2','String3'
$t = $r | Foreach-Object -Process {
      [PSCustomObject]@{
         String = $_
         Length = $_.Length
      }
    }
$t | Out-String | Out-File -FilePath c:\temp\file.log

Thank you again for providing a sample.

I tested the above sample, I get the same results when I run the script thrice with the append parameter.

Here is the outcome, after running it thrice:

String Length


String1 7
String2 7
String3 7

String Length


String1 7
String2 7
String3 7

String Length


String1 7
String2 7
String3 7

 

That’s exactly what it’s supposed to do. It’s an example to show you how to output the headers once followed by the values. Use this example as reference for how to use your data in a loop.

[quote quote=262679]That’s exactly what it’s supposed to do. It’s an example to show you how to output the headers once followed by the values. Use this example as reference for how to use your data in a loop.

[/quote]
My original script posted at the top does the same. I am not after this. I want to create a log file, where it keeps the headers same and append the rest.

I want to see this after running the script thrice:

String Length
—— ——
String1 7
String2 7
String3 7
String1 7
String2 7
String3 7
String1 7
String2 7
String3 7

Thank you

Your script is not designed to do that. It seems you need to separate the data collection from the export. Have one script that you can run “thrice” or as many times as you like and then export it.

Collection Script “collector.ps1”

[PSCustomObject]@{'CacheTotalSize' = 'row1'
                  'CacheFreeSize'  = 'row2'                                   
}

Call the script as many times as you want

$output = 1..3 | Foreach {.\collector.ps1}

then output

$output | Out-File c:\test.log -Encoding UTF8

Note that Set-Content is usually preferred over Out-File, but either will work. Is Export-Csv not a better option? It would make the data easier to use in other scripts. You can also combine the steps

1..3 | Foreach {.\collector.ps1} | Set-Content c:\test.log -Encoding UTF8

Sorry guys!

Seems like I wasn’t clear with my first message.

Here is something I want to capture when I run my script as a historical log. Whenever script will run, it will log these items along with more items which I will add once I figure out how to do that. Currently, this will log the number of processes running at a given time

$Processes = Get-Process | Measure-Object
$nProcess = $Processes.Count
$time = $((get-date).TimeOfDay.ToString())

$capture = [PSCustomObject]@{'NumberOfProcesses' = $nProcess
                  'Time'  = $time                                   
}

$capture | Out-File c:\test.log -Encoding UTF8 -Append

Here are the results when it runs:
NumberOfProcesses Time


200 15:30:30.2609267
NumberOfProcesses Time


201 15:30:43.4145230

I want to turn it into this, whenever I run without adding extra headers:
NumberOfProcesses Time


200 15:30:30.2609267
201 15:30:43.4145230

Thanks for your patience.

No you’ve explained what you desire clearly. It’s just that you’re going to have to change your approach in one way or another to achieve your desired result. The better approach, in my opinion, is to utilize CSV format/cmdlets. To keep the format similar to what you’ve shown, I made it a tab delimited CSV (default is comma)

function test {
    $props = [PSCustomObject]@{'CacheTotalSize' = 'row1'
                               'CacheFreeSize'  = 'row2'                                   
    }

    $props | Export-Csv C:\test.log -Delimiter "`t" -NoTypeInformation -Append
}

1..3 | % {test}

The file will contain

Get-Content C:\test.log

"CacheTotalSize"	"CacheFreeSize"
"row1"	"row2"
"row1"	"row2"
"row1"	"row2"

If you want to keep it just text, not structured like CSV where we can take advantage of it’s built in ability to confirm the headers are present and then appending data, then you would need to handle writing the headers once as well as formatting the rows as desired.

function test {
    if(-not(Test-Path C:\test.log))
    {
        'CacheFreeSize    CacheTotalSize' | Set-Content c:\test.log -Encoding UTF8
    }

    $props = [PSCustomObject]@{'CacheTotalSize' = 'row1'
                               'CacheFreeSize'  = 'row2'                                   
    }

    "{0}             {1}" -f $props.CacheFreeSize,$props.CacheTotalSize | Add-Content C:\test.log -Encoding UTF8
}

1..3 | % {test}

The file contents will be

Get-Content C:\test.log

CacheFreeSize    CacheTotalSize
row2             row1
row2             row1
row2             row1

Thank you heaps :smiley:.

I have added more stuff to it and it all works like a charm.

I tried something similar earlier, but it was a novice approach and the script was looking messy. The solution you offered is tidy and the script looks great as well.

Thank you again.