Skip to content

Instantly share code, notes, and snippets.

@VAllens
Last active June 13, 2024 01:12

Revisions

  1. VAllens renamed this gist Jun 7, 2024. 1 changed file with 0 additions and 0 deletions.
  2. VAllens created this gist Jun 7, 2024.
    157 changes: 157 additions & 0 deletions Get-Installed-.NET-Runtimes.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,157 @@
    1. Using terminal command

    ```bash
    dotnet --list-runtimes
    ```

    2. Using C#/CSharp code

    ```CSharp

    using CliWrap;
    using CliWrap.EventStream;
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using System.Threading;

    // License: Do whatever you want with this. This is what my project uses,
    // I make no guarantees it works or will work in the future
    // THIS IS ONLY FOR .NET CORE DETECTION (no .NET framework!)
    // Requires CliWrap https://github.com/Tyrrrz/CliWrap
    namespace DotnetHelper
    {
    /// <summary>
    /// Class that can determine if a version of .NET Core is installed
    /// </summary>
    public class DotNetRuntimeVersionDetector
    {
    /// <summary>
    /// This is very windows specific
    /// </summary>
    /// <returns>List of versions matching the specified version</returns>
    public static async IAsyncEnumerable<ProductInfo> GetInstalledRuntimesAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
    // No validation. Make sure exit code is checked in the calling process.
    Command cmd = Cli.Wrap("dotnet.exe").WithArguments("--list-runtimes").WithValidation(CommandResultValidation.None);
    await foreach(CommandEvent cmdEvent in cmd.ListenAsync(cancellationToken))
    {
    switch(cmdEvent)
    {
    case StartedCommandEvent started:
    break;
    case StandardOutputCommandEvent stdOut:
    if(string.IsNullOrWhiteSpace(stdOut.Text))
    {
    continue;
    }

    if(stdOut.Text.StartsWith("Microsoft.NETCore.App")
    || stdOut.Text.StartsWith("Microsoft.WindowsDesktop.App")
    || stdOut.Text.StartsWith("Microsoft.AspNetCore.App")
    || stdOut.Text.StartsWith("Microsoft.AspNetCore.All"))
    {
    yield return Parse(stdOut.Text);
    }
    break;
    case StandardErrorCommandEvent stdErr:
    break;
    case ExitedCommandEvent exited:
    break;
    }
    }
    }

    private static ProductInfo Parse(ReadOnlySpan<char> stdOutText)
    {
    int firstIndex = stdOutText.IndexOf(' ');
    string productName = stdOutText.Slice(0, firstIndex).ToString();
    ReadOnlySpan<char> subText = stdOutText.Slice(firstIndex + 1, stdOutText.Length - firstIndex - 2);
    int secondIndex = subText.IndexOf(' ');
    ReadOnlySpan<char> version = subText.Slice(0, secondIndex);
    ReadOnlySpan<char> path = subText.Slice(secondIndex + 2);
    return new ProductInfo(productName, Version.Parse(version), string.Concat(path, "\\", version));
    }

    private static Version ParseVersion(string stdOutText)
    {
    // 0 = SDK name, 1 = version, 2+ = path parts
    string[] split = stdOutText.Split(' ');
    return Version.Parse(split[1]);
    }
    }

    /// <summary>
    /// .NET Product information
    /// </summary>
    /// <param name="ProductName">Product name</param>
    /// <param name="Version">Product version</param>
    /// <param name="InstalledPath">Installed path</param>
    public record struct ProductInfo(string ProductName, Version Version, string InstalledPath);
    }
    ```

    3. Using PowerShell code

    ```PowerShell
    class ProductInfo {
    [string]$ProductName
    [System.Version]$Version
    [string]$InstalledPath
    ProductInfo()
    {
    }
    ProductInfo([string]$productName, [System.Version]$version, [string]$installedPath)
    {
    $this.ProductName = $productName
    $this.Version = $version
    $this.Args = $installedPath
    }
    }
    function Get-InstalledDotNetRuntimes
    {
    [OutputType([ProductInfo[]])]
    param ()
    # Execute `dotnet --list-runtimes` command.
    $runtimes = Invoke-Expression "dotnet --list-runtimes"
    # Create an empty array to store the Product informations.
    # $productInfos = New-Object System.Collections.Generic.List[ProductInfo]
    [ProductInfo[]]$productInfos = @()
    # Foreach line of output
    $runtimes -split "`n" | ForEach-Object {
    # Skip empty line
    if (![string]::IsNullOrWhiteSpace($_))
    {
    # Parse product name, version and installation path
    $parts = $_ -split " ", 3
    $productName = $parts[0]
    $version = [System.Version]::Parse($parts[1])
    $installedPath = $parts[2].TrimStart('[').TrimEnd(']') # 去掉前后的[]字符
    # Create a new ProductInfo object.
    $productInfo = New-Object ProductInfo -Property @{
    ProductName = $productName
    Version = $version
    InstalledPath = $installedPath
    }
    # Add the ProductInfo object to the array
    $productInfos += $productInfo
    }
    }
    # Output the ProductInfo list
    return $productInfos
    }
    # Execute function
    Get-InstalledDotNetRuntimes
    ```