364 lines
12 KiB
Go
364 lines
12 KiB
Go
/*
|
|
Copyright 2022 Zheng Dayu
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package windowsupdate
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/go-ole/go-ole"
|
|
"github.com/go-ole/go-ole/oleutil"
|
|
)
|
|
|
|
// IUpdate contains the properties and methods that are available to an update.
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdate
|
|
type IUpdate struct {
|
|
disp *ole.IDispatch
|
|
AutoSelectOnWebSites bool
|
|
BundledUpdates []*IUpdateIdentity
|
|
CanRequireSource bool
|
|
Categories []*ICategory
|
|
Deadline *time.Time
|
|
DeltaCompressedContentAvailable bool
|
|
DeltaCompressedContentPreferred bool
|
|
DeploymentAction int32 // enum https://docs.microsoft.com/en-us/windows/win32/api/wuapi/ne-wuapi-deploymentaction
|
|
Description string
|
|
DownloadContents []*IUpdateDownloadContent
|
|
DownloadPriority int32 // enum https://docs.microsoft.com/en-us/windows/win32/api/wuapi/ne-wuapi-downloadpriority
|
|
EulaAccepted bool
|
|
EulaText string
|
|
HandlerID string
|
|
Identity *IUpdateIdentity
|
|
Image *IImageInformation
|
|
InstallationBehavior *IInstallationBehavior
|
|
IsBeta bool
|
|
IsDownloaded bool
|
|
IsHidden bool
|
|
IsInstalled bool
|
|
IsMandatory bool
|
|
IsUninstallable bool
|
|
KBArticleIDs []string
|
|
Languages []string
|
|
LastDeploymentChangeTime *time.Time
|
|
MaxDownloadSize int64
|
|
MinDownloadSize int64
|
|
MoreInfoUrls []string
|
|
MsrcSeverity string
|
|
RecommendedCpuSpeed int32
|
|
RecommendedHardDiskSpace int32
|
|
RecommendedMemory int32
|
|
ReleaseNotes string
|
|
SecurityBulletinIDs []string
|
|
SupersededUpdateIDs []string
|
|
SupportUrl string
|
|
Title string
|
|
UninstallationBehavior *IInstallationBehavior
|
|
UninstallationNotes string
|
|
UninstallationSteps []string
|
|
}
|
|
|
|
func toIUpdates(updatesDisp *ole.IDispatch) ([]*IUpdate, error) {
|
|
count, err := toInt32Err(oleutil.GetProperty(updatesDisp, "Count"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
updates := make([]*IUpdate, 0, count)
|
|
for i := 0; i < int(count); i++ {
|
|
updateDisp, err := toIDispatchErr(oleutil.GetProperty(updatesDisp, "Item", i))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
update, err := toIUpdate(updateDisp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
updates = append(updates, update)
|
|
}
|
|
return updates, nil
|
|
}
|
|
|
|
// toIUpdates takes a IUpdateCollection and returns the a
|
|
// []*IUpdateIdentity of the contained IUpdates. This is *not* recursive, though possible should be
|
|
func toIUpdatesIdentities(updatesDisp *ole.IDispatch) ([]*IUpdateIdentity, error) {
|
|
if updatesDisp == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
count, err := toInt32Err(oleutil.GetProperty(updatesDisp, "Count"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identities := make([]*IUpdateIdentity, count)
|
|
for i := 0; i < int(count); i++ {
|
|
updateDisp, err := toIDispatchErr(oleutil.GetProperty(updatesDisp, "Item", i))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identityDisp, err := toIDispatchErr(oleutil.GetProperty(updateDisp, "Identity"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if identityDisp != nil {
|
|
if identities[i], err = toIUpdateIdentity(identityDisp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
return identities, nil
|
|
}
|
|
|
|
func toIUpdate(updateDisp *ole.IDispatch) (*IUpdate, error) {
|
|
var err error
|
|
iUpdate := &IUpdate{
|
|
disp: updateDisp,
|
|
}
|
|
|
|
if iUpdate.AutoSelectOnWebSites, err = toBoolErr(oleutil.GetProperty(updateDisp, "AutoSelectOnWebSites")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bundledUpdatesDisp, err := toIDispatchErr(oleutil.GetProperty(updateDisp, "BundledUpdates"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if bundledUpdatesDisp != nil {
|
|
if iUpdate.BundledUpdates, err = toIUpdatesIdentities(bundledUpdatesDisp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if iUpdate.CanRequireSource, err = toBoolErr(oleutil.GetProperty(updateDisp, "CanRequireSource")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
categoriesDisp, err := toIDispatchErr(oleutil.GetProperty(updateDisp, "Categories"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if categoriesDisp != nil {
|
|
if iUpdate.Categories, err = toICategories(categoriesDisp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if iUpdate.Deadline, err = toTimeErr(oleutil.GetProperty(updateDisp, "Deadline")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.DeltaCompressedContentAvailable, err = toBoolErr(oleutil.GetProperty(updateDisp, "DeltaCompressedContentAvailable")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.DeltaCompressedContentPreferred, err = toBoolErr(oleutil.GetProperty(updateDisp, "DeltaCompressedContentPreferred")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.DeploymentAction, err = toInt32Err(oleutil.GetProperty(updateDisp, "DeploymentAction")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.Description, err = toStringErr(oleutil.GetProperty(updateDisp, "Description")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
downloadContentsDisp, err := toIDispatchErr(oleutil.GetProperty(updateDisp, "DownloadContents"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if downloadContentsDisp != nil {
|
|
if iUpdate.DownloadContents, err = toIUpdateDownloadContents(downloadContentsDisp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if iUpdate.DownloadPriority, err = toInt32Err(oleutil.GetProperty(updateDisp, "DownloadPriority")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.EulaAccepted, err = toBoolErr(oleutil.GetProperty(updateDisp, "EulaAccepted")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.EulaText, err = toStringErr(oleutil.GetProperty(updateDisp, "EulaText")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.HandlerID, err = toStringErr(oleutil.GetProperty(updateDisp, "HandlerID")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
identityDisp, err := toIDispatchErr(oleutil.GetProperty(updateDisp, "Identity"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if identityDisp != nil {
|
|
if iUpdate.Identity, err = toIUpdateIdentity(identityDisp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
imageDisp, err := toIDispatchErr(oleutil.GetProperty(updateDisp, "Image"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if imageDisp != nil {
|
|
if iUpdate.Image, err = toIImageInformation(imageDisp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
installationBehaviorDisp, err := toIDispatchErr(oleutil.GetProperty(updateDisp, "InstallationBehavior"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if installationBehaviorDisp != nil {
|
|
if iUpdate.InstallationBehavior, err = toIInstallationBehavior(installationBehaviorDisp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if iUpdate.IsBeta, err = toBoolErr(oleutil.GetProperty(updateDisp, "IsBeta")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.IsDownloaded, err = toBoolErr(oleutil.GetProperty(updateDisp, "IsDownloaded")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.IsHidden, err = toBoolErr(oleutil.GetProperty(updateDisp, "IsHidden")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.IsInstalled, err = toBoolErr(oleutil.GetProperty(updateDisp, "IsInstalled")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.IsMandatory, err = toBoolErr(oleutil.GetProperty(updateDisp, "IsMandatory")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.IsUninstallable, err = toBoolErr(oleutil.GetProperty(updateDisp, "IsUninstallable")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.KBArticleIDs, err = iStringCollectionToStringArrayErr(toIDispatchErr(oleutil.GetProperty(updateDisp, "KBArticleIDs"))); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.Languages, err = iStringCollectionToStringArrayErr(toIDispatchErr(oleutil.GetProperty(updateDisp, "Languages"))); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.LastDeploymentChangeTime, err = toTimeErr(oleutil.GetProperty(updateDisp, "LastDeploymentChangeTime")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.MaxDownloadSize, err = toInt64Err(oleutil.GetProperty(updateDisp, "MaxDownloadSize")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.MinDownloadSize, err = toInt64Err(oleutil.GetProperty(updateDisp, "MinDownloadSize")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.MoreInfoUrls, err = iStringCollectionToStringArrayErr(toIDispatchErr(oleutil.GetProperty(updateDisp, "MoreInfoUrls"))); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.MsrcSeverity, err = toStringErr(oleutil.GetProperty(updateDisp, "MsrcSeverity")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.RecommendedCpuSpeed, err = toInt32Err(oleutil.GetProperty(updateDisp, "RecommendedCpuSpeed")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.RecommendedHardDiskSpace, err = toInt32Err(oleutil.GetProperty(updateDisp, "RecommendedHardDiskSpace")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.RecommendedMemory, err = toInt32Err(oleutil.GetProperty(updateDisp, "RecommendedMemory")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.ReleaseNotes, err = toStringErr(oleutil.GetProperty(updateDisp, "ReleaseNotes")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.SecurityBulletinIDs, err = iStringCollectionToStringArrayErr(toIDispatchErr(oleutil.GetProperty(updateDisp, "SecurityBulletinIDs"))); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.SupersededUpdateIDs, err = iStringCollectionToStringArrayErr(toIDispatchErr(oleutil.GetProperty(updateDisp, "SupersededUpdateIDs"))); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.SupportUrl, err = toStringErr(oleutil.GetProperty(updateDisp, "SupportUrl")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.Title, err = toStringErr(oleutil.GetProperty(updateDisp, "Title")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
uninstallationBehaviorDisp, err := toIDispatchErr(oleutil.GetProperty(updateDisp, "UninstallationBehavior"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if uninstallationBehaviorDisp != nil {
|
|
if iUpdate.UninstallationBehavior, err = toIInstallationBehavior(uninstallationBehaviorDisp); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if iUpdate.UninstallationNotes, err = toStringErr(oleutil.GetProperty(updateDisp, "UninstallationNotes")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if iUpdate.UninstallationSteps, err = iStringCollectionToStringArrayErr(toIDispatchErr(oleutil.GetProperty(updateDisp, "UninstallationSteps"))); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return iUpdate, nil
|
|
}
|
|
|
|
func toIUpdateCollection(updates []*IUpdate) (*ole.IDispatch, error) {
|
|
unknown, err := oleutil.CreateObject("Microsoft.Update.UpdateColl")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
coll, err := unknown.QueryInterface(ole.IID_IDispatch)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, update := range updates {
|
|
_, err := oleutil.CallMethod(coll, "Add", update.disp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return coll, nil
|
|
}
|
|
|
|
// AcceptEula accepts the Microsoft Software License Terms that are associated with Windows Update. Administrators and power users can call this method.
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdate-accepteula
|
|
func (iUpdate *IUpdate) AcceptEula() error {
|
|
_, err := oleutil.CallMethod(iUpdate.disp, "AcceptEula")
|
|
return err
|
|
}
|