Libraries/OS.Windows/OS.Windows.psm1

$Script:NS = (get-item $PSCommandPath).basename

<#
.SYNOPSIS
Return a the commonly used name for an OS.
 
.DESCRIPTION
Return a the commonly used name for an OS.
 
.PARAMETER Online
True to specify to fetch information from the running OS
 
.PARAMETER Root
The path to the root of an OS.
 
.EXAMPLE
Get-OSName -Online
 
.EXAMPLE
Get-OSName -Root '/mnt/sda3'
 
.EXAMPLE
Get-OSName -Root 'F:\'
 
.NOTES
General notes
#>

function Get-OSName {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(ParameterSetName = 'ONLINE')][switch]$Online,
        [Parameter(ParameterSetName = 'ROOT')][string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'ONLINE' {
                $distrib = Get-OSDistrib -Online
                $releaseId = Get-OSReleaseId -Online
                break
            }
            'ROOT' {
                $distrib = Get-OSDistrib -Root $Root
                $releaseId = Get-OSReleaseId -Root $Root
                break
            }
        }
        # return $Distrib + "." + $ReleaseId.replace('.','')
        return "$Distrib $ReleaseId"
   }

    End {
        Write-LeaveFunction
    }
}

<#
    .SYNOPSIS
    Get the distribution of the OS
#>

function Get-OSCodename {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(ParameterSetName = 'ONLINE')][switch]$Online,
        [Parameter(ParameterSetName = 'ROOT')][string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'ONLINE' {
                $CurrentVersion = OS.WinNT\Get-OSVersion -Online
                $InstallationType = OS.WinNT\Get-OSInstalltype -Online
                $CurrentBuild = OS.WinNT\Get-OSKernelVersion -Online
                $ReleaseId = OS.WinNT\Get-OSReleaseID -Online
                break
            }
            'ROOT' {
                $CurrentVersion = OS.WinNT\Get-OSVersion -Root $Root
                $InstallationType = OS.WinNT\Get-OSInstalltype -Root $Root
                $CurrentBuild = OS.WinNT\Get-OSKernelVersion -Root $Root
                $ReleaseId = OS.WinNT\Get-OSReleaseID -Root $Root
                break
            }
        }
        # edevel("CurrentVersion = $CurrentVersion")
        # edevel("InstallationType = $InstallationType")
        # edevel("CurrentBuild = $CurrentBuild")
        # edevel("ReleaseId = $ReleaseId")
        $value = Get-OSCodenameFromVersion -CurrentVersion $CurrentVersion -InstallationType $InstallationType -CurrentBuild $CurrentBuild -ReleaseId $ReleaseId

        return $value
   }

    End {
        Write-LeaveFunction
    }
}

<#
    .SYNOPSIS
    Convert version number to friendly Windows codename
 
    .DESCRIPTION
    The code name is the friendly name the Windows version is known as.
    The function handle Windows Desktop, Windows Server and Windows PE
 
    .PARAMETER CurrentVersion
    CurrentVersion found in registry. e.g. "6.2"
 
    .PARAMETER InstallationType
    InstallationType found in registry. e.g. "Desktop", "Server"
 
    .EXAMPLE
    Get-OSCodenameFromVersion
 
    .EXAMPLE
    Get-OSCodenameFromVersion "6.2" "Desktop"
 
    .NOTES
    This function is overriden by Windows10 module
 
    .LINK
    https://social.technet.microsoft.com/wiki/contents/articles/33619.windows-pe-version-overview.aspx
 
#>

