Category filter
How to Check the .NET Versions Installed on Windows with Custom Scripts?
TL;DR
This guide provides ready-to-deploy PowerShell and Batch scripts to check the .NET versions installed on Windows, covering legacy 3.5, Framework 4.x, and modern .NET runtimes, remotely via Hexnode UEM. It outlines deployment procedures, runtime detection architecture, and troubleshooting steps to verify endpoint readiness before rolling out a new enterprise application.
Executive Summary
Auditing the .NET versions installed on Windows prevents launch failures, verifies software compatibility, and detects end-of-life (EOL) runtimes before rolling out new enterprise applications. However, devices frequently run multiple .NET versions side by side. Because each version family stores installation metadata in different locations, such as standalone registry keys and local filesystem paths, manually tracking them across an enterprise fleet is impractical.
Deployed through Hexnode UEM’s Execute Custom Script feature, the PowerShell and Batch scripts in this guide automate audit runtimes under the local NT AUTHORITY\SYSTEM context. They inspect native 64-bit registry keys, detect installed dotnet.exe runtimes, and returns a unified report straight back to the Hexnode UEM console without requiring external tools or user prompts.
Use Cases and Implementation Scenarios
- Validating Environmental Dependencies for Applications: Verify that target endpoints have the required .NET runtime versions installed before pushing enterprise applications that rely on them.
- Security and Compliance Auditing: Identify devices running older, unsupported .NET versions that require security patching or upgrades to comply with organizational security baselines.
- OS Upgrade Readiness Assessments: Audit endpoints prior to major Windows OS migrations to record installed .NET versions, making it easy to identify and restore runtime dependencies required by critical applications post-upgrade.
- Helpdesk Troubleshooting: Remotely inspect runtime versions from the Hexnode UEM console when troubleshooting third-party software installation failures or runtime crashes reported by end users.
Prerequisites for Executing the Scripts
To ensure the successful deployment of these .NET audit scripts, the target Windows endpoints must meet the following requirements.
- Supported OS: Windows 10/11 (Home, Pro, Enterprise, Education) and Windows Server (2016, 2019, 2022, and 2025).
- Architecture Support: Compatible with x64, x86, and ARM64 system architectures.
- Management: Hexnode UEM agent must be installed and initialized.
PowerShell Script to Check Installed .NET Versions
This PowerShell script inspects Windows registry keys to map the active .NET Framework 4.x Release key to its corresponding release version, audits legacy .NET 3.5 version, and executes dotnet.exe to retrieve all modern .NET Core / 5+ runtimes.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
<# .SYNOPSIS Audits installed .NET Framework, legacy .NET, and modern .NET runtimes on Windows endpoints. #> try { # Header Write-Host ("{0,-38} {1}" -f "TYPE", "VERSION") Write-Host ("{0,-38} {1}" -f "--------------------------------------", "----------------") # 1. Classic .NET Framework 4.x (Native 64-bit Registry) $regKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey( [Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64 ).OpenSubKey("SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full") if ($null -ne $regKey) { $val = [int]$regKey.GetValue("Release", 0) $regKey.Close() if ($val -gt 0) { $ver = "4.x ($val)" if ($val -ge 533320) { $ver = "4.8.1" } elseif ($val -ge 528040) { $ver = "4.8" } elseif ($val -ge 461808) { $ver = "4.7.2" } elseif ($val -ge 461308) { $ver = "4.7.1" } elseif ($val -ge 460798) { $ver = "4.7" } elseif ($val -ge 394802) { $ver = "4.6.2" } elseif ($val -ge 394254) { $ver = "4.6.1" } elseif ($val -ge 393295) { $ver = "4.6" } elseif ($val -ge 379893) { $ver = "4.5.2" } Write-Host ("{0,-38} {1}" -f ".NET Framework", $ver) } } # 2. Legacy .NET Framework (3.5) $legKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey( [Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64 ).OpenSubKey("SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5") if ($null -ne $legKey) { $legVal = [string]$legKey.GetValue("Version", "") $legKey.Close() if ($legVal) { Write-Host ("{0,-38} {1}" -f ".NET Framework (Legacy)", $legVal) } } # 3. Modern .NET Core / 5+ Runtimes (Dynamic Multi-Path) $candidatePaths = @( "$env:ProgramFiles\dotnet\dotnet.exe", "$env:ProgramW6432\dotnet\dotnet.exe", "${env:ProgramFiles(x86)}\dotnet\dotnet.exe" ) $resolvedDotnet = $null foreach ($p in $candidatePaths) { if (Test-Path $p) { $resolvedDotnet = $p break } } if (-not $resolvedDotnet) { $cmdCheck = Get-Command dotnet.exe -ErrorAction SilentlyContinue if ($cmdCheck) { $resolvedDotnet = $cmdCheck.Source } } if ($resolvedDotnet) { $runtimes = & $resolvedDotnet --list-runtimes 2>$null if ($runtimes) { foreach ($r in $runtimes) { $parts = -split $r if ($parts.Count -ge 2) { Write-Host ("{0,-38} {1}" -f $parts[0], $parts[1]) } } } else { Write-Host ("{0,-38} {1}" -f "Modern .NET (dotnet.exe)", "No Runtimes") } } else { Write-Host ("{0,-38} {1}" -f "Modern .NET (dotnet.exe)", "Not Detected") } exit 0 } catch { Write-Error "Script execution failed: $($_.Exception.Message)" exit 1 } |

