how to check .net version installed on 500 workstations

Posted on 2014-10-24
Medium Priority
Last Modified: 2014-11-03
I work for a company with a lot of workstations and we currently use IBM BigFix to query worksations for their .Net framework version. My question is Is there another way to query workstations besides using BigFix or Tanium? All I want to do is check each workstation for .Net 4.0 and above and report all the names of the workstations that does not have .Net 4.0 or above.
Question by:matthew phung
  • 3
  • 2
  • 2
  • +2

Expert Comment

by:Wylie Bayes
ID: 40403166
What OS are the workstations?  Windows 7 or higher?
LVL 33

Expert Comment

by:Dave Howe
ID: 40403309
Its certainly possible, don't have any code on hand to do it though.  I can think of two ways immediately that you could achieve this.  The first is a bit crude (actually, a lot!) , but has the benefit of being easy to understand and very short indeed :)

Both answers rely on the fact that the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP has one subkey per installed framework - so reading that on each machine in turn would give you the info you need. Further, all dotnet frameworks from 4.0 onwards use a registry key of "v4" - so checking for HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4 would tell you have 4.0 *or better* without investigating further, which is probably good enough

Now, on to the crude method :)

Assuming you have your users logging into a domain, you can establish a network share on a server that is world writable, and have each user login script execute the relatively simple command:


(placing the share path in front of the computername variable so that it writes to the network)

as %COMPUTERNAME% contains the name of the computer (logically enough) that should give you a separate file for each workstation, containing the registry keys under the key indicated. Simply wait a few days, then you should have the info you need (although not really in a tidy list without further processing)

For a less crude method - there is a powershell module (formerly on the ms site, now on codeplex) that lets you query the registry of a remote machine.  You could logically write a powershell script to check the registry key above for a single named remote machine (passed as an argument) then you need to call that script once per machine, and record the result.