function Get-OSCodenameFromVersion {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(Mandatory = $true, Position = 1)][string]$CurrentVersion,
        [Parameter(Mandatory = $true, Position = 2)][string]$InstallationType,
        [Parameter(Mandatory = $true, Position = 3)][string]$CurrentBuild,
        [AllowNull()][AllowEmptyString()][Parameter(Mandatory = $true, Position = 3)][string]$ReleaseId
        )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($CurrentVersion) {
            "5.0" {
                switch -wildcard ($InstallationType) {
                    "WindowsPE" {
                        $Codename = "WinPE 0.0"
                    }
                    "Client" {
                        $Codename = "Windows 2000"
                    }
                    "Server*" {
                        $Codename = "Windows 2000"
                    }
                }
            }
            "5.1" {
                switch -wildcard ($InstallationType) {
                    "WindowsPE" {
                        $Codename = "WinPE 1.0"
                    }
                    "Client" {
                        $Codename = "Windows XP"
                    }
                    "Server*" {
                        $Codename = "Windows Server 2003"
                    }
                }
            }
            "5.2" {
                switch -wildcard ($InstallationType) {
                    "WindowsPE" {
                        $Codename = "WinPE 1.2"
                    }
                    "Client" {
                        $Codename = "Windows XP64"
                    }
                    "Server*" {
                        $Codename = "Windows Server 2003"
                    }
                }
            }
            "6.0" {
                switch ($CurrentBuild) {
                    "6000" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 2.0"
                            }
                            "Client" {
                                $Codename = "Windows Vista"
                            }
                            "Server*" {
                                $Codename = "Windows Server 2008"
                                break
                            }
                        }
                        break
                    }
                    "6001" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 2.1"
                            }
                            "Client" {
                                $Codename = "Windows Vista SP1"
                            }
                            "Server*" {
                                $Codename = "Windows Server 2008 SP1"
                                break
                            }
                        }
                        break
                    }
                    "6002" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 2.2"
                            }
                            "Client" {
                                $Codename = "Windows Vista SP2"
                            }
                            "Server*" {
                                $Codename = "Windows Server 2008 SP2"
                                break
                            }
                        }
                        break
                    }
                }
            }
            "6.1" {
                switch ($CurrentBuild) {
                    "7600" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 3.0"
                            }
                            "Client" {
                                $Codename = "Windows 7"
                            }
                            "Server*" {
                                $Codename = "Windows Server 2008r2"
                            }
                        }
                        break
                    }
                    "7001" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 3.1"
                            }
                            "Client" {
                                $Codename = "Windows 7 SP1"
                            }
                            "Server*" {
                                $Codename = "Windows Server 2008r2 SP1"
                                break
                            }
                        }
                        break
                    }
                }
            }
            "6.2" {
                switch ($CurrentBuild) {
                    "9200" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 4.0"
                            }
                            "Client" {
                                $Codename = "Windows 8"
                            }
                            "Server*" {
                                $Codename = "Windows Server 2012"
                            }
                        }
                        break
                    }
                }
            }
            "6.3" {
                switch ($CurrentBuild) {
                    # * Windows 8
                    "9300" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 5.0"
                            }
                            "Client" {
                                $Codename = "Windows 8.1"
                            }
                            "Server*" {
                                $Codename = "Windows Server 2012r2"
                            }
                        }
                        break
                    }
                    # * Windows 8.1
                    "9600" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 5.1"
                            }
                            "Client" {
                                $Codename = "Windows 8.1 Update 1"
                            }
                            "Server*" {
                                $Codename = "Windows Server 2012r2 Update 1"
                            }
                        }
                        break
                    }
                    # * Windows 10
                    # "10240", etc...
                    default {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $Codename = "WinPE 10"
                            }
                            "Client" {
                                $Codename = Get-Windows10CodeName -ReleaseId $releaseId
                            }
                            "Server*" {
                                $Codename = "Windows Server 2016"
                                switch ($ReleaseId) {
                                    '1607' {
                                        $Codename = "Windows Server 2016"
                                    }
                                    '1809' {
                                        $Codename = "Windows Server 2019"
                                    }
                                }
                            }
                        }
                        break
                    }
                }
            }
        }

        return $Codename
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Get Windows 10 short code name from its releaseId
 
.DESCRIPTION
Translate a Windows 10 releaseId into the Windows 10 codename
 
.PARAMETER ReleaseID
Release Id of Windows 10
 
.EXAMPLE
Get-Windows10CodeName -ReleaseId 1803
 
.NOTES
General notes
 
.LINK
https://en.wikipedia.org/wiki/Windows_10_version_history
 
#>


