Get-WindowsVersion.psm1

function Get-WindowsVersion {
    <#
.SYNOPSIS
    List current or History Windows Version from local or remote computer. List with Active Directory SearchBase.
.DESCRIPTION
    List current or History Windows Version from local or remote computer. List with Active Directory SearchBase.
.PARAMETER ComputerName
    Name of server to list Windows Version from remote computer.
.PARAMETER ADSearchBase
    Active Directory SearchBase of server to list Windows Version from remote computer.
.PARAMETER History
    List History Windows Version from computer.
.PARAMETER Force
    Disable the built-in Format-Table and Sort-Object.
.EXAMPLE
    Get-WindowsVersion
    List Windows Version on local computer with built-in Format-Table and Sort-Object.
.EXAMPLE
    Get-WindowsVersion -ComputerName pc1
    List Windows Version on remote computer with built-in Format-Table and Sort-Object.
.EXAMPLE
    Get-WindowsVersion -ComputerName pc1,pc2
    List Windows Version on multiple remote computer with built-in Format-Table and Sort-Object.
.EXAMPLE
    Get-WindowsVersion -ADSearchBase "OU=Computers,DC=comodo,DC=com" with built-in Format-Table and Sort-Object.
    List Windows Version on Active Directory SearchBase computer.
.EXAMPLE
    Get-WindowsVersion -ComputerName pc1,pc2 -Force
    List Windows Version on multiple remote computer and disable the built-in Format-Table and Sort-Object.
.EXAMPLE
    Get-WindowsVersion -History with built-in Format-Table and Sort-Object.
    List History Windows Version on local computer.
.EXAMPLE
    Get-WindowsVersion -ComputerName pc1,pc2 -History
    List History Windows Version on multiple remote computer with built-in Format-Table and Sort-Object.
.EXAMPLE
    Get-WindowsVersion -ComputerName pc1,pc2 -History -Force
    List History Windows Version on multiple remote computer and disable built-in Format-Table and Sort-Object.
#>

    [CmdletBinding(DefaultParameterSetName = "ParS1")]
    param (
        [parameter(Position = 0, ParameterSetName = "ParS1", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string[]] $ComputerName = "localhost",
        [parameter(ParameterSetName = "ParS2", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string] $ADSearchBase,
        [parameter(ParameterSetName = "ParS1", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [parameter(ParameterSetName = "ParS2", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [switch] $History,
        [parameter(ParameterSetName = "ParS1", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [parameter(ParameterSetName = "ParS2", Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [switch] $Force
    )
    # PsVersion
    if ((($PsVersionTable.PSEdition) -match "desktop") -or (($PsVersionTable.OS) -match "windows")) {
        # ADSearchBase
        if ($ADSearchBase) {
            try {
                $ADSearch = New-Object System.DirectoryServices.DirectorySearcher
                $ADSearch.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$ADSearchBase")
                $ADSearch.Filter = ("(objectCategory=computer)")
                $ADSearchFind = $ADSearch.FindAll()
            }
            catch {
                Write-Warning "ADSearchBase not found"
            }
            $ComputerName = foreach ($ADComputer in $ADSearchFind) {
                $ADComputer.Properties.name
            }
        }
        # Loop ComputerName
        $ComputerName = $ComputerName.ToUpper()
        $Tmp = New-TemporaryFile
        foreach ($Computer in $ComputerName) {
            if ($ComputerName -like "localhost") {
                $TestLocal = $true
            }
            else {
                $TestWinRM = Test-NetConnection -CommonTCPPort WINRM -ComputerName $Computer -ErrorAction SilentlyContinue -ErrorVariable EV01
            }
            if ($TestWinRM.TcpTestSucceeded -or $TestLocal) {
                # Variables
                $WmiClass = [WmiClass]"\\$Computer\root\default:stdRegProv"
                $HKLM = 2147483650
                $Reg1 = "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
                $Reg2 = "SYSTEM\Setup"
                # History
                if ($History) {
                    $KeyArr = ($WmiClass.EnumKey($HKLM, $Reg2)).snames -like "Source*"
                }
                else {
                    $KeyArr = $Reg1
                }
                # Loop KeyArr
                foreach ($Key in $KeyArr) {
                    if ($History) {
                        $Reg = "$Reg2\$Key"
                    }
                    else {
                        $Reg = $Key
                    }
                    $Major = $WmiClass.GetDWordValue($HKLM, $Reg, "CurrentMajorVersionNumber").UValue
                    $Minor = $WmiClass.GetDWordValue($HKLM, $Reg, "CurrentMinorVersionNumber").UValue
                    $Build = $WmiClass.GetStringValue($HKLM, $Reg, "CurrentBuildNumber").sValue
                    $UBR = $WmiClass.GetDWordValue($HKLM, $Reg, "UBR").UValue
                    $ReleaseId = $WmiClass.GetStringValue($HKLM, $Reg, "ReleaseId").sValue
                    $ProductName = $WmiClass.GetStringValue($HKLM, $Reg, "ProductName").sValue
                    $ProductId = $WmiClass.GetStringValue($HKLM, $Reg, "ProductId").sValue
                    $InstallTime1 = $WmiClass.GetQWordValue($HKLM, $Reg, "InstallTime").UValue
                    $InstallTime2 = ([datetime]::FromFileTime($InstallTime1))
                    # Variables Windows 6.x
                    if ($Major.Length -le 0) {$Major = $WmiClass.GetStringValue($HKLM, $Reg, "CurrentVersion").sValue}
                    if ($ReleaseId.Length -le 0) {$ReleaseId = $WmiClass.GetStringValue($HKLM, $Reg, "CSDVersion").sValue}
                    if ($InstallTime1.Length -le 0) {$InstallTime2 = (Get-CimInstance Win32_OperatingSystem -ComputerName $Computer).InstallDate}
                    # Add Points
                    if (-not($Major.Length -le 0)) {$Major = "$Major."}
                    if (-not($Minor.Length -le 0)) {$Minor = "$Minor."}
                    if (-not($UBR.Length -le 0)) {$UBR = ".$UBR"}
                    # Output
                    $Output = New-Object -TypeName PSobject
                    $Output | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer
                    $Output | Add-Member -MemberType NoteProperty -Name ProductName -Value $ProductName
                    $Output | Add-Member -MemberType NoteProperty -Name WindowsVersion -Value $ReleaseId
                    $Output | Add-Member -MemberType NoteProperty -Name WindowsBuild -Value "$Major$Minor$Build$UBR"
                    $Output | Add-Member -MemberType NoteProperty -Name ProductId -Value $ProductId
                    $Output | Add-Member -MemberType NoteProperty -Name InstallTime -Value $InstallTime2
                    $Output | Export-Csv -Path $Tmp -Append
                }
            }
        }
        # Output
        if ($Force) {
            Import-Csv -Path $Tmp
        }
        else {
            Import-Csv -Path $Tmp | Sort-Object -Property ComputerName, WindowsVersion | Format-Table -AutoSize
        }
    }
    else {
        Write-Warning "PSVersion OS not Windows"
    }
}