PowerShell File Versions

05 Dec 2017
 

Today, as part of a larger script, I needed to write a PowerShell function to check that an assembly’s version number had been properly bumped between two builds of a program. Writing this function should be simple (right?).

First things first, get the version numbers. I looked at a File Version in Explorer, ‘16.0.255.0’, cool. Went to do the same in PowerShell.

PS> get-item .\someFile.exe | select VersionInfo | Format-List *

...
FileVersion:        16.00.0255
...

‘16.00.0255’, a bit odd? This particular file was an InstallShield setup.exe which was versioned ‘xx.xx.xxxx’ within the MSI so it didn’t seem too strange of a difference. I then took a look at a few more files, although for the majority of them, their FileVersion in PowerShell matched Explorer, for a few others there were more weird differences. There was sometimes an extra part, sometimes the last part was a seemingly random number and sometimes the last part was just left off altogether. At this point, I started worrying about time, and as such, I Googled it.

This blog post by Matthew Reynolds was my salvation. Essentially, the ‘correct’ FileVersion is contained within the VersionInfo property but is slightly out of the way.

Using Matthew’s example, I wrote this short block to put a corrected version number into the property ‘RealFileVersion’.

try {
    Update-TypeData -TypeName System.Io.FileInfo -MemberType ScriptProperty -MemberName RealFileVersion -ErrorAction stop -Value {
        New-Object System.Version -ArgumentList @(
            $this.VersionInfo.FileMajorPart
            $this.VersionInfo.FileMinorPart
            $this.VersionInfo.FileBuildPart
            $this.VersionInfo.FilePrivatePart
        )
    }
} catch [System.Management.Automation.RuntimeException] {
    if ($_.Exception.Message -match "^Error in TypeData \`"System.IO.FileInfo\`": The member RealFileVersion is already present.$") {
        Write-Warning "Could not add 'RealFileVersion' member to 'FileInfo' as it already exists."
    } else {
        Write-Error "An unknown RuntimeException occurred adding the member 'RealFileVersion' to the type 'FileInfo'!" -ErrorAction Stop
    }
} catch {
    Write-Error "Something went very wrong adding the member 'RealFileVersion' to the type 'FileInfo'... and it wasn't a RuntimeException!" -ErrorAction Stop
}

And now to compare some version numbers! Fun!

function checkBumped ([System.IO.FileInfo]$oldFile, [System.IO.FileInfo]$newFile) {
    foreach ($part in "Major","Minor","Build","Revision") {
        If ($newFile.RealFileVersion.$part       -gt $oldFile.RealFileVersion.$part) {
            return $true
        } elseif ($newFile.RealFileVersion.$part -lt $oldFile.RealFileVersion.$part) {
            Write-Error "$oldFile has been rolled back." -ErrorAction Stop
        }
    }
    return $false
}