function Get-Windows10CodeName {
    [CmdletBinding()][OutputType([String])]Param (
        [string]$ReleaseID
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $commercialName = ""
        switch ($ReleaseID) {
            "1507" {
                $commercialName = "15H1"
                break
            }
            "1511" {
                $commercialName = "15H2"
                break
            }
            "1607" {
                $commercialName = "16H2"
                break
            }
            "1703" {
                $commercialName = "17H1"
                break
            }
            "1709" {
                $commercialName = "17H2"
                break
            }
            "1803" {
                $commercialName = "18H1"
                break
            }
            "1809" {
                $commercialName = "18H2"
                break
            }
            "1903" {
                $commercialName = "19H1"
                break
            }
            "1909" {
                $commercialName = "19H2"
                break
            }
            default {
                $commercialName = $ReleaseID
                break
            }
        }
        return $commercialName
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Get Windows 10 marketing name from its releaseId
 
.DESCRIPTION
Translate a Windows 10 releaseId into a human readable marketing name
 
.PARAMETER ReleaseID
Release Id of Windows 10
 
.EXAMPLE
Get-Windows10LongCodeName -ReleaseId 1803
 
.NOTES
General notes
 
.LINK
https://en.wikipedia.org/wiki/Windows_10_version_history
 
#>


function Get-Windows10LongCodeName {
    [CmdletBinding()][OutputType([String])]Param (
        [string]$ReleaseID
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $commercialName = ""
        switch ($ReleaseID) {
            "1507" {
                $commercialName = ""
                break
            }
            "1511" {
                $commercialName = "November Update"
                break
            }
            "1607" {
                $commercialName = "Anniversary Update"
                break
            }
            "1703" {
                $commercialName = "Creators Update"
                break
            }
            "1709" {
                $commercialName = "Fall Creators Update"
                break
            }
            "1803" {
                $commercialName = "April 2018 Update"
                break
            }
            "1809" {
                $commercialName = "October 2018 Update"
                break
            }
            "1903" {
                $commercialName = "May 2019 Update"
                break
            }
            "1909" {
                $commercialName = "November 2019 Update"
                break
            }
            "2004" {
                $commercialName = "May 2020 Update"
                break
            }
            default {
                $commercialName = $ReleaseID
                break
            }
        }
        return $commercialName
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSEdition {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $edition = ""
        if ($Online) {
            $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
        } else {
            $RegPath = Mount-OfflineWindowsRegistry -Path "$Root\Windows" -Hive SOFTWARE
            $RegPath = $RegPath + "\Microsoft\Windows NT\CurrentVersion"
        }

        if ($PSVersionTable.PSVersion.Major -lt 5) {
            $edition = (Get-ItemProperty $RegPath 'EditionId' -ErrorAction:SilentlyContinue).EditionId
        } else {
            $edition = Get-ItemPropertyValue $RegPath -Name EditionId
        }

        switch -wildcard -regex ($edition) {
            'Ent..prise.*' {
                $edition = "Enterprise"
                break
            }
            'Profes.*' {
                $edition = "Professional"
            }
            '.*Education' {
                $edition += "Education"
            }
            '.*Standard' {
                $edition = "Standard"
            }
            '.*Data.*' {
                $edition = "Datacenter"
            }
            default {

            }
        }

        return $edition
    }

    End {
        Write-LeaveFunction
    }
}

<#
    .SYNOPSIS
    Get the Product name of the OS
#>

function Get-OSLongCodeName {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        return ""
   }

    End {
        Write-LeaveFunction
    }
}

function Get-OSProductname {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Online) {
            $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
        } else {
            $RegPath = Mount-OfflineWindowsRegistry -Path "$Root\Windows" -Hive SOFTWARE
            $RegPath = $RegPath + "\Microsoft\Windows NT\CurrentVersion"
        }


        if ($PSVersionTable.PSVersion.Major -lt 5) {
            return (Get-ItemProperty $RegPath 'ProductName' -ErrorAction:SilentlyContinue).ProductName
        } else {
            return Get-ItemPropertyValue $RegPath -Name ProductName
        }
   }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
 
 
.DESCRIPTION
Long description
 
.PARAMETER Online
Parameter description
 
.PARAMETER Path
Parameter description
 
.EXAMPLE
An example
 
.NOTES
General notes
#>

function Get-OSArch {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root
    )
   Begin {
        Write-EnterFunction
    }

    Process {
        if ($Online) {
            switch ($env:PROCESSOR_ARCHITECTURE) {
                "x86" {
                    $arch = "x86"
                }
                "AMD64" {
                    $arch = "x64"
                }
            }
        } else {
            $RegPath = Mount-OfflineWindowsRegistry -Path "$Root\Windows" -Hive SOFTWARE
            $RegPath = $RegPath + "\Microsoft\Windows NT\CurrentVersion"
            if ($PSVersionTable.PSVersion.Major -lt 5) {
                $buildLabEX = (Get-ItemProperty $RegPath 'BuildLabEX' -ErrorAction:SilentlyContinue).BuildLabEX
            } else {
                $buildLabEX = Get-ItemPropertyValue $RegPath -Name BuildLabEX
            }
            if ($buildLabEX -match "x86fre") { $arch = "x64"}
            if ($buildLabEX -match "amd64fre") { $arch = "x64"}
        }

        return $arch
    }

    End {
        Write-LeaveFunction
    }
}

