big refactor and testing
This commit is contained in:
parent
a2ed11b2fb
commit
d6b1b90034
26 changed files with 908 additions and 70 deletions
|
|
@ -2,6 +2,6 @@ package patching
|
|||
|
||||
func PatchMgmnt(enable bool) error { return nil }
|
||||
|
||||
func GetWinUpdates() {}
|
||||
func GetUpdates() {}
|
||||
|
||||
func InstallUpdates(guids []string) {}
|
||||
func InstallUpdates(guids []string) {}
|
||||
|
|
|
|||
63
agent/patching/patching_test.go
Normal file
63
agent/patching/patching_test.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package patching_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/amidaware/rmmagent/agent/patching"
|
||||
)
|
||||
|
||||
func TestPatchMgmnt(t *testing.T) {
|
||||
testTable := []struct {
|
||||
name string
|
||||
expectedError error
|
||||
status bool
|
||||
}{
|
||||
{
|
||||
name: "Enable Patch Mgmnt",
|
||||
expectedError: nil,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Disable Patch Mgmnt",
|
||||
expectedError: nil,
|
||||
status: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testTable {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := patching.PatchMgmnt(tt.status)
|
||||
if err != tt.expectedError {
|
||||
t.Errorf("expected error (%v), got error (%v)", tt.expectedError, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUpdates(t *testing.T) {
|
||||
testTable := []struct {
|
||||
name string
|
||||
expectedError error
|
||||
atLeast int
|
||||
}{
|
||||
{
|
||||
name: "Get Updates",
|
||||
expectedError: nil,
|
||||
atLeast: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testTable {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := patching.GetUpdates()
|
||||
if !errors.Is(tt.expectedError, err) {
|
||||
t.Errorf("expected (%v), got (%v)", tt.expectedError, err)
|
||||
}
|
||||
|
||||
if len(result) < tt.atLeast {
|
||||
t.Errorf("expected at least %d, got %d", tt.atLeast, len(result))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
package patching
|
||||
|
||||
import "golang.org/x/sys/windows/registry"
|
||||
import (
|
||||
"github.com/amidaware/rmmagent/agent/patching/wua"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
// PatchMgmnt enables/disables automatic update
|
||||
// 0 - Enable Automatic Updates (Default)
|
||||
|
|
@ -25,4 +28,34 @@ func PatchMgmnt(enable bool) error {
|
|||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type PackageList []Package
|
||||
|
||||
func GetUpdates() (PackageList, error) {
|
||||
wuaupdates, err := wua.WUAUpdates("IsInstalled=1 or IsInstalled=0 and Type='Software' and IsHidden=0")
|
||||
packages := []Package{}
|
||||
for _, p := range wuaupdates {
|
||||
packages = append(packages, Package(p))
|
||||
}
|
||||
|
||||
return packages, err
|
||||
// if err != nil {
|
||||
// a.Logger.Errorln(err)
|
||||
// return
|
||||
// }
|
||||
|
||||
// for _, update := range updates {
|
||||
// a.Logger.Debugln("GUID:", update.UpdateID)
|
||||
// a.Logger.Debugln("Downloaded:", update.Downloaded)
|
||||
// a.Logger.Debugln("Installed:", update.Installed)
|
||||
// a.Logger.Debugln("KB:", update.KBArticleIDs)
|
||||
// a.Logger.Debugln("--------------------------------")
|
||||
// }
|
||||
|
||||
// payload := rmm.WinUpdateResult{AgentID: a.AgentID, Updates: updates}
|
||||
// _, err = a.rClient.R().SetBody(payload).Post("/api/v3/winupdates/")
|
||||
// if err != nil {
|
||||
// a.Logger.Debugln(err)
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
16
agent/patching/structs.go
Normal file
16
agent/patching/structs.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package patching
|
||||
|
||||
type Package struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Categories []string `json:"categories"`
|
||||
CategoryIDs []string `json:"category_ids"`
|
||||
KBArticleIDs []string `json:"kb_article_ids"`
|
||||
MoreInfoURLs []string `json:"more_info_urls"`
|
||||
SupportURL string `json:"support_url"`
|
||||
UpdateID string `json:"guid"`
|
||||
RevisionNumber int32 `json:"revision_number"`
|
||||
Severity string `json:"severity"`
|
||||
Installed bool `json:"installed"`
|
||||
Downloaded bool `json:"downloaded"`
|
||||
}
|
||||
33
agent/patching/wua/structs.go
Normal file
33
agent/patching/wua/structs.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package wua
|
||||
|
||||
import (
|
||||
ole "github.com/go-ole/go-ole"
|
||||
)
|
||||
|
||||
type WUAPackage struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Categories []string `json:"categories"`
|
||||
CategoryIDs []string `json:"category_ids"`
|
||||
KBArticleIDs []string `json:"kb_article_ids"`
|
||||
MoreInfoURLs []string `json:"more_info_urls"`
|
||||
SupportURL string `json:"support_url"`
|
||||
UpdateID string `json:"guid"`
|
||||
RevisionNumber int32 `json:"revision_number"`
|
||||
Severity string `json:"severity"`
|
||||
Installed bool `json:"installed"`
|
||||
Downloaded bool `json:"downloaded"`
|
||||
}
|
||||
|
||||
// IUpdateSession is a an IUpdateSession.
|
||||
type IUpdateSession struct {
|
||||
*ole.IDispatch
|
||||
}
|
||||
|
||||
type IUpdateCollection struct {
|
||||
*ole.IDispatch
|
||||
}
|
||||
|
||||
type IUpdate struct {
|
||||
*ole.IDispatch
|
||||
}
|
||||
437
agent/patching/wua/wua_windows.go
Normal file
437
agent/patching/wua/wua_windows.go
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
package wua
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
ole "github.com/go-ole/go-ole"
|
||||
"github.com/go-ole/go-ole/oleutil"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
S_OK = 0
|
||||
S_FALSE = 1
|
||||
)
|
||||
|
||||
var wuaSession sync.Mutex
|
||||
|
||||
func (s *IUpdateSession) Close() {
|
||||
if s.IDispatch != nil {
|
||||
s.IDispatch.Release()
|
||||
}
|
||||
|
||||
ole.CoUninitialize()
|
||||
wuaSession.Unlock()
|
||||
}
|
||||
|
||||
func NewUpdateSession() (*IUpdateSession, error) {
|
||||
wuaSession.Lock()
|
||||
if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil {
|
||||
e, ok := err.(*ole.OleError)
|
||||
// S_OK and S_FALSE are both are Success codes.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/learnwin32/error-handling-in-com
|
||||
if !ok || (e.Code() != S_OK && e.Code() != S_FALSE) {
|
||||
wuaSession.Unlock()
|
||||
return nil, fmt.Errorf(`ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED): %v`, err)
|
||||
}
|
||||
}
|
||||
|
||||
s := &IUpdateSession{}
|
||||
|
||||
unknown, err := oleutil.CreateObject("Microsoft.Update.Session")
|
||||
if err != nil {
|
||||
s.Close()
|
||||
return nil, fmt.Errorf(`oleutil.CreateObject("Microsoft.Update.Session"): %v`, err)
|
||||
}
|
||||
disp, err := unknown.QueryInterface(ole.IID_IDispatch)
|
||||
if err != nil {
|
||||
unknown.Release()
|
||||
s.Close()
|
||||
return nil, fmt.Errorf(`error creating Dispatch object from Microsoft.Update.Session connection: %v`, err)
|
||||
}
|
||||
s.IDispatch = disp
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// InstallWUAUpdate install a WIndows update.
|
||||
func (s *IUpdateSession) InstallWUAUpdate(updt *IUpdate) error {
|
||||
_, err := updt.GetProperty("Title")
|
||||
if err != nil {
|
||||
return fmt.Errorf(`updt.GetProperty("Title"): %v`, err)
|
||||
}
|
||||
|
||||
updts, err := NewUpdateCollection()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer updts.Release()
|
||||
|
||||
eula, err := updt.GetProperty("EulaAccepted")
|
||||
if err != nil {
|
||||
return fmt.Errorf(`updt.GetProperty("EulaAccepted"): %v`, err)
|
||||
}
|
||||
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-oaut/7b39eb24-9d39-498a-bcd8-75c38e5823d0
|
||||
if eula.Val == 0 {
|
||||
if _, err := updt.CallMethod("AcceptEula"); err != nil {
|
||||
return fmt.Errorf(`updt.CallMethod("AcceptEula"): %v`, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := updts.Add(updt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.DownloadWUAUpdateCollection(updts); err != nil {
|
||||
return fmt.Errorf("DownloadWUAUpdateCollection error: %v", err)
|
||||
}
|
||||
|
||||
if err := s.InstallWUAUpdateCollection(updts); err != nil {
|
||||
return fmt.Errorf("InstallWUAUpdateCollection error: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewUpdateCollection() (*IUpdateCollection, error) {
|
||||
updateCollObj, err := oleutil.CreateObject("Microsoft.Update.UpdateColl")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`oleutil.CreateObject("Microsoft.Update.UpdateColl"): %v`, err)
|
||||
}
|
||||
defer updateCollObj.Release()
|
||||
|
||||
updateColl, err := updateCollObj.IDispatch(ole.IID_IDispatch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &IUpdateCollection{IDispatch: updateColl}, nil
|
||||
}
|
||||
|
||||
func (c *IUpdateCollection) Add(updt *IUpdate) error {
|
||||
if _, err := c.CallMethod("Add", updt.IDispatch); err != nil {
|
||||
return fmt.Errorf(`IUpdateCollection.CallMethod("Add", updt): %v`, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *IUpdateCollection) RemoveAt(i int) error {
|
||||
if _, err := c.CallMethod("RemoveAt", i); err != nil {
|
||||
return fmt.Errorf(`IUpdateCollection.CallMethod("RemoveAt", %d): %v`, i, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *IUpdateCollection) Count() (int32, error) {
|
||||
return GetCount(c.IDispatch)
|
||||
}
|
||||
|
||||
func (c *IUpdateCollection) Item(i int) (*IUpdate, error) {
|
||||
updtRaw, err := c.GetProperty("Item", i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`IUpdateCollection.GetProperty("Item", %d): %v`, i, err)
|
||||
}
|
||||
return &IUpdate{IDispatch: updtRaw.ToIDispatch()}, nil
|
||||
}
|
||||
|
||||
// GetCount returns the Count property.
|
||||
func GetCount(dis *ole.IDispatch) (int32, error) {
|
||||
countRaw, err := dis.GetProperty("Count")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf(`IDispatch.GetProperty("Count"): %v`, err)
|
||||
}
|
||||
count, _ := countRaw.Value().(int32)
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (u *IUpdate) kbaIDs() ([]string, error) {
|
||||
kbArticleIDsRaw, err := u.GetProperty("KBArticleIDs")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`IUpdate.GetProperty("KBArticleIDs"): %v`, err)
|
||||
}
|
||||
kbArticleIDs := kbArticleIDsRaw.ToIDispatch()
|
||||
defer kbArticleIDs.Release()
|
||||
|
||||
count, err := GetCount(kbArticleIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var ss []string
|
||||
for i := 0; i < int(count); i++ {
|
||||
item, err := kbArticleIDs.GetProperty("Item", i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`kbArticleIDs.GetProperty("Item", %d): %v`, i, err)
|
||||
}
|
||||
|
||||
ss = append(ss, item.ToString())
|
||||
}
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func (u *IUpdate) categories() ([]string, []string, error) {
|
||||
catRaw, err := u.GetProperty("Categories")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf(`IUpdate.GetProperty("Categories"): %v`, err)
|
||||
}
|
||||
cat := catRaw.ToIDispatch()
|
||||
defer cat.Release()
|
||||
|
||||
count, err := GetCount(cat)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if count == 0 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
var cns, cids []string
|
||||
for i := 0; i < int(count); i++ {
|
||||
itemRaw, err := cat.GetProperty("Item", i)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf(`cat.GetProperty("Item", %d): %v`, i, err)
|
||||
}
|
||||
item := itemRaw.ToIDispatch()
|
||||
defer item.Release()
|
||||
|
||||
name, err := item.GetProperty("Name")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf(`item.GetProperty("Name"): %v`, err)
|
||||
}
|
||||
|
||||
categoryID, err := item.GetProperty("CategoryID")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf(`item.GetProperty("CategoryID"): %v`, err)
|
||||
}
|
||||
|
||||
cns = append(cns, name.ToString())
|
||||
cids = append(cids, categoryID.ToString())
|
||||
}
|
||||
return cns, cids, nil
|
||||
}
|
||||
|
||||
func (u *IUpdate) moreInfoURLs() ([]string, error) {
|
||||
moreInfoURLsRaw, err := u.GetProperty("MoreInfoURLs")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`IUpdate.GetProperty("MoreInfoURLs"): %v`, err)
|
||||
}
|
||||
moreInfoURLs := moreInfoURLsRaw.ToIDispatch()
|
||||
defer moreInfoURLs.Release()
|
||||
|
||||
count, err := GetCount(moreInfoURLs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var ss []string
|
||||
for i := 0; i < int(count); i++ {
|
||||
item, err := moreInfoURLs.GetProperty("Item", i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`moreInfoURLs.GetProperty("Item", %d): %v`, i, err)
|
||||
}
|
||||
|
||||
ss = append(ss, item.ToString())
|
||||
}
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func (c *IUpdateCollection) extractPkg(item int) (*WUAPackage, error) {
|
||||
updt, err := c.Item(item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer updt.Release()
|
||||
|
||||
title, err := updt.GetProperty("Title")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`updt.GetProperty("Title"): %v`, err)
|
||||
}
|
||||
|
||||
description, err := updt.GetProperty("Description")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`updt.GetProperty("Description"): %v`, err)
|
||||
}
|
||||
|
||||
kbArticleIDs, err := updt.kbaIDs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
categories, categoryIDs, err := updt.categories()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
moreInfoURLs, err := updt.moreInfoURLs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
supportURL, err := updt.GetProperty("SupportURL")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`updt.GetProperty("SupportURL"): %v`, err)
|
||||
}
|
||||
|
||||
identityRaw, err := updt.GetProperty("Identity")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`updt.GetProperty("Identity"): %v`, err)
|
||||
}
|
||||
identity := identityRaw.ToIDispatch()
|
||||
defer identity.Release()
|
||||
|
||||
revisionNumber, err := identity.GetProperty("RevisionNumber")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`identity.GetProperty("RevisionNumber"): %v`, err)
|
||||
}
|
||||
|
||||
updateID, err := identity.GetProperty("UpdateID")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`identity.GetProperty("UpdateID"): %v`, err)
|
||||
}
|
||||
|
||||
severity, err := updt.GetProperty("MsrcSeverity")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`updt.GetProperty("MsrcSeverity"): %v`, err)
|
||||
}
|
||||
|
||||
isInstalled, err := updt.GetProperty("IsInstalled")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`updt.GetProperty("IsInstalled"): %v`, err)
|
||||
}
|
||||
|
||||
isDownloaded, err := updt.GetProperty("IsDownloaded")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`updt.GetProperty("IsDownloaded"): %v`, err)
|
||||
}
|
||||
|
||||
return &WUAPackage{
|
||||
Title: title.ToString(),
|
||||
Description: description.ToString(),
|
||||
SupportURL: supportURL.ToString(),
|
||||
KBArticleIDs: kbArticleIDs,
|
||||
UpdateID: updateID.ToString(),
|
||||
Categories: categories,
|
||||
CategoryIDs: categoryIDs,
|
||||
MoreInfoURLs: moreInfoURLs,
|
||||
Severity: severity.ToString(),
|
||||
RevisionNumber: int32(revisionNumber.Val),
|
||||
Downloaded: isDownloaded.Value().(bool),
|
||||
Installed: isInstalled.Value().(bool),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WUAUpdates queries the Windows Update Agent API searcher with the provided query.
|
||||
func WUAUpdates(query string) ([]WUAPackage, error) {
|
||||
session, err := NewUpdateSession()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating NewUpdateSession: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
updts, err := session.GetWUAUpdateCollection(query)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error calling GetWUAUpdateCollection with query %q: %v", query, err)
|
||||
}
|
||||
defer updts.Release()
|
||||
|
||||
updtCnt, err := updts.Count()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if updtCnt == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var packages []WUAPackage
|
||||
for i := 0; i < int(updtCnt); i++ {
|
||||
pkg, err := updts.extractPkg(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packages = append(packages, *pkg)
|
||||
}
|
||||
return packages, nil
|
||||
}
|
||||
|
||||
// DownloadWUAUpdateCollection downloads all updates in a IUpdateCollection
|
||||
func (s *IUpdateSession) DownloadWUAUpdateCollection(updates *IUpdateCollection) error {
|
||||
// returns IUpdateDownloader
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/wuapi/nn-wuapi-iupdatedownloader
|
||||
downloaderRaw, err := s.CallMethod("CreateUpdateDownloader")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error calling method CreateUpdateDownloader on IUpdateSession: %v", err)
|
||||
}
|
||||
downloader := downloaderRaw.ToIDispatch()
|
||||
defer downloader.Release()
|
||||
|
||||
if _, err := downloader.PutProperty("Updates", updates.IDispatch); err != nil {
|
||||
return fmt.Errorf("error calling PutProperty Updates on IUpdateDownloader: %v", err)
|
||||
}
|
||||
|
||||
if _, err := downloader.CallMethod("Download"); err != nil {
|
||||
return fmt.Errorf("error calling method Download on IUpdateDownloader: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstallWUAUpdateCollection installs all updates in a IUpdateCollection
|
||||
func (s *IUpdateSession) InstallWUAUpdateCollection(updates *IUpdateCollection) error {
|
||||
// returns IUpdateInstallersession *ole.IDispatch,
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/wuapi/nf-wuapi-iupdatesession-createupdateinstaller
|
||||
installerRaw, err := s.CallMethod("CreateUpdateInstaller")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error calling method CreateUpdateInstaller on IUpdateSession: %v", err)
|
||||
}
|
||||
installer := installerRaw.ToIDispatch()
|
||||
defer installer.Release()
|
||||
|
||||
if _, err := installer.PutProperty("Updates", updates.IDispatch); err != nil {
|
||||
return fmt.Errorf("error calling PutProperty Updates on IUpdateInstaller: %v", err)
|
||||
}
|
||||
|
||||
// TODO: Look into using the async methods and attempt to track/log progress.
|
||||
if _, err := installer.CallMethod("Install"); err != nil {
|
||||
return fmt.Errorf("error calling method Install on IUpdateInstaller: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetWUAUpdateCollection queries the Windows Update Agent API searcher with the provided query
|
||||
// and returns a IUpdateCollection.
|
||||
func (s *IUpdateSession) GetWUAUpdateCollection(query string) (*IUpdateCollection, error) {
|
||||
// returns IUpdateSearcher
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa386515(v=vs.85).aspx
|
||||
searcherRaw, err := s.CallMethod("CreateUpdateSearcher")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error calling CreateUpdateSearcher: %v", err)
|
||||
}
|
||||
searcher := searcherRaw.ToIDispatch()
|
||||
defer searcher.Release()
|
||||
|
||||
// returns ISearchResult
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa386077(v=vs.85).aspx
|
||||
resultRaw, err := searcher.CallMethod("Search", query)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error calling method Search on IUpdateSearcher: %v", err)
|
||||
}
|
||||
result := resultRaw.ToIDispatch()
|
||||
defer result.Release()
|
||||
|
||||
// returns IUpdateCollection
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa386107(v=vs.85).aspx
|
||||
updtsRaw, err := result.GetProperty("Updates")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error calling GetProperty Updates on ISearchResult: %v", err)
|
||||
}
|
||||
|
||||
return &IUpdateCollection{IDispatch: updtsRaw.ToIDispatch()}, nil
|
||||
}
|
||||
39
agent/patching/wua/wua_windows_test.go
Normal file
39
agent/patching/wua/wua_windows_test.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package wua_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
wua "github.com/amidaware/rmmagent/agent/patching/wua"
|
||||
)
|
||||
|
||||
func TestWUAUpdates(t *testing.T) {
|
||||
testTable := []struct {
|
||||
name string
|
||||
expected []wua.WUAPackage
|
||||
atLeast int
|
||||
expectedError error
|
||||
query string
|
||||
}{
|
||||
{
|
||||
name: "Get WUA Updates",
|
||||
expected: []wua.WUAPackage{},
|
||||
atLeast: 1,
|
||||
expectedError: nil,
|
||||
query: "IsInstalled=1 or IsInstalled=0 and Type='Software' and IsHidden=0",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testTable {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := wua.WUAUpdates(tt.query)
|
||||
if len(result) < tt.atLeast {
|
||||
t.Errorf("expected at least %d, got %d", tt.atLeast, len(result))
|
||||
}
|
||||
|
||||
if !errors.Is(tt.expectedError, err) {
|
||||
t.Errorf("expected (%v), got (%v)", tt.expectedError, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue