fix(scanner/windows): support when default shell is powershell (#1844)
This commit is contained in:
@@ -249,7 +249,7 @@ func sshExecExternal(c config.ServerInfo, cmdstr string, sudo bool) (result exec
|
||||
var cmd *ex.Cmd
|
||||
switch c.Distro.Family {
|
||||
case constant.Windows:
|
||||
cmd = ex.Command(sshBinaryPath, append(args, "powershell.exe", "-NoProfile", "-NonInteractive", fmt.Sprintf(`"%s`, cmdstr))...)
|
||||
cmd = ex.Command(sshBinaryPath, append(args, cmdstr)...)
|
||||
default:
|
||||
cmd = ex.Command(sshBinaryPath, append(args, fmt.Sprintf("stty cols 1000; %s", cmdstr))...)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
// inherit OsTypeInterface
|
||||
type windows struct {
|
||||
base
|
||||
shell string
|
||||
}
|
||||
|
||||
type osInfo struct {
|
||||
@@ -41,6 +42,7 @@ func newWindows(c config.ServerInfo) *windows {
|
||||
VulnInfos: models.VulnInfos{},
|
||||
},
|
||||
},
|
||||
shell: "unknown",
|
||||
}
|
||||
d.log = logging.NewNormalLogger()
|
||||
d.setServerInfo(c)
|
||||
@@ -50,30 +52,43 @@ func newWindows(c config.ServerInfo) *windows {
|
||||
func detectWindows(c config.ServerInfo) (bool, osTypeInterface) {
|
||||
tmp := c
|
||||
tmp.Distro.Family = constant.Windows
|
||||
|
||||
if isLocalExec(c.Port, c.Host) {
|
||||
if r, r2 := exec(tmp, `$CurrentVersion = (Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion"); Format-List -InputObject $CurrentVersion -Property ProductName, CurrentVersion, CurrentMajorVersionNumber, CurrentMinorVersionNumber, CurrentBuildNumber, UBR, CSDVersion, EditionID, InstallationType`, noSudo), exec(tmp, `(Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment").PROCESSOR_ARCHITECTURE`, noSudo); (r.isSuccess() && r.Stdout != "") && (r2.isSuccess() && r2.Stdout != "") {
|
||||
w := newWindows(c)
|
||||
osInfo, err := parseRegistry(r.Stdout, strings.TrimSpace(r2.Stdout))
|
||||
if err != nil {
|
||||
w.setErrs([]error{xerrors.Errorf("Failed to parse Registry. err: %w", err)})
|
||||
return true, w
|
||||
w := newWindows(tmp)
|
||||
w.shell = func() string {
|
||||
if r := w.exec("echo $env:OS", noSudo); r.isSuccess() {
|
||||
switch strings.TrimSpace(r.Stdout) {
|
||||
case "$env:OS":
|
||||
return "cmd.exe"
|
||||
case "Windows_NT":
|
||||
return "powershell"
|
||||
default:
|
||||
if rr := w.exec("Get-ChildItem env:OS", noSudo); rr.isSuccess() {
|
||||
return "powershell"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
return "unknown"
|
||||
}()
|
||||
|
||||
w.log.Debugf("osInfo(Registry): %+v", osInfo)
|
||||
release, err := detectOSName(osInfo)
|
||||
if err != nil {
|
||||
w.setErrs([]error{xerrors.Errorf("Failed to detect os name. err: %w", err)})
|
||||
return true, w
|
||||
}
|
||||
w.setDistro(constant.Windows, release)
|
||||
w.Kernel = models.Kernel{Version: formatKernelVersion(osInfo)}
|
||||
if r := w.exec(w.translateCmd(`Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion" | Format-List -Property ProductName, CurrentVersion, CurrentMajorVersionNumber, CurrentMinorVersionNumber, CurrentBuildNumber, UBR, CSDVersion, EditionID, InstallationType; Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment" | Format-List -Property PROCESSOR_ARCHITECTURE`), noSudo); r.isSuccess() {
|
||||
osInfo, err := parseRegistry(r.Stdout)
|
||||
if err != nil {
|
||||
w.setErrs([]error{xerrors.Errorf("Failed to parse Registry. err: %w", err)})
|
||||
return true, w
|
||||
}
|
||||
|
||||
w.log.Debugf("osInfo(Registry): %+v", osInfo)
|
||||
release, err := detectOSName(osInfo)
|
||||
if err != nil {
|
||||
w.setErrs([]error{xerrors.Errorf("Failed to detect os name. err: %w", err)})
|
||||
return true, w
|
||||
}
|
||||
w.setDistro(constant.Windows, release)
|
||||
w.Kernel = models.Kernel{Version: formatKernelVersion(osInfo)}
|
||||
return true, w
|
||||
}
|
||||
|
||||
if r := exec(tmp, "Get-ComputerInfo -Property WindowsProductName, OsVersion, WindowsEditionId, OsCSDVersion, CsSystemType, WindowsInstallationType", noSudo); r.isSuccess() && r.Stdout != "" {
|
||||
w := newWindows(c)
|
||||
if r := w.exec(w.translateCmd(`$ProgressPreference = "SilentlyContinue"; Get-ComputerInfo -Property WindowsProductName, OsVersion, WindowsEditionId, OsCSDVersion, CsSystemType, WindowsInstallationType`), noSudo); r.isSuccess() {
|
||||
osInfo, err := parseGetComputerInfo(r.Stdout)
|
||||
if err != nil {
|
||||
w.setErrs([]error{xerrors.Errorf("Failed to parse Get-ComputerInfo. err: %w", err)})
|
||||
@@ -91,8 +106,7 @@ func detectWindows(c config.ServerInfo) (bool, osTypeInterface) {
|
||||
return true, w
|
||||
}
|
||||
|
||||
if r := exec(tmp, "$WmiOS = (Get-WmiObject Win32_OperatingSystem); Format-List -InputObject $WmiOS -Property Caption, Version, OperatingSystemSKU, CSDVersion; $WmiCS = (Get-WmiObject Win32_ComputerSystem); Format-List -InputObject $WmiCS -Property SystemType, DomainRole", noSudo); r.isSuccess() && r.Stdout != "" {
|
||||
w := newWindows(c)
|
||||
if r := w.exec(w.translateCmd("Get-WmiObject Win32_OperatingSystem | Format-List -Property Caption, Version, OperatingSystemSKU, CSDVersion; Get-WmiObject Win32_ComputerSystem | Format-List -Property SystemType, DomainRole"), noSudo); r.isSuccess() {
|
||||
osInfo, err := parseWmiObject(r.Stdout)
|
||||
if err != nil {
|
||||
w.setErrs([]error{xerrors.Errorf("Failed to parse Get-WmiObject. err: %w", err)})
|
||||
@@ -110,8 +124,7 @@ func detectWindows(c config.ServerInfo) (bool, osTypeInterface) {
|
||||
return true, w
|
||||
}
|
||||
|
||||
if r := exec(tmp, "systeminfo.exe", noSudo); r.isSuccess() && r.Stdout != "" {
|
||||
w := newWindows(c)
|
||||
if r := w.exec("systeminfo.exe", noSudo); r.isSuccess() {
|
||||
osInfo, _, err := parseSystemInfo(r.Stdout)
|
||||
if err != nil {
|
||||
w.setErrs([]error{xerrors.Errorf("Failed to parse systeminfo.exe. err: %w", err)})
|
||||
@@ -132,6 +145,17 @@ func detectWindows(c config.ServerInfo) (bool, osTypeInterface) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (w *windows) translateCmd(cmd string) string {
|
||||
switch w.shell {
|
||||
case "cmd.exe":
|
||||
return fmt.Sprintf(`powershell.exe -NoProfile -NonInteractive "%s"`, strings.ReplaceAll(cmd, `"`, `\"`))
|
||||
case "powershell":
|
||||
return cmd
|
||||
default: // not tested with bash etc
|
||||
return fmt.Sprintf(`powershell.exe -NoProfile -NonInteractive "%s"`, strings.ReplaceAll(cmd, `"`, `\"`))
|
||||
}
|
||||
}
|
||||
|
||||
func parseSystemInfo(stdout string) (osInfo, []string, error) {
|
||||
var (
|
||||
o osInfo
|
||||
@@ -469,7 +493,7 @@ func parseWmiObject(stdout string) (osInfo, error) {
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func parseRegistry(stdout, arch string) (osInfo, error) {
|
||||
func parseRegistry(stdout string) (osInfo, error) {
|
||||
var (
|
||||
o osInfo
|
||||
major string
|
||||
@@ -535,6 +559,16 @@ func parseRegistry(stdout, arch string) (osInfo, error) {
|
||||
return osInfo{}, xerrors.Errorf(`Failed to detect InstallationType. expected: "InstallationType : <InstallationType>", line: "%s"`, line)
|
||||
}
|
||||
o.installationType = strings.TrimSpace(rhs)
|
||||
case strings.HasPrefix(line, "PROCESSOR_ARCHITECTURE"):
|
||||
_, rhs, found := strings.Cut(line, ":")
|
||||
if !found {
|
||||
return osInfo{}, xerrors.Errorf(`Failed to detect PROCESSOR_ARCHITECTURE. expected: "PROCESSOR_ARCHITECTURE : <PROCESSOR_ARCHITECTURE>", line: "%s"`, line)
|
||||
}
|
||||
formatted, err := formatArch(strings.TrimSpace(rhs))
|
||||
if err != nil {
|
||||
return osInfo{}, xerrors.Errorf("Failed to format arch. arch: %s, err: %w", strings.TrimSpace(rhs), err)
|
||||
}
|
||||
o.arch = formatted
|
||||
default:
|
||||
}
|
||||
}
|
||||
@@ -542,12 +576,6 @@ func parseRegistry(stdout, arch string) (osInfo, error) {
|
||||
o.version = fmt.Sprintf("%s.%s", major, minor)
|
||||
}
|
||||
|
||||
formatted, err := formatArch(arch)
|
||||
if err != nil {
|
||||
return osInfo{}, xerrors.Errorf("Failed to format arch. arch: %s, err: %w", arch, err)
|
||||
}
|
||||
o.arch = formatted
|
||||
|
||||
return o, nil
|
||||
}
|
||||
|
||||
@@ -951,46 +979,46 @@ func formatKernelVersion(osInfo osInfo) string {
|
||||
return v
|
||||
}
|
||||
|
||||
func (o *windows) checkScanMode() error {
|
||||
func (w *windows) checkScanMode() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *windows) checkIfSudoNoPasswd() error {
|
||||
func (w *windows) checkIfSudoNoPasswd() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *windows) checkDeps() error {
|
||||
func (w *windows) checkDeps() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *windows) preCure() error {
|
||||
if err := o.detectIPAddr(); err != nil {
|
||||
o.log.Warnf("Failed to detect IP addresses: %s", err)
|
||||
o.warns = append(o.warns, err)
|
||||
func (w *windows) preCure() error {
|
||||
if err := w.detectIPAddr(); err != nil {
|
||||
w.log.Warnf("Failed to detect IP addresses: %s", err)
|
||||
w.warns = append(w.warns, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *windows) postScan() error {
|
||||
func (w *windows) postScan() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *windows) detectIPAddr() error {
|
||||
func (w *windows) detectIPAddr() error {
|
||||
var err error
|
||||
o.ServerInfo.IPv4Addrs, o.ServerInfo.IPv6Addrs, err = o.ip()
|
||||
w.ServerInfo.IPv4Addrs, w.ServerInfo.IPv6Addrs, err = w.ip()
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *windows) ip() ([]string, []string, error) {
|
||||
r := o.exec("ipconfig.exe", noSudo)
|
||||
func (w *windows) ip() ([]string, []string, error) {
|
||||
r := w.exec("ipconfig.exe", noSudo)
|
||||
if !r.isSuccess() {
|
||||
return nil, nil, xerrors.Errorf("Failed to detect IP address: %v", r)
|
||||
}
|
||||
ipv4Addrs, ipv6Addrs := o.parseIP(r.Stdout)
|
||||
ipv4Addrs, ipv6Addrs := w.parseIP(r.Stdout)
|
||||
return ipv4Addrs, ipv6Addrs, nil
|
||||
}
|
||||
|
||||
func (o *windows) parseIP(stdout string) ([]string, []string) {
|
||||
func (w *windows) parseIP(stdout string) ([]string, []string) {
|
||||
var ipv4Addrs, ipv6Addrs []string
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(stdout))
|
||||
@@ -1024,25 +1052,25 @@ func (o *windows) parseIP(stdout string) ([]string, []string) {
|
||||
return ipv4Addrs, ipv6Addrs
|
||||
}
|
||||
|
||||
func (o *windows) scanPackages() error {
|
||||
if r := o.exec("$Packages = (Get-Package); Format-List -InputObject $Packages -Property Name, Version, ProviderName", noSudo); r.isSuccess() {
|
||||
installed, _, err := o.parseInstalledPackages(r.Stdout)
|
||||
func (w *windows) scanPackages() error {
|
||||
if r := w.exec(w.translateCmd("Get-Package | Format-List -Property Name, Version, ProviderName"), noSudo); r.isSuccess() {
|
||||
installed, _, err := w.parseInstalledPackages(r.Stdout)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to parse installed packages. err: %w", err)
|
||||
}
|
||||
o.Packages = installed
|
||||
w.Packages = installed
|
||||
}
|
||||
|
||||
kbs, err := o.scanKBs()
|
||||
kbs, err := w.scanKBs()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Failed to scan KB. err: %w", err)
|
||||
}
|
||||
o.windowsKB = kbs
|
||||
w.windowsKB = kbs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *windows) parseInstalledPackages(stdout string) (models.Packages, models.SrcPackages, error) {
|
||||
func (w *windows) parseInstalledPackages(stdout string) (models.Packages, models.SrcPackages, error) {
|
||||
installed := models.Packages{}
|
||||
|
||||
var name, version string
|
||||
@@ -1084,10 +1112,11 @@ func (o *windows) parseInstalledPackages(stdout string) (models.Packages, models
|
||||
return installed, nil, nil
|
||||
}
|
||||
|
||||
func (o *windows) scanKBs() (*models.WindowsKB, error) {
|
||||
func (w *windows) scanKBs() (*models.WindowsKB, error) {
|
||||
applied, unapplied := map[string]struct{}{}, map[string]struct{}{}
|
||||
if r := o.exec("$Hotfix = (Get-Hotfix); Format-List -InputObject $Hotfix -Property HotFixID", noSudo); r.isSuccess() {
|
||||
kbs, err := o.parseGetHotfix(r.Stdout)
|
||||
|
||||
if r := w.exec(w.translateCmd("Get-Hotfix | Format-List -Property HotFixID"), noSudo); r.isSuccess() {
|
||||
kbs, err := w.parseGetHotfix(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Get-Hotifx. err: %w", err)
|
||||
}
|
||||
@@ -1096,8 +1125,8 @@ func (o *windows) scanKBs() (*models.WindowsKB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if r := o.exec("$Packages = (Get-Package -ProviderName msu); Format-List -InputObject $Packages -Property Name", noSudo); r.isSuccess() {
|
||||
kbs, err := o.parseGetPackageMSU(r.Stdout)
|
||||
if r := w.exec(w.translateCmd("Get-Package -ProviderName msu | Format-List -Property Name"), noSudo); r.isSuccess() {
|
||||
kbs, err := w.parseGetPackageMSU(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Get-Package. err: %w", err)
|
||||
}
|
||||
@@ -1106,52 +1135,51 @@ func (o *windows) scanKBs() (*models.WindowsKB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if isLocalExec(o.getServerInfo().Port, o.getServerInfo().Host) {
|
||||
var searcher string
|
||||
switch c := o.getServerInfo().Windows; c.ServerSelection {
|
||||
case 3: // https://learn.microsoft.com/en-us/windows/win32/wua_sdk/using-wua-to-scan-for-updates-offline
|
||||
searcher = fmt.Sprintf("$UpdateSession = (New-Object -ComObject Microsoft.Update.Session); $UpdateServiceManager = (New-Object -ComObject Microsoft.Update.ServiceManager); $UpdateService = $UpdateServiceManager.AddScanPackageService(\"Offline Sync Service\", \"%s\"); $UpdateSearcher = $UpdateSession.CreateUpdateSearcher(); $UpdateSearcher.ServerSelection = %d; $UpdateSearcher.ServiceID = $UpdateService.ServiceID;", c.CabPath, c.ServerSelection)
|
||||
default:
|
||||
searcher = fmt.Sprintf("$UpdateSession = (New-Object -ComObject Microsoft.Update.Session); $UpdateSearcher = $UpdateSession.CreateUpdateSearcher(); $UpdateSearcher.ServerSelection = %d;", c.ServerSelection)
|
||||
var searcher string
|
||||
switch c := w.getServerInfo().Windows; c.ServerSelection {
|
||||
case 3: // https://learn.microsoft.com/en-us/windows/win32/wua_sdk/using-wua-to-scan-for-updates-offline
|
||||
searcher = fmt.Sprintf(`$UpdateSession = (New-Object -ComObject Microsoft.Update.Session); $UpdateServiceManager = (New-Object -ComObject Microsoft.Update.ServiceManager); $UpdateService = $UpdateServiceManager.AddScanPackageService("Offline Sync Service", "%s"); $UpdateSearcher = $UpdateSession.CreateUpdateSearcher(); $UpdateSearcher.ServerSelection = %d; $UpdateSearcher.ServiceID = $UpdateService.ServiceID;`, c.CabPath, c.ServerSelection)
|
||||
default:
|
||||
searcher = fmt.Sprintf("$UpdateSession = (New-Object -ComObject Microsoft.Update.Session); $UpdateSearcher = $UpdateSession.CreateUpdateSearcher(); $UpdateSearcher.ServerSelection = %d;", c.ServerSelection)
|
||||
}
|
||||
if r := w.exec(w.translateCmd(fmt.Sprintf(`%s $UpdateSearcher.search("IsInstalled = 1 and RebootRequired = 0 and Type='Software'").Updates | ForEach-Object -MemberName KBArticleIDs`, searcher)), noSudo); r.isSuccess() {
|
||||
kbs, err := w.parseWindowsUpdaterSearch(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Windows Update Search. err: %w", err)
|
||||
}
|
||||
|
||||
if r := o.exec(fmt.Sprintf(`%s $UpdateSearcher.search("IsInstalled = 1 and RebootRequired = 0 and Type='Software'").Updates | ForEach-Object -MemberName KBArticleIDs`, searcher), noSudo); r.isSuccess() {
|
||||
kbs, err := o.parseWindowsUpdaterSearch(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Windows Update Search. err: %w", err)
|
||||
}
|
||||
for _, kb := range kbs {
|
||||
applied[kb] = struct{}{}
|
||||
}
|
||||
}
|
||||
if r := o.exec(fmt.Sprintf(`%s $UpdateSearcher.search("IsInstalled = 0 and Type='Software'").Updates | ForEach-Object -MemberName KBArticleIDs`, searcher), noSudo); r.isSuccess() {
|
||||
kbs, err := o.parseWindowsUpdaterSearch(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Windows Update Search. err: %w", err)
|
||||
}
|
||||
for _, kb := range kbs {
|
||||
unapplied[kb] = struct{}{}
|
||||
}
|
||||
}
|
||||
if r := o.exec(fmt.Sprintf(`%s $UpdateSearcher.search("IsInstalled = 1 and RebootRequired = 1 and Type='Software'").Updates | ForEach-Object -MemberName KBArticleIDs`, searcher), noSudo); r.isSuccess() {
|
||||
kbs, err := o.parseWindowsUpdaterSearch(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Windows Update Search. err: %w", err)
|
||||
}
|
||||
for _, kb := range kbs {
|
||||
unapplied[kb] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if o.getServerInfo().Windows.ServerSelection == 3 {
|
||||
if r := o.exec(`$UpdateServiceManager = (New-Object -ComObject Microsoft.Update.ServiceManager); $UpdateServiceManager.Services | Where-Object {$_.Name -eq "Offline Sync Service"} | ForEach-Object { $UpdateServiceManager.RemoveService($_.ServiceID) };`, noSudo); !r.isSuccess() {
|
||||
return nil, xerrors.Errorf("Failed to remove Windows Update Offline Sync Service: %v", r)
|
||||
}
|
||||
for _, kb := range kbs {
|
||||
applied[kb] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if r := o.exec("$UpdateSearcher = (New-Object -ComObject Microsoft.Update.Session).CreateUpdateSearcher(); $HistoryCount = $UpdateSearcher.GetTotalHistoryCount(); $UpdateSearcher.QueryHistory(0, $HistoryCount) | Sort-Object -Property Date | Format-List -Property Title, Operation, ResultCode", noSudo); r.isSuccess() {
|
||||
kbs, err := o.parseWindowsUpdateHistory(r.Stdout)
|
||||
if r := w.exec(w.translateCmd(fmt.Sprintf(`%s $UpdateSearcher.search("IsInstalled = 0 and Type='Software'").Updates | ForEach-Object -MemberName KBArticleIDs`, searcher)), noSudo); r.isSuccess() {
|
||||
kbs, err := w.parseWindowsUpdaterSearch(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Windows Update Search. err: %w", err)
|
||||
}
|
||||
for _, kb := range kbs {
|
||||
unapplied[kb] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.exec(w.translateCmd(fmt.Sprintf(`%s $UpdateSearcher.search("IsInstalled = 1 and RebootRequired = 1 and Type='Software'").Updates | ForEach-Object -MemberName KBArticleIDs`, searcher)), noSudo); r.isSuccess() {
|
||||
kbs, err := w.parseWindowsUpdaterSearch(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Windows Update Search. err: %w", err)
|
||||
}
|
||||
for _, kb := range kbs {
|
||||
unapplied[kb] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
if w.getServerInfo().Windows.ServerSelection == 3 {
|
||||
if r := w.exec(w.translateCmd(`$UpdateServiceManager = (New-Object -ComObject Microsoft.Update.ServiceManager); $UpdateServiceManager.Services | Where-Object {$_.Name -eq "Offline Sync Service"} | ForEach-Object { $UpdateServiceManager.RemoveService($_.ServiceID) };`), noSudo); !r.isSuccess() {
|
||||
return nil, xerrors.Errorf("Failed to remove Windows Update Offline Sync Service: %v", r)
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.exec(w.translateCmd("$UpdateSearcher = (New-Object -ComObject Microsoft.Update.Session).CreateUpdateSearcher(); $HistoryCount = $UpdateSearcher.GetTotalHistoryCount(); $UpdateSearcher.QueryHistory(0, $HistoryCount) | Sort-Object -Property Date | Format-List -Property Title, Operation, ResultCode"), noSudo); r.isSuccess() {
|
||||
kbs, err := w.parseWindowsUpdateHistory(r.Stdout)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to parse Windows Update History. err: %w", err)
|
||||
}
|
||||
@@ -1160,7 +1188,7 @@ func (o *windows) scanKBs() (*models.WindowsKB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
kbs, err := DetectKBsFromKernelVersion(o.getDistro().Release, o.Kernel.Version)
|
||||
kbs, err := DetectKBsFromKernelVersion(w.getDistro().Release, w.Kernel.Version)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Failed to detect KBs from kernel version. err: %w", err)
|
||||
}
|
||||
@@ -1174,7 +1202,7 @@ func (o *windows) scanKBs() (*models.WindowsKB, error) {
|
||||
return &models.WindowsKB{Applied: maps.Keys(applied), Unapplied: maps.Keys(unapplied)}, nil
|
||||
}
|
||||
|
||||
func (o *windows) parseGetHotfix(stdout string) ([]string, error) {
|
||||
func (w *windows) parseGetHotfix(stdout string) ([]string, error) {
|
||||
var kbs []string
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(stdout))
|
||||
@@ -1194,7 +1222,7 @@ func (o *windows) parseGetHotfix(stdout string) ([]string, error) {
|
||||
return kbs, nil
|
||||
}
|
||||
|
||||
func (o *windows) parseGetPackageMSU(stdout string) ([]string, error) {
|
||||
func (w *windows) parseGetPackageMSU(stdout string) ([]string, error) {
|
||||
var kbs []string
|
||||
|
||||
kbIDPattern := regexp.MustCompile(`KB(\d{6,7})`)
|
||||
@@ -1218,7 +1246,7 @@ func (o *windows) parseGetPackageMSU(stdout string) ([]string, error) {
|
||||
return kbs, nil
|
||||
}
|
||||
|
||||
func (o *windows) parseWindowsUpdaterSearch(stdout string) ([]string, error) {
|
||||
func (w *windows) parseWindowsUpdaterSearch(stdout string) ([]string, error) {
|
||||
var kbs []string
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(stdout))
|
||||
@@ -1231,7 +1259,7 @@ func (o *windows) parseWindowsUpdaterSearch(stdout string) ([]string, error) {
|
||||
return kbs, nil
|
||||
}
|
||||
|
||||
func (o *windows) parseWindowsUpdateHistory(stdout string) ([]string, error) {
|
||||
func (w *windows) parseWindowsUpdateHistory(stdout string) ([]string, error) {
|
||||
kbs := map[string]struct{}{}
|
||||
|
||||
kbIDPattern := regexp.MustCompile(`KB(\d{6,7})`)
|
||||
@@ -4571,19 +4599,19 @@ func DetectKBsFromKernelVersion(release, kernelVersion string) (models.WindowsKB
|
||||
}
|
||||
}
|
||||
|
||||
func (o *windows) detectPlatform() {
|
||||
if o.getServerInfo().Mode.IsOffline() {
|
||||
o.setPlatform(models.Platform{Name: "unknown"})
|
||||
func (w *windows) detectPlatform() {
|
||||
if w.getServerInfo().Mode.IsOffline() {
|
||||
w.setPlatform(models.Platform{Name: "unknown"})
|
||||
return
|
||||
}
|
||||
|
||||
ok, instanceID, err := o.detectRunningOnAws()
|
||||
ok, instanceID, err := w.detectRunningOnAws()
|
||||
if err != nil {
|
||||
o.setPlatform(models.Platform{Name: "other"})
|
||||
w.setPlatform(models.Platform{Name: "other"})
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
o.setPlatform(models.Platform{
|
||||
w.setPlatform(models.Platform{
|
||||
Name: "aws",
|
||||
InstanceID: instanceID,
|
||||
})
|
||||
@@ -4591,40 +4619,40 @@ func (o *windows) detectPlatform() {
|
||||
}
|
||||
|
||||
//TODO Azure, GCP...
|
||||
o.setPlatform(models.Platform{Name: "other"})
|
||||
w.setPlatform(models.Platform{Name: "other"})
|
||||
}
|
||||
|
||||
func (o *windows) detectRunningOnAws() (bool, string, error) {
|
||||
if r := o.exec("Invoke-WebRequest -MaximumRetryCount 3 -TimeoutSec 1 -NoProxy http://169.254.169.254/latest/meta-data/instance-id", noSudo); r.isSuccess() {
|
||||
func (w *windows) detectRunningOnAws() (bool, string, error) {
|
||||
if r := w.exec(w.translateCmd("Invoke-WebRequest -MaximumRetryCount 3 -TimeoutSec 1 -NoProxy http://169.254.169.254/latest/meta-data/instance-id"), noSudo); r.isSuccess() {
|
||||
id := strings.TrimSpace(r.Stdout)
|
||||
if o.isAwsInstanceID(id) {
|
||||
if w.isAwsInstanceID(id) {
|
||||
return true, id, nil
|
||||
}
|
||||
}
|
||||
|
||||
if r := o.exec("Invoke-WebRequest -Method Put -MaximumRetryCount 3 -TimeoutSec 1 -NoProxy -Headers @{\"X-aws-ec2-metadata-token-ttl-seconds\"=\"300\"} http://169.254.169.254/latest/api/token", noSudo); r.isSuccess() {
|
||||
r := o.exec(fmt.Sprintf("Invoke-WebRequest -MaximumRetryCount 3 -TimeoutSec 1 -NoProxy -Headers @{\"X-aws-ec2-metadata-token\"=\"%s\"} http://169.254.169.254/latest/meta-data/instance-id", strings.TrimSpace(r.Stdout)), noSudo)
|
||||
if r := w.exec(w.translateCmd(`Invoke-WebRequest -Method Put -MaximumRetryCount 3 -TimeoutSec 1 -NoProxy -Headers @{"X-aws-ec2-metadata-token-ttl-seconds"="300"} http://169.254.169.254/latest/api/token`), noSudo); r.isSuccess() {
|
||||
r := w.exec(w.translateCmd(fmt.Sprintf(`Invoke-WebRequest -MaximumRetryCount 3 -TimeoutSec 1 -NoProxy -Headers @{"X-aws-ec2-metadata-token"="%s"} http://169.254.169.254/latest/meta-data/instance-id`, strings.TrimSpace(r.Stdout))), noSudo)
|
||||
if r.isSuccess() {
|
||||
id := strings.TrimSpace(r.Stdout)
|
||||
if !o.isAwsInstanceID(id) {
|
||||
if !w.isAwsInstanceID(id) {
|
||||
return false, "", nil
|
||||
}
|
||||
return true, id, nil
|
||||
}
|
||||
}
|
||||
|
||||
if r := o.exec("where.exe curl.exe", noSudo); r.isSuccess() {
|
||||
if r := o.exec("curl.exe --max-time 1 --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id", noSudo); r.isSuccess() {
|
||||
if r := w.exec("where.exe curl.exe", noSudo); r.isSuccess() {
|
||||
if r := w.exec("curl.exe --max-time 1 --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id", noSudo); r.isSuccess() {
|
||||
id := strings.TrimSpace(r.Stdout)
|
||||
if o.isAwsInstanceID(id) {
|
||||
if w.isAwsInstanceID(id) {
|
||||
return true, id, nil
|
||||
}
|
||||
}
|
||||
|
||||
if r := o.exec("curl.exe -X PUT --max-time 1 --noproxy 169.254.169.254 -H \"X-aws-ec2-metadata-token-ttl-seconds: 300\" http://169.254.169.254/latest/api/token", noSudo); r.isSuccess() {
|
||||
if r := o.exec(fmt.Sprintf("curl.exe -H \"X-aws-ec2-metadata-token: %s\" --max-time 1 --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id", strings.TrimSpace(r.Stdout)), noSudo); r.isSuccess() {
|
||||
if r := w.exec(`curl.exe -X PUT --max-time 1 --noproxy 169.254.169.254 -H "X-aws-ec2-metadata-token-ttl-seconds: 300" http://169.254.169.254/latest/api/token`, noSudo); r.isSuccess() {
|
||||
if r := w.exec(fmt.Sprintf(`curl.exe -H "X-aws-ec2-metadata-token: %s" --max-time 1 --noproxy 169.254.169.254 http://169.254.169.254/latest/meta-data/instance-id`, strings.TrimSpace(r.Stdout)), noSudo); r.isSuccess() {
|
||||
id := strings.TrimSpace(r.Stdout)
|
||||
if !o.isAwsInstanceID(id) {
|
||||
if !w.isAwsInstanceID(id) {
|
||||
return false, "", nil
|
||||
}
|
||||
return true, id, nil
|
||||
@@ -4632,5 +4660,5 @@ func (o *windows) detectRunningOnAws() (bool, string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return false, "", xerrors.Errorf("Failed to Invoke-WebRequest or curl.exe to AWS instance metadata on %s. container: %s", o.ServerInfo.ServerName, o.ServerInfo.Container.Name)
|
||||
return false, "", xerrors.Errorf("Failed to Invoke-WebRequest or curl.exe to AWS instance metadata on %s. container: %s", w.ServerInfo.ServerName, w.ServerInfo.Container.Name)
|
||||
}
|
||||
|
||||
@@ -306,20 +306,15 @@ SystemType : x64-based PC`,
|
||||
}
|
||||
|
||||
func Test_parseRegistry(t *testing.T) {
|
||||
type args struct {
|
||||
stdout string
|
||||
arch string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
args string
|
||||
want osInfo
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "happy",
|
||||
args: args{
|
||||
stdout: `
|
||||
args: `
|
||||
ProductName : Windows 10 Pro
|
||||
CurrentVersion : 6.3
|
||||
CurrentMajorVersionNumber : 10
|
||||
@@ -327,9 +322,10 @@ CurrentMinorVersionNumber : 0
|
||||
CurrentBuildNumber : 19044
|
||||
UBR : 2364
|
||||
EditionID : Professional
|
||||
InstallationType : Client`,
|
||||
arch: "AMD64",
|
||||
},
|
||||
InstallationType : Client
|
||||
|
||||
PROCESSOR_ARCHITECTURE : AMD64
|
||||
`,
|
||||
want: osInfo{
|
||||
productName: "Windows 10 Pro",
|
||||
version: "10.0",
|
||||
@@ -344,7 +340,7 @@ InstallationType : Client`,
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseRegistry(tt.args.stdout, tt.args.arch)
|
||||
got, err := parseRegistry(tt.args)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseRegistry() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user