# function Get-WindowsShortName {
# [CmdletBinding()]Param (
# [string]$Distrib = "",
# [string]$Edition = "",
# [string]$ReleaseId = ""
# )
# Begin {
         Write-EnterFunction
# }

# Process {
# return ($Distrib + "." + $ReleaseId).replace(' ','')
# }

# End {
         Write-LeaveFunction
# }
# }

function Get-OSIdentity {
    [CmdletBinding()][OutputType([Object])][OutputType([Hashtable])]Param (
        [Parameter(ParameterSetName = 'ONLINE')][switch]$Online,
        [Parameter(ParameterSetName = 'ROOT')][string]$Root,
        [Alias('Version')][Parameter(ParameterSetName = 'OBJECT', ValueFromPipelineByPropertyName = $true)][string]$CurrentVersion,
        [Alias('installType')][Parameter(ParameterSetName = 'OBJECT', ValueFromPipelineByPropertyName = $true)][string]$InstallationType,
        [Alias('buildNumber', 'kernelVersion')][Parameter(ParameterSetName = 'OBJECT', ValueFromPipelineByPropertyName = $true)][string]$CurrentBuild,
        [AllowNull()][AllowEmptyString()][Parameter(ParameterSetName = 'OBJECT', ValueFromPipelineByPropertyName = $true)][string]$ReleaseId
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        switch ($PSCmdlet.ParameterSetName) {
            'ONLINE' {
                $CurrentVersion = OS.WinNT\Get-OSVersion -Online
                $InstallationType = OS.WinNT\Get-OSInstalltype -Online
                $CurrentBuild = OS.WinNT\Get-OSKernelVersion -Online
                $ReleaseId = OS.WinNT\Get-OSReleaseID -Online
                break
            }
            'ROOT' {
                $CurrentVersion = OS.WinNT\Get-OSVersion -Root $Root
                $InstallationType = OS.WinNT\Get-OSInstalltype -Root $Root
                $CurrentBuild = OS.WinNT\Get-OSKernelVersion -Root $Root
                $ReleaseId = OS.WinNT\Get-OSReleaseID -Root $Root
                break
            }
        }
        # edevel("CurrentVersion = $CurrentVersion")
        # edevel("InstallationType = $InstallationType")
        # edevel("CurrentBuild = $CurrentBuild")
        # edevel("ReleaseId = $ReleaseId")

        $obj = @{}
        $obj.codename = $null
        $obj.distrib = $null
        $obj.family = $null
        $obj.longCodeName = $null
        $obj.releaseId = $null
        $obj.servicePack = $null
        # generic values :
        switch -wildcard ($InstallationType) {
            "WindowsPE" {
                $obj.family = $InstallationType
                $obj.distrib = "WinPE"
            }
            "Server*" {
                $obj.family = $InstallationType
                $obj.distrib = "Windows Server"
            }
            "Client" {
                $obj.family = "Desktop"
                $obj.distrib = "Windows"
            }
        }
        switch ($CurrentVersion) {
            "5.0" {
                # $obj.family = "Windows2000"
                # $obj.distrib = "Windows 2000"
                switch -wildcard ($InstallationType) {
                    "WindowsPE" {
                        $obj.releaseId = "0.0"
                        $obj.codename = $("WinPE " + $obj.releaseId)
                        $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                    }
                    "Client" {
                        $obj.releaseId = "2000"
                        $obj.codename = $("Windows " + $obj.releaseId)
                        $obj.longCodename = $("Windows " + $obj.releaseId)
                    }
                    "Server*" {
                        $obj.releaseId = "2000"
                        $obj.codename = $("Windows " + $obj.releaseId + " Server")
                        $obj.longCodename = $("Windows " + $obj.releaseId + " Server")
                    }
                }
            }
            "5.1" {
                # $obj.family = "WindowsXP"
                # $obj.distrib = "Windows XP"
                switch -wildcard ($InstallationType) {
                    "WindowsPE" {
                        $obj.releaseId = "1.0"
                        $obj.codename = $("WinPE " + $obj.releaseId)
                        $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                    }
                    "Client" {
                        $obj.releaseId = "XP"
                        $obj.codename = $("Windows " + $obj.releaseId)
                        $obj.longCodename = $("Windows " + $obj.releaseId)
                    }
                    "Server*" {
                        $obj.releaseId = "2003"
                        $obj.codename = $("Windows Server " + $obj.releaseId)
                        $obj.longCodename = $("Windows Server " + $obj.releaseId)
                    }
                }
            }
            "5.2" {
                # $obj.family = "WindowsXP"
                # $obj.distrib = "Windows XP"
                switch -wildcard ($InstallationType) {
                    "WindowsPE" {
                        $obj.releaseId = "1.2"
                        $obj.codename = $("WinPE " + $obj.releaseId)
                        $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                    }
                    "Client" {
                        $obj.releaseId = "XP64"
                        $obj.codename = $("Windows " + $obj.releaseId)
                        $obj.longCodename = $("Windows " + $obj.releaseId)
                    }
                    "Server*" {
                        $obj.releaseId = "2003"
                        $obj.codename = $("Windows Server " + $obj.releaseId)
                        $obj.longCodename = $("Windows Server " + $obj.releaseId)
                    }
                }
            }
            "6.0" {
                # $obj.family = "WindowsVista"
                # $obj.distrib = "Windows Vista"
                switch ($CurrentBuild) {
                    "6000" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.releaseId = "2.0"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.releaseId = "Vista"
                                $obj.codename = $("Windows " + $obj.releaseId)
                                $obj.longCodename = $("Windows " + $obj.releaseId)
                            }
                            "Server*" {
                                $obj.releaseId = "2008"
                                $obj.codename = $("Windows Server " + $obj.releaseId)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId)
                            }
                        }
                        break
                    }
                    "6001" {
                        $obj.servicePack = "SP1"
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.releaseId = "2.1"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.releaseId = "Vista"
                                $obj.codename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                            }
                            "Server*" {
                                $obj.releaseId = "2008"
                                $obj.codename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                            }
                        }
                        break
                    }
                    "6002" {
                        $obj.servicePack = "SP2"
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.releaseId = "2.2"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.releaseId = "Vista"
                                $obj.codename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                            }
                            "Server*" {
                                $obj.releaseId = "2008"
                                $obj.codename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                            }
                        }
                        break
                    }
                }
            }
            "6.1" {
                # $obj.family = "Windows7"
                # $obj.distrib = "Windows 7"
                switch ($CurrentBuild) {
                    "7600" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.releaseId = "3.0"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.releaseId = "7"
                                $obj.codename = $("Windows " + $obj.releaseId)
                                $obj.longCodename = $("Windows " + $obj.releaseId)
                            }
                            "Server*" {
                                $obj.releaseId = "2008r2"
                                $obj.codename = $("Windows Server " + $obj.releaseId)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId)
                            }
                        }
                        break
                    }
                    "7601" {
                        $obj.servicePack = "SP1"
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.releaseId = "3.1"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.releaseId = "7"
                                $obj.codename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                            }
                            "Server*" {
                                $obj.releaseId = "2008r2"
                                $obj.codename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                            }
                        }
                        break
                    }
                }
            }
            "6.2" {
                # $obj.family = "Windows8"
                # $obj.distrib = "Windows 8"
                switch ($CurrentBuild) {
                    "9200" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.releaseId = "4.0"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.releaseId = "8"
                                $obj.codename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                            }
                            "Server*" {
                                $obj.releaseId = "2012"
                                $obj.codename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                            }
                        }
                        break
                    }
                }
            }
            "6.3" {
                # $obj.family = "Windows8.1"
                # $obj.distrib = "Windows 8.1"
                switch ($CurrentBuild) {
                    # * Windows 8
                    "9300" {
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.releaseId = "5.0"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.releaseId = "8.1"
                                $obj.codename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                            }
                            "Server*" {
                                $obj.releaseId = "2012r2"
                                $obj.codename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                            }
                        }
                        break
                    }
                    # * Windows 8.1
                    "9600" {
                        $obj.servicePack = "Update 1"
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.releaseId = "5.1"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.releaseId = "8.1"
                                $obj.codename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows " + $obj.releaseId + " " + $obj.servicePack)
                            }
                            "Server*" {
                                $obj.releaseId = "2012r2"
                                $obj.codename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId + " " + $obj.servicePack)
                            }
                        }
                        break
                    }
                    # * Windows 10
                    # "10240", etc...
                    { $_ -gt 10000 } {
                        $obj.releaseId = $ReleaseId
                        switch -wildcard ($InstallationType) {
                            "WindowsPE" {
                                $obj.distrib = "WinPE 10"
                                $obj.codename = $("WinPE " + $obj.releaseId)
                                $obj.longCodename = $("WindowsPE " + $obj.releaseId)
                            }
                            "Client" {
                                $obj.distrib = "Windows 10"
                                $obj.codename = OS.Windows\Get-Windows10CodeName -ReleaseId $obj.releaseId
                                $obj.longCodename = $("Windows " + $obj.codename)
                            }
                            "Server*" {
                                switch ($ReleaseId) {
                                    '1607' {
                                        $obj.releaseId = "2016"
                                    }
                                    '1809' {
                                        $obj.releaseId = "2019"
                                    }
                                }
                                $obj.distrib = "Windows Server"
                                $obj.codename = $("Windows Server " + $obj.releaseId)
                                $obj.longCodename = $("Windows Server " + $obj.releaseId)
                            }
                        }
                        break
                    }
                }
            }
        }
        # edevel($obj | ConvertTo-Json)

        return $obj
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSFiles {
    [CmdletBinding()][OutputType([Hashtable])]Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $Root = $Root.Trim('\')
        $wkFiles = @{}
        if (FileExist ("$Root\Windows\System32\ntoskrnl.exe")) {
            $wkFiles.Add('kernel', "$Root\Windows\System32\ntoskrnl.exe")
        }
        return ($wkFiles | Sort-HashTable)
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSFolders {
    [CmdletBinding()][OutputType([Hashtable])]Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        $Root = $Root.Trim('\')
        $wkFolders = @{}
        if (DirExist ("$Root\ProgramData")) {
            $wkFolders.Add('etc', "$Root\ProgramData")
            $wkFolders.Add('var', "$Root\ProgramData")
            $wkFolders.Add('ProgramData', "$Root\ProgramData")
        }
        if (DirExist ("$Root\Program Files")) {
            $wkFolders.Add('bin', "$Root\Program Files")
            $wkFolders.Add('bin-x86', "$Root\Program Files")
            $wkFolders.Add('bin-x64', "$Root\Program Files")
            $wkFolders.Add('ProgramFiles', "$Root\Program Files")
            $wkFolders.Add('ProgramFiles-x86', "$Root\Program Files")
            $wkFolders.Add('ProgramFiles-x64', "$Root\Program Files")
        }
        if (DirExist ("$Root\Program Files (x86)")) {
            $wkFolders.'bin-x86' = "$Root\Program Files (x86)"
            $wkFolders.'ProgramFiles-x86' = "$Root\Program Files (x86)"
        }
        if (DirExist ("$Root\Windows\System32")) {
            $wkFolders.Add('sbin', "$Root\Windows\System32")
            $wkFolders.Add('sbin-x64', "$Root\Windows\System32")
            $wkFolders.Add('System-x86', "$Root\Windows\System32")
            $wkFolders.Add('System-x64', "$Root\Windows\System32")
        }
        if (DirExist ("$Root\Windows\SysWOW64")) {
            $wkFolders.'sbin-x86' = "$Root\Windows\SysWOW64"
            $wkFolders.'System-x86' = "$Root\Windows\SysWOW64"
        }
        if (DirExist ("$Root\Windows\Logs")) {
            $wkFolders.Add('log', "$Root\Windows\Logs")
        }
        return ($wkFolders | Sort-HashTable)
    }

    End {
        Write-LeaveFunction
    }
}

function Get-OSDisplayVersion {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Online) {
            $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
        } else {
            $RegPath = Mount-OfflineWindowsRegistry -Path "$Root\Windows" -Hive SOFTWARE
            $RegPath = $RegPath + "\Microsoft\Windows NT\CurrentVersion"
        }


        if ($PSVersionTable.PSVersion.Major -lt 5) {
            return (Get-ItemProperty $RegPath 'DisplayVersion' -ErrorAction:SilentlyContinue).DisplayVersion
        } else {
            return Get-ItemPropertyValue $RegPath -Name DisplayVersion
        }
   }

    End {
        Write-LeaveFunction
    }
}

