I am trying to find .sql files in a folder and filtering them based on the last write time. Based on the last write time I got 4 files as output.
TestScript1
Thanks for all your suggestions above for my question. After streamlining the suggestions, the code below worked well for my situation. This is helping me sort in the natural order like Windows Explorer does.
$ToNatural= { [regex]::Replace($_, '\d+',{$args[0].Value.Padleft(20)})}
$File= Get-ChildItem $FileLocation -Filter *.sql | Where-Object {$_.LastWriteTime -gt $datetime} | Sort-Object $ToNatural
Hm... finally figure it out.
Windows explorer is using a legacy API in shlwapi.dll called StrCmpLogicalW when sorting strings.
I don't want to use padding zeros, so wrote a script.
https://github.com/LarrysGIT/Powershell-Natural-sort
Find the following powershell script, it using the same API. You may need to check the latest code from the repo as I am not updating here always.
function Sort-Naturally
{
PARAM(
[System.Collections.ArrayList]$Array,
[switch]$Descending
)
Add-Type -TypeDefinition @'
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace NaturalSort {
public static class NaturalSort
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string psz1, string psz2);
public static System.Collections.ArrayList Sort(System.Collections.ArrayList foo)
{
foo.Sort(new NaturalStringComparer());
return foo;
}
}
public class NaturalStringComparer : IComparer
{
public int Compare(object x, object y)
{
return NaturalSort.StrCmpLogicalW(x.ToString(), y.ToString());
}
}
}
'@
$Array.Sort((New-Object NaturalSort.NaturalStringComparer))
if($Descending)
{
$Array.Reverse()
}
return $Array
}
Find the test results below.
PS> # Natural sort
PS> . .\NaturalSort.ps1
PS> Sort-Naturally -Array @('2', '1', '11')
1
2
11
PS> # If regular sort is used
PS> @('2', '1', '11') | Sort-Object
1
11
2
And,
PS> # Not good
PS> $t = (ls .\Scripts*.txt).name
PS> $t | Sort-Object
Scripts1.txt
Scripts10.txt
Scripts2.txt
PS> # Good
PS> Sort-Naturally -Array $t
Scripts1.txt
Scripts2.txt
Scripts10.txt
I like @mjolinor solution better, as it shows how powerful sorting in PowerShell can be. But just in case you would like to "fix" file names with prefix mentioned in comments:
Get-ChildItem Test*.sql |
Rename-Item -NewName { 'TestScript{0:D2}.sql' -f [int]($_.BaseName -replace '\D') }
Once renamed, files will be sorted as you expected. If you need more than two digits - just change formating ({0:D#}
).
Something like this:
| sort-object {[int]($_.basename -replace '\D')}