farosch
farosch

Reputation: 218

Split property value in Powershell

I am currently trying to do an Out-GridView to get a simple overview about our group policy objects. To do so, I am using the Get-GPO cmdlet, like so:

Get-GPO -all |
    Select-Object -Property DisplayName, Description |
    Sort-Object -Property DisplayName |
    Out-GridView

In our company we use the first line of the description field to store the name of the admin who created the policy, and all following lines hold a short description.

I would want to be able to grab the first line of the the Description field with the column header Responsability and all other lines of the field in a separate column. So assuming my current code would give me a table like this:

DisplayName | Description
-------------------------
GPO1        | Username
            | stuff
            | stuff

I would want it to look like this:

DisplayName | Responsability | Description
------------------------------------------
GPO1        | Username       | stuff
            |                | stuff

How can I achieve this?

Upvotes: 1

Views: 6397

Answers (3)

Bill_Stewart
Bill_Stewart

Reputation: 24525

I would probably use something like this:

Get-GPO -All | ForEach-Object {
  $info = $_.Description
  $pos = $info.IndexOf([Environment]::NewLine)
  if ( $pos -gt 0 ) {
    $responsibility = $info.Substring(0,$pos)
    $description    = $info.Substring($pos + [Environment]::NewLine.Length)
  }
  else {
    $responsibility = ""
    $description    = $info
  }
  [PSCustomObject] @{
    "DisplayName"    = $_.DisplayName
    "Responsibility" = $responsibility
    "Description"    = $description
  }
}

This way you can preserve formatting.

Upvotes: 2

BenH
BenH

Reputation: 10034

As @Matt suggested, you can use a calculated property.

Then since Description is a string, rather than an array of strings, you will need to split the line at the line breaks. This can be done by using -split and since it's information from a GPO we can assume Windows line endings `r`n (Otherwise you could use [environment]::newline)

The first property, use array element [0] will be the first line. For the second property, we'll need to save the array in a variable. Then we can use the length of that variable to get first element through the last.

Get-GPO -all |
    Select-Object -Property DisplayName, @{
            Name = "Responsibility"
            Expression = {($_.Description -split "`r`n")[0]}
        }, @{
            Name = "Description"
            Expression = {
                $linearray = ($_.Description -split "`r`n")
                $linearray[1..($linearray.length - 1)] | Out-String
            }
        } |
    Sort-Object -Property DisplayName |
    Out-GridView

Alternatively, you could create a new object rather than using the calculated property.

Get-GPO -all |
    ForEach-Object {
        $linearray = ($_.Description -split "`r`n")
        [pscustomobject]@{
            "DisplayName" = $_.DisplayName
            "Responsibility"= $linearray[0]
            "Description" = $linearray[1..($linearray.length - 1)] | Out-String
        }
    } |
    Sort-Object -Property DisplayName |
    Out-GridView

Upvotes: 4

briantist
briantist

Reputation: 47792

The first thing to understand is what Get-GPO is returning: an array of objects, each of which has a set of properties.

What is displayed in your table is a series of rows (one per object), with the columns being the values of the properties for that object.

Therefore if you want a new column, you need a new property.

There are two ways you can do this: create a calculated property with Select-Object or add a property to the objects via Add-Member.

Calculated

You may provide a hashtable as a property to Select-Object, and the hashtable must have two keys:

  • Name (the name of the property)
  • Expression (a scriptblock that will be executed to determine the value, where $_ refers to the object itself)
Get-GPO -all |
Select-Object -Property DisplayName, Description, @{
    Name = 'Responsibility'
    Expression = {
        ($_.Description -split '\r?\n')[0] # First line
    }
} |
Sort-Object -Property DisplayName |
Out-GridView

New Member

You can use a ScriptProperty that will execute a scriptblock each time the property is called on the object. Use $this to refer to the object in this context.

Get-GPO -all |
Add-Member -MemberType ScriptProperty -Name Responsibility -Value {
    ($this.Description -split '\r?\n')[0] # First line
} -Force -PassThru |
Select-Object -Property DisplayName, Responsibility, Description |
Sort-Object -Property DisplayName |
Out-GridView

Upvotes: 3

Related Questions