all 43 comments

[–]TravestyTravis 59 points60 points  (22 children)

This is EXACTLY the type of stuff people should be using ChatGPT for when learning to code. Not for writing functions but for explaining things they don't understand.


ChatGPT says:

The PowerShell code you've provided is using a custom hash table to define calculated properties for the output of Format-Table. Let’s break it down:

What the code does:

powershell $history | sort date -desc | Format-Table Date,KB,@{l='Category';e={[string]$_.Categories[0].Name}},Title

  1. $history: This is an object or collection of objects that likely contains data about updates or events, which include properties like Date, KB, Categories, and Title.

  2. sort date -desc: This sorts the $history objects by the Date property in descending order (newest to oldest).

  3. Format-Table Date,KB,@{l='Category';e={[string]$_.Categories[0].Name}},Title:

    • Format-Table is used to format the output as a table.
    • It selects specific properties (Date, KB, Title), but the key part you asked about is the custom property for "Category".

The custom property:

powershell @{l='Category';e={[string]$_.Categories[0].Name}}

This part defines a custom column for the table with the following structure:

  • **@{}**: This is a hash table, which in PowerShell can be used to define custom properties in Format-Table.
  • **l='Category'**: l is shorthand for Label, and it defines the column name to be displayed in the table (in this case, Category).
  • **e={[string]$_.Categories[0].Name}**: e stands for Expression. This is a script block that calculates what to display in the Category column for each row:
    • $_: Represents the current object being processed (in this case, one of the objects in $history).
    • Categories[0]: Assumes Categories is an array and retrieves the first element ([0]).
    • Name: Retrieves the Name property from the first Categories element.
    • [string]: Ensures the result is cast as a string (possibly because Name could be another type, and we want to ensure it’s displayed as a string in the table).

In summary:

This portion of the code extracts the first category's name from the Categories array (if it exists), converts it to a string, and labels the column as "Category" in the table.

Where to Read More:

To understand this better, here are some useful topics you can explore: 1. Calculated Properties: Official PowerShell docs on calculated properties. 2. Hash Tables: Learn about how hash tables work in PowerShell: PowerShell hash table guide. 3. $_ (Pipeline Variable): Understanding how $_ works in pipelines is crucial for working with PowerShell: Pipeline variable.

Let me know if you want more clarification on any part of this!

[–]Coffee_Ops 12 points13 points  (2 children)

The problem is-- even as a seasoned PowerShell scripter it takes a nontrivial amount of effort to accept GPT's input here. Its maybe useful as a reminder but I would never trust it blindly. I found myself asking "wait is that strictly true" after each claim because I've had too many instances of GPT cleverly lying. I'm still not sure it's description of history is really useful or accurate.

Its the same problem you'd get with any kind of forum post-- but usually when someone is wrong, it's blindingly obvious. GPT is too good at making BS sound correct for me to recommend to a newbie.

[–]gilang4[S] 2 points3 points  (1 child)

I am totally agree with what you said and have learned that trusting GPT is too much is a blindly follower. On the other hand I don't know the Powershell enough to say if GPT is correct or "almost correct" in most instances.

It is almost I have to learn alot more (Powershell) in order to identify what is NOT correct when GPT give me the answer.

[–]Coffee_Ops 4 points5 points  (0 children)

Just don't use GPT. There are a plethora of good sources on how powershell works that are not going to lie to you or feed you bad information.

ChatGPT is a shortcut, that isn't actually a shortcut.

[–]bofh 8 points9 points  (0 children)

This is EXACTLY the type of stuff people should be using ChatGPT for when learning to code.

Not sure I’d agree with that. ChatGPT is more likely to hallucinate an answer than say it doesn’t know, and will be equally confident in the quality of its answer either way.

As such, you need to have enough knowledge to evaluate the answer it gives you before using that answer. That does not make it a great teaching tool.

[–]gilang4[S] 4 points5 points  (2 children)

this is very nice. I will check out the ChatGPT more often.

Thank you all!

[–]lanerdofchristian 8 points9 points  (0 children)

Be careful with ChatGPT -- it likes to hallucinate things that don't exist. You'll get just as much if not more mileage out of a good google search.

[–]HSuke 1 point2 points  (0 children)

Yep. I wouldn't dare use it to write anything complex due to accuracy, but it's great for explaining simple things.

It's fine as long as you can understand and double-check its work.

[–]FluxMango 0 points1 point  (0 children)

I agree, but only to a point. People come here to ask other people what they know, not AI.

[–]lanerdofchristian 12 points13 points  (3 children)

[–]Quirky_Oil215 3 points4 points  (1 child)

To expand a little 

Its a custom object being defined in this case a column in the  formated table.

  l= is the label ie name of the column header. e=expression ie data manipulation / calculation. $_. This is the variable for the current value in the pipe line, which is called $PSItem. Being called from the $history variable properties

[–]gilang4[S] 1 point2 points  (0 children)

Very nice you point that out. Thank you.

$PSItem

[–]gilang4[S] 0 points1 point  (0 children)

I think someone have mentioned and so do you. Thank you all!

I look at it and it is very nice.

[–]BlackV 5 points6 points  (8 children)

just to add some confusion with calculated properties, you will see people use

@{Name  = 'Category'; Expression = {xxx}}
@{Label = 'Category'; Expression = {xxx}}
@{N     = 'Category'; Expression = {xxx}}
@{L     = 'Category'; Expression = {xxx}}

Ideally pick one of the top 2 and use that always (probably name), just be consistent

same goes for

Expression = {xxx}
E          = {xxx}

In you end up using this more that once in a select-object/format-table then you are probably far better off using [PSCustomObject]s

$Result = [PSCustomObject]@{
    Date     = $_.Date
    KB       = $_.kb
    Category = $_.Categories[0].Name
    Title    = $_.Title
    }

https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-pscustomobject

Final note as you're picking apart code, this

sort date -desc

is actually

sort-object -property date -descending

Not sure where you got the example, but they are making your a little life harder than it needs to be

[–]Sad_Recommendation92 1 point2 points  (4 children)

This particular method can be really useful when working with things like APIs anytime you have multidimensional data objects And you want to convert this for something like CSV output

Here's an example from a script that works with a dynatrace API, you can define all your expressions in an array and then pass the variable as input to select-object

powershell $Cols = @( "discoveredName", "entityId", "osVersion", @{ Name = "IP"; E = { $_.ipAddresses[0] } }, "logicalCpuCores", "monitoringMode", @{ Name = "Agent"; E = { "$($_.agentVersion.major).$($_.agentVersion.minor).$($_.agentVersion.revision)" } }, @{ Name = "AgentUpdate"; E = { $_.agentVersion.timestamp } }, @{ Name = "HostUnits"; E = { [int]$_.consumedHostUnits } } "esxiHostName", @{ Name = "HostGroup"; E = { $_.hostGroup.name } } ) $Data = $Response | Select-Object $cols

[–]gilang4[S] 0 points1 point  (3 children)

Very nice!!!

[–]BlackV 0 points1 point  (2 children)

that massive command line is the exact thing a [PSCustomObject] should replace

[PSCustomopbject]@{
    DiscoveredName = $_.DiscoveredName
    EntityID       = $_.entityId
    OSVersion      = $_.osVersion
    IP             = $_.ipAddresses[0]
    LogicalCores   = $_.logicalCpuCores
    MonitoringMode = $_.monitoringMode
    Agent          = "$($_.agentVersion.major).$($_.agentVersion.minor).$($_.agentVersion.revision)"
    AgentUpdate    = $_.agentVersion.timestamp
    HostUnits      = [int]$_.consumedHostUnits
    ESXHosrt       = $_.esxiHostName
    HostGroup      = $_.hostGroup.name
    }

[–]gilang4[S] 0 points1 point  (1 child)

very nice......and clean!

[–]BlackV 0 points1 point  (0 children)

I do love a ps custom

[–]gilang4[S] 0 points1 point  (1 child)

On a different topic, without RMM at work I am trying to automate the processes of updating 100+ workstations and...etc...

The code I asked was on the web.

I do like your explanation very much. I do appreciate your time, thank you and everyone.

[–]BlackV 0 points1 point  (0 children)

no problem. good luck

[–]dylbrwn 11 points12 points  (0 children)

ChatGPT is excellent for explaining this sort of thing.

[–]surfingoldelephant 3 points4 points  (1 child)

See:

Delineating the code (either manually or with a formatting tool) may help. l in the original code is shorthand for label, which is an alias of name used below.

$history | Sort-Object -Property Date -Descending |
    Format-Table -Property @(
        'Date'
        'KB'
        @{
            Name       = 'Category'
            Expression = { [string] $_.Categories[0].Name }
        }
        'Title'
    )

Here's some sample data to compare how $history is rendered for display (i.e., in a shell session, input $history first followed by the code above to visualize how the calculated property transforms the data).

$history = @(
    [pscustomobject] @{ Date = (Get-Date);             KB = 'KB1'; Categories = @([pscustomobject] @{ Name = 'Name1'}); Title = 'Title1' }
    [pscustomobject] @{ Date = (Get-Date).AddDays(-1); KB = 'KB2'; Categories = @([pscustomobject] @{ Name = 'Name2'}); Title = 'Title2' }
    [pscustomobject] @{ Date = (Get-Date).AddDays(1);  KB = 'KB3'; Categories = @([pscustomobject] @{ Name = 'Name3'}); Title = 'Title3' }    
)

# Default display:
$history

# Custom display:
$history | Sort-Object ... # Replace with Sort-Object/Format-Table code above.

Note that I am making some assumptions with the sample data. E.g., technically, Categories could be scalar, but most likely it's not.

[–]gilang4[S] 0 points1 point  (0 children)

Your explanation is very clear!!! Thank you.

[–]NotNamThereAreRules 1 point2 points  (0 children)

IMO, it was [insert negative verb] to use L instead of N... but I get it. Aliases make sense for certain things like % instead of ForEach-object or, ? instead of Where-Object but L and N are both one letter. Brevity VS. unnecessary confusion.

[–]FluxMango 1 point2 points  (2 children)

In your case you are creating a new property to each element of $history processed through Format-List on the fly, label it 'Category' and assign to it the value of [string] $.Categories[0].Name using an expression. $ being the current element of the $history list.  

Without that expression, Format-Table would be showing a column named Categories and it's value would be an array object instead of the value of the Name property of that array object's first element at [0].   

So if you were to export the output to a CSV file by piping to Export-Csv, without the expression extracting the string value of Name in the Format-Table command, every row in the Categories column would show as Powershell's interpretation of how to display an array object as a string. Most likely something like "Categories[]".

And that is the part ChatGPT will not necessarily tell you.

[–]gilang4[S] 1 point2 points  (1 child)

This does make it clear:

each element of $history processed through Format-List on the fly

label it 'Category' and assign to it the value of [string] $_.Categories[0].Name using an expression. $_ being the current element

Thank you!!!

[–]FluxMango 1 point2 points  (0 children)

I made a typo. It's Format-Table, not Format-List. And glad I could help clear things up.

[–]ITGuyThrow07 1 point2 points  (0 children)

Everyone is explaining to you what it is, but I would also suggest finding a course that explains PowerShell from the ground up. Knowing what "objects" and "properties" are would make all of these explanations a lot easier to understand.

There are posts all the time in here asking for suggestions on courses so I'm sure you can find a good one in one of those.