Skip to content

Instantly share code, notes, and snippets.

@mklement0
Last active September 25, 2018 04:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mklement0/e4d480fe0fbad0c7cc85a8670ac04be7 to your computer and use it in GitHub Desktop.
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.
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