12

I have a simple script that runs a cmdlet of a 3rd party application and outputs a table with 3 columns - Name, Result, JobName. Result only contains one of three values: Success, Warning, or Failed.

Output:

Name      Result   JobName                          
----      ------   -------                          
server1   Success  servers-A            
server2   Success  servers-A            
server3   Warning  servers-A            
server4   Success  servers-A   
server5   Warning  servers-B            
server6   Success  servers-B            
server7   Failed   servers-C            
server8   Failed   servers-C   

What I'd like to do is sort the table by the Result column but in the following custom order (order of importance): Failed, Warning, then Success.

Example

Name    Result  JobName    
----    ------  -------                      
server7 Failed  servers-C            
server8 Failed  servers-C
server3 Warning servers-A            
server5 Warning servers-B            
server1 Success servers-A            
server2 Success servers-A            
server4 Success servers-A   
server6 Success servers-B

How can this be achieved?

1
  • Are you able to post your code please so we can see how it is doing this? You could specify the -decending switch in the Sort-Object command, but seeing your code will help see exactly what to do. Commented Feb 9, 2018 at 8:26

3 Answers 3

31

You can use Array.IndexOf(), which effectively translates strings into numbers:

$importance = "Failed", "Warning", "Success"

$result | Sort-Object { $importance.IndexOf($_.Result) }

Catch: Any unexpected value in Result will be sorted to the top, because IndexOf will return -1 for values it can't find.

Test:

$importance = "Failed", "Warning", "Success"

$list = @(
    @{ Result = "Warning" }
    @{ Result = "Success" }
    @{ Result = "Failed" }
)

$list | Sort-Object { $importance.IndexOf($_.Result) }

Result:

Name                           Value                                                                                                                                                                 
----                           -----                                                                                                                                                                 
Result                         Failed                                                                                                                                                                
Result                         Warning                                                                                                                                                               
Result                         Success                                                                                                                                                               
Sign up to request clarification or add additional context in comments.

7 Comments

This is genius! When a scriptblock is provided in Sort-Object , the array is sorted based on the output of the scriptblock, in that case will be something like -1;-1;0;-1;-1;2;-1-1;1 and when you sort this you get -1;-1;-1;-1;-1;0;1;2 . Looks like the scriptblock acts like a temporary column attached to original array.
@Vasil Yes, that's exactly what it does - it sorts by any expression. The simplest expression would be "some property of the original object", but "some value that I just calculated" works the exactly same.
Works like a charm! However, I'm not able to understand the above inner working of Sort-Object { ... } explained by Vasil & Tomalak. Can one of you help me understand this or point out any docs that I can refer to?
@KarthickGanesan Sort-Object { ... } evaluates the script block for each item in the input. The result of the script block is then used for sorting. In the above code, the result of the script block is the numerical index of the input string in the $importance array. Therefore the order of that array determines the order things will be sorted.
Thanks, Tomalak for your response. It makes sense! I was confused when Vasil listed out 8 elements in his comment. Just found that he referred to the dataset in the OP. :)
|
7

Here is a script block option:

ForEach ($Result in 'Success','Warning','Failed') {
    $Obj | Where-Object {$_.Result -eq $Result } | Sort-Object Name
}

Assumes that your cmdlet has output the original object into a variable named $Obj.

2 Comments

Thank you, your suggestion worked for me! To complicate things further, is it possible to then sort by Name? I get the Result column sorted as I want but the name objects (server names) are random. Thanks again
Yes, we can just add it in after the Where-Object. I've edited to include that.
0

Here is how I did this, you pass the encompassing object and the property name you want to sort on and it brings you back a properly sorted object without having to try and work around the sort-object command (which is awesome) without knowing what's going on under its hood. Hopefully this helps.

function sortObjectManually
{
    Param(
    [parameter(Mandatory=$true)]
    $unsortedObject,
    [parameter(Mandatory=$true)]
    $propertyName
    )
    
    $sortedObject = New-Object System.Collections.ArrayList;
    foreach ($object in $unsortedObject)
    {
        if ($sortedObject.Count -eq 0)
        {
            $sortedObject.Add($object) | Out-Null;
        }
        else
        {
            $inserted = $false;
            for ($i = 0; $i -lt $sortedObject.Count; $i++)
            {
                if ($object.$propertyName -lt $sortedObject[$i].$propertyName)
                {
                    $sortedObject.Insert($i, $object);
                    $inserted = $true;
                    break;
                }
            }
            
            if ($inserted -eq $false)
            {
                $sortedObject.Add($object) | Out-Null;
            }
        }
    }
    
    return $sortedObject;
}

cls;
$prop = "ServerName";
$results = sortObjectManually -unsortedObject $endInvokeArr -propertyName $prop;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.