function Get-OSSystemRoot {
    [CmdletBinding()][OutputType([String])]Param (
        [switch]$Online,
        [string]$Root
    )
    Begin {
        Write-EnterFunction
    }

    Process {
        if ($Online) {
            $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
        } else {
            $RegPath = Mount-OfflineWindowsRegistry -Path "$Root\Windows" -Hive SOFTWARE
            $RegPath = $RegPath + "\Microsoft\Windows NT\CurrentVersion"
        }


        if ($PSVersionTable.PSVersion.Major -lt 5) {
            return (Get-ItemProperty $RegPath 'SystemRoot' -ErrorAction:SilentlyContinue).SystemRoot
        } else {
            return Get-ItemPropertyValue $RegPath -Name SystemRoot
        }
   }

    End {
        Write-LeaveFunction
    }
}

function Get-OSPackages {
    [CmdletBinding()][OutputType([Hashtable])]Param (
        [switch]$Online,
        [string]$Root = "/"
    )
    Begin {
        Write-EnterFunction
        $regPath = @(
            "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\",
            "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"
        )
    }

    Process {
        if ($Online) { $Root = '' }
        $hPackages = @{}
        $rawPackages = @()
        foreach ($reg in $regPath) {
            $rawPackages += Get-ChildItem $reg -ErrorAction SilentlyContinue
        }
        foreach ($raw in $rawPackages) {
            $package = @{}
            $key = $raw.PSChildName
            if ([System.Guid]::TryParse($key, [System.Management.Automation.PSReference][System.Guid]::empty)) {
                $package.guid = $key
            }
            $raw.property | ForEach-Object {
                switch -wildcard ($_) {
                    # try to handle fancy version numbers
                    "*Version*" {
                        $package.$_ = [system.version]($raw.$k | ConvertTo-VersionNumber)
                    }
                    default {
                        $package.$_ = Get-ItemPropertyValue $raw.PSPath -Name $_
                    }
                }
            }
            $package.regPath = $raw.PSPath
            $package.Path = $raw.PSPath
            # try to get consistent data across platforms
            $package.Name = $package.DisplayName -replace "\(.*\)$", "" -replace "[ _()-.\d]*$", ""
            if (![string]::IsNullOrEmpty($package.DisplayName)) {
                $hPackages.Add($key, $package)
            }
        }
        return ($hPackages | Sort-HashTable)
    # return $hPackages
    }

    End {
        Write-LeaveFunction
    }
}