go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/detector/windows/build_version.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package windows
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"regexp"
    11  	"strconv"
    12  
    13  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    14  	"go.mondoo.com/cnquery/providers/os/resources/powershell"
    15  )
    16  
    17  var WinBuildVersionRegex = regexp.MustCompile(`^(\d+)(?:\.(\d+)){0,1}`)
    18  
    19  type BuildVersion struct {
    20  	Build int
    21  	UBR   int
    22  }
    23  
    24  // WindowsVersion parses the version generated by motor
    25  // It uses the format: major.minor.build.ubr
    26  func Version(ver string) (*BuildVersion, error) {
    27  	// check that we go a valid windows version
    28  	m := WinBuildVersionRegex.FindStringSubmatch(ver)
    29  	if len(m) < 2 {
    30  		return nil, fmt.Errorf("the requested windows version is not supported: %s", ver)
    31  	}
    32  
    33  	build, err := strconv.Atoi(m[1])
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	var ubr int
    39  	if len(m) == 3 && len(m[2]) > 0 {
    40  		ubr, err = strconv.Atoi(m[2])
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  	}
    45  
    46  	return &BuildVersion{
    47  		Build: build,
    48  		UBR:   ubr,
    49  	}, nil
    50  }
    51  
    52  func (b BuildVersion) OSBuild() string {
    53  	if b.UBR > 0 {
    54  		return fmt.Sprintf("%d.%d", b.Build, b.UBR)
    55  	} else {
    56  		return fmt.Sprintf("%d", b.Build)
    57  	}
    58  }
    59  
    60  type WindowsCurrentVersion struct {
    61  	CurrentBuild string `json:"CurrentBuild"`
    62  	EditionID    string `json:"EditionID"`
    63  	ReleaseId    string `json:"ReleaseId"`
    64  	// Update Build Revision
    65  	UBR int `json:"UBR"`
    66  }
    67  
    68  func ParseWinRegistryCurrentVersion(r io.Reader) (*WindowsCurrentVersion, error) {
    69  	data, err := io.ReadAll(r)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	var winCurrentVersion WindowsCurrentVersion
    75  	err = json.Unmarshal(data, &winCurrentVersion)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	return &winCurrentVersion, nil
    81  }
    82  
    83  // powershellGetWindowsOSBuild runs a powershell script to retrieve the current version from windows
    84  func powershellGetWindowsOSBuild(conn shared.Connection) (*WindowsCurrentVersion, error) {
    85  	pscommand := "Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion' -Name CurrentBuild, UBR, EditionID | ConvertTo-Json"
    86  	cmd, err := conn.RunCommand(powershell.Wrap(pscommand))
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	return ParseWinRegistryCurrentVersion(cmd.Stdout)
    91  }