Batch Script to Check Installed .NET Versions
This Batch script uses native reg query commands to extract the active .NET Framework 4.x Release DWORD, converts hexadecimal value to decimal to map the release version, checks for legacy .NET 3.5 version, and executes dotnet.exe to list modern runtimes.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
@echo off setlocal enabledelayedexpansion :: ============================================================================== :: Batch: .NET Version Audit :: ============================================================================== echo TYPE VERSION echo -------------------------------------- ---------------- set "AUDIT_FOUND=0" :: 1. Active .NET Framework 4.x (Native 64-bit Registry) for /f "tokens=3" %%a in ('reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v Release /reg:64 2^>nul ^| findstr /i "Release"') do ( set /a relDec=%%a set "fwVer=4.x (!relDec!)" if !relDec! geq 533320 set "fwVer=4.8.1" if !relDec! geq 528040 if !relDec! lss 533320 set "fwVer=4.8" if !relDec! geq 461808 if !relDec! lss 528040 set "fwVer=4.7.2" if !relDec! geq 461308 if !relDec! lss 461808 set "fwVer=4.7.1" if !relDec! geq 460798 if !relDec! lss 461308 set "fwVer=4.7" if !relDec! geq 394802 if !relDec! lss 460798 set "fwVer=4.6.2" if !relDec! geq 394254 if !relDec! lss 394802 set "fwVer=4.6.1" if !relDec! geq 393295 if !relDec! lss 394254 set "fwVer=4.6" if !relDec! geq 379893 if !relDec! lss 393295 set "fwVer=4.5.2" set "pad=.NET Framework " echo !pad:~0,38! !fwVer! set "AUDIT_FOUND=1" ) :: 2. Legacy .NET Framework (3.5) for /f "tokens=3" %%a in ('reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" /v Version /reg:64 2^>nul ^| findstr /i "Version"') do ( set "padLeg=.NET Framework (Legacy) " echo !padLeg:~0,38! %%a set "AUDIT_FOUND=1" ) :: 3. Modern .NET Core / 5+ Runtimes (Multi-Path Detection) set "DOTNET_BIN=" if exist "%ProgramFiles%\dotnet\dotnet.exe" set "DOTNET_BIN=%ProgramFiles%\dotnet\dotnet.exe" if not defined DOTNET_BIN if exist "%ProgramW6432%\dotnet\dotnet.exe" set "DOTNET_BIN=%ProgramW6432%\dotnet\dotnet.exe" if not defined DOTNET_BIN if exist "%ProgramFiles(x86)%\dotnet\dotnet.exe" set "DOTNET_BIN=%ProgramFiles(x86)%\dotnet\dotnet.exe" if defined DOTNET_BIN ( set "HAS_RUNTIMES=0" for /f "tokens=1,2" %%a in ('"%DOTNET_BIN%" --list-runtimes 2^>nul') do ( set "HAS_RUNTIMES=1" set "padMod=%%a " echo !padMod:~0,38! %%b ) if !HAS_RUNTIMES! equ 0 ( set "padNone=Modern .NET (dotnet.exe) " echo !padNone:~0,38! No Runtimes ) set "AUDIT_FOUND=1" ) else ( set "padMiss=Modern .NET (dotnet.exe) " echo !padMiss:~0,38! Not Detected ) :: Exit with failure only if no audit checks could be read at all if !AUDIT_FOUND! equ 0 ( echo Error: Failed to query registry or detect runtime environments. >&2 exit /b 1 ) exit /b 0 |

