At the end of part one, I built a custom Puppet structured fact to relate the Powershell and .NET version information from a Powershell Object to a Ruby Hash that was readable by Facter. The end result was, well, a pile of info.
PS C:\Users\vagrant> facter -p psversiontable
{"psversion"=>{"major"=>4, "minor"=>0, "build"=>-1, "revision"=>-1, "majorrevision"=>-1, "minorrevision"=>-1}, "wsmansta
ckversion"=>{"major"=>3, "minor"=>0, "build"=>-1, "revision"=>-1, "majorrevision"=>-1, "minorrevision"=>-1}, "serializat
ionversion"=>{"major"=>1, "minor"=>1, "build"=>0, "revision"=>1, "majorrevision"=>0, "minorrevision"=>1}, "clrversion"=>
{"major"=>4, "minor"=>0, "build"=>30319, "revision"=>34209, "majorrevision"=>0, "minorrevision"=>-31327}, "buildversion"
=>{"major"=>6, "minor"=>3, "build"=>9600, "revision"=>17400, "majorrevision"=>0, "minorrevision"=>17400}, "pscompatiblev
ersions"=>[{"major"=>1, "minor"=>0, "build"=>-1, "revision"=>-1, "majorrevision"=>-1, "minorrevision"=>-1}, {"major"=>2,
"minor"=>0, "build"=>-1, "revision"=>-1, "majorrevision"=>-1, "minorrevision"=>-1}, {"major"=>3, "minor"=>0, "build"=>-
1, "revision"=>-1, "majorrevision"=>-1, "minorrevision"=>-1}, {"major"=>4, "minor"=>0, "build"=>-1, "revision"=>-1, "maj
orrevision"=>-1, "minorrevision"=>-1}], "psremotingprotocolversion"=>{"major"=>2, "minor"=>2, "build"=>-1, "revision"=>-
1, "majorrevision"=>-1, "minorrevision"=>-1}}
In this post, I will create a couple of additional facts to crunch the above into something a bit more…legible.
PowerShell Version
On the first line of output above, you can see ‘psversion’ contains a hash with the major, minor, build and revision info for PowerShell. Since PowerShell (and the underlying Windows Management Framework) tend to stick to major releases, I’ll create a fact for PowerShell version using the major and minor numbers from the hash above.
Facter: powershell
Facter.add(:powershell) do
confine :kernel => :windows
setcode do
ps = Facter.value(:psversiontable)
ps_major = ps['psversion']['major']
ps_minor = ps['psversion']['minor']
if ps_major
"#{ps_major}.#{ps_minor}"
else
"unavailable"
end
end
end
In the above example, I’ve:
1. Created a new fact called ‘powershell’.
2. Confined it to Windows hosts
3. In the code block, instead of more powershell, I’m taking the hash that we already have in ‘psversion’ and extracting the numbers I need. In this case, I’m grabbing the major and minor values from the ‘psversion’ nested hash, then pushing them together into a string that resembles a version number. On a Windows 2012 server it should return ‘4.0’ by default.
4. I have it verify that at least something came back for the version info otherwise report the fact as ‘unavailable’.
Fairly simple, yes? You can do the same for the .NET framework, but there’s a bit of math involved. The .NET framework is hiding in the psversiontable hash under the CLRVersion.
"clrversion"=>{"major"=>4, "minor"=>0, "build"=>30319, "revision"=>34209, "majorrevision"=>0, "minorrevision"=>-31327}
This is where your patience can be tested very quickly. I tend to want the version of the .NET framework that corresponds to the available version numbers, for example .NET 2, 3.5, 4, 4.5, 4.5.1, 4.5.2, etc… but you need to decipher what version that is based on the info in this hash. I ended up using a case statement to return a useable string like this:
Facter.add("dotnet") do
confine :kernel => :windows
setcode do
clr = Facter.value(:psversiontable)
if !clr
"unavailable"
else
major = clr['clrversion']['major']
revision = clr['clrversion']['revision']
case major
when 4
case revision
when 1, 269, 276, 296, 544, 1008, 1022, 1026, 2034
"4.0"
when 17626, 17929, 18010, 18052, 18063
"4.5"
when 18408, 18444, 34014
"4.5.1"
when 34209, 90210
"4.5.2"
else
"unavailable"
end
when major == 2
"legacy"
else
"unavailable"
end
end
end
end
With the above two facts working off of the psversiontable fact, you should end up with some very usable results:
PS> facter -p powershell
powershell => 4.0
PS> facter -p dotnet
dotnet => 4.5