I am trying to write a query in SCCM to look for .Net Framework that is less than a certain version.
What I have:
select distinct SMS_R_System.Name from SMS_R_System where SMS_R_System.Name not in (select distinct SMS_R_System.Name from SMS_R_System inner join SMS_G_System_ADD_REMOVE_PROGRAMS on SMS_G_System_ADD_REMOVE_PROGRAMS.ResourceId = SMS_R_System.ResourceId where SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName = "Microsoft .NET Framework 4.6.2")
This shows everything not named 4.6.2. I want it to display everything less than 4.6.2. Also, when the query is ran, it shows only the machine name. What is the best way to display not just the machine name, but what version is installed?
The WQL Query would be
select distinct SMS_R_System.Name, SMS_G_System_ADD_REMOVE_PROGRAMS.Version from SMS_R_System inner join SMS_G_System_ADD_REMOVE_PROGRAMS on SMS_G_System_ADD_REMOVE_PROGRAMS.ResourceId = SMS_R_System.ResourceId where SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName like 'Microsoft .NET Framework 4%' and Version < '4.6.2'
There are however several caveats. The first is that the less than for the version is just a string compare. This means version 10 is smaller than 4 and 4.10 smaller than 4.6. However as we know the range of the .NET Versions and we know that those do not exist I think it should be fine. If you want to be sure you would have to use some programming language to further split the version into its parts and analyze them.
Another is that this only checks for version 4 in general. This is because version 1 can be installed alongside version 4 and you would get every computer listed in the results. However as .NET works in a special way where version 1 is often installed alongside version 4 but version 2 and 3 are not it could lead to problems if you have really old installations. As this would mean pre Windows 7 installations I assumed it is probably no problem in your case.
The last thing is that unforutnately WQL is not SQL and behaves really crazy if you join classes and take information form both. So if you execute this query in some WMI Tool there is a high chance you get a result like System.Management.ManagementBaseObject
instead of the results you want. To avoid this you can use powershell to execute the query like this:
$computername = "<SiteServer>"
$namespace = 'Root\SMS\site_<SiteCode>'
$query = "select distinct SMS_R_System.Name, SMS_G_System_ADD_REMOVE_PROGRAMS.Version from SMS_R_System inner join SMS_G_System_ADD_REMOVE_PROGRAMS on SMS_G_System_ADD_REMOVE_PROGRAMS.ResourceId = SMS_R_System.ResourceId where SMS_G_System_ADD_REMOVE_PROGRAMS.DisplayName like 'Microsoft .NET Framework 4%' and SMS_G_System_ADD_REMOVE_PROGRAMS.Version < '4.6.2'"
gwmi -ComputerName $computername -Namespace $namespace -Query $query | Select-Object -Property @{n='Name';e={$_.SMS_R_System.Name}}, @{n='Version';e={$_.SMS_G_System_ADD_REMOVE_PROGRAMS.Version}}
Finally if you have access to the SCCM DB you could also use SQL instead of WQL which is a lot faster and allows for better joining. If this is a possibility for you I'd recommend it for quick queries/lookups over WQL. The classes have a little different names there so the query would be:
select distinct v_R_System.Name0, v_Add_Remove_Programs.Version0
from
v_R_System inner join v_Add_Remove_Programs
on
v_Add_Remove_Programs.ResourceId = v_R_System.ResourceId
where
v_Add_Remove_Programs.DisplayName0 like 'Microsoft .NET Framework 4%'
and
v_Add_Remove_Programs.Version0 < '4.6.2'