Last active
September 25, 2018 04:33
-
-
Save mklement0/e4d480fe0fbad0c7cc85a8670ac04be7 to your computer and use it in GitHub Desktop.
PowerShell v6+ script for getting version information about a .NET Core installation in general or a specific .NET Core project.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-DotNetCoreVersion { | |
<# | |
.SYNOPSIS | |
Gets version information about a .NET Core installation or project. | |
.DESCRIPTION | |
Gets version information about the globally installed .NET Core components | |
or a specific project. | |
Note: Requires PSv6+, due to use of type | |
[System.Management.Automation.SemanticVersion]. | |
.PARAMETER LatestOnly | |
Multiple .NET Core versions can be installed side by side. | |
By default - unless a specific project is targeted - information about all | |
versions is output. | |
If you specify this switch, only the components with the highest version | |
numbers are reported. | |
.PARAMETER InformationType | |
Restricts output to one or more specific component types. | |
By default, information about all component types is output. | |
.PARAMETER ProjectPath | |
If specified, only outputs information about the .NET Core source-code project | |
at the specified location. | |
.EXAMPLE | |
> Get-DotNetCoreVersion | |
Outputs version information about all globally installed components. | |
.EXAMPLE | |
> Get-DotNetCoreVersion -ProjectPath /path/to/project | |
Outputs version information about what runtime the specified project | |
targets and what SDK version's tools to use to manage the project. | |
#> | |
[CmdletBinding(PositionalBinding=$false, DefaultParameterSetName='global')] | |
param( | |
[Parameter(ParameterSetName='global')] | |
[switch] $LatestOnly, | |
# Note: If you add / rename values here, change the code below accordingly. | |
# The order in which the values appear here determins the order of properties | |
# on the output object. | |
[Parameter(ParameterSetName='global')] | |
[ValidateSet('runtime', 'corefx', 'netstandard', 'sdk', 'host')] | |
[string[]] $InformationType, | |
[Parameter(Position=0, ParameterSetName='project', ValueFromPipeline,ValueFromPipelineByPropertyName='PSPath')] | |
[ValidateNotNullOrEmpty()] | |
[string] $ProjectPath | |
) | |
begin { | |
$ErrorActionPreference = 'Stop' | |
if ($PSVersionTable.PSVersion.Major -lt 6) { Throw "This function requires PowerShell v6 or higher."} | |
# Determine the CLI's true containing directory. | |
# Note that on Linux the CLI is symlinked to /usr/bin/, so we must resolve the symlink first. | |
$cliPath = Get-Item -LiteralPath (Get-Command -Type application 'dotnet').Path | |
$rootDirPath = Split-Path $(if ($cliPath.Target) { $cliPath.Target[-1] } else { $cliPath.FullName }) | |
$componentDirPaths = @{ | |
host = "$rootDirPath/host/fxr" | |
sdk = "$rootDirPath/sdk" | |
runtime = "$rootDirPath/shared/Microsoft.NETCore.App" # !! On Linux, case matters. | |
} | |
# Determine globally active host and SDK versions | |
$activeHostVersion = [System.Management.Automation.SemanticVersion] ((dotnet) -join ' ' -split '\A.*Version\s*:|Build.*\Z')[1] | |
# Note: Since the globally active SDK version can be overridden by a | |
# global.json file in the *current* folder, we switch to the .NET Core | |
# *root* folder temporarily to get the global value. | |
Push-Location $rootDirPath | |
$activeSdkVersion = [System.Management.Automation.SemanticVersion] (dotnet --version) | |
Pop-Location | |
} | |
process { | |
$htOut = [ordered] @{ InstallPath = $rootDirPath } | |
switch ($PSCmdlet.ParameterSetName) { | |
'global' { # Note: no pipeline input is processed by this branch | |
$allInfo = -not $InformationType | |
# Prepend the info about *globally active* versions | |
if ($allInfo -or 'sdk' -in $InformationType) { | |
$htOut.ActiveSDK = $activeSdkVersion | |
} | |
if ($allInfo -or 'host' -in $InformationType) { | |
$htOut.ActiveHost = $activeHostVersion | |
} | |
foreach($infoType in (Get-Variable InformationType).Attributes.ValidValues) { | |
if ($allInfo -or $infoType -in $InformationType) { | |
switch ($infoType) { | |
'host' { | |
# Get the version numbers of the installed components, sorted in -Descending | |
# order by (semantic) version number. | |
$htOut.Hosts = [System.Management.Automation.SemanticVersion[]] (Get-ChildItem -Directory $componentDirPaths['host']).Name | Sort-Object -Descending | |
if ($LatestOnly) { $htOut.Hosts = $htOut.Hosts[0] } | |
break | |
} | |
'runtime' { | |
$htOut.Runtimes = [System.Management.Automation.SemanticVersion[]] (Get-ChildItem -Directory $componentDirPaths['runtime']).Name | Sort-Object -Descending | |
if ($LatestOnly) { $htOut.Runtimes = $htOut.Runtimes[0] } | |
break | |
} | |
'sdk' { | |
# !! On Ubuntu as of SDK v1.0.1, the folder name is "@"-prefixed. Why? | |
$htOut.SDKs = [System.Management.Automation.SemanticVersion[]] ((Get-ChildItem -Directory $componentDirPaths['sdk']).Name -replace '@?(.*)', '$1') | Sort-Object -Descending | |
if ($LatestOnly) { $htOut.SDKs = $htOut.SDKs[0] } | |
break | |
} | |
{ $_ -in 'corefx', 'netstandard' } { | |
# From the "Microsoft.NETCore.App.deps.json" file in each runtime folder, | |
# extract the information about the CoreFX / NetStandard version numbers. | |
$keyOut = ('CoreFX', 'NetStandard')[$_ -ne 'CoreFX'] | |
$keyJson = ('microsoft.netcore.platforms', 'netstandard.library')[$infoType -ne 'CoreFX'] | |
$htOut.$keyOut = foreach ($rt in $htOut.Runtimes) { | |
$jsonFile = "$($componentDirPaths['runtime'])/$rt/Microsoft.NETCore.App.deps.json" | |
((ConvertFrom-Json (Get-Content -Raw -LiteralPath $jsonFile)).libraries | Get-Member "$keyJson/*").Name.Split('/')[1] | |
} | |
break | |
} | |
Default { | |
Throw "DESIGN ERROR: Unanticipated info type: $_" | |
} | |
} | |
} # if ($allInfo) | |
} # foreach | |
break | |
} # 'global' | |
'project' { | |
$projFile = Resolve-Path (Join-Path $ProjectPath *.csproj) | |
if (-not $?) { return } | |
if (-not $projFile) { Write-Error "No *.csproj file found in specified project path: $ProjectPath"; return } | |
# Extract the target framework version from the XML inside *.csproj | |
$xml = [xml] (Get-Content -Raw $projFile) | |
$htOut.ProjectTargetFramework = $xml.Project.PropertyGroup.TargetFramework | |
$htOut.ProjectRuntime = [System.Management.Automation.SemanticVersion] $xml.Project.PropertyGroup.RuntimeFrameworkVersion | |
# If there's a 'global.json' present, extract the | |
$configJsonFile = Join-Path $ProjectPath 'global.json' | |
$effectiveSdkVersion = $null | |
if (Test-Path $configJsonFile) { | |
if ($customSdkVersion = (ConvertFrom-Json (Get-Content -Raw $configJsonFile)).sdk.version) { | |
$effectiveSdkVersion = [System.Management.Automation.SemanticVersion] $customSdkVersion | |
} | |
} | |
$htOut.EffectiveSDK = if ($effectiveSdkVersion) { $effectiveSdkVersion } else { $activeSdkVersion } | |
$htOut.UsesActiveSDK = $null -eq $effectiveSdkVersion # -ne $activeSdkVersion | |
break | |
} | |
Default { Throw "DESIGN-TIME ERROR: Unanticipated parameter set name: $infoType" } | |
} | |
# Output the hashtable as a custom object. | |
[pscustomobject] $htOut | |
} # process | |
} | |
# If this script is invoked directly - as opposed to being dot-sourced in order | |
# to define the embedded function for later use - invoke the embedded function, | |
# relaying any arguments passed. | |
if (-not ($MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -eq '')) { | |
Get-DotNetCoreVersion @Args | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment