
Identify .NET and Visual C++ Dependencies Using PowerShell
Have you ever found yourself patching software vulnerabilities and come across a vulnerability for older .NET or Visual C++ packages but didn’t know if removing the packages would cause issues with random software? If so, you came to the right place. Here I will go over how to Identify .NET and Visual C++ Dependencies Using PowerShell
I was recently patching some clients’ machines and kept seeing Visual C++ from 2008, 2010, and 2011, which of course I wanted to promptly remove. However, after some further research, I discovered that these old Visual C++ versions were actually dependencies for some proprietary software my client was using. Of course, this isn’t the place to discuss why my clients are still using almost decade-old software — Trust me, it irritates me too.
While working on this, I needed a way to tell which software relies on which versions of .NET and Visual C++, so I developed my own PowerShell script to accomplish just that. Of course, I could achieve the same results in almost any other language, but since my clients use Windows and our RMM agent utilizes PowerShell, it seemed appropriate.
I designed the script to scan the entire system and output a CSV file with the relevant data, making it easier to identify which versions of .NET and Visual C++ are necessary for which applications. This method ensures that we don’t accidentally remove a critical dependency and cause unforeseen issues.
The PowerShell Script
Here’s the PowerShell script I created to scan the computer for installed .NET (host and runtime), Visual C++ Redistributable, and ASP.NET versions, and determine which software requires which versions:
#
# Program Name: .NET and Visual C++ Determinier
#
# Description: This will look through all installed applications and tell you which app requires which version of .NET and Visual C++.
# Output will be displayed through the terminal and written to a CSV file ("C:\ProgramDependencies.csv")
#
# Author: Quynn Bell
#
# Date Modified: 23rd of May 2024
#
# Function to get installed programs
function Get-InstalledPrograms {
$programs = Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
Select-Object DisplayName, DisplayVersion, InstallDate, Publisher, InstallLocation
$programs += Get-ItemProperty "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
Select-Object DisplayName, DisplayVersion, InstallDate, Publisher, InstallLocation
$programs | Where-Object { $_.DisplayName } | Sort-Object DisplayName
}
# Function to search for dependencies in program files
function Get-ProgramDependencies {
param(
[string]$installLocation,
[string[]]$patterns
)
$dependencies = @()
foreach ($pattern in $patterns) {
$dependencies += Get-ChildItem -Path $installLocation -Recurse -Filter $pattern -ErrorAction SilentlyContinue
}
$dependencies
}
# Function to get installed .NET versions
function Get-DotNetVersion {
param(
[string]$filePath
)
try {
$versionInfo = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($filePath)
return $versionInfo.ProductVersion
} catch {
return $null
}
}
# Get installed programs
$installedPrograms = Get-InstalledPrograms
# Define patterns for common .NET and Visual C++ dependencies
$dotNetPatterns = @("System.*.dll", "mscorlib.dll")
$vcppPatterns = @("msvcp*.dll", "msvcr*.dll", "vccorlib*.dll", "vcomp*.dll", "vcruntime*.dll")
# Collect dependency information
$dependencyInfo = @()
foreach ($program in $installedPrograms) {
if ($program.InstallLocation) {
# Check for .NET dependencies
$dotNetDependencies = Get-ProgramDependencies -installLocation $program.InstallLocation -patterns $dotNetPatterns
foreach ($dependency in $dotNetDependencies) {
$dotNetVersion = Get-DotNetVersion -filePath $dependency.FullName
if ($dotNetVersion) {
$dependencyInfo += [PSCustomObject]@{
Program = $program.DisplayName
Version = $program.DisplayVersion
Dependency = $dependency.Name
DependencyType = "DotNet"
DependencyVersion = $dotNetVersion
}
}
}
# Check for Visual C++ dependencies
$vcppDependencies = Get-ProgramDependencies -installLocation $program.InstallLocation -patterns $vcppPatterns
foreach ($dependency in $vcppDependencies) {
$vcppVersion = Get-DotNetVersion -filePath $dependency.FullName # Using same function to get version
if ($vcppVersion) {
$dependencyInfo += [PSCustomObject]@{
Program = $program.DisplayName
Version = $program.DisplayVersion
Dependency = $dependency.Name
DependencyType = "VisualCpp"
DependencyVersion = $vcppVersion
}
}
}
}
}
# Output the dependency information
$dependencyInfo | Format-Table -AutoSize
# Save to a CSV file for easier visualization
$outputPath = "C:\ProgramDependencies.csv"
$dependencyInfo | Export-Csv -Path $outputPath -NoTypeInformation
Write-Output "Dependency information saved to $outputPath"
How the Script Works
- Get-InstalledPrograms: This function retrieves all installed programs from the registry.
- Get-ProgramDependencies: This function searches the installation directories of programs for specific patterns indicating .NET or Visual C++ dependencies.
- Get-DotNetVersion: This function retrieves the version information of a given file, used to identify the .NET version.
- Search Patterns: The script checks for .NET and Visual C++ dependencies by looking for common DLL names and retrieves their version information.
- Output: The script outputs the dependency information in a table format and saves it to a CSV file on the root of the C: drive for easy access.
Conclusion
This script provides a practical solution for IT professionals who need to manage software dependencies on Windows machines. By identifying which versions of .NET and Visual C++ are required by installed applications, you can make informed decisions about patching or removing old versions without causing disruptions. This approach has saved me countless hours and headaches, and I hope it does the same for you.
If you have any questions or need further assistance, feel free to leave a comment below or reach out directly. Happy patching!
Leave a Reply
You must be logged in to post a comment.