Reputation: 11
I'm trying to find all applications that rely on outdated.NET Framework versions. For instance, on a client environment, they have .NET Framework version 1.0 enabled in their registry. This is from 2002 and is horribly vulnerable with multiple CVEs of 9.3, security-wise. Same for .NET Framework 2.0., possibly 3.0.
.NET is one of the most vulnerable applications via CISA, and this issue consistently pops up across multiple clients. I want to remove these outdated Framework versions, but I've read that applications built using those older versions may not be able to switch to newer versions, so it could break very important applications that are needed to save lives and require 100% uptime.
I've tried tasklist /m "mscore*" as a cmd command to return applications currently being executed via the .dll engine. So it only returns running applications, and it also doesn't tell me which versions of .NET Framework are used on the running applications. There is also no mscorlib.dll version in either the 3.0 or 3.5 directories.
I can also do this simply with ProcMon, but I face the same issue: this will only tell me the active and running processes
I've tried using a C# script using ICorPublish interface, but this also just returns PIDs, so it also relies on the application running.
ICorPublishProcess process;
process = publish.GetProcess(PidToCheck);
if (process == null || !process.IsManaged)
{
return "Process managed by .NET"
}
else
{
return "Process not managed by .NET."
}
I can find all installed versions of .NET Framework easily enough via: https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
However, I can't find anything regarding how to find all applications--with running processes or not running--that have dependencies on specific .NET Framework versions.
Is there a way to find applications that aren't currently running that are reliant on older .NET Framework versions to function?
Upvotes: 1
Views: 701
Reputation: 437688
You can try the following brute-force approach - which will run for a long time, however:
Open an elevated PowerShell instance (run as admin), so as to get access to as many directories as possible.
Starting from the root of all drives of interest, search for all *.exe
files across the entire disk (depending on your needs you may have to examine *.dll
files too) and determine their target .NET CLR version using [System.Reflection.Assembly]::LoadFile($filePath).ImageRuntimeVersion
The following code demonstrates this:
# You can pass multiple root directories, if needed.
# If you need to include DLLs too, replace -Filter *.exe
# with -Include *.exe, *.dll
Get-ChildItem C:\ -Filter *.exe -Recurse -ErrorAction SilentlyContinue -ErrorVariable errs |
ForEach-Object {
try {
[pscustomobject] @{
Path = $_.FullName
CLRVersion = [System.Reflection.Assembly]::LoadFile($_.FullName).ImageRuntimeVersion
}
}
catch {}
} |
Format-List
Note:
The Format-List
command is solely for display formatting.
If instead you want to save the results in CSV format, for instance, pipe to Export-Csv
instead.
If you want to save the results to a variable ($results = ...
), simply omit | Format-List
.
If you want to limit output to specific versions, insert the following before | Format-List
:
To find those below a threshold, such as all CLR version lower than 4.0
| Where-Object { [version] $_.CLRVersion.Substring(1) -lt [version] '4.0' }
To find those for a specific version, such as v1.1:
| Where-Object { $_.CLRVersion -like 'v1.1.*' }
Variable $errs
will contain any errors that occurred during file enumeration.
Caveats:
The Assembly.ImageRuntimeVersion
is only supported in .NET Framework v1.1 and above - if you really still have applications for 1.0, you'll need a different approach (perhaps the answers to this question provide pointers).
The version number reported - e.g. v4.0.30319
- is that of the CLR (the runtime engine), not that of the framework (the class library; e.g., the 3.0 framework builds on the 2.0 CLR).
Assemblies created for the cross-platform .NET Core / .NET 5+ editions, apparently for backward compatibility, present as if they target .NET Framework's version 4.0 CLR (v4.0.30319
)
TargetFramework
attribute, as shown in this answer; said answer is written for .NET Framework, where it works for assemblies written for .NET Framework version 4.0 and above; to make it work with the cross-platform editions, method ReflectionOnlyLoadFrom
must be replaced with method LoadFile
.Upvotes: 1