1

I am working with a powershell script that automates some long running deployment tasks.

I'm using

$scripts = Get-ChildItem -r -Path server-deploy | select -expand fullname

to get an array that looks like this

D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-10.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-20.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-30.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-40.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-50.ps1

I've left some 'holes' in there to add extra scripts if the requirements change on me. The scripts will always be named "install-someword-int.ps1" and ordering is determined by the int.

I know that Get-ChildItem has sorted them in the correct order, but i'd like to be able to create a function that can always order them so if I need to add a script for instance, install-builder-15.ps1, I know it will run after 10 and before 20. Being a good custodian, I don't inherently trust Get-ChildItem to ALWAYS return them in the correct order.

I'm looking for the proper way to sort $scripts, or use a for loop of some kind to iterate the array, but always in the correct order.

EDIT: @boxdog Using the files:

install-builder-10.ps1                                                                                                                 
install-builder-20.ps1                                                                                                                 
install-builder-30.ps1                                                                                                                 
install-builder-4.ps1                                                                                                                  
install-builder-5.ps1 

if I run Sort-Object @{e={$_ -match ".*install-.*-(?<number>\d+).ps1"; $matches.number}} I see they are in the same order. I would expect

install-builder-4.ps1                                                                                                                  
install-builder-5.ps1 
install-builder-10.ps1                                                                                                                 
install-builder-20.ps1                                                                                                                 
install-builder-30.ps1     

3 Answers 3

4

here is yet another variant on the "sort by calculated value" idea. this casts the ending digits to [int] before sorting them. [grin]

$FakeFileList = @(
    [System.IO.FileInfo]'install-builder-10.ps1'
    [System.IO.FileInfo]'install-builder-20.ps1'
    [System.IO.FileInfo]'install-builder-30.ps1'
    [System.IO.FileInfo]'install-builder-4.ps1'
    [System.IO.FileInfo]'install-builder-5.ps1'
    )

$FakeFileList |
    Sort-Object {[int]$_.BaseName.Split('-')[-1]}

output ...

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
darhsl       1600-12-31   6:00 PM                install-builder-4.ps1
darhsl       1600-12-31   6:00 PM                install-builder-5.ps1
darhsl       1600-12-31   6:00 PM                install-builder-10.ps1
darhsl       1600-12-31   6:00 PM                install-builder-20.ps1
darhsl       1600-12-31   6:00 PM                install-builder-30.ps1
Sign up to request clarification or add additional context in comments.

4 Comments

You just beat me to it! (+1)
@Theo - i started off trying to rename the files with proper zero-padding for the numbers. then i gave up and went the easier way ... [grin]
Another fine solution. I wish I could select both as answers. this is cleaner.
@CarComp - thank you! i enjoyed fiddling with it ... a nice problem that was fun to play with. [grin]
3

If all you are interested in is sorting by the int at the end of the string, then you can sort them with Sort-Object like this:

$paths = "D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-30.ps1",
         "D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-sortofbuilder-20.ps1",
         "D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-10.ps1",
         "D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-20.ps1",
         "D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-50.ps1",
         "D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-notbuilder-10.ps1",
         "D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-15.ps1"

$paths | Sort-Object @{e={$_ -match ".*install-.*-(?<number>\d+).ps1" | Out-Null; [int]$matches.number}}

Which gives this output:

D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-10.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-notbuilder-10.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-15.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-sortofbuilder-20.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-20.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-30.ps1
D:\BitBucket\CI\serverdeploy\builder\server-deploy\install-builder-50.ps1

5 Comments

ok, so it sorts like this install-builder-10.ps1 install-builder-20.ps1 install-builder-30.ps1 install-builder-4.ps1 install-builder-5.ps1
To left pad the number with zeroes to a unique length use $paths | Sort-Object @{e={$_ -match ".*install-.*-(?<number>\d+).ps1"; $matches.number.PadLeft(20,'0')}}
Oops! Not enough testing before posting. I've corrected my example and it should work properly now.
sort {[int]($_ -replace '.*(\d+)\.ps1$', '$1')}?
@CarComp Not to turn this political, but if there is any lesson to be learned from Brexit, it’s that you should always have the option to change your vote when better information come along. Feel free to deselect my answer; I won’t be upset ... honest 😉
0

You could sort an array of strings by 1st integer match like this.

$a =("__133____2_.ps1",
     "__13____12_.ps1",
     "__3____122_.ps1")

"`n=============SORTED AS NUMBERS by 1st occuring number"
$a | Sort-Object @{ e = {$_ -match ".*?(\d+).*?(\d+).*" Out-Null; [int]$matches[1]} }

enter image description here


For 2nd/lAST-match REPLACE:

> $matches\[1]    with ( $matches[2]   OR $matches.2 )

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.