@@ -25,6 +25,8 @@ import (
2525 "go.mondoo.com/cnquery/v11/providers/os/resources/cpe"
2626 "go.mondoo.com/cnquery/v11/providers/os/resources/powershell"
2727 "go.mondoo.com/cnquery/v11/providers/os/resources/purl"
28+ "go.mondoo.com/ranger-rpc/codes"
29+ "go.mondoo.com/ranger-rpc/status"
2830)
2931
3032// ProcessorArchitecture Enum
@@ -130,38 +132,9 @@ func (p winAppxPackages) toPackage(platform *inventory.Platform) Package {
130132 p .arch = arch
131133 }
132134
133- pkg := Package {
134- Name : p .Name ,
135- Version : p .Version ,
136- Arch : p .arch ,
137- Format : "windows/appx" ,
138- Vendor : p .Publisher ,
139- PUrl : purl .NewPackageURL (platform , purl .TypeAppx , p .Name , p .Version ).String (),
140- }
141- if p .InstallLocation != "" {
142- pkg .Files = []FileRecord {
143- {
144- Path : p .InstallLocation ,
145- },
146- }
147- pkg .FilesAvailable = PkgFilesIncluded
148- }
149-
150- if p .Version != "" {
151- cpeWfns , err := cpe .NewPackage2Cpe (p .Publisher , p .Name , p .Version , "" , "" )
152- if err != nil {
153- log .Debug ().Err (err ).
154- Str ("name" , p .Name ).
155- Str ("version" , p .Version ).
156- Msg ("could not create cpe for windows appx package" )
157- } else {
158- pkg .CPEs = cpeWfns
159- }
160- } else {
161- log .Debug ().Msg ("ignored package since information is missing" )
162- }
135+ pkg := createPackage (p .Name , p .Version , "windows/appx" , p .arch , p .Publisher , p .InstallLocation , platform )
163136
164- return pkg
137+ return * pkg
165138}
166139
167140// Good read: https://www.wintips.org/view-installed-apps-and-packages-in-windows-10-8-1-8-from-powershell/
@@ -278,9 +251,63 @@ func (w *WinPkgManager) getLocalInstalledApps() ([]Package, error) {
278251 packages = append (packages , * p )
279252 }
280253 }
254+
255+ // These are the .NET Framework packages
256+ // They do not show up in the general apps or features list, so we need to discover them separately
257+ dotNetFramework , err := w .getDotNetFramework ()
258+ if err != nil {
259+ return nil , err
260+ }
261+ packages = append (packages , dotNetFramework ... )
262+
281263 return packages , nil
282264}
283265
266+ // getDotNetFramework returns the .NET Framework package
267+ func (w * WinPkgManager ) getDotNetFramework () ([]Package , error ) {
268+ // https://learn.microsoft.com/en-us/dotnet/framework/install/how-to-determine-which-versions-are-installed#net-framework-45-and-later-versions
269+ dotNet45plus := "HKEY_LOCAL_MACHINE\\ SOFTWARE\\ Microsoft\\ NET Framework Setup\\ NDP\\ v4\\ Full"
270+ // https://learn.microsoft.com/en-us/dotnet/framework/install/how-to-determine-which-versions-are-installed#use-registry-editor-older-framework-versions
271+ dotNet35 := "HKEY_LOCAL_MACHINE\\ SOFTWARE\\ Microsoft\\ NET Framework Setup\\ NDP\\ v3.5"
272+
273+ return getDotNetFrameworkPackageFromRegistryKeys (dotNet45plus , dotNet35 , w .platform )
274+ }
275+
276+ // getDotNetFrameworkFs returns the .NET Framework package discovered on the filesystem
277+ func (w * WinPkgManager ) getDotNetFrameworkFs () ([]Package , error ) {
278+ // https://learn.microsoft.com/en-us/dotnet/framework/install/how-to-determine-which-versions-are-installed#net-framework-45-and-later-versions
279+ dotNet45plus := "Microsoft\\ NET Framework Setup\\ NDP\\ v4\\ Full"
280+ // https://learn.microsoft.com/en-us/dotnet/framework/install/how-to-determine-which-versions-are-installed#use-registry-editor-older-framework-versions
281+ dotNet35 := "Microsoft\\ NET Framework Setup\\ NDP\\ v3.5"
282+
283+ return getDotNetFrameworkPackageFromRegistryKeys (dotNet45plus , dotNet35 , w .platform )
284+ }
285+
286+ // getDotNetFrameworkPackageFromRegistryKeys returns the .NET Framework package from the registry keys
287+ func getDotNetFrameworkPackageFromRegistryKeys (dotNet45plus , dotNet35 string , platform * inventory.Platform ) ([]Package , error ) {
288+ items , err := registry .GetNativeRegistryKeyItems (dotNet45plus )
289+ if err != nil && status .Code (err ) != codes .NotFound {
290+ return nil , err
291+ }
292+
293+ if len (items ) == 0 {
294+ items , err = registry .GetNativeRegistryKeyItems (dotNet35 )
295+ if err != nil && status .Code (err ) != codes .NotFound {
296+ return nil , err
297+ }
298+ }
299+
300+ if len (items ) == 0 {
301+ return nil , nil
302+ }
303+
304+ p := getDotNetFrameworkPackageFromRegistryKeyItems (items , platform )
305+ if p == nil {
306+ return nil , nil
307+ }
308+ return []Package {* p }, nil
309+ }
310+
284311func (w * WinPkgManager ) getInstalledApps () ([]Package , error ) {
285312 if w .conn .Type () == shared .Type_Local && runtime .GOOS == "windows" {
286313 return w .getLocalInstalledApps ()
@@ -374,6 +401,14 @@ func (w *WinPkgManager) getFsInstalledApps() ([]Package, error) {
374401 }
375402 }
376403
404+ // These are the .NET Framework packages
405+ // They do not show up in the general apps or features list, so we need to discover them separately
406+ dotNetFramework , err := w .getDotNetFrameworkFs ()
407+ if err != nil {
408+ return nil , err
409+ }
410+ packages = append (packages , dotNetFramework ... )
411+
377412 msSqlHotfixes := findMsSqlHotfixes (packages )
378413 if len (msSqlHotfixes ) > 0 {
379414 packages = updateMsSqlPackages (packages , msSqlHotfixes [len (msSqlHotfixes )- 1 ])
@@ -490,35 +525,31 @@ func getPackageFromRegistryKeyItems(children []registry.RegistryKeyItem, platfor
490525 return nil
491526 }
492527
493- pkg := & Package {
494- Name : displayName ,
495- Version : displayVersion ,
496- Format : "windows/app" ,
497- Arch : platform .Arch ,
498- Vendor : publisher ,
499- PUrl : purl .NewPackageURL (
500- platform , purl .TypeWindows , displayName , displayVersion ,
501- ).String (),
502- }
503- if installLocation != "" {
504- pkg .Files = []FileRecord {
505- {
506- Path : installLocation ,
507- },
528+ pkg := createPackage (displayName , displayVersion , "windows/app" , platform .Arch , publisher , installLocation , platform )
529+
530+ return pkg
531+ }
532+
533+ // getDotNetFrameworkPackageFromRegistryKeyItems returns the .NET Framework package from the registry key items
534+ func getDotNetFrameworkPackageFromRegistryKeyItems (items []registry.RegistryKeyItem , platform * inventory.Platform ) * Package {
535+ var version string
536+ var installLocation string
537+
538+ for _ , i := range items {
539+ switch i .Key {
540+ case "Version" :
541+ version = i .Value .String
542+ case "InstallLocation" :
543+ installLocation = i .Value .String
508544 }
509- pkg .FilesAvailable = PkgFilesIncluded
510545 }
511546
512- if displayVersion != "" {
513- cpeWfns , err := cpe .NewPackage2Cpe (publisher , displayName , displayVersion , "" , "" )
514- if err != nil {
515- log .Debug ().Err (err ).Str ("name" , displayName ).Str ("version" , displayVersion ).Msg ("could not create cpe for windows app package" )
516- } else {
517- pkg .CPEs = cpeWfns
518- }
519- } else {
520- log .Debug ().Msg ("ignored package since information is missing" )
547+ if version == "" {
548+ return nil
521549 }
550+
551+ pkg := createPackage ("Microsoft .NET Framework" , version , "windows/app" , platform .Arch , "Microsoft" , installLocation , platform )
552+
522553 return pkg
523554}
524555
@@ -596,44 +627,15 @@ func ParseWindowsAppPackages(platform *inventory.Platform, input io.Reader) ([]P
596627 if entry .UninstallString == "" {
597628 continue
598629 }
599- cpeWfns := []string {}
600630
601631 // TODO: We need to figure out why we have empty displayNames.
602632 // this is common in windows but we need to verify it is a windows
603633 // issue and not a cnquery issue.
604634 if entry .DisplayName == "" {
605635 continue
606636 }
607- if entry .DisplayVersion != "" {
608- cpeWfns , err = cpe .NewPackage2Cpe (entry .Publisher , entry .DisplayName , entry .DisplayVersion , "" , "" )
609- if err != nil {
610- log .Debug ().Err (err ).
611- Str ("name" , entry .DisplayName ).
612- Str ("version" , entry .DisplayVersion ).
613- Msg ("could not create cpe for windows app package" )
614- }
615- } else {
616- log .Debug ().Msg ("ignored package since information is missing" )
617- }
618- pkg := Package {
619- Name : entry .DisplayName ,
620- Version : entry .DisplayVersion ,
621- Format : "windows/app" ,
622- CPEs : cpeWfns ,
623- Vendor : entry .Publisher ,
624- Arch : platform .Arch ,
625- PUrl : purl .NewPackageURL (
626- platform , purl .TypeWindows , entry .DisplayName , entry .DisplayVersion ,
627- ).String (),
628- }
629- if entry .InstallLocation != "" {
630- pkg .Files = []FileRecord {
631- {
632- Path : entry .InstallLocation ,
633- },
634- }
635- }
636- pkgs = append (pkgs , pkg )
637+ pkg := createPackage (entry .DisplayName , entry .DisplayVersion , "windows/app" , platform .Arch , entry .Publisher , entry .InstallLocation , platform )
638+ pkgs = append (pkgs , * pkg )
637639 }
638640
639641 return pkgs , nil
@@ -682,3 +684,41 @@ func updateMsSqlPackages(pkgs []Package, latestMsSqlHotfix Package) []Package {
682684 }
683685 return pkgs
684686}
687+
688+ // createPackage creates a new package with the given parameters
689+ func createPackage (name , version , format , arch , publisher , installLocation string , platform * inventory.Platform ) * Package {
690+ purlType := purl .TypeWindows
691+ if format == "windows/appx" {
692+ purlType = purl .TypeAppx
693+ }
694+
695+ pkg := & Package {
696+ Name : name ,
697+ Version : version ,
698+ Format : format ,
699+ Arch : arch ,
700+ Vendor : publisher ,
701+ PUrl : purl .NewPackageURL (
702+ platform , purlType , name , version ,
703+ ).String (),
704+ }
705+ if installLocation != "" {
706+ pkg .Files = []FileRecord {
707+ {
708+ Path : installLocation ,
709+ },
710+ }
711+ pkg .FilesAvailable = PkgFilesIncluded
712+ }
713+
714+ if version != "" {
715+ cpeWfns , err := cpe .NewPackage2Cpe (publisher , name , version , "" , "" )
716+ if err != nil {
717+ log .Debug ().Err (err ).Str ("name" , name ).Str ("version" , version ).Msg ("could not create cpe for windows app package" )
718+ } else {
719+ pkg .CPEs = cpeWfns
720+ }
721+ }
722+
723+ return pkg
724+ }
0 commit comments