# encoding: ascii
# api: powershell
# title: Get-NtVersionNumbers
# description: Nice solution to detect current Windows version (instead buggy [Environment]::OSVersion). Fount at https://github.com/gregzakh/alt-ps/blob/master/Get-NtVersionNumbers.ps1
# version: 0.1
# type: function
# author: roger
# license: CC0
# function: Get-NtVersionNumbers
# x-poshcode-id: 6475
# x-archived: 2016-08-18T21:15:38
# x-published: 2016-08-16T13:44:00
#
#
function Get-NtVersionNumbers {
<#
.SYNOPSIS
Gets the version numbers of the run time library.
#>
begin {
@(
[Runtime.InteropServices.CallingConvention],
[Runtime.InteropServices.HandleRef],
[Reflection.Emit.OpCodes]
) | ForEach-Object {
$keys = ($ta = [PSObject].Assembly.GetType(
'System.Management.Automation.TypeAccelerators'
))::Get.Keys
$collect = @()
}{
if ($keys -notcontains $_.Name) {
$ta::Add($_.Name, $_)
}
$collect += $_.Name
}
function private:Set-Delegate {
param(
[Parameter(Mandatory=$true, Position=0)]
[ValidateNotNullOrEmpty()]
[String]$Module,
[Parameter(Mandatory=$true, Position=1)]
[ValidateNotNullOrEmpty()]
[String]$Function,
[Parameter(Mandatory=$true, Position=2)]
[ValidateNotNullOrEmpty()]
[String]$Delegate
)
begin {
[Regex].Assembly.GetType(
'Microsoft.Win32.UnsafeNativeMethods'
).GetMethods() | Where-Object {
$_.Name -cmatch '\AGet(ProcA|ModuleH)'
} | ForEach-Object {
Set-Variable $_.Name $_
}
$ptr = $GetProcAddress.Invoke($null, @(
[HandleRef](New-Object HandleRef(
(New-Object IntPtr), $GetModuleHandle.Invoke($null, @($Module))
)), $Function
))
}
process { $proto = Invoke-Expression $Delegate }
end {
$method = $proto.GetMethod('Invoke')
$returntype = $method.ReturnType
$paramtypes = $method.GetParameters() |
Select-Object -ExpandProperty ParameterType
$holder = New-Object Reflection.Emit.DynamicMethod(
'Invoke', $returntype, $paramtypes, $proto
)
$il = $holder.GetILGenerator()
0..($paramtypes.Length - 1) | ForEach-Object {
$il.Emit([OpCodes]::Ldarg, $_)
}
switch ([IntPtr]::Size) {
4 { $il.Emit([OpCodes]::Ldc_I4, $ptr.ToInt32()) }
8 { $il.Emit([OpCodes]::Ldc_I8, $ptr.ToInt64()) }
}
$il.EmitCalli(
[OpCodes]::Calli, [CallingConvention]::StdCall, $returntype, $paramtypes
)
$il.Emit([OpCodes]::Ret)
$holder.CreateDelegate($proto)
}
}
$RtlGetNtVersionNumbers = Set-Delegate ntdll RtlGetNtVersionNumbers `
'[Action[[Byte[]], [Byte[]], [Byte[]]]]'
}
process {
$maj, $min = [Byte[]]@(0, 0, 0, 0), [Byte[]]@(0, 0, 0, 0)
$RtlGetNtVersionNumbers.Invoke($maj, $min, $null)
($maj, $min | ForEach-Object { [BitConverter]::ToUInt32($_, 0) }) -join '.'
}
end {
$collect | ForEach-Object { [void]$ta::Remove($_) }
}
}