Powershell array sort and separate into two different array

358 Views Asked by At

I have this array :

[

"org-dummyemail-123-AccountName",
"org-dummyemail-123-Email",
"org-dummyemail-123-PAT",
"org-dummyemail-123-PATName",
"org-dummyemail-123-PATValidTo",
"org-dummyemail1-joemarmoto-AccountName",
"org-dummyemail1-joemarmoto-Email",
"org-dummyemail1-joemarmoto-PAT",
"org-dummyemail1-joemarmoto-PATName",
"org-dummyemail1-joemarmoto-PATValidTo"
]

And want to sort it out and make two seperate arrays like this one

[
"org-dummyemail-123-AccountName",
"org-dummyemail-123-Email",
"org-dummyemail-123-PAT",
"org-dummyemail-123-PATName",
"org-dummyemail-123-PATValidTo"
]


[
"org-dummyemail1-joemarmoto-AccountName",
"org-dummyemail1-joemarmoto-Email",
"org-dummyemail1-joemarmoto-PAT",
"org-dummyemail1-joemarmoto-PATName",
"org-dummyemail1-joemarmoto-PATValidTo"
]

Hoping for your help! Thanks :)

6

There are 6 best solutions below

0
On

Treating your input as a Json object (from a here string) The script

  • builds akey from the first 3 -/dash delimited parts with Select-Object and
    calculated properties.
  • Groups by this key
  • rebuilds Json objects from the group values.

$Json = @"
[
"org-dummyemail-123-AccountName",
"org-dummyemail-123-Email",
"org-dummyemail-123-PAT",
"org-dummyemail-123-PATName",
"org-dummyemail-123-PATValidTo",
"org-dummyemail1-joemarmoto-AccountName",
"org-dummyemail1-joemarmoto-Email",
"org-dummyemail1-joemarmoto-PAT",
"org-dummyemail1-joemarmoto-PATName",
"org-dummyemail1-joemarmoto-PATValidTo"
]
"@ | ConvertFrom-JSon

$Json | Select-Object @{n='key';E={($_ -split '-')[0..2] -join '-'}},
                      @{n='value';e={$_}} |
    Group-Object key | ForEach-Object{
        $_.Group.Value | ConvertTo-Json
    }

Has this output:

[
    "org-dummyemail-123-AccountName",
    "org-dummyemail-123-Email",
    "org-dummyemail-123-PAT",
    "org-dummyemail-123-PATName",
    "org-dummyemail-123-PATValidTo"
]
[
    "org-dummyemail1-joemarmoto-AccountName",
    "org-dummyemail1-joemarmoto-Email",
    "org-dummyemail1-joemarmoto-PAT",
    "org-dummyemail1-joemarmoto-PATName",
    "org-dummyemail1-joemarmoto-PATValidTo"
]
0
On

Working with the $PSItem variable

$arr="org-dummyemail-123-AccountName",
"org-dummyemail-123-Email",
"org-dummyemail-123-PAT",
"org-dummyemail-123-PATName",
"org-dummyemail-123-PATValidTo",
"org-dummyemail1-joemarmoto-AccountName",
"org-dummyemail1-joemarmoto-Email",
"org-dummyemail1-joemarmoto-PAT",
"org-dummyemail1-joemarmoto-PATName",
"org-dummyemail1-joemarmoto-PATValidTo"

$arr2 = $arr | Where-Object {$PSItem -match 'joemarmoto'}
$arr3 = $arr | Where-Object {$PSItem -match '123'}

Have a look here: https://blogs.msdn.microsoft.com/mvpawardprogram/2013/04/15/working-with-the-new-psitem-automatic-variable-in-windows-powershell-3-0/

From that site: Get-Help about_Automatic_Variables -ShowWindow

Type “psitem” in the Find box to highlight all text containing this word:

As we can see, $PSItem is the same as $_. The goal with the introduction of the $PSItem variable is making the code containing the “current object in the pipeline” easier to read and understand.

Answer is almost identical to Gert Jan Kraaijeveld, but with explenation what that $PSItem does and where that info comes from.

0
On

Same idea, but with a hashtable:

$json = @'
[
"org-dummyemail-123-AccountName",
"org-dummyemail-123-Email",
"org-dummyemail-123-PAT",
"org-dummyemail-123-PATName",
"org-dummyemail-123-PATValidTo",
"org-dummyemail1-joemarmoto-AccountName",
"org-dummyemail1-joemarmoto-Email",
"org-dummyemail1-joemarmoto-PAT",
"org-dummyemail1-joemarmoto-PATName",
"org-dummyemail1-joemarmoto-PATValidTo"
]
'@