With 500 workstations though, iterating though the set (particularly if you aren't going to know what IP they might have or if they are turned on at any given moment) could be interesting.  You can also use WMI (although its more awkward to code for than a dedicated PS module) - both methods would have the benefit of outputting a tidy list.  Combining this with the first method, you could run (say) vbscript in the login script, extract the info you need locally, then write it to a database or similar on a server - but that's a fair bit of work to code up (of course, if you wanted to re-use the technique for other checks, then it might be worth investing time coding a solution so that you have an example to modify when you have something you want and can't get easily by any other method)

Expert Comment

by:Wylie Bayes
ID: 40403349
This can be easily achieved with powershell.  If the workstations are Windows 7 or higher.
Who's Defending Your Organization from Threats?

Protecting against advanced threats requires an IT dream team – a well-oiled machine of people and solutions working together to defend your organization. Download our resource kit today to learn more about the tools you need to build you IT Dream Team!


Author Comment

by:matthew phung
ID: 40403407
Thank you Dave for your detailed answer. I am not too familiar with PowerShell so is there a good tutorial/resource you guys recommend. I am very strong in C# and VB.Net. I appreciate your help, guys

Accepted Solution

Wylie Bayes earned 2000 total points
ID: 40403419
Gather Machine IP's via LDAP / Pulling from OU and machine objects:

<#          .SYNOPSIS
        AD Searcher unites with .Net DNS object to quickly provide IPs by organizations
            for asset list import to Nessus.
            Collects IP addresses for Active Directory computer objects by OU.
            Name: Get-PMOIPs
        Author: Steve Jarvi
        DateCreated: 9 April 2014
          FOR Changing Machine OUs: "LDAP://OU=SomeOU,OU=SomeOU,OU=SomeOU,OU=SomeOU,DC=SomeDC,DC=SomeDC,DC=SomeDC,DC=COM"

$searcher = New-Object System.DirectoryServices.DirectorySearcher $([ADSI] "LDAP://OU=SomeOU,OU=SomeOU,OU=SomeOU,OU=SomeOU,DC=SomeDC,DC=SomeDC,DC=SomeDC,DC=COM")
$searcher.pagesize = 1
$searcher.filter = ("(objectCategory=computer)")
$array = @($($searcher.findall()) | % {$_.properties.cn})

@(for ($i=0;$i -lt $array.count; $i++){
            Try {
            Write-Host "Forward lookup entry found for: $($array[$i])" -Fore green
            Catch {
            Write-Host "There is no forward lookup DNS entry for: $($array[$i])" -Fore red
      }) > machine_ips.txt

get-software function (Can be tuned for just ".net" frameworks)

Function Get-Software{
    <# .SYNOPSIS
        Gets the software applications on a remote computer.
        This function interrogates the remote registry for installed
            software products.
        It then returns an array of powershell objects that can be sorted
            and parsed.
        Optionally, you can provide a product name that will filter
            applications based on displayname before they are returned, thus reducing the typing
            needed to get specific results.
            .PARAMETER computer
        The name of the computer to retrieve a software list from.
            .PARAMETER product
        The partial name of a software application to search for.
        Name: Get-Software
        Author: Geoffrey Guynn
        DateCreated 9 Aug 2011
        Get-Software -computer "computer" -command "Adobe"
        Returns all instances of Adobe software on the computer.

        SupportsShouldProcess = $True,
        DefaultParameterSetName = "process",
        ConfirmImpact = "low"
    if (TestRemoteAdmin $Computer){
        #Get Architechture Type of the system
        #$OSArch = (Gwmi -computer $Computer win32_operatingSystem).OSArchitecture
         $OSArch = (Gwmi -computer $Computer win32_operatingSystem).caption
        if ($OSArch -like "*64*") {$Architectures = @("32bit","64bit")}
        else {$Architectures = @("32bit")}
        #Create an array to capture program objects.
        $arApplications = @()
        foreach ($Architecture in $Architectures){
            #We have a 64bit machine, get the 32 bit software.
            if ($Architecture -like "*64*"){
                #Define the entry point to the registry.
                $strSubKey = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
                $SoftArchitecture = "32bit"
                $RegViewEnum = [Microsoft.Win32.RegistryView]::Registry64
            #We have a 32bit machine, use the 32bit registry provider.
            elseif ($Architectures -notcontains "64bit"){
                #Define the entry point to the registry.
                $strSubKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
                $SoftArchitecture = "32bit"
                $RegViewEnum = [Microsoft.Win32.RegistryView]::Registry32
            #We have "64bit" in our array, capture the 64bit software.
                #Define the entry point to the registry.
                $strSubKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
                $SoftArchitecture = "64bit"
                $RegViewEnum = [Microsoft.Win32.RegistryView]::Registry64
            #The standard routine to get software.
            #Create a remote registry connection to the server.
            $remRegistry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer, $RegViewEnum)
            #Open the entry point.
            $remKey = $remRegistry.OpenSubKey($strSubKey)
            #Get all subkeys that exist in the entry point.
            $remSoftware = $remKey.GetSubKeyNames()
            #Loop through the applications and capture data.
            foreach ($remApplication in $RemSoftware){
                $remProgram = $remRegistry.OpenSubKey("$strSubKey\\$remApplication")
                $strDisplayName = $remProgram.GetValue("DisplayName")
                if ($strDisplayName){
                    #Get a list of all available properties for the program.
                    $arProperties = $remProgram.GetValueNames()
                    #Create a custom object for this program.
                    $objApplication = New-Object System.Object
                    #Write-Host "`n"
                    foreach ($strProperty in $arProperties){
                        #Get the value associated with the current property.
                        $strValue = [string]($remProgram.GetValue($strProperty))
                        if ($strValue){
                            #If the property has a value but no name, then it is the default property.
                            if (!$strProperty){
                                $objApplication | Add-Member -type NoteProperty -Name "(Default)" -Value $strValue
                            #The property has a value and a name, assign them both as a new property on the object.
                                $objApplication | Add-Member -type NoteProperty -Name ([string]$strProperty) -Value $strValue
                        #Write-Host $strValue ": "
                    #Add a final property to denote the software architecture type.
                    $objApplication | Add-Member -type NoteProperty -Name "Architecture" -Value $SoftArchitecture
                    #Add the last application to the array of programs.
                    $arApplications += $objApplication
            #Sort the array by each object's displayName.
        if ($Product){
            $objApplication = $arApplications | ? {$_.DisplayName -Like "*$Product*"}
            return $objApplication
        $arApplications = $arApplications | Sort-Object -property Architecture,DisplayName
        return $arApplications
    return $null

Expert Comment

ID: 40403856
Are you able to run a DOS command remotely on all the 500 workstations ?
It could search for the .net string to detect if the .NET is installed or not.
Would that be sufficient ? If Yes i can provide the command i have somewhere.

Author Comment

by:matthew phung
ID: 40404170
Wiley, Thank you for the detailed reply again. I will definitely play around with the code.

Stampel, I  might be able to run DOS remotely so can you provide me the command? Once again, thank you everyone for your help

Expert Comment

ID: 40404172
Some of this may already be covered before, but Microsoft has a good MSDN article that helps summarize how to do this: http://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx

In BigFix, you should be able to create a simple fixlet to search for the reg key and values you need -- e.g., HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP (from article above). Fixlets are much easier than writing custom scripts in my opinion. You may as well use BF if you already have it, to keep it simple.

IBM has lots of sample solutions to help with this, for instance this example to search for a value in a reg key:

Hope this helps.

Expert Comment

ID: 40404722
Ok here is the command to return any installed software matching ".NET"

C:\>wmic product get name | findstr .NET
result for me =>
Microsoft .NET Framework 4.5.1 (EN)
Microsoft .NET Framework 4.5.1

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This installment of Make It Better gives Media Temple customers the latest news, plugins, and tutorials to make their VPS hosting experience that much smoother.
This installment of Make It Better gives Media Temple customers the latest news, plugins, and tutorials to make their Grid shared hosting experience that much smoother.
If you're a developer or IT admin, you’re probably tasked with managing multiple websites, servers, applications, and levels of security on a daily basis. While this can be extremely time consuming, it can also be frustrating when systems aren't wor…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…
Suggested Courses

615 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question