How to Deploy the Script via Hexnode UEM?
- Save either the PowerShell script (as a .ps1 file) or the Batch script (as a .bat file) on your computer, depending on which script you intend to deploy.
- Log in to your Hexnode UEM portal.
- Navigate to Manage > Endpoints and select the target Windows device(s).
- Click Actions > Deployments > Execute Custom Script.
- Upload the saved script file and click Execute.
How to Verify Script Output in Hexnode UEM?
To check the execution status and view the script output:
- Navigate to Manage > Endpoints and select the target endpoint in the Hexnode UEM portal.
- Click the Action History tab to view the log of actions dispatched to the endpoint.
- Locate the Execute Custom Script entry in the action list.
- If Status is “Success”: Click the Show Output button to inspect the formatted table displaying active .NET Framework releases, legacy .NET 3.5, and modern .NET runtimes.
- If Status is “Failed”: Hover over the information icon (i) next to the status badge to review the execution error message and script error output.
- If Status is “Pending/In progress”: The target endpoint is powered off, disconnected from the network, or sleeping. The script action remains queued in Hexnode UEM and will execute automatically when the device next checks in.
Key Technical Insights and Architecture Notes
- .NET Framework 4.x Latest Version Reporting: .NET Framework 4.x updates install as in-place replacements. Because Windows stores .NET 4.x metadata in a single registry value that gets overwritten with every update, older 4.x entries no longer exist on the system. The script therefore reads and reports only the single active, highest version installed (such as 4.8.1).
- Side-by-Side Modern Runtimes: Unlike .NET Framework, modern .NET (.NET Core and .NET 5+) versions run side-by-side in distinct installation folders. The script lists every installed major, minor, and patch release, as well as distinct workload packages (Microsoft.NETCore.App, Microsoft.WindowsDesktop.App, and Microsoft.AspNetCore.App) individually. Note that these scripts report globally installed shared runtimes and excludes private, self-contained application bundles.
- Explicit Verification for Missing Runtimes: If modern .NET is not deployed on an endpoint, the script does not skip the validation or fail silently. It explicitly reports Modern .NET (dotnet.exe) Not Detected (or No Runtimes), providing administrators with affirmative confirmation that the check was performed.
- Modern .NET Detection Across ARM64 Endpoints: On ARM64 devices (such as Microsoft Surface Pro X or Snapdragon X Elite endpoints), modern .NET can exist as a native ARM64 runtime or under an x64/x86 emulation directory. The scripts dynamically prioritize native 64-bit paths before checking architectural fallback locations, ensuring that installed runtimes are accurately reported without being misidentified by emulation layers.
Troubleshooting Common Issues
| Issue | Probable Cause | Solution |
|---|---|---|
| Action History status shows “Pending” indefinitely. | The target device is offline, powered off, or unable to reach the Hexnode UEM server. | Ensure that the endpoint is connected to an active network. The action will be executed automatically once the device checks back in with Hexnode UEM. |
| Modern .NET packages appear in Installed Apps on the endpoint, but script output shows “Not Detected”. | The installed runtime is inaccessible to the 64-bit SYSTEM audit context. This typically occurs under two conditions:
|
|
| Script output displays only legacy .NET (missing .NET 4.x). | The registry key HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full is missing or corrupted on the target endpoint. The script runs successfully but cleanly skips .NET 4.x detection because the key cannot be read. | On modern Windows operating systems, .NET Framework 4.x is an integrated OS component maintained by the Windows Component-Based Servicing (CBS) engine. Resolve the corruption by performing the following remediation workflow:
|
Frequently Asked Questions
What is the difference between .NET Framework and .NET Core?
.NET Framework is a Windows-exclusive runtime where 4.x versions install as in-place upgrades. .NET Core (and modern .NET 5+) is cross-platform and supports side-by-side installations, allowing multiple runtime versions to coexist on the same system simultaneously.
Why does Hexnode execute custom scripts under the SYSTEM account?
Executing custom scripts under the local SYSTEM context guarantees elevated privileges across all managed endpoints, allowing scripts to read protected registry keys and execute administrative commands without prompting the end user or requiring an active user login session.
Can these scripts be deployed to 32-bit (x86) Windows devices?
Yes. The scripts automatically detect the operating system architecture and query the appropriate native registry and filesystem locations on both 32-bit (x86) and 64-bit (x64) Windows devices.
Will the script detect the installed .NET versions if an endpoint is running specialized workloads, such as ASP.NET Core or Windows Desktop runtimes?
The modern .NET runtime check identifies all official Microsoft runtime packages associated with the native dotnet.exe host. This includes Microsoft.NETCore.App (base runtime), Microsoft.WindowsDesktop.App (WPF/Windows Forms desktop apps), and Microsoft.AspNetCore.App (web hosting components). Each detected package and its exact version string will appear on its own line in the script’s output.