$a = $json | ConvertFrom-Json
$b = @{}

$a | ForEach-Object {
    $b[$_.Split('-')[0..2] -join '-'] += @($_)
}

$b | ConvertTo-Json
0
On

Simple array filtering:

$arr="org-dummyemail-123-AccountName",
"org-dummyemail-123-Email",
"org-dummyemail-123-PAT",
"org-dummyemail-123-PATName",
"org-dummyemail-123-PATValidTo",
"org-dummyemail1-joemarmoto-AccountName",
"org-dummyemail1-joemarmoto-Email",
"org-dummyemail1-joemarmoto-PAT",
"org-dummyemail1-joemarmoto-PATName",
"org-dummyemail1-joemarmoto-PATValidTo"

$arr2 = $arr.where{$PSItem -match 'joemarmoto'}
$arr3 = $arr.where{$PSItem -notmatch 'joemarmoto'}
0
On

Here's a version using regex to determine which part of the input string to group by:

clear-host

'REGEX 1; org-dummyemail-123 vs org-dummyemail1-joemarmoto'

$groupedByAllButLast = @(
"org-dummyemail-123-AccountName",
"org-dummyemail-123-Email",
"org-dummyemail-123-PAT",
"org-dummyemail-123-PATName",
"org-dummyemail-123-PATValidTo",
"org-dummyemail1-joemarmoto-AccountName",
"org-dummyemail1-joemarmoto-Email",
"org-dummyemail1-joemarmoto-PAT",
"org-dummyemail1-joemarmoto-PATName",
"org-dummyemail1-joemarmoto-PATValidTo"
) | Group-Object -Property @{E={$_ -replace '([^-]+-[^-]+-[^-]+)-.*', '$1'}} 

for ([int]$i = 0; $i -lt $groupedByAllButLast.Count; $i++)
{
    Write-Verbose $groupedByAllButLast[$i].Name -Verbose
    $groupedByAllButLast[$i].Group
}

'REGEX 2; 123 vs joemarmoto'
$groupedByTheNameOrEmailBit = @(
"org-dummyemail-123-AccountName",
"org-dummyemail-123-Email",
"org-dummyemail-123-PAT",
"org-dummyemail-123-PATName",
"org-dummyemail-123-PATValidTo",
"org-dummyemail1-joemarmoto-AccountName",
"org-dummyemail1-joemarmoto-Email",
"org-dummyemail1-joemarmoto-PAT",
"org-dummyemail1-joemarmoto-PATName",
"org-dummyemail1-joemarmoto-PATValidTo"
) | Group-Object -Property @{E={$_ -replace '[^-]+-[^-]+-([^-]+)-.*', '$1'}} #all we've changed is the location of the opening bracket in this line 

for ([int]$i = 0; $i -lt $groupedByTheNameOrEmailBit.Count; $i++)
{
    Write-Verbose $groupedByTheNameOrEmailBit[$i].Name -Verbose
    $groupedByTheNameOrEmailBit[$i].Group
}

NB: This is basically the same approach as Lee's; only instead of using split and taking a signle segment, we use regex to capture all those parts of the string which are relevant for our key... See MS Docs for a bit more info on this useful function.

4
On

a somewhat different method would be to use the Group-Object cmdlet to group on a calculated property. you did not specify the exact part to sort on - the dummy email or the name that comes after it - so i used the part after the dummy email.

the result gives you a collection of arrays with a name [the calculated property] and a group [the items that matched that calculated property]. you can address them individually OR use them to make new arrays.

$AllNames = @(
    'org-dummyemail-123-AccountName',
    'org-dummyemail-123-Email',
    'org-dummyemail-123-PAT',
    'org-dummyemail-123-PATName',
    'org-dummyemail-123-PATValidTo'
    'org-dummyemail1-joemarmoto-AccountName',
    'org-dummyemail1-joemarmoto-Email',
    'org-dummyemail1-joemarmoto-PAT',
    'org-dummyemail1-joemarmoto-PATName',
    'org-dummyemail1-joemarmoto-PATValidTo'
    )

# 3rd item index = 2
$PartToGroupOn = 2

$GroupedAllNames = $AllNames |
    Group-Object -Property {$_.Split('-')[$PartToGroupOn]}

$GroupedAllNames[1].Group

output ...

org-dummyemail-123-AccountName
org-dummyemail-123-Email
org-dummyemail-123-PAT
org-dummyemail-123-PATName
org-dummyemail-123-PATValidTo