2

How can I force conversion to type System.Version in PowerShell, or more likely, better understand why I cannot arbitrarily assign number strings type System.Version?

We ingest some software updates in folders whose titles include version numbers. In trying to get reports on what the latest versions ingested are, I have been doing the following quick and dirty:

ForEach ($Folder in $(Get-ChildItem -Path $SoftwareDirectory -Directory))
{
    $CurrentVersion = $Folder -Replace "[^0-9.]"
    If ($CurrentVersion -ne $null)
    {
        If ([System.Version]$CurrentVersion -gt [System.Version]$MaxVersion)
        {
            $MaxVersion = $CurrentVersion
            $MaxFolder = $Folder
        }
    }
}

This would be fed directory titles like the following,

  • foo-tools-1.12.file
  • bar-static-3.4.0.file

Most of the time, this is acceptable. However, when encountering some oddballs with longer numbers, like the following,

  • applet-4u331r364.file

In which case, System.Version refuses the resulting string as being too long.

Cannot convert value "4331364" to type "System.Version". Error: "Version string portion was too short or too long."
branpurn
  • 25
  • 4
  • Well it makes sense because `4u331r364` is not a valid version string. See [Remarks](https://learn.microsoft.com/en-us/dotnet/api/system.version?view=net-6.0#remarks). – Santiago Squarzon May 06 '22 at 18:53
  • Thanks for that link. What I didn't spot right away (will of course keep looking), is why I can't make the version string theoretically "4331364.0" just for the purposes of comparison. It wouldn't have to be a valid interpretation of 4u331r364 for my purposes, just a quick determination of whether there was a new version. – branpurn May 06 '22 at 18:55
  • 1
    @branpurn `[System.Version]` stores the individual revision numbers as 16-bit integers, making the largest possible value `32767`. You'll want to rewrite `4u331r364` to `4.331.364` before attempting to convert it – Mathias R. Jessen May 06 '22 at 18:57
  • In addition, `$(""),$null | Where {$_ -ne $CurrentVersion}` makes no sense, it's not clear what is doing there or why is there – Santiago Squarzon May 06 '22 at 19:01
  • 1
    @MathiasR.Jessen Actually it is 32-Bit integer per `Version` property (Major, Minor, Build, Revision). Test: `([Version] "$(2GB-1).0").Major -eq (2GB-1)`. Version resources of executable files can only use 16 bits per field, but in this case the version comes from the folder name, so this doesn't matter. – zett42 May 06 '22 at 19:03
  • @SantiagoSquarzon, previously was forcing `System.Version` before this block which caused issues when comparing `$CurrentVersion -ne $null`; don't recall 100% details but will remove the red herring – branpurn May 06 '22 at 19:06

1 Answers1

5

You need to ensure that your version strings have at least two components in order for a cast to [version] to succeed:

(
  @(
    'oo-tools-1.12.file'
    'bar-static-3.4.0.file'
    'applet-4u331r364.file'
  ) -replace '[^0-9.]'
).TrimEnd('.') -replace '^[^.]+$', '$&.0' | ForEach-Object { [version] $_ }

The above transforms 'applet-4u331r364.file' into '4331364.0', which works when cast to [version].

Note that you can avoid the need for .TrimEnd('.') if you exclude the filename extension to begin with: $Folder.BaseName -replace '[^0-9.]'

-replace '^[^.]+$', '$&.0' matches only strings that contain no . chars., in full, i.e. only those that don't already have at least two components; replacement expression $&.0 appends literal .0 to the matched string ($&).

Output (via Format-Table -AutoSize):

Major   Minor Build Revision
-----   ----- ----- --------
1       12    -1    -1
3       4     0     -1
4331364 0     -1    -1
mklement0
  • 382,024
  • 64
  • 607
  • 775