ROIScan Vbs
ROIScan Vbs
'
'
'
'
'
Option Explicit
On Error Resume Next
Const SCRIPTBUILD = "1.6.3"
Dim sPathOutputFolder : sPathOutputFolder = ""
Dim fQuiet : fQuiet = False
Dim fLogFeatures : fLogFeatures = False
Dim fLogFull : fLogFull = False
dim fBasicMode : fBasicMode = False
Dim fLogChainedDetails : fLogChainedDetails = False
Dim fLogVerbose : fLogVerbose = False
Dim fListNonOfficeProducts : fListNonOfficeProducts = False
Dim fFileInventory : fFileInventory = False
Dim fFeatureTree : fFeatureTree = False
Dim fDisallowCScript : fDisallowCScript = False
'===============================================================================
========================
'[INI] Section for script behavior customizations
'Directory for Log output.
'Example: "\\<server>\<share>\"
'Default: sPathOutputFolder = vbNullString -> %temp% directory is used
sPathOutputFolder = ""
'Quiet switch.
'Default: False -> Open inventory log when done
fQuiet = False
'Basic Mode
'Generates a basic list of installed Office products with licensing information
only
'Disables all other extended analysis options
'Default: False -> Allow extended analysis options
fBasicMode = False
'Log full (verbose) details. This enables all possible scans for Office products
.
'Default: False -> Only list standard details
fLogFull = False
'Enables additional logging details
'like the "FeatureTree" display and
'the additional individual listing of the chained Office SKU's
'Default: False -> Do not log additional details
fLogVerbose = False
'Starting with Office 2007 a SKU can contain several .msi packages
'The default does not list the details for each chained package
'This option allows to show the full details for each chained package
'Default: Comprehensive view - do not show details for chained packages
fLogChainedDetails = False
Const VIS_2002
= "6D54-11D4-BEE3-00C04F990354}"
Const OFFICE_2002
= "6000-11D3-8CFE-0050048383C9}"
Const OFFICE_2003
= "6000-11D3-8CFE-0150048383C9}"
Const WSS2
= "7000-11D3-8CFE-0150048383C9}"
Const SPS_2003
= "BE5F-4ED1-A0F7-759D40C7622E}"
Const PPS_2007
= "CFDA-404E-8992-6AF153ED1719}" 'Project
Portfolio Server 2007
Const POWERPIVOT_2010
= "{72F8ECCE-DAB0-4C23-A471-625FEDABE323},
{A37E1318-29CA-4A9F-9CCA-D9BFDD61D17B}" 'UpgradeCode!
Const OFFICEID
= "000-0000000FF1CE}" 'cover O12, O14 with
32 & 64 bit
Const OREGREFC2R15
= "Microsoft Office 15"
Const PRODLEN
= 13
Const FOR_READING
= 1
Const FOR_WRITING
= 2
Const FOR_APPENDING
= 8
Const TRISTATE_USEDEFAULT
= -2 'Opens the file using the system defa
ult.
Const TRISTATE_TRUE
= -1 'Opens the file as Unicode.
Const TRISTATE_FALSE
= 0 'Opens the file as ASCII.
Const USERSID_EVERYONE
= "s-1-1-0"
Const MACHINESID
= ""
Const PRODUCTCODE_EMPTY
= ""
Const MSIOPENDATABASEMODE_READONLY
= 0
Const MSIOPENDATABASEMODE_PATCHFILE = 32
Const MSICOLUMNINFONAMES
= 0
Const MSICOLUMNINFOTYPES
= 1
'Summary Information fields
Const PID_TITLE
= 2 'Type of installer package. E.g. "Inst
allation Database" or "Transform" or "Patch"
Const PID_SUBJECT
= 3 'Displayname
Const PID_TEMPLATE
= 7 'compatible platform and language vers
ions for .msi / PatchTargets for .msp
Const PID_REVNUMBER
= 9 'PackageCode
Const PID_WORDCOUNT
= 15'InstallSource type
Const MSIPATCHSTATE_UNKNOWN
= -1 'Patch is in an unknown state to this
product instance.
Const MSIPATCHSTATE_APPLIED
= 1 'Patch is applied to this product inst
ance.
Const MSIPATCHSTATE_SUPERSEDED
= 2 'Patch is applied to this product inst
ance but is superseded.
Const MSIPATCHSTATE_OBSOLETED
= 4 'Patch is applied in this product inst
ance but obsolete.
Const MSIPATCHSTATE_REGISTERED
= 8 'The enumeration includes patches that
are registered but not yet applied.
Const MSIPATCHSTATE_ALL
= 15
Const MSIINSTALLCONTEXT_USERMANAGED = 1
Const MSIINSTALLCONTEXT_USERUNMANAGED = 2
Const MSIINSTALLCONTEXT_MACHINE
= 4
Const MSIINSTALLCONTEXT_ALL
= 7
Const MSIINSTALLCONTEXT_C2RV2
= 8 'C2r V2 virtualized context
Const MSIINSTALLMODE_DEFAULT
= 0
'Provide the component and perform
any installation necessary to provide the component.
Const MSIINSTALLMODE_EXISTING
= -1 'Provide the component only if the
feature exists. This option will verify that the assembly exists.
Const MSIINSTALLMODE_NODETECTION
= -2 'Provide the component only if the
feature exists. This option does not verify that the assembly exists.
Const MSIINSTALLMODE_NOSOURCERESOLUTION = -3 'Provides the assembly only if the
assembly is installed local.
Const MSIPROVIDEASSEMBLY_NET
= 0
'A .NET assembly.
Const MSIPROVIDEASSMBLY_WIN32
= 1
'A Win32 side-by-side assembly.
Const MSITRANSFORMERROR_ALL
= 319
'Installstates for products, features, components
Const INSTALLSTATE_NOTUSED
= -7 ' component disabled
Const INSTALLSTATE_BADCONFIG
= -6 ' configuration data corrupt
Const INSTALLSTATE_INCOMPLETE
= -5 ' installation suspended or in progr
ess
Const INSTALLSTATE_SOURCEABSENT
= -4 ' run from source, source is unavail
able
Const INSTALLSTATE_MOREDATA
= -3 ' return buffer overflow
Const INSTALLSTATE_INVALIDARG
= -2 ' invalid function argument. The pro
duct/feature is neither advertised or installed.
Const INSTALLSTATE_UNKNOWN
= -1 ' unrecognized product or feature
Const INSTALLSTATE_BROKEN
= 0 ' broken
Const INSTALLSTATE_ADVERTISED
= 1 'The product/feature is advertised but
not installed.
Const INSTALLSTATE_REMOVED
= 1 'The component is being removed (acti
on state, not settable)
Const INSTALLSTATE_ABSENT
= 2 'The product/feature is not installed.
Const INSTALLSTATE_LOCAL
= 3 'The product/feature/component is inst
alled.
Const INSTALLSTATE_SOURCE
= 4 'The product or feature is installed t
o run from source, CD, or network.
Const INSTALLSTATE_DEFAULT
= 5 'The product or feature will be instal
led to use the default location: local or source.
Const INSTALLSTATE_VIRTUALIZED
= 8 'The product is virtualized (C2R).
Const VERSIONCOMPARE_LOWER
= -1 'Left hand file version is lower than
right hand
Const VERSIONCOMPARE_MATCH
= 0 'File versions are identical
Const VERSIONCOMPARE_HIGHER
= 1 'Left hand file versin is higher than
right hand
Const VERSIONCOMPARE_INVALID
= 2 'Cannot compare. Invalid compare atte
mpt.
Const COPY_OVERWRITE
= &H10&
Const COPY_SUPPRESSERROR
= &H400&
Const HKEY_CLASSES_ROOT
= &H80000000
Const HKEY_CURRENT_USER
= &H80000001
Const HKEY_LOCAL_MACHINE
= &H80000002
Const HKEY_USERS
= &H80000003
Const HKCR
= &H80000000
Const HKCU
= &H80000001
Const HKLM
= &H80000002
Const HKU
= &H80000003
Const KEY_QUERY_VALUE
= &H0001
Const KEY_SET_VALUE
= &H0002
Const KEY_CREATE_SUB_KEY
= &H0004
Const DELETE
= &H00010000
Const REG_SZ
= 1
Const REG_EXPAND_SZ
= 2
Const REG_BINARY
= 3
Const REG_DWORD
= 4
Const REG_MULTI_SZ
= 7
Const REG_QWORD
= 11
Const REG_GLOBALCONFIG
= "SOFTWARE\Microsoft\Windows\CurrentVersi
on\Installer\UserData\"
Const REG_CONTEXTMACHINE
= "Installer\"
Const REG_CONTEXTUSER
= "Software\Microsoft\Installer\"
Const REG_CONTEXTUSERMANAGED
= "Software\Microsoft\Windows\CurrentVersi
on\Installer\Managed\"
Const REG_ARP
= "SOFTWARE\Microsoft\Windows\CurrentVersi
on\Uninstall\"
Const REG_C2RVIRT_HKLM
= "SOFTWARE\Microsoft\Office\15.0\ClickToR
un\REGISTRY\MACHINE\"
Const REG_C2RACTIVEPRODS
= "SOFTWARE\Microsoft\Office\15.0\ClickToR
un\ProductReleaseIDs\Active"
Const REG_C2RPROPERTYBAG
= "SOFTWARE\Microsoft\Office\15.0\ClickToR
un\propertyBag"
Const REG_C2RSCENARIO
= "SOFTWARE\Microsoft\Office\15.0\ClickToR
un\scenario"
Const GUID_UNCOMPRESSED
= 0
Const GUID_COMPRESSED
= 1
Const GUID_SQUISHED
= 2
Const LOGPOS_COMPUTER
= 0 '
ArrLogPosition 0: "Computer"
Const LOGPOS_REVITEM
= 1 '
ArrLogPosition 1: "Review Items"
Const LOGPOS_PRODUCT
= 2 '
ArrLogPosition 2: "Products Inven
tory"
Const LOGPOS_RAW
= 3 '
ArrLogPosition 3: "Raw Data"
Const LOGHEADING_NONE
= 0 '
Not a heading
Const LOGHEADING_H1
= 1 '
Heading 1 '='
Const LOGHEADING_H2
= 2 '
Heading 2 '-'
Const LOGHEADING_H3
= 3 '
Heading 3 ' '
Const TEXTINDENT
= "
"
Const CATEGORY
= 1
Const TAG
= 2
Const OSPP_ID = 0
Const OSPP_APPLICATIONID = 1
Const OSPP_PARTIALPRODUCTKEY = 2
Const OSPP_DESCRIPTION = 3
Const OSPP_NAME = 4
Const OSPP_LICENSESTATUS = 5
Const OSPP_LICENSESTATUSREASON = 6
Const OSPP_PRODUCTKEYID = 7
Const OSPP_GRACEPERIODREMAINING = 8
Const OSPP_LICENSEFAMILY = 9
Const OSPP_DISCOVEREDKEYMANAGEMENTSERVICEMACHINENAME = 10
Const OSPP_KEYMANAGEMENTSERVICEPORT = 11
Const OSPP_VLACTIVATIONINTERVAL = 12
Const OSPP_VLRENEWALINTERVAL = 13
'Arrays
Const UBOUND_LOGARRAYS
= 12
Const UBOUND_LOGCOLUMNS
= 30 ' Controlled by array with the most c
olumns
Redim arrLogFormat(UBOUND_LOGARRAYS,UBOUND_LOGCOLUMNS)
Const ARRAY_MASTER
= 0 'Master
Const UBOUND_MASTER
= 30
' ProductCode
Const COL_PRODUCTCODE
= 0
arrLogFormat(ARRAY_MASTER,COL_PRODUCTCODE)
' Msi ProductName
Const COL_PRODUCTNAME
= 1
arrLogFormat(ARRAY_MASTER,COL_PRODUCTNAME)
' UserSid
Const COL_USERSID
= 2
arrLogFormat(ARRAY_MASTER,COL_USERSID)
' ProductContext
Const COL_CONTEXTSTRING
= 3
arrLogFormat(ARRAY_MASTER,COL_CONTEXTSTRING)
data array id
= "ProductCode"
= "Msi ProductName"
= "UserSid"
= "ProductContext"
' ProductState
Const COL_STATESTRING
= 4
arrLogFormat(ARRAY_MASTER,COL_STATESTRING)
' ProductContext
Const COL_CONTEXT
= 5
arrLogFormat(ARRAY_MASTER,COL_CONTEXT)
' ProductState
Const COL_STATE
= 6
arrLogFormat(ARRAY_MASTER,COL_STATE)
' Arp SystemComponent
Const COL_SYSTEMCOMPONENT
= 7
arrLogFormat(ARRAY_MASTER,COL_SYSTEMCOMPONENT)
' Arp ParentCount
Const COL_ARPPARENTCOUNT
= 8
arrLogFormat(ARRAY_MASTER,COL_ARPPARENTCOUNT)
' Arp Parents
Const COL_ARPPARENTS
= 9
arrLogFormat(ARRAY_MASTER,COL_ARPPARENTS)
' Arp Productname
Const COL_ARPPRODUCTNAME
= 10
arrLogFormat(ARRAY_MASTER,COL_ARPPRODUCTNAME)
' ProductVersion
Const COL_PRODUCTVERSION
= 11
arrLogFormat(ARRAY_MASTER,COL_PRODUCTVERSION)
' ServicePack Level
Const COL_SPLEVEL
= 12
arrLogFormat(ARRAY_MASTER,COL_SPLEVEL)
' InstallDate
Const COL_INSTALLDATE
= 13
arrLogFormat(ARRAY_MASTER,COL_INSTALLDATE)
' Cached .msi
Const COL_CACHEDMSI
= 14
arrLogFormat(ARRAY_MASTER,COL_CACHEDMSI)
' Original .msi name
Const COL_ORIGINALMSI
= 15
arrLogFormat(ARRAY_MASTER,COL_ORIGINALMSI)
' Build/Origin Property
Const COL_ORIGIN
= 16
arrLogFormat(ARRAY_MASTER,COL_ORIGIN)
' ProductID Property
Const COL_PRODUCTID
= 17
arrLogFormat(ARRAY_MASTER,COL_PRODUCTID)
' Package Code
Const COL_PACKAGECODE
= 18
arrLogFormat(ARRAY_MASTER,COL_PACKAGECODE)
' Transform
Const COL_TRANSFORMS
= 19
arrLogFormat(ARRAY_MASTER,COL_TRANSFORMS)
' Architecture
Const COL_ARCHITECTURE
= 20
arrLogFormat(ARRAY_MASTER,COL_ARCHITECTURE)
' Error
Const COL_ERROR
= 21
arrLogFormat(ARRAY_MASTER,COL_ERROR)
' Notes
Const COL_NOTES
= 22
arrLogFormat(ARRAY_MASTER,COL_NOTES)
' MetadataState
Const COL_METADATASTATE
= 23
arrLogFormat(ARRAY_MASTER,COL_METADATASTATE)
= "ProductState"
= "ProductContext"
= "ProductState"
= "Arp SystemComponent"
= "Arp ParentCount"
= "Configuration SKU"
= "ARP ProductName"
= "ProductVersion"
= "ServicePack Level"
= "InstallDate"
= "Cached .msi Package"
= "Original .msi Name"
= "Build/Origin"
= "ProductID (MSI)"
= "Package Code"
= "Transforms"
= "Architecture"
= "Errors"
= "Notes"
= "MetadataState"
' IsOfficeProduct
Const COL_ISOFFICEPRODUCT
= 24
arrLogFormat(ARRAY_MASTER,COL_ISOFFICEPRODUCT)
' PatchFamily
Const COL_PATCHFAMILY
= 25
arrLogFormat(ARRAY_MASTER,COL_PATCHFAMILY)
' OSPP License
Const COL_OSPPLICENSE
= 26
arrLogFormat(ARRAY_MASTER,COL_OSPPLICENSE)
Const COL_OSPPLICENSEXML
= 27
arrLogFormat(ARRAY_MASTER, COL_OSPPLICENSEXML)
' UpgradeCode
Const COL_UPGRADECODE
= 28
arrLogFormat(ARRAY_MASTER,COL_UPGRADECODE)
' Virtualized
Const COL_VIRTUALIZED
= 29
arrLogFormat(ARRAY_MASTER,COL_VIRTUALIZED)
' InstallType
Const COL_INSTALLTYPE
= 30
arrLogFormat(ARRAY_MASTER,COL_INSTALLTYPE)
= "IsOfficeProduct"
= "PatchFamily"
= "OSPP License"
= "OSPP License XML"
= "UpgradeCode"
= "Virtualized"
= "InstallType"
Const ARRAY_PATCH
= 1 'Patch data array id
Const PATCH_COLUMNCOUNT
= 14
Const PATCH_LOGSTART
= 1
Const PATCH_LOGCHAINEDMAX
= 8
Const PATCH_LOGMAX
= 11
' Product
Const PATCH_PRODUCT
= 0
arrLogFormat(ARRAY_PATCH,PATCH_PRODUCT)
= "Patched Product: "
' KB
Const PATCH_KB
= 1
arrLogFormat(ARRAY_PATCH,PATCH_KB)
= "KB: "
' PackageName
Const PATCH_PACKAGE
= 3
arrLogFormat(ARRAY_PATCH,PATCH_PACKAGE)
= "Package: "
' PatchState
Const PATCH_PATCHSTATE
= 2
arrLogFormat(ARRAY_PATCH,PATCH_PATCHSTATE)
= "State: "
' Sequence
Const PATCH_SEQUENCE
= 4
arrLogFormat(ARRAY_PATCH,PATCH_SEQUENCE)
= "Sequence: "
' Uninstallable
Const PATCH_UNINSTALLABLE
= 5
arrLogFormat(ARRAY_PATCH,PATCH_UNINSTALLABLE) = "Uninstallable: "
' InstallDate
Const PATCH_INSTALLDATE
= 6
arrLogFormat(ARRAY_PATCH,PATCH_INSTALLDATE)
= "InstallDate: "
' PatchCode
Const PATCH_PATCHCODE
= 7
arrLogFormat(ARRAY_PATCH,PATCH_PATCHCODE)
= "PatchCode: "
' LocalPackage
Const PATCH_LOCALPACKAGE
= 8
arrLogFormat(ARRAY_PATCH,PATCH_LOCALPACKAGE) = "LocalPackage: "
' PatchTransform
Const PATCH_TRANSFORM
= 9
arrLogFormat(ARRAY_PATCH,PATCH_TRANSFORM)
= "PatchTransform: "
' DisplayName
Const PATCH_DISPLAYNAME
= 10
arrLogFormat(ARRAY_PATCH,PATCH_DISPLAYNAME)
= "DisplayName: "
' MoreInfoUrl
Const PATCH_MOREINFOURL
= 11
arrLogFormat(ARRAY_PATCH,PATCH_MOREINFOURL)
' Client side patch or patched AIP
Const PATCH_CSP
= 12
arrLogFormat(ARRAY_PATCH,PATCH_CSP)
' Local .msp package OK/available
Const PATCH_CPOK
= 13
arrLogFormat(ARRAY_PATCH,PATCH_CPOK)
= "MoreInfoUrl: "
= "ClientSidePatch: "
= "CachedMspOK: "
' arrMsp(MSPDEFAULT,MSP_COLUMNCOUNT)
Const ARRAY_MSPFILES
= 10
Const MSPFILES_COLUMNCOUNT
= 18
Const MSPFILES_LOGMAX
= 9
' Product
Const MSPFILES_TARGETS
= 0
arrLogFormat(ARRAY_MSPFILES,MSPFILES_TARGETS)
' KB
Const MSPFILES_KB
= 1
arrLogFormat(ARRAY_MSPFILES,MSPFILES_KB)
' PackageName
Const MSPFILES_PACKAGE
= 2
arrLogFormat(ARRAY_MSPFILES,MSPFILES_PACKAGE)
' Family
Const MSPFILES_FAMILY
= 3
arrLogFormat(ARRAY_MSPFILES,MSPFILES_FAMILY)
' Sequence
Const MSPFILES_SEQUENCE
= 4
arrLogFormat(ARRAY_MSPFILES,MSPFILES_SEQUENCE)
' PatchState
Const MSPFILES_PATCHSTATE
= 5
arrLogFormat(ARRAY_MSPFILES,MSPFILES_PATCHSTATE)
' Uninstallable
Const MSPFILES_UNINSTALLABLE
= 6
arrLogFormat(ARRAY_MSPFILES,MSPFILES_UNINSTALLABLE)
' InstallDate
Const MSPFILES_INSTALLDATE
= 7
arrLogFormat(ARRAY_MSPFILES,MSPFILES_INSTALLDATE)
' DisplayName
Const MSPFILES_DISPLAYNAME
= 8
arrLogFormat(ARRAY_MSPFILES,MSPFILES_DISPLAYNAME)
' MoreInfoUrl
Const MSPFILES_MOREINFOURL
= 9
arrLogFormat(ARRAY_MSPFILES,MSPFILES_MOREINFOURL)
' PatchCode
Const MSPFILES_PATCHCODE
= 10
arrLogFormat(ARRAY_MSPFILES,MSPFILES_PATCHCODE)
' LocalPackage
Const MSPFILES_LOCALPACKAGE
= 11
arrLogFormat(ARRAY_MSPFILES,MSPFILES_LOCALPACKAGE)
' Bucket
Const MSPFILES_BUCKET
= 12
arrLogFormat(ARRAY_MSPFILES,MSPFILES_BUCKET)
' Attribute msidbPatchSequenceSupersedeEarlier
Const MSPFILES_ATTRIBUTE
= 14
arrLogFormat(ARRAY_MSPFILES,MSPFILES_ATTRIBUTE)
persedeEarlier: "
' PatchTransform
Const MSPFILES_TRANSFORM
= 14
arrLogFormat(ARRAY_MSPFILES,MSPFILES_TRANSFORM)
' PatchXml
= "PatchTransform: "
Const MSPFILES_XML
= 15
arrLogFormat(ARRAY_MSPFILES,MSPFILES_XML)
' PatchTables
Const MSPFILES_TABLES
= 16
arrLogFormat(ARRAY_MSPFILES,MSPFILES_TABLES)
' Local .msp package OK/available
Const MSPFILES_CPOK
= 17
arrLogFormat(ARRAY_MSPFILES,MSPFILES_CPOK)
= "PatchXml: "
= "PatchTables: "
= "CachedMspOK: "
Const ARRAY_AIPPATCH
= 11
Const AIPPATCH_COLUMNCOUNT
= 3
' Product
Const AIPPATCH_PRODUCT
= 0
arrLogFormat(ARRAY_AIPPATCH,AIPPATCH_PRODUCT) = "Patched Product: "
' PatchCode
Const AIPPATCH_PATCHCODE
= 1
arrLogFormat(ARRAY_AIPPATCH,AIPPATCH_PATCHCODE)= "PatchCode: "
' DisplayName
Const AIPPATCH_DISPLAYNAME
= 3
arrLogFormat(ARRAY_AIPPATCH,AIPPATCH_DISPLAYNAME)= "DisplayName: "
Const ARRAY_FEATURE
Const FEATURE_COLUMNCOUNT
Const FEATURE_PRODUCTCODE
Const FEATURE_TREE
=
=
=
=
Const ARRAY_ARP
= 4 'Add/remove products data array id
Const ARP_CHILDOFFSET
= 6
' Config Productcode
Const ARP_CONFIGPRODUCTCODE
= 0
arrLogFormat(ARRAY_ARP,ARP_CONFIGPRODUCTCODE) = "Config ProductCode"
' Config Productname
Const COL_CONFIGNAME
= 1
arrLogFormat(ARRAY_ARP,COL_CONFIGNAME)
= "Config ProductName"
' Config ProductVersion
Const ARP_PRODUCTVERSION
= 2
arrLogFormat(ARRAY_ARP,ARP_PRODUCTVERSION)
= "ProductVersion"
' Config InstallType
Const COL_CONFIGINSTALLTYPE
= 3
arrLogFormat(ARRAY_ARP,COL_CONFIGINSTALLTYPE) = "Config InstallType"
' Config PackageID
Const COL_CONFIGPACKAGEID
= 4
arrLogFormat(ARRAY_ARP,COL_CONFIGPACKAGEID)
= "Config PackageID"
Const COL_ARPALLPRODUCTS
= 5
Const COL_LBOUNDCHAINLIST
= 6
Const ARRAY_IS
= 5 ' MSI InstallSource data array id
Const UBOUND_IS
= 6
Const IS_LOG_LBOUND
= 2
Const IS_LOG_UBOUND
= 6
Const IS_PRODUCTCODE
= 0
Const IS_SOURCETYPE
= 1
Const IS_SOURCETYPESTRING
= 2
arrLogFormat(ARRAY_IS,IS_SOURCETYPESTRING)
= "InstallSource Type"
Const IS_ORIGINALSOURCE
= 3
arrLogFormat(ARRAY_IS,IS_ORIGINALSOURCE)
= "Initially Used Source"
Const IS_LASTUSEDSOURCE
= 4
arrLogFormat(ARRAY_IS,IS_LASTUSEDSOURCE)
= "Last Used Source"
Const IS_LISRESILIENCY
= 5
arrLogFormat(ARRAY_IS,IS_LISRESILIENCY)
= "LIS Resiliency Sources"
Const IS_ADDITIONALSOURCES
= 6
arrLogFormat(ARRAY_IS,IS_ADDITIONALSOURCES)
= "Network Sources"
Const ARRAY_VIRTPROD
= 6 ' Non MSI based virtualized products
Const UBOUND_VIRTPROD
= 8
' Productcode
arrLogFormat(ARRAY_VIRTPROD, COL_PRODUCTCODE)
= "ProductCode"
' Productname
arrLogFormat(ARRAY_VIRTPROD, COL_PRODUCTNAME)
= "ProductName"
' ConfigName
Const VIRTPROD_CONFIGNAME
= 2
arrLogFormat(ARRAY_VIRTPROD, VIRTPROD_CONFIGNAME) = "Config ProductName"
' ProductVersion
Const VIRTPROD_PRODUCTVERSION = 3
arrLogFormat(ARRAY_VIRTPROD, VIRTPROD_PRODUCTVERSION) = "ProductVersion"
' Service Pack Level
Const VIRTPROD_SPLEVEL
= 4
arrLogFormat(ARRAY_VIRTPROD, VIRTPROD_SPLEVEL)
= "ServicePack Level"
' Architecture
Const VIRTPROD_BITNESS
= 5
arrLogFormat(ARRAY_VIRTPROD, VIRTPROD_BITNESS)
= "Architecture"
' (O)SPP License
Const VIRTPROD_OSPPLICENSE
= 6
arrLogFormat(ARRAY_VIRTPROD, VIRTPROD_OSPPLICENSE) = "OSPP License"
' (O)SPP License XML
Const VIRTPROD_OSPPLICENSEXML = 7
arrLogFormat(ARRAY_VIRTPROD, VIRTPROD_OSPPLICENSEXML) = "OSPP License XML"
' Child Packages
Const VIRTPROD_CHILDPACKAGES
= 8
arrLogFormat(ARRAY_VIRTPROD, VIRTPROD_CHILDPACKAGES) = "Child Packages"
Const CSV
= ", "
Const DSV
= " - "
Const DOT
= ". "
Const ERR_CATEGORYNOTE
= "Note: "
Const ERR_CATEGORYWARN
= "Warning: "
Const ERR_CATEGORYERROR
= "Error: "
Const ERR_NONADMIN
= "The script appears to run outside admin
istrator context"
Const ERR_NONELEVATED
= "The script does not appear to run eleva
ted"
Const ERR_DATAINTEGRITY
= "A script internal error occurred. The i
ntegrity of the logged data might be affected"
Const ERR_OBJPRODUCTINFO
= "Installer.ProductInfo -> "
Const ERR_INITSUMINFO
= "Could not connect to summary informatio
n stream"
Const ERR_NOARRAY
= "Array check failed"
Const ERR_UNKNOWNHANDLER
= "Unknown Error Handler: '"
Const ERR_PRODUCTSEXALL
= "ProductsEx for MSIINSTALLCONTEXT_ALL fa
iled"
Const ERR_PATCHESEX
= "PatchesEx failed to get a list of patch
es for: "
Const ERR_PATCHES
= "Installer.Patches failed to get a list
of patches"
Const ERR_MISSINGCHILD
= "A chained product is missing which brea
ks the ability to maintain or uninstall this product. "
Const ERR_ORPHANEDITEM
= "Office application without entry point
in Add/Remove Programs"
Const ERR_INVALIDPRODUCTCODE
= "Critical Windows Installer metadata cor
ruption detected 'Invalid ProductCode'"
Const ERR_INVALIDGUID
= "GUID validation failed"
Const ERR_INVALIDGUIDCHAR
= "Guid contains invalid character(s)"
Const ERR_INVALIDGUIDLENGTH
= "Invalid length for GUID "
Const ERR_GUIDCASE
= "Guid contains lower case character(s)"
Const ERR_BADARPMETADATA
= "Crititcal ARP metadata corruption detec
ted in key: "
Const ERR_OFFSCRUB_TERMINATED
= "Bad ARP metadata. This can be caused by
an OffScrub run that was terminated before it could complete:"
Const ERR_ARPENTRYMISSING
= "Expected regkey not present for ARP con
fig parent"
Const ERR_REGKEYMISSING
= "Regkey does not exist: "
Const ERR_CUSTOMSTACKCORRUPTION
= "Custom stack list string corrupted"
Const ERR_BADMSPMETADATA
= "Metadata mismatch for patch registratio
n"
Const ERR_BADMSINAMEMETADATA
= "Failed to retrieve value for original .
msi name"
Const ERR_BADPACKAGEMETADATA
= "Failed to retrieve value for cached .ms
i package"
Const ERR_PACKAGEAPIFAILURE
= "API failed to retrieve value for cached
.msi package"
Const ERR_BADPACKAGECODEMETADATA
= "Failed to retrieve value for Package Co
de"
Const ERR_PACKAGECODEMISMATCH
= "PackageCode mismatch between registered
value and cached .msi"
Const ERR_LOCALPACKAGEMISSING
= "Local cached .msi appears to be missing
"
Const ERR_BADTRANSFORMSMETADATA
= "Failed to retrieve value for Transforms
"
Const ERR_SICONNECTFAILED
= "Failed to connect to SummaryInformation
stream"
Const ERR_MSPOPENFAILED
= "OpenDatabase failed to open .msp file "
Const ERR_MSIOPENFAILED
= "OpenDatabase failed to open .msi file "
Const ERR_BADFILESTATE
= " has unexpected file state(s). "
Const ERR_FILEVERSIONLOW
= "Review file versions for product "
Const BPA_WIMETADATA
= "This indicates WI metadadata corruption
"
Const BPA_GUID
= "For details on 'GUID' see http://msdn.m
icrosoft.com/en-us/library/Aa368767.aspx"
Const BPA_PACKAGECODE
= "For details on 'Package Codes' see http
://msdn.microsoft.com/en-us/library/aa370568.aspx"
Const BPA_PRODUCTCODE
= "For details on 'Product Codes' see http
://msdn.microsoft.com/en-us/library/aa370860.aspx"
Const BPA_PACKAGECODEMISMATCH
= "A mismatch of the PackageCode will forc
e the Windows Installer to recache the local .msi from the InstallSource. For de
tails on 'Package Code' see http://msdn2.microsoft.com/en-us/library/aa370568.as
px"
'===============================================================================
========================
Main
'===============================================================================
========================
'Module Main
'===============================================================================
========================
Sub Main
Dim fCheckPreReq, FsoLogFile, FsoXmlLogFile
'CheckPreReq needs to be the first thing.
On Error Resume Next
PrepareLog sLogFormat
' Write the output file
If fCScript AND NOT fQuiet Then wscript.echo "Stage 11 of 11: Write log"
WriteLog
Set FsoLogFile = oFso.GetFile(sLogFile)
Set FsoXmlLogFile = oFso.GetFile(sPathOutputFolder & sComputerName & "_ROISc
an.xml")
If fFileInventory Then
If (oFso.FileExists(sPathOutputFolder & sComputerName & "_ROIScan.zip")
AND NOT fZipError) Then
CopyToZip ShellApp.NameSpace(sPathOutputFolder & sComputerName & "_R
OIScan.zip"), FsoLogFile
CopyToZip ShellApp.NameSpace(sPathOutputFolder & sComputerName & "_R
OIScan.zip"), FsoXmlLogFile
End If
End If
If fCScript AND NOT fQuiet Then wscript.echo "Done!"
' Open the output file
If Not fQuiet Then
Set oShell = CreateObject("WScript.Shell")
If fFileInventory Then
If oFso.FileExists(sPathOutputFolder & sComputerName & "_ROIScan.zip
") AND NOT fZipError Then
oShell.Run "explorer /e," & chr(34) & sPathOutputFolder&sCompute
rName & "_ROIScan.zip" & chr(34)
Else
oShell.Run "explorer /e," & chr(34) & sPathOutputFolder & "ROISc
an" & chr(34)
End If
End If 'fFileInventory
oShell.Run chr(34) & sLogFile & chr(34)
Set oShell = Nothing
End If 'fQuiet
' Clear up Objects
CleanUp
End Sub
'===============================================================================
========================
'Initialize defaults, setting and collect current user information
Sub Initialize
Dim oApp, oWmiLocal, Process, Processes
Dim sEnvVar, Argument
Dim iPopup, iInstanceCnt
Dim fPrompt
On Error Resume Next
'Ensure there's only a single instance running of this script
iInstanceCnt = 0
Set oWmiLocal = GetObject("winmgmts:\\.\root\cimv2")
wscript.sleep 500
Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process")
For Each Process in Processes
If LCase(Mid(Process.Name,2,6))="script" Then
If InStr(LCase(Process.CommandLine),"roiscan")>0 AND NOT InStr(Proce
ss.CommandLine," UAC") > 0 Then iInstanceCnt=iInstanceCnt+1
End If
Next 'Process
If iInstanceCnt>1 Then
If NOT fQuiet Then wscript.echo "Error: Another instance of this script
is already running."
wscript.quit
End If
If Left(sPathOutputFolder,1)="%" Then
sEnvVar = oShell.ExpandEnvironmentStrings(Mid(sPathOutputFolder,1,InStr(
2,sPathOutputFolder,"%")))
If Len(sPathOutputFolder) = InStr(2,sPathOutputFolder,"%") Then
sPathOutputFolder = sEnvVar
Else
sPathOutputFolder = sEnvVar & Mid(sPathOutputFolder,InStr(2,sPathOu
tputFolder,"%")+1,Len(sPathOutputFolder))
End If
ElseIf Trim(UCase(sPathOutputFolder)) = "DESKTOP" Then
Set oApp = CreateObject ("Shell.Application")
Const DESKTOP = &H10&
sPathOutputFolder = oApp.Namespace(DESKTOP).Self.Path
Set oApp = Nothing
ElseIf InStr(":\",Mid(sPathOutputFolder,2,1))>0 Then
'Validate Folder exists
If Not oFso.FolderExists(sPathOutputFolder) Then sPathOutputFolder = oSh
ell.ExpandEnvironmentStrings("%TEMP%")
Else
sPathOutputFolder = oShell.ExpandEnvironmentStrings("%TEMP%")
End If
sPathOutputFolder = oFso.GetAbsolutePathName(sPathOutputFolder)
While Right(sPathOutputFolder,1) = "\"
sPathOutputFolder = Left(sPathOutputFolder,Len(sPathOutputFolder)-1)
Wend
If Not Right(sPathOutputFolder,1) = "\" Then sPathOutputFolder = sPathOutput
Folder & "\"
If Not oFso.FolderExists(sPathOutputFolder) Then sPathOutputFolder = oShell.
ExpandEnvironmentStrings("%TEMP%") & "\"
sLogFile = sPathOutputFolder & sComputerName & "_ROIScan.log"
CacheLog LOGPOS_COMPUTER,LOGHEADING_H1,Null,"Computer"
CacheLog LOGPOS_REVITEM,LOGHEADING_H1,Null,"Review Items"
'CacheLog LOGPOS_PRODUCT,LOGHEADING_H1,Null,"Products Inventory"
CacheLog LOGPOS_RAW,LOGHEADING_H1,Null,"Raw Data"
iPopup = -1
fPrompt = True
If Wscript.Arguments.Count > 0 Then
For Each Argument in Wscript.Arguments
If Argument = "UAC" Then fPrompt = False
Next 'Argument
End If
'Add warning to log if non-admin was detected
If Not fIsAdmin Then
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,ERR_NONADMIN
If NOT fQuiet AND fPrompt Then RelaunchElevated
End If
If fIsAdmin AND (NOT fIsElevated) Then
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,ERR_NONELEVATE
D
If NOT fQuiet AND fPrompt Then RelaunchElevated
End If
'Ensure CScript as engine
If (NOT UCase(Mid(Wscript.FullName, Len(Wscript.Path) + 2, 1)) = "C") AND (N
OT fDisallowCScript) Then RelaunchAsCScript
'Check on 64 bit OS -> see CheckPreReq
'Init sCurUserSid
GetUserSids("Current")
'Init "arrUUSids"
Redim arrUUSids(-1)
GetUserSids("UserUnmanaged")
'Init "arrUMSids"
Redim arrUMSids(-1)
GetUserSids("UserManaged")
'Set defaults for ProductList arrays
InitPLArrays
Set dicMspIndex = CreateObject("Scripting.Dictionary")
bOsppInit = False
'Other defaults
Set dicPatchLevel = CreateObject("Scripting.Dictionary")
Set dicScenario = CreateObject("Scripting.Dictionary")
fZipError = False
fInitArrProdVer = False
End Sub 'Initialize
'===============================================================================
========================
'End Of Main Module
'===============================================================================
========================
'Module LicenseState (OSPP)
'===============================================================================
========================
Sub OsppInit
On Error Resume Next
Dim oWmiLocal
Set oWmiLocal = GetObject("winmgmts:\\.\root\cimv2")
If iVersionNt > 601 Then
Set Spp = oWmiLocal.ExecQuery("SELECT ID, ApplicationId, PartialProductK
ey, Description, Name, LicenseStatus, LicenseStatusReason, ProductKeyID, GracePe
riodRemaining, LicenseFamily, DiscoveredKeyManagementServiceMachineName, KeyMana
gementServicePort, VLActivationInterval, VLRenewalInterval FROM SoftwareLicensin
gProduct")
End If
Set Ospp = oWmiLocal.ExecQuery("SELECT ID, ApplicationId, PartialProductKey,
Description, Name, LicenseStatus, LicenseStatusReason, ProductKeyID, GracePerio
dRemaining, LicenseFamily, DiscoveredKeyManagementServiceMachineName, KeyManagem
entServicePort, VLActivationInterval, VLRenewalInterval FROM OfficeSoftwareProte
ctionProduct")
bOsppInit = True
End Sub 'OsppInit
'===============================================================================
========================
Function GetLicCnt(iPosMaster, iVersionMajor, ByVal sConfigName, sPossibleSkus,
sPossibleSkusFull)
On Error Resume Next
Dim iLicCnt, iLeft, iCnt
Dim sPrefix
Dim ProdLic, ConfigProd, prop, ProtectionClass
Dim arrLic
Dim fMsiMatchesOsppID, fExclude
If NOT bOsppInit Then OsppInit
If NOT CheckArray(Ospp) AND NOT IsObject(Ospp) Then Exit Function
GetPrefixAndConfig iVersionMajor, sConfigName, sPrefix
If sConfigName <> "" Then arrLic = Split(sConfigName,";")
iLicCnt = 0
If CheckArray(arrLic) Then
arrLicData(OSPP_LICENSESTATUSREASON) = ProdLic.LicenseSt
atusReason
arrLicData(OSPP_PRODUCTKEYID) = ProdLic.ProductKeyID
arrLicData(OSPP_GRACEPERIODREMAINING) = ProdLic.GracePer
iodRemaining
arrLicData(OSPP_LICENSEFAMILY) = ProdLic.LicenseFamily
arrLicData(OSPP_DISCOVEREDKEYMANAGEMENTSERVICEMACHINENAM
E) = ProdLic.DiscoveredKeyManagementServiceMachineName
arrLicData(OSPP_KEYMANAGEMENTSERVICEPORT) = ProdLic.KeyM
anagementServicePort
arrLicData(OSPP_VLACTIVATIONINTERVAL) = ProdLic.VLActiva
tionInterval
arrLicData(OSPP_VLRENEWALINTERVAL) = ProdLic.VLRenewalIn
terval
GetLicenseData = arrLicData
Exit Function
End If
End If
Next
Next 'ProdLic
End If
GetLicenseData = arrLicData
End Function 'GetLicenseData
'===============================================================================
========================
Function GetLicErrDesc(hErr)
On Error Resume Next
Select Case "0x"& hErr
Case "0x0" : GetLicErrDesc = "Success."
Case "0xC004B001" : GetLicErrDesc = "The activation server determined that the l
icense is invalid."
Case "0xC004B002" : GetLicErrDesc = "The activation server determined that the l
icense is invalid."
Case "0xC004B003" : GetLicErrDesc = "The activation server determined that the l
icense is invalid."
Case "0xC004B004" : GetLicErrDesc = "The activation server determined that the l
icense is invalid."
Case "0xC004B005" : GetLicErrDesc = "The activation server determined that the l
icense is invalid."
Case "0xC004B006" : GetLicErrDesc = "The activation server determined that the l
icense is invalid."
Case "0xC004B007" : GetLicErrDesc = "The activation server reported that the com
puter could not connect to the activation server."
Case "0xC004B008" : GetLicErrDesc = "The activation server determined that the c
omputer could not be activated."
Case "0xC004B009" : GetLicErrDesc = "The activation server determined that the l
icense is invalid."
Case "0xC004B011" : GetLicErrDesc = "The activation server determined that your
computer clock time is not correct. You must correct your clock before you can a
ctivate."
Case "0xC004B100" : GetLicErrDesc = "The activation server determined that the c
omputer could not be activated."
Case "0xC004C001" : GetLicErrDesc = "The activation server determined the specif
ied product key is invalid."
Case "0xC004C002" : GetLicErrDesc = "The activation server determined there is a
problem with the specified product key."
Case "0xC004C003" : GetLicErrDesc = "The activation server determined the specif
ied product key has been blocked."
Case "0xC004C004" : GetLicErrDesc = "The activation server determined the specif
t there is a mismatched between a policy value and information stored in the Oth
erInfo section."
Case "0xC004E021" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Genuine information contained in the license is not consistent."
Case "0xC004E022" : GetLicErrDesc = "The Software Licensing Service reported tha
t the secure store id value in license does not match with the current value."
Case "0x8004E101" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Token Store file version is invalid."
Case "0x8004E102" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Token Store contains an invalid descriptor table."
Case "0x8004E103" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Token Store contains a token with an invalid header/footer."
Case "0x8004E104" : GetLicErrDesc = "The Software Licensing Service reported tha
t a Token Store token has an invalid name."
Case "0x8004E105" : GetLicErrDesc = "The Software Licensing Service reported tha
t a Token Store token has an invalid extension."
Case "0x8004E106" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Token Store contains a duplicate token."
Case "0x8004E107" : GetLicErrDesc = "The Software Licensing Service reported tha
t a token in the Token Store has a size mismatch."
Case "0x8004E108" : GetLicErrDesc = "The Software Licensing Service reported tha
t a token in the Token Store contains an invalid hash."
Case "0x8004E109" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Token Store was unable to read a token."
Case "0x8004E10A" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Token Store was unable to write a token."
Case "0x8004E10B" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Token Store attempted an invalid file operation."
Case "0x8004E10C" : GetLicErrDesc = "The Software Licensing Service reported tha
t there is no active transaction."
Case "0x8004E10D" : GetLicErrDesc = "The Software Licensing Service reported tha
t the Token Store file header is invalid."
Case "0x8004E10E" : GetLicErrDesc = "The Software Licensing Service reported tha
t a Token Store token descriptor is invalid."
Case "0xC004F001" : GetLicErrDesc = "The Software Licensing Service reported an
internal error."
Case "0xC004F002" : GetLicErrDesc = "The Software Licensing Service reported tha
t rights consumption failed."
Case "0xC004F003" : GetLicErrDesc = "The Software Licensing Service reported tha
t the required license could not be found."
Case "0xC004F004" : GetLicErrDesc = "The Software Licensing Service reported tha
t the product key does not match the range defined in the license."
Case "0xC004F005" : GetLicErrDesc = "The Software Licensing Service reported tha
t the product key does not match the product key for the license."
Case "0xC004F006" : GetLicErrDesc = "The Software Licensing Service reported tha
t the signature file for the license is not available."
Case "0xC004F007" : GetLicErrDesc = "The Software Licensing Service reported tha
t the license could not be found."
Case "0xC004F008" : GetLicErrDesc = "The Software Licensing Service reported tha
t the license could not be found."
Case "0xC004F009" : GetLicErrDesc = "The Software Licensing Service reported tha
t the grace period expired."
Case "0xC004F00A" : GetLicErrDesc = "The Software Licensing Service reported tha
t the application ID does not match the application ID for the license."
Case "0xC004F00B" : GetLicErrDesc = "The Software Licensing Service reported tha
t the product identification data is not available."
Case "0x4004F00C" : GetLicErrDesc = "The Software Licensing Service reported tha
t the application is running within the valid grace period."
Case "0x4004F00D" : GetLicErrDesc = "The Software Licensing Service reported tha
t the application is running within the valid out of tolerance grace period."
qViewAssembly.Close
End If 'InStr(sTables,"MsiAssembly")>0
If InStr(sTables,"SxsMsmGenComponents,")>0 Then
sQueryAssembly = "SELECT DISTINCT `Component_` FROM SxsMsmGe
nComponents"
Set qViewAssembly = MsiDb.OpenView(sQueryAssembly)
qViewAssembly.Execute
' If the MsiAssmbly table does not exist it returns an error
If Not Err = 0 Then Err.Clear
Set Record = qViewAssembly.Fetch
' must not enter the loop in case of an error!
If Not Err = 0 Then
Err.Clear
Else
Do Until Record Is Nothing
If Not dicAssembly.Exists(Record.StringData(1)) Then
dicAssembly.Add Record.StringData(1),Record.Stri
ngData(1)
End If
Set Record = qViewAssembly.Fetch
Loop
End If 'Not Err = 0
qViewAssembly.Close
End If 'InStr(sTables,"MsiAssembly")>0
' Build directory reference
Set SessionDir = Nothing
oMsi.UILevel = 2 'None
Set SessionDir = oMsi.OpenProduct(sProductCode)
SessionDir.DoAction("CostInitialize")
SessionDir.DoAction("FileCost")
SessionDir.DoAction("CostFinalize")
Set dicFolders = Nothing
Set dicFolders = CreateObject("Scripting.Dictionary")
Err.Clear
Set SessionDb = SessionDir.Database
sQueryDir = "SELECT DISTINCT `Directory` FROM Directory"
Set qViewDir = SessionDb.OpenView(sQueryDir)
qViewDir.Execute
Set Record = qViewDir.Fetch
' must not enter the loop in case of an error!
If Not Err = 0 Then
Err.Clear
Else
Do Until Record Is Nothing
If Not dicFolders.Exists(Record.Stringdata(1)) Then
sTargetPath = "" : sTargetPath = SessionDir.TargetPa
th(Record.Stringdata(1))
If NOT sTargetPath = "" Then dicFolders.Add Record.S
tringdata(1), sTargetPath
End If
Set Record = qViewDir.Fetch
Loop
End If 'Not Err = 0
qViewDir.Close
' .msi file inventory
' ------------------sQueryFT = "SELECT * FROM File"
iles(FILES_COMPONENTSTATE,iPosArr),arrFiles(FILES_FULLNAME,iPosArr))
' add Language
arrFiles(FILES_LANGUAGE,iPosArr) = Record.StringData(6)
' get next row
Set Record = qViewFT.Fetch()
Loop
Set Record = Nothing
qViewFT.Close
Set qViewFT = Nothing
'
'
'
'
End If
Set Record = Nothing
' get the files being modified from the "_TransformView"
'File' table
Set qViewMst = MspDb.OpenView(SQL_FILETABLE) : qView
Mst.Execute()
' loop all of the entries in the File table from "_Trans
formView"
Set Record = qViewMst.Fetch()
' initial defaults
sFtk = ""
bFtkViewComplete = True
bFtkInScope = False
Do
' is this the next FTK?
If (Not sFtk = Record.StringData(3)) OR (Record
Is Nothing) Then
If Record Is Nothing Then Err.Clear
' yes this is the next FTK or the last time befo
re exit of the loop
' is previous FTK handling complete?
If Not bFtkViewComplete Then
' previous FTK handling is not complete
' is previous FTK in scope?
If bFtkInScope AND NOT bFtkForceOutOfSco
pe Then
'FTK is in scope - reset the scope flag
bFtkInScope = False
If bBaseRefFound Then
' update base entry fields with patc
h information
' check if the filename got updated
If bFileNameChanged Then
arrFiles(FILES_FILE,iPosArr)
= GetLongFileName(arrFiles(FILES_FILE,iPosArr))
' the filename got changed by a
patch
' if the patch is in the 'Applie
d' state -> care about this change
If LCase(arrFiles(FILES_PATC
HSTATE,iPosArr)) = "applied" Then
' update the filename in the
baseref if this is (NOT Assembly) OR (broken)
If NOT(dicAssembly.Exist
s(arrFiles(FILES_COMPONENTNAME,iPosArr))) OR (arrFiles(FILES_FILESTATUS,iPosArr)
= INSTALLSTATE_BROKEN) Then
' correct the baseref fi
lename field
arrFiles(FILES_FILE,
iCnt) = arrFiles(FILES_FILE,iPosArr)
' File FullName
arrFiles(FILES_FULLN
AME,iPosArr) = GetFileFullName(arrFiles(FILES_COMPONENTSTATE,iPosArr),arrFiles(F
ILES_FOLDER,iPosArr),arrFiles(FILES_FILE,iPosArr))
' recheck the filestate
arrFiles(FILES_FILES
TATUS,iPosArr) = GetFileState(arrFiles(FILES_COMPONENTSTATE,iPosArr),arrFiles(FI
LES_FULLNAME,iPosArr))
arrFiles(FILES_FILES
TATUS,iCnt) = arrFiles(FILES_FILESTATUS,iPosArr)
(sQueryCompID)
If Not Err = 0 Then
Err.Clear
Set Record2 = Nothing
Else
qViewCompID.Execute
Set Record2 = qViewCompID.Fe
tch()
End If
If Not Record2 Is Nothing Then
' found the ComponentId
' this is a new file added to an
existing component
arrFiles(FILES_COMPONENTID,i
PosArr) = Record2.StringData(2)
' add the Directory_ reference
arrFiles(FILES_DIRECTORY,iPo
sArr) = Record2.StringData(3)
Set Record2 = Nothing
qViewCompID.Close
Set qViewCompID = Nothing
Else
' did not find the ComponentId i
n the base .msi
' this is a new file AND a new c
omponent -> need to query the .msp for details
Set qViewMspCompId = MspDb.O
penView("SELECT * FROM `_TransformView` WHERE `Table`='Component' ORDER BY `Row`
")
qViewMspCompID.Execute
Do
Set Record3 = qViewMspCo
mpId.Fetch()
If Record3 Is Nothing Th
en Exit Do
If Record3.StringData(3)
= arrFiles(FILES_COMPONENTNAME,iPosArr) Then
If Record3.StringDat
a(2) = "ComponentId" Then
arrFiles(FILES_C
OMPONENTID,iPosArr) = Record3.StringData(4)
ElseIf Record3.Strin
gData(2) = "Directory_" Then
arrFiles(FILES_D
IRECTORY,iPosArr) = Record3.StringData(4)
End If
End If
Loop
qViewMspCompID.Close
If arrFiles(FILES_COMPONENTI
D,iPosArr)="" Then bFtkForceOutOfScope = True
End If 'Not Record2 Is Nothing
' all other logic is only needed if
in scope
If Not bFtkForceOutOfScope Then
' ensure the directory reference
exists
If Not dicFolders.Exists(arr
Files(FILES_DIRECTORY,iPosArr)) Then
If SessionDir Is Nothing
Then
' try to recover lost Se
ssionDir object
Set SessionDir = oMs
i.OpenProduct(sProductCode)
SessionDir.DoAction(
"CostInitialize")
SessionDir.DoAction(
"FileCost")
SessionDir.DoAction(
"CostFinalize")
End If
dicFolders.Add arrFiles(
FILES_DIRECTORY,iPosArr),SessionDir.TargetPath(arrFiles(FILES_DIRECTORY,iPosArr)
)
If Not Err = 0 Then
Err.Clear
' still failed to identi
fy the path - get rid of this entry
bNeedKeyPathFallback
= True
End If
End If
' ComponentState
arrFiles(FILES_COMPONENTSTAT
E,iPosArr) = GetComponentState(sProductCode,arrFiles(FILES_COMPONENTID,iPosArr),
iPosMaster)
' add ComponentClients
arrFiles(FILES_COMPONENTCLIE
NTS,iPosArr) = GetComponentClients(arrFiles(FILES_COMPONENTID,iPosArr),arrFiles(
FILES_COMPONENTSTATE,iPosArr))
' add Features that use the comp
onent
Set qViewMspFC = MspDb.OpenV
iew("SELECT * FROM `_TransformView` WHERE `Table`='FeatureComponents' ORDER BY `
Row`")
qViewMspFC.Execute
Set Record2 = qViewMspFC.Fet
ch()
Do
Set Record2 = qViewMspFC
.Fetch()
If Record2 Is Nothing Th
en Exit Do
If Record2.StringData(4)
= arrFiles(FILES_COMPONENTNAME,iPosArr) Then
If Record2.StringDat
a(2) = "Feature_" Then
arrFiles(FILES_F
EATURENAMES,iPosArr) = arrFiles(FILES_FEATURENAMES,iPosArr)&Record2.StringData(3
)& _
"("&TranslateFea
tureState(oMsi.FeatureState(sProductCode,Record2.StringData(3)))&")"& ","
End If
End If
Loop
qViewMspFC.Close
Set Record2 = Nothing
RTrimComma arrFiles(FILES_FE
ATURENAMES,iPosArr)
Else
' No - FTK not in scope
bFtkForceOutOfScope = False
' delete all row contents
For iColCnt = 0 To FILES_COLUMNCNT
arrFiles(iColCnt,iPosArr) = ""
Next 'iColCnt
' decrease array counter
iPosArr = iPosArr - 1
End If 'bFtkInScope
If bFtkForceOutOfScope Then
' delete all row contents
For iColCnt = 0 To FILES_COLUMNCNT
arrFiles(iColCnt,iPosArr) = ""
Next 'iColCnt
' decrease array counter
iPosArr = iPosArr - 1
End If
End If 'bFtkViewComplete
bFtkViewComplete = True
' Previous FTK handling is now complete
' ------------------------------------If Record Is Nothing Then Exit Do
' Init new FTK row
' ---------------' increase array pointer
iPosArr = iPosArr + 1
bFtkViewComplete = False
bFtkInScope = False
bFtkForceOutOfScope = False
bInsert = False
bFileNameChanged = False
If iPosArr > iArrMaxCnt Then
' add more rows to array
iArrMaxCnt = iArrMaxCnt + 1000
ReDim Preserve arrFiles(FILES_COLUMNCNT,
iArrMaxCnt)
End If 'iPosArr > iArrMaxCnt
' update current FTK cache reference
sFtk = Record.StringData(3)
' locate the FTK reference from msi base
bBaseRefFound = False
For iCnt = 0 To iBaseRefCnt
If arrFiles(FILES_FTK,iCnt) = sFtk Then
bBaseRefFound = True
' copy known fields from Base version if
applicable
If bBaseRefFound Then
For iColCnt = 0 To FILES_COLUMNC
NT
arrFiles(iColCnt,iPosArr) =
arrFiles(iColCnt,iCnt)
Next 'iColCnt
bFtkInScope = True
End If 'bBaseRefFound
Exit For 'iCnt = 0 To UBound(arrFile
s,2)-1
End If 'arrFiles(FILES_FTK,iCnt) = sFtk
Then
Next 'iCnt
' add initial available data
' correct/ensure FTK name
arrFiles(FILES_FTK,iPosArr) = Record.StringD
ata(3)
' correct IsPatched field
arrFiles(FILES_ISPATCHED,iPosArr) = False
' correct/ensure FileSource
arrFiles(FILES_SOURCE,iPosArr) = "Msp"
' add fields from patch array
arrFiles(FILES_PATCHSTATE,iPosArr) = arrPatc
h(iPosMaster,PATCH_PATCHSTATE,iPosPatch)
arrFiles(FILES_PATCHCODE,iPosArr) = arrPatch
(iPosMaster,PATCH_PATCHCODE,iPosPatch)
arrFiles(FILES_PATCHMOREINFO,iPosArr) = arrP
atch(iPosMaster,PATCH_MOREINFOURL,iPosPatch)
' add KB reference
If dicMspIndex.Exists(sPatchCode) Then
iIndex = dicMspIndex.Item(sPatchCode)
arrFiles(FILES_PATCHKB,iPosArr) = arrMsp
Files(iIndex,MSPFILES_KB)
arrFiles(FILES_PATCHPACKAGE,iPosArr) = a
rrMspFiles(iIndex,MSPFILES_PACKAGE)
End If
' new FTK row init complete
End If 'Not sFtk = Record.StringData(3)
' add data from _TransformView
Select Case Record.StringData(2)
Case "File"
Case "FileSize"
Case "Component_"
arrFiles(FILES_COMPONENTNAME,iPosArr) = Reco
rd.StringData(4)
Case "CREATE"
Case "DELETE"
Case "DROP"
Case "FileName"
'Add the filename
bFileNameChanged = True
arrFiles(FILES_FILE,iPosArr) = Record.String
Data(4)
Case "Version"
' don't allow version field to contain alpha cha
racters
bAsc = True : sAscCheck = "" : sAscCheck = R
ecord.StringData(4)
If Len(sAscCheck)>0 Then
For iAscCnt = 1 To Len(sAscCheck)
iAsc = Asc(UCase(Mid(sAscCheck,iAscC
nt,1)))
If (iAsc>64) AND (iAsc<91) Then
bAsc = False
Exit For
End If
Next 'iCnt
End If 'Len(sAscCheck)>0
If bAsc Then arrFiles(FILES_PATCHVERSION,iPo
sArr) = Record.StringData(4)
Case "Language"
arrFiles(FILES_LANGUAGE,iPosArr) = Recor
d.StringData(4)
Case "Attributes"
Case "Sequence"
Case "INSERT"
' this is a new file added by the pach
bFtkInScope = True
bInsert = True
Case Else
End Select
' get the next record (column) from _TransformView
Set Record = qViewMst.Fetch()
Loop
' _TransformView analysis for this patch complete
' reset views
MspDb.OpenView("ALTER TABLE _TransformView FREE").Ex
ecute
MspDb.OpenView("DROP TABLE `File`").Execute
End If 'Err = 0
End If 'IsEmpty
Next 'iPosPatch
Next 'iFoo
' Final field & verb fixups
' ------------------------For iFile = 0 To iPosArr
' File VersionState translation
iCmp = 2 : sCmp = "" : sCurVer = ""
If arrFiles(FILES_ISPATCHED,iFile) OR (arrFiles(FILES_SOURCE,iFi
le)="Msp") Then
' compare actual file version to patch file version
sCurVer = arrFiles(FILES_PATCHVERSION,iFile)
Else
' compare actual file version to base file version
sCurVer = arrFiles(FILES_BASEVERSION,iFile)
End If 'arrFiles(FILES_ISPATCHED,iFile)
iCmp = CompareVersion(arrFiles(FILES_CURRENTVERSION,iFile),sCurV
er,False)
Select Case iCmp
Case VERSIONCOMPARE_LOWER
sCmp="ERROR_VersionLow"
' log error
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,ER
R_FILEVERSIONLOW & arrMaster(iPosMaster,COL_PRODUCTCODE) & DSV & _
arrMaster(iPosMaster,COL_PRODUCTNAME)
If Not InStr(arrMaster(iPosMaster,COL_ERROR),arrFiles(FILES_
FILE,iFile)&" expected: ")>0 Then
arrMaster(iPosMaster,COL_ERROR) = arrMaster(iPosMaster,C
OL_ERROR) & ERR_CATEGORYERROR & arrFiles(FILES_FILE,iFile) & " expected: "&sCurV
er& " found: " & arrFiles(FILES_CURRENTVERSION,iFile) & CSV
End If
Case VERSIONCOMPARE_MATCH : sCmp="SUCCESS_VersionMatch"
Case VERSIONCOMPARE_HIGHER : sCmp="SUCCESS_VersionHigh"
Case VERSIONCOMPARE_INVALID : sCmp=""
End Select
arrFiles(FILES_VERSIONSTATUS,iFile) = sCmp
' FileState translation
sCmp = ""
Select Case arrFiles(FILES_FILESTATUS,iFile)
Case INSTALLSTATE_LOCAL : sCmp = "OK_Local"
Case INSTALLSTATE_BROKEN
sCmp = "ERROR_Broken"
' log error
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,"P
roduct " & arrMaster(iPosMaster,COL_PRODUCTCODE) & DSV & _
arrMaster(iPosMaster,COL_PRODUCTNAME) & ": " & ERR_BADFILEST
ATE
If Not InStr(arrMaster(iPosMaster,COL_ERROR),arrFiles(FILES_
FILE,iFile)&" FileState: Broken")>0 Then
arrMaster(iPosMaster,COL_ERROR) = arrMaster(iPosMaster,C
OL_ERROR) & ERR_CATEGORYERROR & arrFiles(FILES_FILE,iFile) & " FileState: Broken
" & CSV
End If
Case INSTALLSTATE_UNKNOWN
sCmp = "Unknown"
If Not arrFiles(FILES_FEATURENAMES,iFile) = "" Then sCmp=Mid
(arrFiles(FILES_FEATURENAMES,iFile),InStrRev(arrFiles(FILES_FEATURENAMES,iFile),
"(")+1, Len(arrFiles(FILES_FEATURENAMES,iFile))-InStrRev(arrFiles(FILES_FEATUREN
AMES,iFile),"(")-1)
Case INSTALLSTATE_NOTUSED : sCmp = "NotUsed"
Case INSTALLSTATE_ASSEMBLY : sCmp = "Assembly"
Case Else
End Select
arrFiles(FILES_FILESTATUS,iFile) = sCmp
' ComponentState translation
sCmp = ""
Select Case arrFiles(FILES_COMPONENTSTATE,iFile)
Case INSTALLSTATE_LOCAL : sCmp = "Local"
Case INSTALLSTATE_BROKEN : sCmp = "Broken"
Case INSTALLSTATE_UNKNOWN : sCmp = "Unknown"
Case INSTALLSTATE_NOTUSED : sCmp = "NotUsed"
Case Else
End Select
arrFiles(FILES_COMPONENTSTATE,iFile) = sCmp
' PatchCode field trim
arrFiles(FILES_PATCHCODE,iFile) = RTrimComma(arrFiles(FILES_PATC
HCODE,iFile))
' PatchKB field trim
arrFiles(FILES_PATCHKB,iFile) = RTrimComma(arrFiles(FILES_PATCHK
B,iFile))
' PatchInfo field trim
arrFiles(FILES_PATCHMOREINFO,iFile) = RTrimComma(arrFiles(FILES_
PATCHMOREINFO,iFile))
Next 'iFile
' dump out the collected data to file
' create the AllOffice file
If IsEmpty(AllOfficeFiles) Then
If NOT oFso.FolderExists(sPathOutputFolder & "ROIScan") Then oFs
o.CreateFolder(sPathOutputFolder & "ROIScan")
Set AllOfficeFiles = oFso.CreateTextFile(sPathOutputFolder&"ROIS
can\"&sComputerName&"_OfficeAll_FileList.xml",True,True)
AllOfficeFiles.WriteLine "<?xml version=""1.0""?>"
AllOfficeFiles.WriteLine "<FILEDATA>"
End If
' individual products file
If NOT oFso.FolderExists(sPathOutputFolder & "ROIScan") Then oFso.Cr
eateFolder(sPathOutputFolder & "ROIScan")
Set FileStream = oFso.CreateTextFile(sPathOutputFolder&"ROIScan\"&sC
omputerName&"_"&sProductCode&"_FileList.xml",True,True)
FileStream.WriteLine "<?xml version=""1.0""?>"
FileStream.WriteLine "<FILEDATA>"
FileStream.WriteLine vbTab & "<PRODUCT ProductCode="""&sProductCode&
""" >"
If arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) Then AllOfficeFiles.Wri
teLine vbTab & "<PRODUCT ProductCode="""&sProductCode&""" >"
For iFile = 0 To iPosArr
sXmlLine = ""
sXmlLine = vbTab & vbTab & "<FILE " & _
"FileName="&chr(34)&arrFiles(FILES_FI
LE,iFile)&chr(34)&" " & _
"FileState="&chr(34)&arrFiles(FILES_F
ILESTATUS,iFile)&chr(34)&" " & _
"VersionStatus="&chr(34)&arrFiles(FIL
ES_VERSIONSTATUS,iFile)&chr(34)&" " & _
"CurrentVersion="&chr(34)&arrFiles(FI
LES_CURRENTVERSION,iFile)&chr(34)&" " & _
"InitialVersion="&chr(34)&arrFiles(FI
LES_BASEVERSION,iFile)&chr(34)&" " & _
"PatchVersion="&chr(34)&arrFiles(FILE
S_PATCHVERSION,iFile)&chr(34)&" " & _
"FileSource="&chr(34)&arrFiles(FILES_
SOURCE,iFile)&chr(34)&" " & _
"IsPatched="&chr(34)&arrFiles(FILES_I
SPATCHED,iFile)&chr(34)&" " & _
"KB="&chr(34)&arrFiles(FILES_PATCHKB,
iFile)&chr(34)&" " & _
"Package="&chr(34)&arrFiles(FILES_PAT
CHPACKAGE,iFile)&chr(34)&" " & _
"PatchState="&chr(34)&arrFiles(FILES_
PATCHSTATE,iFile)&chr(34)&" " & _
"FolderName="&chr(34)&arrFiles(FILES_
FOLDER,iFile)&chr(34)&" " & _
"PatchCode="&chr(34)&arrFiles(FILES_P
ATCHCODE,iFile)&chr(34)&" " & _
"PatchInfo="&chr(34)&arrFiles(FILES_P
ATCHMOREINFO,iFile)&chr(34)&" " & _
"FtkName="&chr(34)&arrFiles(FILES_FTK
,iFile)&chr(34)&" " & _
"KeyPath="&chr(34)&arrFiles(FILES_KEY
PATH,iFile)&chr(34)&" " & _
"MsiDirectory="&chr(34)&arrFiles(FILE
S_DIRECTORY,iFile)&chr(34)&" " & _
"Language="&chr(34)&arrFiles(FILES_LA
NGUAGE,iFile)&chr(34)&" " & _
"ComponentState="&chr(34)&arrFiles(FI
LES_COMPONENTSTATE,iFile)&chr(34)&" " & _
"ComponentID="&chr(34)&arrFiles(FILES
_COMPONENTID,iFile)&chr(34)&" " & _
"ComponentName="&chr(34)&arrFiles(FIL
ES_COMPONENTNAME,iFile)&chr(34)&" " & _
"ComponentClients="&chr(34)&arrFiles(
FILES_COMPONENTCLIENTS,iFile)&chr(34)&" " & _
"FeatureReference="&chr(34)&arrFiles(
FILES_FEATURENAMES,iFile)&chr(34)&" " & _
" />"
If InStr(sXmlLine,"&")>0 Then sXmlLine = Replace(sXmlLine,"&","&
amp;")
FileStream.WriteLine sXmlLine
If arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) Then AllOfficeFiles
.WriteLine sXmlLine
Next 'iFile
FileStream.WriteLine vbTab & "</PRODUCT>"
If arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) Then AllOfficeFiles.Wri
teLine vbTab & "</PRODUCT>"
FileStream.WriteLine "</FILEDATA>"
FileStream.Close
Set FileStream = Nothing
End If 'arrMaster(iPosMaster,COL_ISOFFICEPRODUCT)
Next 'iPosMaster
' close the AllOffice file
If Not AllOfficeFiles Is Nothing Then
AllOfficeFiles.WriteLine "</FILEDATA>"
AllOfficeFiles.Close
Set AllOfficeFiles = Nothing
End if
' compress the files
Dim i,iWait
Dim FileScanFolder,FileVerScanZip,xmlFile,item,zipfile
Dim sDat,sDatCln
Dim fCopyComplete
If oFso.FileExists(sPathOutputFolder&sComputerName&"_ROIScan.zip") Then
' rename existing .zip container by appending a timestamp to prevent overwri
te.
Dim oRegExp
Set oRegExp = CreateObject("Vbscript.RegExp")
Set zipfile = oFso.GetFile(sPathOutputFolder&sComputerName&"_ROIScan.zip
")
oRegExp.Global = True
oRegExp.Pattern = "\D"
Err.Clear
zipfile.Name = sComputerName&"_ROIScan_" & oRegExp.Replace(zipfile.DateL
astModified, "") & ".zip"
If NOT Err = 0 Then
zipfile.Delete
Err.Clear
End If
End If
Set FileVerScanZip = oFso.OpenTextFile(sPathOutputFolder&sComputerName&"_ROI
Scan.zip",FOR_WRITING,True)
FileVerScanZip.write "PK" & chr(5) & chr(6) & String(18,chr(0))
FileVerScanZip.close
Set FileScanFolder = oFso.GetFolder(sPathOutputFolder&"ROIScan")
For Each xmlFile in FileScanFolder.Files
If Right(LCase(xmlFile.Name),4)=".xml" Then
If NOT fZipError Then CopyToZip ShellApp.NameSpace(sPathOutputFolder
&sComputerName&"_ROIScan.zip"), xmlFile
End If
Next 'xmlFile
If fCScript AND NOT fQuiet Then wscript.echo vbTab & "File version scan comp
lete"
End Sub 'FileInventory
'===============================================================================
========================
'Identify the InstallState of a component
Function GetComponentState(sProductCode,sComponentId,iPosMaster)
On Error Resume Next
Dim Product
Dim sPath
GetComponentState = INSTALLSTATE_UNKNOWN
If iWiVersionMajor > 2 Then
'WI 3.x or higher
Set Product = oMsi.Product(sProductCode,arrMaster(iPosMaster,COL_USERSID
),arrMaster(iPosMaster,COL_CONTEXT))
Err.Clear
GetComponentState = Product.ComponentState(sComponentId)
If Not Err = 0 Then
GetComponentState = INSTALLSTATE_UNKNOWN
Err.Clear
End If ' Err = 0
Else
'WI 2.x
If Not Err = 0 Then Err.Clear
sPath = ""
sPath = oMsi.ComponentPath(sProductCode,sComponentId)
If Not Err = 0 Then
GetComponentState = INSTALLSTATE_UNKNOWN
Err.Clear
Else
If oFso.FileExists(sPath) Then
GetComponentState = INSTALLSTATE_LOCAL
Else
GetComponentState = INSTALLSTATE_NOTUSED
End If 'oFso.FileExists(sPath)
End If 'Not Err = 0
End If 'iWiVersionMajor > 2
End Function 'GetComponentState
'===============================================================================
========================
'Get a list of client products that are registered to the component
Function GetComponentClients(sComponentId,iComponentState)
On Error Resume Next
Dim sClients,prod
sClients = ""
GetComponentClients = ""
If Not(iComponentState = INSTALLSTATE_UNKNOWN) Then
For Each prod in oMsi.ComponentClients(sComponentId)
If Not Err = 0 Then
Err.Clear
Exit For
End If 'Not Err = 0
sClients = sClients & prod & ","
Next 'prod
RTrimComma sClients
GetComponentClients = sClients
End If 'Not (arrFiles(FILES_COMPONENTSTATE,...
End Function 'GetComponentClients
'===============================================================================
========================
'Get the keypath value for the component
Function GetComponentPath(sProductCode,sComponentId,iComponentState)
sFile = sName&".cat"
Else
If oFso.FileExists(sRoot&"Policies\"&sName&".cat") Then
sFolder = sRoot&"Policies\"
sFile = sName&".cat"
End If
End If
End If
Case ".manifest"
sFile = Left(sFile,InStrRev(sFile,"."))&"manifest"
If oFso.FileExists(sRoot&"Manifests\"&sName&".manifest") Then
sFolder = sRoot&"Manifests\"
sFile = sName&".manifest"
End If
Case ".policy"
If iVersionNT < 600 Then
sFile = Left(sFile,InStrRev(sFile,"."))&"policy"
If oFso.FileExists(sRoot&"Policies\"&sName&".policy") Then
sFolder = sRoot&"Policies\"
sFile = sName&".policy"
End If
Else
sFile = Left(sFile,InStrRev(sFile,"."))&"manifest"
If oFso.FileExists(sRoot&"Manifests\"&sName&".manifest") The
n
sFolder = sRoot&"Manifests\"
sFile = sName&".manifest"
End If
End If
Case Else
End Select
'Check if the file exists
If Not oFso.FileExists(sFolder&sFile) Then
'Ensure the right folder
End If
End If 'InStr(sFile,".")>0
End If
GetAssemblyPath = sFolder&sFile
End Function 'GetAssemblyPath
'===============================================================================
========================
'
Function GetFileFullName(iComponentState,sComponentPath,sFileName)
On Error Resume Next
Dim sFileFullName
sFileFullName = ""
If iComponentState = INSTALLSTATE_LOCAL Then
If Len(sComponentPath) > 2 Then sFileFullName = sComponentPath & sFileNa
me
End If 'iComponentState = INSTALLSTATE_LOCAL
GetFileFullName = sFileFullName
End Function 'GetFileFullName
'===============================================================================
========================
'
Function GetLongFileName(sMsiFileName)
On Error Resume Next
Dim sFileTmp
sFileTmp = ""
sFileTmp = sMsiFileName
If InStr(sFileTmp,"|") > 0 Then sFileTmp = Mid(sFileTmp,InStr(sFileTmp,"|")+
1,Len(sFileTmp))
GetLongFileName = sFileTmp
End Function 'GetLongFileName
'===============================================================================
========================
'
Function GetFileState(iComponentState,sFileFullName)
On Error Resume Next
GetFileState = INSTALLSTATE_UNKNOWN
If iComponentState = INSTALLSTATE_LOCAL Then
If oFso.FileExists(sFileFullName) Then
GetFileState = INSTALLSTATE_LOCAL
Else
GetFileState = INSTALLSTATE_BROKEN
End If 'oFso.FileExists(sFileFullName)
Else
If oFso.FileExists(sFileFullName) Then
'This should not happen!
GetFileState = INSTALLSTATE_LOCAL
Else
GetFileState = iComponentState
End If 'oFso.FileExists(sFileFullName)
End If 'iComponentState = INSTALLSTATE_LOCAL
End Function 'GetFileState
'===============================================================================
========================
'
Function GetFileVersion(iComponentState,sFileFullName)
On Error Resume Next
GetFileVersion = ""
If iComponentState = INSTALLSTATE_LOCAL Then
If oFso.FileExists(sFileFullName) Then
GetFileVersion = oFso.GetFileVersion(sFileFullName)
End If 'oFso.FileExists(sFileFullName)
Else
If oFso.FileExists(sFileFullName) Then
'This should not happen!
GetFileVersion = oFso.GetFileVersion(sFileFullName)
End If 'oFso.FileExists(sFileFullName)
End If 'iComponentState = INSTALLSTATE_LOCAL
Features,oRecordSet,oDicLevel,oDicParent
sProductCode,sFeature,sFTree,sFParent,sLeft,sRight
iFoo,iPosMaster,iMaxNestLevel,iNestLevel,iLevel,iFCnt,iLeft,iStart
arrFName,arrFLevel,arrFParent
to array
oDicLevel.Keys
oDicLevel.Items
oDicParent.Items
Loop 'iFoo=0
arrFeature(iPosMaster,FEATURE_TREE)=vbCrLf&sFTree
Next 'iProdMaster
End Sub 'FindFeatureStates
'===============================================================================
========================
'Translate the FeatureState value
Function TranslateFeatureState(iFState)
Select Case iFState
Case INSTALLSTATE_UNKNOWN
Case INSTALLSTATE_ADVERTISED
Case INSTALLSTATE_ABSENT
Case INSTALLSTATE_LOCAL
Case INSTALLSTATE_SOURCE
Case INSTALLSTATE_DEFAULT
Case INSTALLSTATE_VIRTUALIZED
Case INSTALLSTATE_BADCONFIG
Case Else
End Select
:
:
:
:
:
:
:
:
:
TranslateFeatureState="Unknown"
TranslateFeatureState="Advertised"
TranslateFeatureState="Absent"
TranslateFeatureState="Local"
TranslateFeatureState="Source"
TranslateFeatureState="Default"
TranslateFeatureState="Virtualized"
TranslateFeatureState="BadConfig"
TranslateFeatureState="Error"
Dim
Dim
Dim
Dim
oProduct, oSumInfo
iProdCnt, iSourceCnt
sSource
MsiSources
ReDim arrIS(UBound(arrMaster),UBOUND_IS)
For iProdCnt = 0 To UBound(arrMaster)
arrIS(iProdCnt,IS_SOURCETYPESTRING) = "No Data Available"
arrIS(iProdCnt,IS_ORIGINALSOURCE) = "No Data Available"
'Add the ProductCode to the array
arrIS(iProdCnt,IS_PRODUCTCODE) = arrMaster(iProdCnt,COL_PRODUCTCODE)
If arrMaster(iProdCnt, COL_VIRTUALIZED) = 1 Then
' do nothing
Else
'SourceType
If oFso.FileExists(arrMaster(iProdCnt,COL_CACHEDMSI)) Then
Err.Clear
Set oSumInfo = oMsi.SummaryInformation(arrMaster(iProdCnt,COL_CA
CHEDMSI),MSIOPENDATABASEMODE_READONLY)
If Err = 0 Then
arrIS(iProdCnt,IS_SOURCETYPE) = oSumInfo.Property(PID_WORDCO
UNT)
Select Case arrIS(iProdCnt,IS_SOURCETYPE)
Case 0 : arrIS(iProdCnt,IS_SOURCETYPESTRING) = "Original sou
rce using long file names"
Case 1 : arrIS(iProdCnt,IS_SOURCETYPESTRING) = "Original sou
rce using short file names"
Case 2 : arrIS(iProdCnt,IS_SOURCETYPESTRING) = "Compressed s
ource files using long file names"
Case 3 : arrIS(iProdCnt,IS_SOURCETYPESTRING) = "Compressed s
ource files using short file names"
Case 4 : arrIS(iProdCnt,IS_SOURCETYPESTRING) = "Administrati
ve image using long file names"
Case 5 : arrIS(iProdCnt,IS_SOURCETYPESTRING) = "Administrati
ve image using short file names"
Case Else : arrIS(iProdCnt,IS_SOURCETYPESTRING) = "Unknown I
nstallSource Type"
End Select
Else
'ERR_SICONNECTFAILED
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,"P
roduct " & arrMaster(iProdCnt,COL_PRODUCTCODE) & DSV & _
arrMaster(iProdCnt,COL_PRODUCTNAME) & ": " & ERR_SICONNECTFA
ILED
arrMaster(iProdCnt,COL_ERROR) = arrMaster(iProdCnt,COL_ERROR
) & ERR_CATEGORYERROR & ERR_SICONNECTFAILED & CSV
End If 'Err
End If
'Get the original InstallSource
arrIS(iProdCnt,IS_ORIGINALSOURCE) = oMsi.ProductInfo(arrMaster(iProd
Cnt,COL_PRODUCTCODE),"InstallSource")
If Not Len(arrIS(iProdCnt,IS_ORIGINALSOURCE)) > 0 Then arrIS(iProdCn
t,IS_ORIGINALSOURCE) = "Not Registered"
'Get Network InstallSource(s)
'With WI 3.x and later the 'Product' object can be used to gather so
me data
If iWiVersionMajor > 2 Then
Err.Clear
Set oProduct = oMsi.Product(arrMaster(iProdCnt,COL_PRODUCTCODE),
arrMaster(iProdCnt,COL_USERSID),arrMaster(iProdCnt,COL_CONTEXT))
If Err = 0 Then
'Get the last used source
arrIS(iProdCnt,IS_LASTUSEDSOURCE) = oProduct.SourceListInfo(
"LastUsedSource")
Set MsiSources = oProduct.Sources(1)
For Each sSource in MsiSources
If IsEmpty(arrIS(iProdCnt,IS_ADDITIONALSOURCES)) Then
arrIS(iProdCnt,IS_ADDITIONALSOURCES)=sSource 'MsiSou
rces(iSourceCnt)
Else
arrIS(iProdCnt,IS_ADDITIONALSOURCES)=arrIS(iProdCnt,
IS_ADDITIONALSOURCES)&" || "& sSource'MsiSources(iSourceCnt)
End If
Next 'MsiSources
End If 'Err
End If 'iWiVersionMajor
'Get the LIS resiliency source (if applicable)
If GetDeliveryResiliencySource(arrMaster(iProdCnt,COL_PRODUCTCODE),i
ProdCnt,sSource) Then arrIS(iProdCnt,IS_LISRESILIENCY)=sSource
End If 'Not Virtualized
Next 'iProdCnt
End Sub 'ReadMsiInstallSources
'===============================================================================
========================
'Return True/False and the LIS source path as sSource
'Empty string for sProductCode forces to identify the DownloadCode from Setup.xm
l
Function GetDeliveryResiliencySource (sProductCode,iPosMaster,sSource)
On Error Resume Next
Dim
Dim
Dim
,source
Dim
Dim
Dim
arrSources,arrDownloadCodeKeys
dicDownloadCode
sSubKeyName,sValue,key,sku,sSkuName,sText,sDownloadCode,sTmpDownloadCode
arrKeys,arrSku
iVersionMajor,iSrc
fFound
GetDeliveryResiliencySource=False
sSource = Empty
iVersionMajor = GetVersionMajor(sProductCode)
Set dicDownloadCode = CreateObject("Scripting.Dictionary")
Select Case iVersionMajor
'Case 14
Case 12,14
'Note: ProductCode doesn't work consistently for this logic
'
To locate the Setup.xml requires additional logic so the tweak he
re is to use the
'
original source location to identify the DownloadCode
sText=arrIS(iPosMaster,IS_ORIGINALSOURCE)
If InStr(source,"{")>0 Then sDownloadCode=Mid(sText,InStr(sText,"{"),40)
Else sDownloadCode=sProductCode
dicDownloadCode.Add sDownloadCode,sProductCode
'Find the additional download locations
'Check if more than one sources are registered
If InStr(arrIS(iPosMaster,IS_ADDITIONALSOURCES),"||")>0 Then
arrSources = Split(arrIS(iPosMaster,IS_ADDITIONALSOURCES)," || ")
For Each source in arrSources
If InStr(source,"{")>0 Then
sTmpDownloadCode=Mid(source,InStr(source,"{"),40)
If Not dicDownloadCode.Exists(sTmpDownloadCode) Then dicDown
loadCode.Add sTmpDownloadCode,sProductCode
End If 'InStr
Next'
End If 'InStr
arrDownloadCodeKeys = dicDownloadCode.Keys
For iSrc = 0 To dicDownloadCode.Count-1
sDownloadCode = UCase(arrDownloadCodeKeys(iSrc))
'Enum HKLM\SOFTWARE\Microsoft\Office\Delivery\SourceEngine\Downloads
sSubKeyName="SOFTWARE\Microsoft\Office\Delivery\SourceEngine\Downloa
ds\"
If RegEnumKey(HKLM,sSubKeyName,arrKeys) Then
For Each key in arrKeys
fFound = False
If Len(key)>37 Then
fFound = (UCase(Left(key,38))=sDownloadCode) OR (UCase(k
ey)=sDownloadCode)
Else
fFound = (UCase(key)=sDownloadCode)
End If 'Len > 37
If fFound Then
'Found the Delivery reference
'Enum the 'Sources' subkey
sSubKeyName=sSubKeyName&key&"\Sources\"
If RegEnumKey(HKLM,sSubKeyName,arrSku) Then
For Each sku in arrSku
If RegReadStringValue(HKLM,sSubKeyName&sku,"Path
",sValue) Then
sSkuName=""
sSkuName=" (" & Left(sku,InStr(sku,"(")-1) &
")"
If IsEmpty(sSource) Then
sSource = sValue & sSkuName
Else
sSource = sSource&" || "&sValue&sSkuName
End If 'IsEmpty
End If 'RegReadStringValue
Next 'sku
End If 'RegEnumKey
'GUID is unique no need to continue loop once we found a
match
Exit For
End If
Next 'key
End If 'RegEnumKey
Next 'iSrc
Case 11
'Get the DownloadCode
sSubKeyName="SOFTWARE\Microsoft\Office\11.0\Delivery\"&sProductCode&"\"
If RegReadStringValue(HKLM,sSubKeyName,"DownloadCode",sDownloadCode) The
n
sSubKeyName="SOFTWARE\Microsoft\Office\Delivery\SourceEngine\Downloa
ds\"&sDownloadCode&"\Sources\"&Mid(sProductCode,2,36)&"\"
If RegReadStringValue(HKLM,sSubKeyName,"Path",sValue) Then sSource =
sValue
End If
Case Else 'Does not have LIS
End Select
If Not IsEmpty(sSource) Then GetDeliveryResiliencySource=True
End Function 'GetDeliveryResiliencySource
'===============================================================================
========================
'===============================================================================
========================
'Module Product Properties
'===============================================================================
========================
'Gather additional properties for the product
'Add them to master array
Sub ProductProperties
Dim sActiveSub, sErrHnd,sProdId,n
Dim prod,MsiDb
Dim iPosMaster,iVersionMajor,iContext,iProd
Dim sProductCode,sSpLevel,sCachedMsi,sSid,sComp,sComp2,sPath,sRef
Dim fVer,fCx
Dim arrCx,arrCxN,arrCxErr,arrKeys,arrTypes,arrNames
On Error Resume Next
If NOT fInitArrProdVer Then InitProdVerArrays
For iPosMaster = 0 to UBound (arrMaster)
' collect properties only for products in state '5' (Default)
If arrMaster(iPosMaster,COL_STATE) = INSTALLSTATE_DEFAULT OR arrMaster(i
PosMaster,COL_STATE) = INSTALLSTATE_VIRTUALIZED Then
sProductCode = arrMaster(iPosMaster,COL_PRODUCTCODE)
sSid = arrMaster(iPosMaster,COL_USERSID)
iContext = arrMaster(iPosMaster,COL_CONTEXT)
' ProductID
sProdId = GetProductId(sProductCode,iPosMaster)
If NOT sProdId = "" Then arrMaster(iPosMaster,COL_PRODUCTID) = sProd
Id
' ProductVersion
arrMaster(iPosMaster,COL_PRODUCTVERSION) = GetProductVersion(sProduc
tCode,iContext,sSid)
If NOT fBasicMode Then
' cached .msi package
Set MsiDb = Nothing
arrMaster(iPosMaster,COL_CACHEDMSI) = GetCachedMsi(sProductCode,
iPosMaster)
If NOT arrMaster(iPosMaster,COL_CACHEDMSI) = "" AND arrMaster(iP
osMaster, COL_VIRTUALIZED) = 0 Then Set MsiDb = oMsi.OpenDatabase(arrMaster(iPos
Master,COL_CACHEDMSI), MSIOPENDATABASEMODE_READONLY)
' PackageCode
arrMaster(iPosMaster,COL_PACKAGECODE) = GetPackageCode(sProductC
ode,iPosMaster,MsiDb)
' UpgradeCode
arrMaster(iPosMaster,COL_UPGRADECODE) = GetUpgradeCode(MsiDb)
' Transforms
arrMaster(iPosMaster,COL_TRANSFORMS) = GetTransforms(sProductCod
e, iPosMaster)
' InstallDate
arrMaster(iPosMaster,COL_INSTALLDATE) = GetInstallDate(sProductC
ode,iContext,sSid,arrMaster(iPosMaster,COL_CACHEDMSI))
' original .MSI Name
arrMaster(iPosMaster,COL_ORIGINALMSI) = GetOriginalMsiName(sProd
uctCode, iPosMaster)
End If 'fBasicMode
' some of this is only valid for Office products
If arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) Then
' SP level
iVersionMajor = GetVersionMajor(sProductCode)
sSpLevel = OVersionToSpLevel(sProductCode, iVersionMajor, arrMas
ter(iPosMaster, COL_PRODUCTVERSION))
arrMaster(iPosMaster, COL_SPLEVEL) = sSpLevel
' Build/Origin
If NOT fBasicMode Then arrMaster(iPosMaster,COL_ORIGIN) = CheckO
rigin(MsiDb)
' Architecture (Bitness)
If Left(arrMaster(iPosMaster,COL_PRODUCTVERSION),2)>11 Then
If Mid(sProductCode,21,1) = "1" Then arrMaster(iPosMaster, C
OL_ARCHITECTURE) = "x64" Else arrMaster(iPosMaster, COL_ARCHITECTURE) = "x86"
End If
If NOT fBasicMode Then
' Cx
fVer = False : fCx = False
Select Case iVersionMajor
Case 11
sComp = "{1EBDE4BC-9A51-4630-B541-2561FA45CCC5}"
sRef = "11.0.8320.0"
Case 12
sComp = "{0638C49D-BB8B-4CD1-B191-051E8F325736}"
sRef = "12.0.6514.5001"
If Mid(sProductCode,11,4) = "0020" Then fVer = True
Case 14
If Mid(sProductCode,21,1) = "1" Then
sComp = "{C0AC079D-A84B-4CBD-8DBA-F1BB44146899}"
sComp2= "{E6AC97ED-6651-4C00-A8FE-790DB0485859}"
Else
sComp = "{019C826E-445A-4649-A5B0-0BF08FCC4EEE}"
sComp2= "{398E906A-826B-48DD-9791-549C649CACE5}"
End If
sRef = "14.0.5123.5004"
Case Else
sComp = "" : sComp2 = "" : sRef = ""
End Select
' obtain product handle
Err.Clear
If oMsi.Product(sProductCode, sSid, iContext).ComponentState
If RegEnumValues(HKLM,hAtS(arrCx),arrNames,arrTypes)
Then
For Each n in arrNames
If UCase(n) = hAtS(arrCxN) Then arrMaster(iP
osMaster,COL_NOTES) = arrMaster(iPosMaster,COL_NOTES) & hAtS(arrCxErr) & CSV
Next 'n
End If
Case 14
arrCxErr = Array("43","75","73","74","6F","6D","20",
"58","4D","4C","20","66","65","61","74","75","72","65","20","65","6E","61","62",
"6C","65","64","20","62","79","20","57","6F","72","64","20","32","30","31","30",
"20","4B","42","20","32","34","32","38","36","37","20","61","64","64","2D","69",
"6E")
For Each prod in arrMaster
If Mid(prod,11,4)="0126" Then arrMaster(iPosMast
er,COL_NOTES) = arrMaster(iPosMaster,COL_NOTES) & hAtS(arrCxErr) & CSV
Next 'prod
Case Else
End Select
Else
If (iVersionMajor = 14) AND fCx Then
arrCxErr = Array("43","75","73","74","6F","6D","20",
"58","4D","4C","20","66","65","61","74","75","72","65","20","66","6F","72","20",
"74","68","65","20","62","69","6E","61","72","79","20","2E","64","6F","63","20",
"66","6F","72","6D","61","74","20","72","65","71","75","69","72","65","73","20",
"4B","42","20","32","34","31","33","36","35","39")
arrMaster(iPosMaster,COL_NOTES) = arrMaster(iPosMast
er,COL_NOTES) & hAtS(arrCxErr) & CSV
End If '14
End If 'fVer
End If 'fBasicMode
Else
arrMaster(iPosMaster,COL_ORIGIN) = "n/a"
' checks for known add-ins
' POWERPIVOT_2010
If InStr(POWERPIVOT_2010,arrMaster(iPosMaster,COL_UPGRADECODE))
> 0 Then
If CompareVersion(arrMaster(iPosMaster,COL_PRODUCTVERSION),"
10.50.1747.0",True) < 1 Then
arrMaster(iPosMaster,COL_NOTES) = arrMaster(iPosMaster,C
OL_NOTES) & ERR_CATEGORYWARN & "This is a preview version. Please obtain version
10.50.1747.0 or higher." & CSV
End If
End If 'POWERPIVOT_2010
End If 'IsOfficeProduct
End If 'INSTALLSTATE_DEFAULT
Next 'iPosMaster
End Sub 'ProductProperties
'===============================================================================
========================
'The name of the original installation package 'PackageName' is obtained from HK
CR.
'This limits the availability to products which are installed 'per-machine' or f
or the current user!
'Exception situations WI < 3.x or user profile not available are covered in the
'Error handler'
Function GetOriginalMsiName(sProductCode, iPosMaster)
Dim iPos
Dim sCompGuid, sRegName
Dim fVirtual
On Error Resume Next
fVirtual = (arrMaster(iPosMaster, COL_VIRTUALIZED) = 1)
sRegName = ""
If NOT fVirtual Then sRegName = oMsi.ProductInfo(sProductCode,"PackageName")
'Error Handler
If (Not Err = 0) OR sRegName = "" Then
'This can happen if WI < 3.x or product is installed for other user
Err.Clear
iPos = GetArrayPosition(arrMaster,sProductCode)
sCompGuid = GetCompressedGuid(sProductCode)
sRegName = GetRegOriginalMsiName(sCompGuid,arrMaster(iPos,COL_CONTEXT),a
rrMaster(iPos,COL_USERSID))
If sRegName = "-" AND NOT fVirtual Then arrMaster(iPos,COL_ERROR) = arrM
aster(iPos,COL_ERROR) & ERR_CATEGORYERROR & ERR_BADMSINAMEMETADATA & CSV
End If
GetOriginalMsiName = sRegName
End Function
'===============================================================================
========================
'The 'Transforms' property is obtained from HKCR.
'This limits the availability to products which are installed 'per-machine' or f
or the current user!
'Exception situations WI < 3.x or user profile not available are covered in the
'Error handler'
Function GetTransforms(sProductCode, iPosMaster)
Dim sTransforms, sCompGuid, sRegTransforms
Dim iPos
On Error Resume Next
GetTransforms = "-" : sTransforms = ""
If arrMaster(iPosMaster, COL_VIRTUALIZED) = 0 Then sTransforms = oMsi.Produc
tInfo(sProductCode,"Transforms")
'Error Handler
If NOT Err = 0 OR arrMaster(iPosMaster, COL_VIRTUALIZED) = 1 Then
Err.Clear
iPos = GetArrayPosition(arrMaster,sProductCode)
sCompGuid = GetCompressedGuid(sProductCode)
sTransforms = GetRegTransforms(sCompGuid,arrMaster(iPos,COL_CONTEXT),arr
Master(iPos,COL_USERSID))
End If
If Len(sTransforms) > 0 Then GetTransforms = sTransforms
End Function
'===============================================================================
========================
'InstallDate is available as part of the ProductInfo.
'It's stored in the global key. Introduced with WI 3.x
Function GetInstallDate(sProductCode,iContext,sSid,sCachedMsi)
Dim iPos
Dim hDefKey
Dim sSubKeyName, sName, sValue, sDateLocalized, sDateNormalized, sYY, sMM, s
DD
On Error Resume Next
GetInstallDate = ""
hDefKey = HKEY_LOCAL_MACHINE
sSubKeyName = GetRegConfigKey(sProductCode,iContext,sSid,True) & "InstallPro
perties"
sName = "InstallDate"
GetInstallDate = "-"
If RegReadValue(hDefKey,sSubKeyName,sName,sValue,"REG_EXPAND_SZ") Then GetIn
stallDate = sValue
'The InstallDate is reset with every patch transaction
'As a workaround the CreateDate of the cached .msi package will be used to o
btain the correct date
If oFso.FileExists(sCachedMsi) Then
'GetInstallDate = oFso.GetFile(sCachedMsi).DateCreated
sDateLocalized = oFso.GetFile(sCachedMsi).DateCreated
sYY = Year(sDateLocalized)
sMM = Right("0" & Month(sDateLocalized), 2)
sDD = Right("0" & Day(sDateLocalized), 2)
sDateNormalized = sYY & " " & sMM & " " & sDD & " (yyyy mm dd)"
GetInstallDate = sDateNormalized
End If
End Function 'GetInstallDate
'===============================================================================
========================
'The package code associates a .msi file with an application or product
'This property is used for source verification
'3 possible checks here:
' a) Installer.ProductInfo
Note: ProductInfo object is limited to per-machin
e and current user scope
' b) SummaryInformation stream from cached .msi
' c) SummaryInformation stream from .msi in InstallSource
Function GetPackageCode(sProductCode,iPosMaster,MsiDb)
Dim sValidate, sCompGuid, sPackageCode
Dim oSumInfo
On Error Resume Next
sPackageCode = ""
If arrMaster(iPosMaster, COL_VIRTUALIZED) = 0 Then sPackageCode = oMsi.Produ
ctInfo(sProductCode, "PackageCode")
If (Not Err = 0) OR (sPackageCode="") Then
' Error Handler
sCompGuid = GetCompressedGuid(sProductCode)
sPackageCode = GetRegPackageCode(sCompGuid,arrMaster(iPosMaster,COL_CONT
EXT),arrMaster(iPosMaster,COL_USERSID))
Exit Function
End If
If Not sPackageCode = "n/a" Then
If Not IsValidGuid(sPackageCode,GUID_UNCOMPRESSED) Then
If fGuidCaseWarningOnly Then
arrMaster(iPosMaster,COL_NOTES) = arrMaster(iPosMaster,COL_NOTES
) & ERR_CATEGORYNOTE & ERR_GUIDCASE & DOT & sErrBpa & CSV
Else
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE, ERR_CATEGORYERROR,"Prod
uct " & sProductCode & DSV & arrMaster(iPosMaster,COL_PRODUCTNAME) & _
": " & sError & " for PackageCode '" & sPackageCode & "
'" & DOT & sErrBpa
sError = "" : sErrBpa = ""
arrMaster(iPosMaster,COL_ERROR) = arrMaster(iPosMaster,COL_ERROR
) & ERR_CATEGORYERROR & sError & DOT & sErrBpa & CSV
End If 'fGuidCaseWarningOnly
End If
End If
' Scan cached .msi
If Not arrMaster(iPosMaster,COL_CACHEDMSI) = "" Then
Set oSumInfo = MsiDb.SummaryInformation(MSIOPENDATABASEMODE_READONLY
)
If Not (Err = 0) Then
arrMaster(iPosMaster,COL_NOTES) = arrMaster(iPosMaster,COL_NOTES
) & ERR_CATEGORYWARN & ERR_INITSUMINFO & CSV
Exit Function
End If 'Not Err
If Not sPackageCode = oSumInfo.Property(PID_REVNUMBER) Then
arrMaster(iPosMaster,COL_ERROR) = arrMaster(iPosMaster,COL_ERROR
) & ERR_CATEGORYERROR & ERR_PACKAGECODEMISMATCH & CSV
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,"Produ
ct " & sProductCode & DSV & arrMaster(iPosMaster,COL_PRODUCTNAME) & _
": " & ERR_PACKAGECODEMISMATCH & DOT & BPA_PACKAGECODEMISM
ATCH
End If
End If 'arrMaster
' Scan .msi in InstallSource has to be deferred to module InstallSource
GetPackageCode = sPackageCode
End Function 'GetPackageCode
'===============================================================================
========================
Function GetUpgradeCode (MsiDb)
Dim Record
Dim qView
On Error Resume Next
GetUpgradeCode = ""
If MsiDb Is Nothing Then Exit Function
Set qView = MsiDb.OpenView("SELECT `Value` FROM Property WHERE `Property`='U
pgradeCode'")
qView.Execute()
Set Record = qView.Fetch()
If NOT Err = 0 Then Exit Function
GetUpgradeCode = Record.StringData(1)
WriteDebug sActiveSub,"Upgradecode: " & Record.StringData(1)
End Function 'GetPackageCode
'===============================================================================
========================
'Read the Build / Origin property from the cached .msi
Function CheckOrigin(MsiDb)
Dim sQuery, sCachedMsi
Dim Record
Dim qView
On Error Resume Next
' not all products do support this so the return value is not guaranteed.
CheckOrigin = ""
If MsiDb Is Nothing Then Exit Function
' read the 'Build' entry first
sQuery = "SELECT `Value` FROM Property WHERE `Property` = 'BUILD'"
Set qView = MsiDb.OpenView(sQuery)
qView.Execute
sTmp = GetRegProductVersion(sProductCode,iContext,sSid)
End If
GetProductVersion = sTmp
End Function
'===============================================================================
========================
'Get the ProductVersion from Registry
Function GetRegProductVersion (sProductCode,iContext,sSid)
Dim hDefKey
Dim sSubKeyName,sValue
Dim iTmpContext
On Error Resume Next
GetRegProductVersion = "Error"
hDefKey = HKEY_LOCAL_MACHINE
If iContext = MSIINSTALLCONTEXT_USERMANAGED Then
iTmpContext = MSIINSTALLCONTEXT_USERUNMANAGED
Else
iTmpContext = iContext
End If 'iContext = MSIINSTALLCONTEXT_USERMANAGED
sSubKeyName = GetRegConfigKey(GetCompressedGuid(sProductCode),iTmpContext,sS
id,True) & "InstallProperties\"
If RegReadStringValue(hDefKey,sSubKeyName,"DisplayVersion",sValue) Then GetR
egProductVersion = sValue
End Function
'===============================================================================
========================
'Translate the Office ProductVersion to the service pack level
Function OVersionToSpLevel (sProductCode,iVersionMajor,sProductVersion)
On Error Resume Next
'SKU identifier constants for SP level detection
Const O15_EXCEPTION = ""
Const O14_EXCEPTION = "007A,007B,007C,007D,007F,2005"
'#Devonly O12_Server = "1014,1015,104B,104E,1080,1088,10D7,10D8,10EB,10F5,10F6
,10F7,10F8,10FB,10FC,10FD,1103,1104,110D,1105,1110,1121,1122"
Const O12_EXCEPTION = "001C,001F,0020,003F,0045,00A4,00A7,00B0,00B1,00B2,00B
9,011F,CFDA"
Const O11_EXCEPTION = "14,15,16,17,18,19,1A,1B,1C,24,32,3A,3B,44,51,52,53,5E
,A1,A4,A9,E0"
Const O10_EXCEPTION = "17,1D,25,27,30,36,3A,3B,51,52,53,54"
Const O09_EXCEPTION = "3A,3B,3C,5F"
Dim iSpCnt,iExptnCnt,iLevel,iRetry
Dim sSpLevel,sSku
iLevel = 0 : iRetry = 0
Select Case iVersionMajor
Case 9
'Sku ProductID is 2 digits starting at pos 4
sSku = Mid(sProductCode,4,2)
If InStr(O09_EXCEPTION,sSku)>0 Then
For iExptnCnt = 1 To UBound(arrProdVer09,1)
If InStr(arrProdVer10(iExptnCnt,0),sSku)>0 Then Exit For
Next 'iExptnCnt
Else
iExptnCnt = 0
End If 'InStr(O09_Exception,sSku)>0
For iRetry = 0 To 1
For iSpCnt = 1 To UBound(arrProdVer09,2)
If sProductVersion = Left(arrProdVer09(iExptnCnt,iSpCnt),Len(sPr
oductVersion)) Then
'Special release references are noted within same field with
a "," separator
If InStr(arrProdVer09(iExptnCnt,iSpCnt),",")>0 Then
OVersionToSpLevel = Mid(arrProdVer09(iExptnCnt,iSpCnt),I
nStr(arrProdVer09(iExptnCnt,iSpCnt),",")+1,Len(arrProdVer09(iExptnCnt,iSpCnt)))
Exit Function
Else
iLevel = iSpCnt
End If
End If
Next 'iSpCnt
If iLevel > 0 Then Exit For
'Did not find the SP level yet. Retry with core build numbers
iExptnCnt = 0
Next 'iRetry
Case 10
'Sku ProductID is 2 digits starting at pos 4
sSku = Mid(sProductCode,4,2)
If InStr(O10_EXCEPTION,sSku)>0 Then
For iExptnCnt = 1 To UBound(arrProdVer10,1)
If InStr(arrProdVer10(iExptnCnt,0),sSku)>0 Then Exit For
Next 'iExptnCnt
Else
iExptnCnt = 0
End If 'InStr(O10_Exception,sSku)>0
For iRetry = 0 To 1
For iSpCnt = 1 To UBound(arrProdVer10,2)
If sProductVersion = Left(arrProdVer10(iExptnCnt,iSpCnt),Len(sPr
oductVersion)) Then
'Special release references are noted within same field with
a "," separator
If InStr(arrProdVer10(iExptnCnt,iSpCnt),",")>0 Then
OVersionToSpLevel = Mid(arrProdVer10(iExptnCnt,iSpCnt),I
nStr(arrProdVer10(iExptnCnt,iSpCnt),",")+1,Len(arrProdVer10(iExptnCnt,iSpCnt)))
Exit Function
Else
iLevel = iSpCnt
Exit For
End If
End If
Next 'iSpCnt
If iLevel > 0 Then Exit For
'Did not find the SP level yet. Retry with core build numbers
iExptnCnt = 0
Next 'iRetry
Case 11
'Sku ProductID is 2 digits starting at pos 4
sSku = Mid(sProductCode,4,2)
If InStr(O11_EXCEPTION,sSku)>0 Then
Next 'iRetry
'Beta build detection
If (iLevel=0) AND (CInt(Mid(sProductVersion,6,4))>6219) AND (CInt(Mid(sP
roductVersion,6,4))<6425) Then
OVersionToSpLevel = "SP2 Beta"
Exit Function
End If
Case 14
'Sku ProductID is 4 digits starting at pos 11
sSku = Mid(sProductCode,11,4)
If InStr(O14_EXCEPTION,sSku)>0 Then
For iExptnCnt = 1 To UBound(arrProdVer14,1)
If InStr(arrProdVer14(iExptnCnt,0),sSku)>0 Then Exit For
Next 'iExptnCnt
Else
iExptnCnt = 0
End If 'InStr(O14_Exception,sSku)>0
For iRetry = 0 To 1
For iSpCnt = 1 To UBound(arrProdVer14,2)
If Left(sProductVersion,10) = Left(arrProdVer14(iExptnCnt,iSpCnt
),10) Then
'Special release references are noted within same field with
a "," separator
If InStr(arrProdVer14(iExptnCnt,iSpCnt),",")>0 Then
OVersionToSpLevel = Mid(arrProdVer14(iExptnCnt,iSpCnt),I
nStr(arrProdVer14(iExptnCnt,iSpCnt),",")+1,Len(arrProdVer14(iExptnCnt,iSpCnt)))
Exit Function
Else
iLevel = iSpCnt
Exit For
End If
End If
Next 'iSpCnt
If iLevel > 0 Then Exit For
'Did not find the SP level yet. Retry with core build numbers
iExptnCnt = 0
Next 'iRetry
'Beta build detection
If (iLevel=0) AND (CInt(Mid(sProductVersion,6,4))<4537) Then
OVersionToSpLevel = "Beta"
Exit Function
End If
If (iLevel=0) AND (CInt(Mid(sProductVersion,6,4))<4763) Then
OVersionToSpLevel = "RC"
Exit Function
End If
If (iLevel=0) AND (CInt(Mid(sProductVersion,6,4))>5999) AND (CInt(Mid(sP
roductVersion,6,4))<6029) Then
OVersionToSpLevel = "SP1 Beta"
Exit Function
End If
Case 15
'Sku ProductID is 4 digits starting at pos 11
sSku = Mid(sProductCode,11,4)
If InStr(O15_EXCEPTION, sSku) > 0 Then
For iExptnCnt = 1 To UBound(arrProdVer15, 1)
If InStr(arrProdVer15(iExptnCnt, 0), sSku) > 0 Then Exit For
Next 'iExptnCnt
Else
iExptnCnt = 0
End If 'InStr(O15_Exception, sSku) > 0
For iRetry = 0 To 1
For iSpCnt = 1 To UBound(arrProdVer15, 2)
If Left(sProductVersion, 10) = Left(arrProdVer15(iExptnCnt, iSpC
nt), 10) Then
'Special release references are noted within same field with
a "," separator
If InStr(arrProdVer15(iExptnCnt, iSpCnt), ",") > 0 Then
OVersionToSpLevel = Mid(arrProdVer15(iExptnCnt, iSpCnt),
InStr(arrProdVer15(iExptnCnt, iSpCnt), ",") + 1, Len(arrProdVer15(iExptnCnt, iS
pCnt)))
Exit Function
Else
iLevel = iSpCnt
Exit For
End If
End If
Next 'iSpCnt
If iLevel > 0 Then Exit For
'Did not find the SP level yet. Retry with core build numbers
iExptnCnt = 0
Next 'iRetry
'Beta build detection
If (iLevel = 0) AND (CInt(Mid(sProductVersion, 6, 4)) < 3919) Then
OVersionToSpLevel = "Technical Preview"
Exit Function
End If
If (iLevel=0) AND (CInt(Mid(sProductVersion,6,4))= 3919) Then
OVersionToSpLevel = "Technical Preview Refresh"
Exit Function
End If
If (iLevel=0) AND (CInt(Mid(sProductVersion,6,4))=4128) Then
OVersionToSpLevel = "Customer Preview"
Exit Function
End If
Case Else
End Select
Select Case iLevel
Case 1 : sSpLevel = "RTM"
Case 2 : sSpLevel = "SP1"
Case 3 : sSpLevel = "SP2"
Case 4 : sSpLevel = "SP3"
Case Else : sSpLevel = "?"
End Select
OVersionToSpLevel = sSpLevel
End Function 'OVersionToSpLevel
'===============================================================================
========================
'Initialize arrays for translation ProductVersion -> ServicePackLevel
Sub InitProdVerArrays
On Error Resume Next
Patches,Patch,siSumInfo,MsiDb,Record,qView
sQuery,sErr
iMspMax,iMspCnt
fVirtual
fVirtual = (arrMaster(iPosMaster,COL_VIRTUALIZED) = 1)
sPatches = vbNullString
If Not RegReadValue(hDefKey,sSubKeyName,"Patches",sPatches,REG_MULTI_SZ)
Then bPatchRegOk = False
sTmpPatches = sPatches
For iName = 0 To UBound(arrName)
If arrType(iName) = REG_SZ Then
ReDim Preserve arrRegPatch(REGDIM1,UBound(arrRegPatch,2)+1)
sValue = ""
If RegReadStringValue(hDefKey,sSubKeyName,arrName(iName),sValue)
Then sPatch = arrName(iName)
arrRegPatch(0,UBound(arrRegPatch,2)) = GetExpandedGuid(sPatch)
arrRegPatch(1,UBound(arrRegPatch,2)) = MSIPATCHSTATE_APPLIED
If NOT InStr(sTmpPatches,sPatch)>0 Then
bPatchRegOk = False
bPatchMultiSzBroken = True
Else
'Strip current patch from sTmpPatches
sTmpPatches = Replace(sTmpPatches,sPatch,"")
End If 'InStr(sTmpPatches,sPatch)
'Check Patches key
sSubKeyNamePatches = GetRegConfigPatchesKey(iContext,sSid,False)
If Not RegKeyExists(hDefKey,sSubKeyNamePatches & sPatch) Then
bPatchOrgMspNameBroken = True
End If
'Check Global Patches key
sSubKeyNamePatches = ""
sSubKeyNamePatches = GetRegConfigPatchesKey(iContext,sSid,True)
If Not RegKeyExists(hDefKeyGlobal,sSubKeyNamePatches & sPatch) T
hen
bPatchCachedMspLinkBroken = True
End If
'Check Global Product key
sSubKeyNamePatches = ""
sSubKeyNamePatches = GetRegConfigKey(sProductCode,iContext,sSid,
True) & "Patches\" & sPatch
If Not RegKeyExists(hDefKeyGlobal,sSubKeyNamePatches) Then
bPatchProdGlobalBroken = True
Else
If RegReadDWordValue(hDefKeyGlobal,sSubKeyNamePatches,"State
",sValue) Then
arrRegPatch(1,UBound(arrRegPatch,2)) = CInt(sValue)
End If 'RegReadDWordValue
End If 'RegKeyExists(hDefKeyGlobal,sSubKeyNamePatches)
End If 'arrType
Next 'iName
End If 'RegEnumValues
'sTmpPatches should be an empty string now
sTmpPatches = Replace(sTmpPatches,Chr(34),"")
If (Not sTmpPatches = "") OR (NOT fPatchesOk) Then arrMaster(iPosMaster,COL_
ERROR) = arrMaster(iPosMaster,COL_ERROR) & ERR_BADMSPMETADATA & CSV
'Find patches in other states (than 'Applied')
'--------------------------------------------'Get a list from the global patches key
sSubKeyName = GetRegConfigKey(sProductCode,iContext,sSid,True) & "Patches\"
bPatchGlobalMultiSzBroken = NOT RegReadValue(hDefKeyGlobal,sSubKeyName,"AllP
atches",sAllPatches,REG_MULTI_SZ)
'LocalPackage availability:
arrPatch(iPosMaster,PATCH_CPOK,iMspCnt) = False
arrPatch(iPosMaster,PATCH_CPOK,iMspCnt) = oFso.FileExists(arrPatch(iPosM
aster,PATCH_LOCALPACKAGE,iMspCnt))
'DisplayName:
arrPatch(iPosMaster,PATCH_DISPLAYNAME,iMspCnt) = Patch.PatchProperty("Di
splayName")
'Ensure displayname is not blank
If IsEmpty(arrPatch(iPosMaster,PATCH_DISPLAYNAME,iMspCnt)) OR (arrPatch(
iPosMaster,PATCH_DISPLAYNAME,iMspCnt)=vbNullString) Then
'Fall back to registry mode detection
arrPatch(iPosMaster,PATCH_DISPLAYNAME,iMspCnt) = GetRegMspProperty(G
etCompressedGuid(Patch.PatchCode),iMspCnt,iPosMaster,arrMaster(iPosMaster,COL_CO
NTEXT),arrMaster(iPosMaster,COL_USERSID),"DisplayName")
End If 'IsEmpty(iPosMaster,PATCH_DISPLAYNAME,iMspCnt)
'InstallState:
Select Case (Patch.State)
Case MSIPATCHSTATE_APPLIED,MSIPATCHSTATE_SUPERSEDED
If Patch.State = MSIPATCHSTATE_APPLIED Then sTmpState = "App
lied" Else sTmpState = "Superseded"
arrPatch(iPosMaster,PATCH_PATCHSTATE,iMspCnt) = sTmpState
'Check stuff that is only useful/valid for patches in Applie
d/Superseded state
'Uninstallable
If Patch.PatchProperty("Uninstallable") = "1" Then
arrPatch(iPosMaster,PATCH_UNINSTALLABLE,iMspCnt) = "
Yes"
Else
arrPatch(iPosMaster,PATCH_UNINSTALLABLE,iMspCnt) = "
No"
End If
'Check cached package
If Not arrPatch(iPosMaster,PATCH_CPOK,iMspCnt) Then
arrMaster(iPosMaster,COL_ERROR) = arrMaster(iPosMaster,C
OL_ERROR) & _
ERR_CATEGORYERROR & "Local patch package '" & arrPatch(iPos
Master,PATCH_LOCALPACKAGE,iMspCnt) & _
"' missing for patch '." & arrPatch(iPosMaster,PATCH_PA
TCHCODE,iMspCnt) & "'" & CSV
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,"L
ocal patch package '" & arrPatch(iPosMaster,PATCH_LOCALPACKAGE,iMspCnt) & _
"' missing for patch '" & arrPatch(iPosMaster,PATCH_PAT
CHCODE,iMspCnt) & "'"
End If
'InstallDate
arrPatch(iPosMaster,PATCH_INSTALLDATE,iMspCnt) = Pat
ch.PatchProperty("InstallDate")
'MoreInfoUrl
arrPatch(iPosMaster,PATCH_MOREINFOURL,iMspCnt) = Pat
ch.PatchProperty("MoreInfoURL")
Case MSIPATCHSTATE_OBSOLETED
arrPatch(iPosMaster,PATCH_PATCHSTATE,iMspCnt) = "Obsoleted"
'InstallDate
arrPatch(iPosMaster,PATCH_INSTALLDATE,iMspCnt) = Pat
ch.PatchProperty("InstallDate")
'MoreInfoUrl
arrPatch(iPosMaster,PATCH_MOREINFOURL,iMspCnt) = Pat
ch.PatchProperty("MoreInfoURL")
Case MSIPATCHSTATE_REGISTERED
arrPatch(iPosMaster,PATCH_PATCHSTATE,iMspCnt) = "Registered"
'MoreInfoUrl
arrPatch(iPosMaster,PATCH_MOREINFOURL,iMspCnt) = Pat
ch.PatchProperty("MoreInfoURL")
Case Else
arrPatch(iPosMaster,PATCH_PATCHSTATE,iMspCnt) = "Unknown Pat
chstate"
End Select
'PatchTransform
arrPatch(iPosMaster,PATCH_TRANSFORM,iMspCnt) = GetRegMspProperty(GetComp
ressedGuid(Patch.PatchCode),iMspCnt,iPosMaster,arrMaster(iPosMaster,COL_CONTEXT)
,arrMaster(iPosMaster,COL_USERSID),"PatchTransform")
iMspCnt = iMspCnt + 1
Next 'Patch
End Sub 'ReadPatchDetails
'===============================================================================
========================
Sub ReadRegPatchDetails(arrRegPatch,iPosMaster)
Dim hDefKey
Dim sSid,sSubKeyName,sSubKeyNamePatch,sValue,sProductCode,sPatchCodeCompress
ed,sTmpState
Dim iContext
On Error Resume Next
Dim Patch,siSumInfo
Dim iMspCnt
iContext = arrMaster(iPosMaster,COL_CONTEXT)
sSid = arrMaster(iPosMaster,COL_USERSID)
sProductCode = arrMaster(iPosMaster,COL_PRODUCTCODE)
hDefKey = GetRegHive(iContext,sSid,True)
sSubKeyName = GetRegConfigKey(sProductCode,iContext,sSid,True) & "Patches\"
'iMspCnt = 0
'For Each Patch in Patches
For iMspCnt = 0 To UBound(arrRegPatch,2)
sPatchCodeCompressed = GetCompressedGuid(arrRegPatch(0,iMspCnt))
'Add patch data to array
'ProductCode:
arrPatch(iPosMaster,PATCH_PRODUCT,iMspCnt) = arrMaster(iPosMaster,COL_PR
ODUCTCODE)
'PatchCode:
arrPatch(iPosMaster,PATCH_PATCHCODE,iMspCnt) = arrRegPatch(0,iMspCnt)
'CSP flag:
arrPatch(iPosMaster,PATCH_CSP,iMspCnt) = True
'LocalPackage:
arrPatch(iPosMaster,PATCH_LOCALPACKAGE,iMspCnt) = GetRegMspProperty(sPat
chCodeCompressed,iMspCnt,iPosMaster,iContext,sSid,"LocalPackage")
arrPatch(iPosMaster,PATCH_CPOK,iMspCnt) = oFso.FileExists(arrPatch(iPosM
aster,PATCH_LOCALPACKAGE,iMspCnt))
'DisplayName:
arrPatch(iPosMaster,PATCH_DISPLAYNAME,iMspCnt) = GetRegMspProperty(sPatc
hCodeCompressed,iMspCnt,iPosMaster,iContext,sSid,"DisplayName")
'InstallState:
Select Case (arrRegPatch(1,iMspCnt))
Case MSIPATCHSTATE_APPLIED,MSIPATCHSTATE_SUPERSEDED
If arrRegPatch(1,iMspCnt) = MSIPATCHSTATE_APPLIED Then sTmpS
Dim sProductCode,sSubKeyName,sValue
Dim siSumInfo
On Error Resume Next
GetRegMspProperty = ""
sProductCode = arrMaster(iPosMaster,COL_PRODUCTCODE)
'Default to 'Global' registry patch location
hDefKey = GetRegHive(iContext,sSid,True)
sSubKeyName = GetRegConfigKey(sProductCode,iContext,sSid,True) & "Patches\"
& sPatchCodeCompressed & "\"
sValue = ""
Select Case UCase(sProperty)
Case "DISPLAYNAME"
If RegReadStringValue(hDefKey,sSubKeyName,"DisplayName",sValue) Then Get
RegMspProperty = sValue
'Ensure displayname is not blank
If GetRegMspProperty="" Then
'Try to get the value from SummaryInformation stream. Use the PatchC
ode in case of failure
If arrPatch(iPosMaster,PATCH_CPOK,iMspCnt) Then
Err.Clear
Set siSumInfo = oMsi.SummaryInformation(arrPatch(iPosMaster,PATC
H_LOCALPACKAGE,iMspCnt),MSIOPENDATABASEMODE_READONLY)
If Not Err = 0 Then
GetRegMspProperty = GetExpandedGuid(sPatchCodeCompressed)
Else
GetRegMspProperty = siSumInfo.Property(PID_TITLE)
If GetRegMspProperty = vbNullString Then GetRegMspProperty =
GetExpandedGuid(sPatchCodeCompressed)
End If 'Err = 0
Else
GetRegMspProperty = GetExpandedGuid(sPatchCodeCompressed)
End If 'arrPatch(iPosMaster,PATCH_CPOK,iMspCnt)
End If 'GetRegMspProperty=""
Case "INSTALLDATE"
If RegReadStringValue(hDefKey,sSubKeyName,"Installed",sValue) Then GetRe
gMspProperty = sValue
Case "LOCALPACKAGE"
If iContext = MSIINSTALLCONTEXT_USERMANAGED Then iContext = MSIINSTALLCO
NTEXT_USERUNMANAGED
sSubKeyName = GetRegConfigPatchesKey(iContext,sSid,True) & sPatchCodeCom
pressed & "\"
If RegReadStringValue(hDefKey,sSubKeyName,"LocalPackage",sValue) Then Ge
tRegMspProperty = sValue
Case "MOREINFOURL"
If RegReadStringValue(hDefKey,sSubKeyName,"MoreInfoURL",sValue) Then Get
RegMspProperty = sValue
Case "PATCHTRANSFORM"
hDefKey = GetRegHive(iContext,sSid,False)
sSubKeyName = GetRegConfigKey(sProductCode,iContext,sSid,False) & "Patch
es\"
If RegReadStringValue(hDefKey,sSubKeyName,sPatchCodeCompressed,sValue) T
hen GetRegMspProperty = sValue
Case "UNINSTALLABLE"
GetRegMspProperty = "No"
If (RegReadDWordValue(hDefKey,sSubKeyName,"Uninstallable",sValue) AND sV
alue = "1") Then GetRegMspProperty = "Yes"
Case Else
End Select
End Function 'GetRegMspDisplayName
'===============================================================================
========================
'Check if usage of PatchesEx API calls are safe for use.
'PatchesEx requires WI 3.x or higher
'If PatchesEx API calls fail this triggers a fallback to direct registry detecti
on mode
Sub CheckPatchApi
Dim sActiveSub, sErrHnd
sActiveSub = "CheckPatchApi" : sErrHnd = ""
On Error Resume Next
Dim MspCheckEx, MspCheck
'Defaults
fPatchesExOk = False
fPatchesOk = False
iPatchesExError = 0
'WI 2.x specific check
Set MspCheck = oMsi.Patches(arrMaster(0,COL_PRODUCTCODE))
If Err = 0 Then fPatchesOk = True Else Err.Clear
'Ensure WI 3.x for PatchesEx checks
If iWiVersionMajor = 2 Then
Exit Sub
End If 'iWiVersionMajor = 2
'ROIScan error values for PatchesEx to allow to distinguish into unique erro
r messages
Set MspCheckEx = oMsi.PatchesEx(PRODUCTCODE_EMPTY,USERSID_EVERYONE,MSIINSTAL
LCONTEXT_ALL,MSIPATCHSTATE_ALL)
If Err <> 0 Then
iPatchesExError = 8
CheckError sActiveSub,sErrHnd
Else
fPatchesExOk = True
Exit Sub
End If 'Not Err <> 0
Set MspCheckEx = oMsi.PatchesEx(PRODUCTCODE_EMPTY,USERSID_EVERYONE,MSIINSTAL
LCONTEXT_USERMANAGED,MSIPATCHSTATE_ALL)
If Err <> 0 Then
iPatchesExError = iPatchesExError + MSIINSTALLCONTEXT_USERMANAGED
CheckError sActiveSub,sErrHnd
End If 'Not Err <> 0 - MSIINSTALLCONTEXT_USERMANAGED
Set MspCheckEx = oMsi.PatchesEx(PRODUCTCODE_EMPTY,USERSID_EVERYONE,MSIINSTAL
LCONTEXT_USERUNMANAGED,MSIPATCHSTATE_ALL)
If Err <> 0 Then
iPatchesExError = iPatchesExError + MSIINSTALLCONTEXT_USERUNMANAGED
CheckError sActiveSub,sErrHnd
End If 'Not Err <> 0 - MSIINSTALLCONTEXT_USERUNMANAGED
Set MspCheckEx = oMsi.PatchesEx(PRODUCTCODE_EMPTY,MACHINESID,MSIINSTALLCONTE
XT_MACHINE,MSIPATCHSTATE_ALL)
If Err <> 0 Then
iPatchesExError = iPatchesExError + MSIINSTALLCONTEXT_MACHINE
CheckError sActiveSub,sErrHnd
End If 'Not Err <> 0 - MSIINSTALLCONTEXT_MACHINE
Select Case iPatchesExError
Case 8 CacheLog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,ERR_PA
TCHESEX & "MSIINSTALLCONTEXT_ALL" & DOT
Element,Elements,Key,XmlDoc,Msp,SumInfo,Record
dicMspSequence,dicMspTmp
sFamily,sSeq,sMsp,sBaseSeqShort
iPosMaster,iPosPatch,iCnt,iIndex
fAdd
qView
arrTitle,arrTmpFam,arrTmpSeq,arrVer
'Defaults
Set XmlDoc = CreateObject("Microsoft.XMLDOM")
Set dicMspSequence = CreateObject("Scripting.Dictionary")
Set dicMspTmp = CreateObject("Scripting.Dictionary")
'Initialize the patch index dictionary to assign each distinct PatchCode an
index number
iCnt = -1
For iPosMaster = 0 To UBound(arrMaster)
For iPosPatch = 0 to UBound(arrPatch,3)
If Not (IsEmpty (arrPatch(iPosMaster,PATCH_PATCHCODE,iPosPatch))) AN
D (arrPatch(iPosMaster,PATCH_CSP,iPosPatch)) Then
If NOT dicMspIndex.Exists(arrPatch(iPosMaster,PATCH_PATCHCODE,iP
osPatch)) Then
iCnt=iCnt+1
dicMspIndex.Add arrPatch(iPosMaster,PATCH_PATCHCODE,iPosPatc
h),iCnt
dicMspTmp.Add arrPatch(iPosMaster,PATCH_PATCHCODE,iPosPatch)
,arrPatch(iPosMaster,PATCH_LOCALPACKAGE,iPosPatch)
End If
End If
Next 'iPosPatch
Next 'iPosMaster
'Initialize the PatchFiles array
ReDim arrMspFiles(dicMspIndex.Count-1,MSPFILES_COLUMNCOUNT-1)
'Open the .msp for reading to add the data to the array
For Each Key in dicMspTmp.Keys
iPosPatch = dicMspIndex.Item(Key)
sMsp = dicMspTmp.Item(Key)
Err.Clear
Set Msp = oMsi.OpenDatabase (sMsp,MSIOPENDATABASEMODE_PATCHFILE)
Set SumInfo = Msp.SummaryInformation
If Not Err = 0 Then
'An error at this points indicates a severe issue
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,ERR_MSPOPE
NFAILED & sMsp
Else
'LocalPackage
arrMspFiles(iPosPatch,MSPFILES_LOCALPACKAGE)=sMsp
'PatchCode
arrMspFiles(iPosPatch,MSPFILES_PATCHCODE)=Key
'PatchTargets
arrMspFiles(iPosPatch,MSPFILES_TARGETS)=SumInfo.Property(PID_TEMPLAT
E)
'PatchTables
arrMspFiles(iPosPatch,MSPFILES_TABLES)=GetPatchTables(Msp)
'KB
If InStr(arrMspFiles(iPosPatch,MSPFILES_TABLES),"MsiPatchMetadata")>
0 Then
Set qView = Msp.OpenView("SELECT `Property`,`Value` FROM MsiPatc
hMetadata WHERE `Property`='KBArticle Number'")
qView.Execute : Set Record = qView.Fetch()
If Not Record Is Nothing Then
arrMspFiles(iPosPatch,MSPFILES_KB) = UCase(Record.StringData
(2))
arrMspFiles(iPosPatch,MSPFILES_KB) = Replace(arrMspFiles(iPo
sPatch,MSPFILES_KB),"KB","")
Else
arrMspFiles(iPosPatch,MSPFILES_KB) = ""
End If
qView.Close
'StdPackageName
Set qView = Msp.OpenView("SELECT `Property`,`Value` FROM MsiPatc
hMetadata WHERE `Property`='StdPackageName'")
qView.Execute : Set Record = qView.Fetch()
If Not Record Is Nothing Then
arrMspFiles(iPosPatch,MSPFILES_PACKAGE) = Record.StringData(
2)
Else
arrMspFiles(iPosPatch,MSPFILES_PACKAGE) = ""
End If
qView.Close
Else
arrMspFiles(iPosPatch,MSPFILES_KB) = ""
arrMspFiles(iPosPatch,MSPFILES_PACKAGE) = ""
End If
arrTitle = Split(SumInfo.Property(PID_TITLE),";")
If arrMspFiles(iPosPatch,MSPFILES_KB) = "" Then
If UBound(arrTitle)>0 Then
arrMspFiles(iPosPatch,MSPFILES_KB) = arrTitle(1)
End If
End If
If arrMspFiles(iPosPatch,MSPFILES_PACKAGE) = "" Then
If UBound(arrTitle)>0 Then
arrMspFiles(iPosPatch,MSPFILES_PACKAGE) = arrTitle(1)
End If
End If
'PatchSequence & PatchFamily
If InStr(arrMspFiles(iPosPatch,MSPFILES_TABLES),"MsiPatchSequence")>
0 Then
Set qView = Msp.OpenView("SELECT `PatchFamily`,`Sequence`,`Attri
butes` FROM MsiPatchSequence")
qView.Execute : Set Record = qView.Fetch()
If Not Record Is Nothing Then
Do Until Record Is Nothing
arrMspFiles(iPosPatch,MSPFILES_FAMILY) = arrMspFiles(iPo
sPatch,MSPFILES_FAMILY)&Record.StringData(1)&","
arrMspFiles(iPosPatch,MSPFILES_SEQUENCE) = arrMspFiles(i
PosPatch,MSPFILES_SEQUENCE)&Record.StringData(2)&","
arrMspFiles(iPosPatch,MSPFILES_ATTRIBUTE) = Record.Strin
gData(3)
Set Record = qView.Fetch()
Loop
arrMspFiles(iPosPatch,MSPFILES_FAMILY) = RTrimComma(arrMspFi
les(iPosPatch,MSPFILES_FAMILY))
arrMspFiles(iPosPatch,MSPFILES_SEQUENCE) = RTrimComma(arrMsp
Files(iPosPatch,MSPFILES_SEQUENCE))
Else
arrMspFiles(iPosPatch,MSPFILES_FAMILY) = ""
arrMspFiles(iPosPatch,MSPFILES_SEQUENCE) = "0"
arrMspFiles(iPosPatch,MSPFILES_ATTRIBUTE) = "0"
End If
qView.Close
Else
arrMspFiles(iPosPatch,MSPFILES_FAMILY) = ""
arrMspFiles(iPosPatch,MSPFILES_SEQUENCE) = "0"
arrMspFiles(iPosPatch,MSPFILES_ATTRIBUTE) = "0"
End If
End If
Next 'Key
'Copy the collected data to the arrPatch array
For iPosMaster = 0 To UBound(arrMaster)
dicMspSequence.RemoveAll
sBaseSeqShort = ""
arrVer = Split(arrMaster(iPosMaster,COL_PRODUCTVERSION),".")
If UBound(arrVer)>1 Then sBaseSeqShort = arrVer(2)
For iPosPatch = 0 to UBound(arrPatch,3)
If Not (IsEmpty (arrPatch(iPosMaster,PATCH_PATCHCODE,iPosPatch))) AN
D (arrPatch(iPosMaster,PATCH_CSP,iPosPatch)) Then
iIndex = -1
iIndex = dicMspIndex.Item(arrPatch(iPosMaster,PATCH_PATCHCODE,iP
osPatch))
If NOT iIndex = -1 Then
'KB field
arrPatch(iPosMaster,PATCH_KB,iPosPatch) = arrMspFiles(iIndex
,MSPFILES_KB)
'StdPackageName
arrPatch(iPosMaster,PATCH_PACKAGE,iPosPatch) = arrMspFiles(i
Index,MSPFILES_PACKAGE)
'PatchSequenece
Set arrTmpSeq = Nothing
arrTmpSeq = Split(arrMspFiles(iIndex,MSPFILES_SEQUENCE),",")
arrPatch(iPosMaster,PATCH_SEQUENCE,iPosPatch) = arrTmpSeq(0)
'PatchFamily
Function GetPatchTables(Msp)
Dim ViewTables,Table
Dim sTables
On Error Resume Next
sTables = ""
Set Table = Nothing
Set ViewTables = Msp.OpenView("SELECT `Name` FROM `_Tables` ORDER BY `Name`"
)
ViewTables.Execute
Do
Set Table = ViewTables.Fetch
If Table Is Nothing then Exit Do
sTables = sTables&Table.StringData(1)&","
Loop
ViewTables.Close
GetPatchTables=RTrimComma(sTables)
End Function 'GetPatchTables
'===============================================================================
========================
'Module ARP - Add Remove Programs
'===============================================================================
========================
'Build array with data from Add/Remove Programs.
'This is essential for Office 2007 family applications
Sub ARPData
On Error Resume Next
'Filter for >O12 products since the logic is proprietary to >O12
FindArpParents
AddArpParentsToMaster
AddSystemComponentFlagToMaster
ValidateSystemComponentProducts
FindArpConfigMsi
End Sub 'ARPData
'===============================================================================
========================
'Identify the core configuration .msi for multi .msi ARP entries
Sub FindArpConfigMsi
Dim n, i, k
Dim hDefKey
Dim sSubKeyName, sCurKey, sName, sValue, sArpProd, sArpProdWW
Dim arrKeys, arrValues, arrTmpArp
Dim ProdId
On Error Resume Next
'Get Reg_Multi_Sz 'PackageIds' entry from 'uninstall' key
'Do an InStr compare on each entry against ARP keyname
'The identified position matches the position of the Reg_Multi_Sz 'ProductCo
des'
hDefKey = HKEY_LOCAL_MACHINE
If Not CheckArray(arrArpProducts) Then
If Not UBound(arrArpProducts) = -1 Then
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,ERR_NOARRA
Y& " Terminated ARP detection"
End If
Err.Clear
Exit Sub
End If
For n = 0 To UBound(arrArpProducts)
k = -1
sArpProd = arrArpProducts(n,COL_CONFIGNAME)
'Server products do not follow the 'WW' naming logic
If Not InStr(sArpProd,".") > 0 Then sArpProdWW = sArpProd & "WW"
sName = "PackageIds"
If UCase(Left(sArpProd,9))="OFFICE14." OR UCase(Left(sArpProd,9))="OFFIC
E15." Then
sName = "PackageRefs"
sArpProdWW = Right(sArpProd,Len(sArpProd)-9) & "WW"
End If
sSubKeyName = REG_ARP & arrArpProducts(n,COL_CONFIGNAME) & "\"
If RegReadMultiStringValue(hDefKey,sSubKeyName,sName,arrValues) Then
i = 0
'The target product is usually at the last entry of the array
'Check last entry first. If this fails search the array
If InStr(UCase(arrValues(UBound(arrValues))),UCase(sArpProdWW)) > 0
Then
k = UBound(arrValues)
ElseIf InStr(UCase(arrValues(UBound(arrValues))),UCase(sArpProd)) >
0 Then
k = UBound(arrValues)
Else
For Each ProdId in arrValues
If InStr(UCase(ProdID),UCase(sArpProdWW)) > 0 Then
k = i
Exit For
End If 'InStr
i = i + 1
Next 'ProdId
'Before failing completely try without the 'WW' extension
If k = - 1 Then
For Each ProdId in arrValues
If InStr(UCase(ProdID),UCase(sArpProd)) > 0 Then
k = i
Exit For
End If 'InStr
i = i + 1
Next 'ProdId
End If 'k = -1
End If 'InStr
Else
'Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,ERR_NOARR
AY
End If 'RegReadMultiStringValue
If Not k = -1 Then 'found a matching 'Config Guid' for the product
'Add the Config PackageID to the array
arrArpProducts(n,COL_CONFIGPACKAGEID) = arrValues(k)
End If 'k
Next 'n
End Sub 'FindArpConfigMsi
'===============================================================================
========================
'Check if every Office product flagged as 'SystemComponent = 1' has a parent reg
istered
Sub ValidateSystemComponentProducts
Dim n
On Error Resume Next
For n = 0 To UBound (arrMaster)
If Not Err=0 Then Exit For
If arrMaster(n,COL_ISOFFICEPRODUCT) Then
If (NOT arrMaster(n, COL_SYSTEMCOMPONENT) = 0) AND (arrMaster(n, CO
L_ARPPARENTCOUNT) = 0) Then
'Identified orphaned product
'Log warning except for C2R, AER or Rosebud
Select Case Mid(arrMaster(n, COL_PRODUCTCODE), 11, 4)
Case "0010", "00B9", "008C", "008F", "007E"
' don't add warning
Case Else
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYNOTE,ERR
_ORPHANEDITEM & DSV & arrMaster(n,COL_PRODUCTNAME) & DSV & arrMaster(n,COL_PRODU
CTCODE)
arrMaster(n,COL_NOTES) = arrMaster(n,COL_NOTES) & ERR_CATEGO
RYNOTE & ERR_ORPHANEDITEM & CSV
End Select
End If 'Not arrMaster
End If 'IsOfficeProduct
Next 'n
End Sub
'===============================================================================
========================
'Adds the ARP config product information to the individual products
Sub AddArpParentsToMaster
Dim i, n
On Error Resume Next
For n = 0 To UBound(arrMaster)
If Not Err=0 Then Exit For
If arrMaster(n,COL_ISOFFICEPRODUCT) Then
For i = 0 To UBound(arrArpProducts)
If InStr(arrArpProducts(i,COL_ARPALLPRODUCTS),arrMaster(n,COL_PR
ODUCTCODE)) > 0 Then
'add COL_ARPPARENTCOUNT COL_ARPPARENTS
arrMaster(n,COL_ARPPARENTCOUNT) = arrMaster(n,COL_ARPPARENTC
OUNT) + 1
arrMaster(n,COL_ARPPARENTS) = arrMaster(n,COL_ARPPARENTS) &
"," & arrArpProducts(i,COL_CONFIGNAME)
End If
Next 'i
End If
Next 'n
End Sub
'===============================================================================
========================
'Add applications 'SystemComponent' flag from ARP to Master array
Sub AddSystemComponentFlagToMaster
Dim sValue, sSubKeyName
Dim n
On Error Resume Next
For n = 0 To UBound(arrMaster)
If Not Err=0 Then Exit For
sSubKeyName = REG_ARP & arrMaster(n,COL_PRODUCTCODE) & "\"
If RegReadDWordValue(HKEY_LOCAL_MACHINE,sSubKeyName,"SystemComponent",sV
alue) Then
arrMaster(n,COL_SYSTEMCOMPONENT) = sValue
Else
arrMaster(n,COL_SYSTEMCOMPONENT) = 0
End If 'RegReadDWordValue "SystemComponent"
Next 'n
End Sub
'===============================================================================
========================
'Find parent entries from 'Add/Remove Programs' for Office applications which ar
e flagged as 'Systemcomponent'
'ARP entries flagged as Systemcomponent will not display under 'Add/Remove Progr
ams'
'From Office 2007 on ARP groups the multi MSI configuration together.
Sub FindArpParents
Dim ArpProd, ProductCode, Key, dicKey
Dim n, i, j, iMaxVal, iArpCnt, iPosMaster, iLoop
Dim bNoSysComponent, bOConfigEntry, fFoundConfigProductCode, fUninstallStrin
g
Dim hDefKey
Dim sSubKeyName, sCurKey, sName, sValue, sNames, sArpProductName, sRegArp
Dim arrKeys, arrValues, arrTmpArp, arrNames, arrTypes
Dim dicArpTmp
Dim tModulStart, tModulEnd
On Error Resume Next
iLoop = 0 : iMaxVal = 0: iArpCnt = 0 : Redim arrTmpArp(-1)
Set dicArpTmp = CreateObject("Scripting.Dictionary")
While iLoop < 2
iLoop = iLoop + 1
hDefKey = HKEY_LOCAL_MACHINE
sRegArp = REG_ARP
If iLoop = 2 Then sRegArp = REG_C2RVIRT_HKLM & REG_ARP
sSubKeyName = sRegArp
Set dicMissingChild = CreateObject("Scripting.Dictionary")
If RegEnumKey (hDefKey,sSubKeyName,arrKeys) Then
For Each ArpProd in arrKeys
sCurKey = sSubKeyName & ArpProd & "\"
bNoSysComponent = True
bOConfigEntry = False
sNames = "" : Redim arrNames(-1) : Redim arrTypes(-1)
If RegEnumValues(hDefKey,sCurKey,arrNames,arrTypes) Then sNames
= Join(arrNames)
If InStr(sNames,"PackageIds") OR InStr(sNames,"PackageRefs") OR
UCase(Left(ArpProd, 9)) = "OFFICE14." OR UCase(Left(ArpProd, 9)) = "OFFICE15."
Then bOConfigEntry = True
If bOConfigEntry Then
sName = "SystemComponent"
'If RegDWORD 'SystemComponent' = 1 then it's not showing up
in ARP
If RegReadDWordValue(hDefKey,sCurKey,sName,sValue) Then
If CInt(sValue) = 1 Then
End If 'UBound(arrValues)
j = ARP_CHILDOFFSET
For Each ProductCode in arrValues
arrArpProducts(n,COL_ARPALLPRODUCTS) = arrArpProducts(n,COL_ARPA
LLPRODUCTS) & ProductCode
arrArpProducts(n,j) = ProductCode
' validate that the product is installed
If NOT dicProducts.Exists(ProductCode) Then
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,ER
R_MISSINGCHILD&"Config Product: "&ArpProd& CSV & "Missing Product: "&ProductCode
If NOT dicMissingChild.Exists(ProductCode) Then dicMissingCh
ild.Add ProductCode,ArpProd
End If
j = j + 1
Next 'ProductCode
' identify the config ProductCode
fFoundConfigProductCode = False
sArpProductName = ""
sArpProductName = GetArpProductName(ArpProd)
For Each ProductCode in arrValues
iPosMaster = GetArrayPosition(arrMaster,ProductCode)
If NOT iPosMaster = -1 Then
If LCase(Trim(sArpProductName)) = LCase(Trim(arrMaster(GetAr
rayPosition(arrMaster,ProductCode),COL_PRODUCTNAME))) Then
arrArpProducts(n,ARP_CONFIGPRODUCTCODE) = ProductCode
fFoundConfigProductCode = True
Exit For
End If
End If
Next 'ProductCode
If NOT fFoundConfigProductCode Then
i = 0
For Each ProductCode in arrValues
If (NOT Mid(ProductCode,11,4)="002A") AND (Mid(ProductCode,1
6,4)="0000") _
OR (Mid(ProductCode,12,2)="10") _
Then
i = i + 1
arrArpProducts(n,ARP_CONFIGPRODUCTCODE) = ProductCode
End If
Next 'ProductCode
' ensure to not have ambigious hits
If i > 1 Then
Dim MsiDb,Record
Dim qView
For Each ProductCode in arrValues
If (NOT Mid(ProductCode,11,4)="002A") AND (Mid(ProductCo
de,16,4)="0000") _
OR (Mid(ProductCode,12,2)="10") _
Then
Set MsiDb = oMsi.OpenDatabase(arrMaster(GetArrayPosi
tion(arrMaster,ProductCode),COL_CACHEDMSI),MSIOPENDATABASEMODE_READONLY)
Set qView = MsiDb.OpenView("SELECT * FROM Proper
ty WHERE `Property` = 'SetupExeArpId'")
qView.Execute
Set Record = qView.Fetch()
If Not Record Is Nothing Then
arrArpProducts(n,ARP_CONFIGPRODUCTCODE) = Pr
oductCode
qView.Close
Exit For
End If 'Is Nothing
'SetupExeArpId'
End If
Next 'ProductCode
End If
End If 'NOT fFoundConfigProductCode
Else
' handle Click2Run
arrArpProducts(n,COL_CONFIGNAME) = ArpProd
arrArpProducts(n, COL_CONFIGINSTALLTYPE) = "C2R"
If 1 + ARP_CHILDOFFSET > iMaxVal Then
iMaxVal = 1 + ARP_CHILDOFFSET
Redim Preserve arrArpProducts(iArpCnt, iMaxVal)
End If
' V1
If RegEnumKey (HKLM, REG_ARP, arrKeys) Then
For Each Key in arrKeys
If Len(Key)=38 Then
If Mid(Key,11,4) = "006D" Then
arrArpProducts(n,COL_ARPALLPRODUCTS) = Key
arrArpProducts(n,ARP_CHILDOFFSET) = Key
arrArpProducts(n,ARP_CONFIGPRODUCTCODE) = Key
End If
End If
Next 'Key
End If
' V2
iPosMaster = GetArrayPositionFromPattern(arrMaster, "150000-000F-000
0-0000-0000000FF1CE}")
If iPosMaster = -1 Then iPosMaster = GetArrayPositionFromPattern(arr
Master, "150000-000F-0000-1000-0000000FF1CE}")
If InStr(UCase(ArpProd), ".MONDO") > 0 Then
arrArpProducts(n, COL_CONFIGINSTALLTYPE) = "VIRTUAL"
If NOT iPosMaster = -1 Then
arrArpProducts(n,ARP_CONFIGPRODUCTCODE) = arrMaster(iPosMast
er, COL_PRODUCTCODE)
End If
If UBound (arrMVProducts) + ARP_CHILDOFFSET > iMaxVal Then
iMaxVal = UBound (arrMVProducts) + ARP_CHILDOFFSET
Redim Preserve arrArpProducts(iArpCnt,iMaxVal)
End If 'UBound(arrMVProducts)
' fill the array set
j = ARP_CHILDOFFSET
i = 0
For i = 0 To UBound(arrMVProducts)
'If arrMaster(i, COL_VIRTUALIZED) = 1 Then
arrArpProducts(n, COL_ARPALLPRODUCTS) = arrArpProducts(n
, COL_ARPALLPRODUCTS) & arrMVProducts(i, COL_PRODUCTCODE)
arrArpProducts(n, j) = arrMVProducts(i, COL_PRODUCTCODE)
j = j + 1
'End If
Next 'i
Else
If NOT iPosMaster = -1 Then
arrArpProducts(n,COL_ARPALLPRODUCTS) = arrMaster(iPosMaster,
COL_PRODUCTCODE)
arrArpProducts(n,ARP_CHILDOFFSET) = arrMaster(iPosMaster, CO
L_PRODUCTCODE)
arrArpProducts(n,ARP_CONFIGPRODUCTCODE) = arrMaster(iPosMast
er, COL_PRODUCTCODE)
End If
End If
End If 'RegReadValue "ProductCodes"
n = n + 1
Next 'ArpProd
End Sub 'FindArpParents
'===============================================================================
========================
'Module OSPP - Licensing Data
'===============================================================================
========================
'Use WMI to query the license details for installed Office products
'The license details of the products are mapped to the OSPP data based on the "C
onfiguration Productname"
Sub OsppCollect
Dim iArpCnt, iPosMaster, iLicCnt, iLicPos, iLic, iVPCnt, iVersionMajor
Dim sText, sOsppLicenses, sPossibleSkus, sPossibleSkusFull, sTmp, sXmlLogLin
e
Dim arrLicData
If CheckArray(arrArpProducts) Then
For iArpCnt = 0 To UBound(arrArpProducts)
sOsppLicenses = ""
sXmlLogLine = ""
'Get the link to the master array
iPosMaster = GetArrayPosition(arrMaster,arrArpProducts(iArpCnt,ARP_C
ONFIGPRODUCTCODE))
If iPosMaster > -1 Then
iLicCnt = 0
'OSPP is first used by O14
iVersionMajor = CInt(GetVersionMajor(arrMaster(iPosMaster, COL_P
RODUCTCODE)))
If (arrMaster(iPosMaster, COL_ISOFFICEPRODUCT)) AND iVersionMajo
r > 13 Then
'Get the Config Productname
sText = "" : sText = arrArpProducts(iArpCnt,COL_CONFIGNAME)
If InStr(sText,".") > 0 Then sText = Mid(sText, InStr(sText,
".") + 1)
'A list of all possible licenses this product can use is sto
red in sPossibleSkus
sPossibleSkus = ""
sXmlLogLine = ""
'Loop all licenses
iLicCnt = GetLicCnt(iPosMaster, iVersionMajor, sText, sPossi
bleSkus, sPossibleSkusFull)
If iLicCnt > 0 Then
sOsppLicenses = "Possible Licenses;" & Mid(sPossibleSkus
, 3)
'List installed licenses (ProductKeyID <> "")
iLicPos = 0
sXmlLogLine = ""
For iLic = 1 To iLicCnt
arrLicData = GetLicenseData(iPosMaster,CInt(GetVersi
onMajor(arrMaster(iPosMaster,COL_PRODUCTCODE))),sText,iLicPos,sPossibleSkusFull)
""
Case iState
: sTmp = "UNLICENSED"
: sTmp = "LICENSED"
: sTmp = "OOB GRACE"
: sTmp = "OOT GRACE"
CRIPTION)
sOsppLicenses = sOsppLicenses & "#;#" & "License Family;" & arrLicData(OSPP_
LICENSEFAMILY)
sTmp = GetLicenseStateString(arrLicData(OSPP_LICENSESTATUS))
sTmp = arrLicData(OSPP_LICENSESTATUS) & " - " & sTmp & " (Error Code: 0x" &
Hex(arrLicData(OSPP_LICENSESTATUSREASON))
sTmp = sTmp & " - " & GetLicErrDesc(Hex(arrLicData(OSPP_LICENSESTATUSREASON)
)) & ")"
sOsppLicenses = sOsppLicenses & "#;#" & "License Status;" & sTmp
sOsppLicenses = sOsppLicenses & "#;#" & "Partial ProductKey;" & arrLicData(O
SPP_PARTIALPRODUCTKEY)
sOsppLicenses = sOsppLicenses & "#;#" & "ApplicationID;" & arrLicData(OSPP_A
PPLICATIONID)
sOsppLicenses = sOsppLicenses & "#;#" & "ProductKeyID;" & arrLicData(OSPP_PR
ODUCTKEYID)
sOsppLicenses = sOsppLicenses & "#;#" & "SKU ID;" & arrLicData(OSPP_ID)
If InStr(arrLicData(OSPP_DESCRIPTION),"VOLUME_KMSCLIENT") > 0 Then
sOsppLicenses = sOsppLicenses & "#;#" & "KMS Server;" & arrLicData(OSPP_
DISCOVEREDKEYMANAGEMENTSERVICEMACHINENAME)
sOsppLicenses = sOsppLicenses & "#;#" & "KMS Port;" & arrLicData(OSPP_KE
YMANAGEMENTSERVICEPORT)
sOsppLicenses = sOsppLicenses & "#;#" & "Licensed Days Remaining;" & CIn
t(arrLicData(OSPP_GRACEPERIODREMAINING) / 1440)
sOsppLicenses = sOsppLicenses & "#;#" & "VL Activation Interval;" & arrL
icData(OSPP_VLACTIVATIONINTERVAL) / 60 & " hours"
sOsppLicenses = sOsppLicenses & "#;#" & "VL Renewal Interval;" & arrLicD
ata(OSPP_VLRENEWALINTERVAL) / 1440 & " days"
Else
If arrLicData(OSPP_GRACEPERIODREMAINING) <> 0 Then _
sOsppLicenses = sOsppLicenses & "#;#" & "Remaining Grace Period;" &
CInt(arrLicData(OSPP_GRACEPERIODREMAINING) / 1440) & " days"
End If
End Sub 'AddLicTxtString
'===============================================================================
========================
'Module Productslist
'===============================================================================
========================
Sub FindAllProducts
Dim sActiveSub, sErrHnd
Dim AllProducts, ProdX
Dim arrTmpSids()
Dim sSid, Arr
Dim i
sActiveSub = "FindAllProducts" : sErrHnd = ""
On Error Resume Next
'Build an array of all applications registered to Windows Installer
'Iterate products depending of available WI version
Select Case iWiVersionMajor
Case 3, 4, 5, 6
sErrHnd = "_ErrorHandler3x" : Err.Clear
Set AllProducts = oMsi.ProductsEx("",USERSID_EVERYONE,MSIINSTALLCONTEXT_
ALL) : CheckError sActiveSub,sErrHnd
If CheckObject(AllProducts) Then WritePLArrayEx 3, arrAllProducts, AllPr
oducts, Null, Null
Case 2
'Only available for backwards compatibility reasons
tePLArrayEx 3,arrUUProducts,Products,iContext,sSid
Case MSIINSTALLCONTEXT_USERMANAGED : If CheckObject(Products) Then Write
PLArrayEx 3,arrUMProducts,Products,iContext,sSid
Case Else
End Select
End Sub
'===============================================================================
========================
Sub FindProducts_ErrorHandler (iContext)
Dim sSid, Arr
Dim n
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,"ProductsEx for "
& GetContextString(iContext) & " failed. Error Details: " & _
Err.Source & " " & Hex( Err ) & ": " & Err.Description
On Error Resume Next
FindRegProducts iContext
End Sub
'===============================================================================
========================
'General entry point for getting a list of products from the registry.
Sub FindRegProducts (iContext)
Dim arrKeys,arrTmpKeys
Dim sSid,sSubKeyName,sUMSids,sProd,sTmpProd
Dim hDefKey
Dim n,iProdCnt,iProdFind,iProdTotal
On Error Resume Next
Select Case iContext
Case MSIINSTALLCONTEXT_MACHINE
sSid = MACHINESID
hDefKey = GetRegHive(iContext, sSid, False)
sSubKeyName = GetRegConfigKey("", iContext, sSid, False)
FindRegProductsEx hDefKey, sSubKeyName, sSid, iContext, arrMProducts
Case MSIINSTALLCONTEXT_C2RV2
sSid = MACHINESID
hDefKey = GetRegHive(iContext, sSid, False)
sSubKeyName = GetRegConfigKey("", iContext, sSid, False)
FindRegProductsEx hDefKey, sSubKeyName, sSid, iContext, arrMVProducts
Case MSIINSTALLCONTEXT_USERUNMANAGED
sUMSids = ""
If CheckArray (arrUMSids) Then sUMSids = Join(arrUMSids)
If CheckArray (arrUUSids) Then
iProdTotal = -1
For iProdFind = 0 To 1
For n = 0 To UBound(arrUUSids)
sSid = arrUUSids(n)
hDefKey = GetRegHive(iContext, sSid, False)
sSubKeyName = GetRegConfigKey("", iContext, sSid, False)
If InStr(sUMSids, sSid)>0 Then
'Current SID has installed managed per-user products
'Create a string list with products
sTmpProd = ""
'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\14.0\CVH
'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\<Product
Code> -> InstallLocation = "Virtualized Application"
Set dicVirtProd = CreateObject("Scripting.Dictionary")
If RegEnumKey (HKLM,REG_ARP,arrKeys) Then
For Each Key in arrKeys
If Len(Key)=38 Then
If IsOfficeProduct(Key) Then
If RegReadValue(HKLM,REG_ARP&"\"&Key,"CVH",sValue,"REG_DWORD") T
hen
If sValue = "1" Then
If NOT dicVirtProd.Exists(Key) Then dicVirtProd.Add Key,
Key
End If
End If
End If
End If
Next 'Key
End If
'Fill the virtual products array
If dicVirtProd.Count > 0 Then
ReDim arrVirtProducts(dicVirtProd.Count-1,UBOUND_VIRTPROD)
iVCnt = 0
End Select
End If
'Architecture (bitness)
RegReadValue HKLM, REG_C2RPROPERTYBAG, "platform", sValue, "REG_SZ"
arrVirt2Products(iVCnt,VIRTPROD_BITNESS) = sValue
'Child Packages
If RegEnumKey(HKLM, REG_C2RACTIVEPRODS, arrConfigProducts) Then
For Each ConfigProd in arrConfigProducts
Select Case ConfigProd
Case "culture", "stream"
' ignore
Case arrVirt2Products(iVCnt,VIRTPROD_CONFIGNAME)
sCurKey = REG_C2RACTIVEPRODS & "\" & ConfigProd
If RegEnumKey(HKLM, REG_C2RACTIVEPRODS & "\" & ConfigPro
d, arrCultures) Then
For Each culture in arrCultures
sCurKey = REG_C2RACTIVEPRODS & "\" & ConfigProd
& "\" & culture
RegReadValue HKLM, sCurKey, "Version", sValue, "
REG_SZ"
arrVirt2Products(iVCnt,VIRTPROD_CHILDPACKAGES) =
arrVirt2Products(iVCnt,VIRTPROD_CHILDPACKAGES) & culture & " - " & sValue & ";"
If RegEnumKey(HKLM, sCurKey, arrChildPackages) T
hen
For Each child in arrChildPackages
sCurKey = REG_C2RACTIVEPRODS & "\" & Con
figProd & "\" & culture & "\" & child
sChild = "" : sPackageGuid = "" : sVersi
on = "" : sFileName = ""
RegReadValue HKLM, sCurKey, "PackageGuid
", sPackageGuid, "REG_SZ"
If Len(sPackageGuid) > 0 Then sChild = "
{" & sPackageGuid & "}" & " - "
RegReadValue HKLM, sCurKey, "Version", s
Version, "REG_SZ"
If Len(sVersion) > 0 Then sChild = sChil
d & sVersion & " - "
RegReadValue HKLM, sCurKey, "FileName",
sFileName, "REG_SZ"
If Len(sFileName) > 0 Then
sFileName = Replace(sFileName, ".zip
", "")
sChild = sChild & sFileName
End If
If NOT sChild = "" Then arrVirt2Products
(iVCnt,VIRTPROD_CHILDPACKAGES) = arrVirt2Products(iVCnt,VIRTPROD_CHILDPACKAGES)
& sChild & ";"
Next 'child
End If
Next 'culture
End If
Case Else
' not the targeted product
End Select
Next 'ConfigProd
End If
iVCnt = iVCnt + 1
Next 'VProd
End If 'dicVirtProd > 0
End Sub 'FindV2VirtualizedProducts
'------------------------------------------------------------------------------' GetConfigName
'
' Get the configuration name from the ARP key name
'------------------------------------------------------------------------------Function GetConfigName(ArpItem)
Dim sCurKey, sValue, sDisplayVersion, sUninstallString
dim sCulture, sConfigName
Dim iLeft, iRight
Dim fSystemComponent0, fDisplayVersion, fUninstallString
sCurKey = REG_ARP & ArpItem & "\"
sValue = ""
sDisplayVersion = ""
fSystemComponent0 = NOT (RegReadValue(HKLM, sCurKey, "SystemComponent", sVal
ue, "REG_DWORD") AND (sValue = "1"))
fDisplayVersion = RegReadValue(HKLM, sCurKey, "DisplayVersion", sValue, "REG
_SZ")
If fDisplayVersion Then
sDisplayVersion = sValue
If Len(sValue) > 1 Then
fDisplayVersion = (Left(sValue, 2) = "15")
Else
fDisplayVersion = False
End If
End If
fUninstallString = RegReadValue(HKLM, sCurKey, "UninstallString", sUninstall
String, "REG_SZ")
'C2R
If (fSystemComponent0 AND fDisplayVersion AND InStr(UCase(sUninstallString),
UCase(OREGREFC2R15)) > 0) Then
iLeft = InStr(ArpItem, " - ") + 2
iRight = InStr(iLeft, ArpItem, " - ") - 1
If iRight > 0 Then
sConfigName = Trim(Mid(ArpItem, iLeft, (iRight - iLeft)))
sCulture = Mid(ArpItem, iRight + 3)
Else
sConfigName = Trim(Left(ArpItem, iLeft - 3))
sCulture = Mid(ArpItem, iLeft)
End If
sConfigName = Replace(sConfigName, "Microsoft", "")
sConfigName = Replace(sConfigName, "Office", "")
sConfigName = Replace(sConfigName, "Professional", "Pro")
sConfigName = Replace(sConfigName, "Standard", "Std")
sConfigName = Replace(sConfigName, "(Technical Preview)", "")
sConfigName = Replace(sConfigName, "15", "")
sConfigName = Replace(sConfigName, "2013", "")
sConfigName = Replace(sConfigName, " ", "")
'sConfigName = Replace(sConfigName, "Project", "Prj")
'sConfigName = Replace(sConfigName, "Visio", "Vis")
GetConfigName = sConfigName
Exit Function
End If
GetObjUserSid = sSid
End Function
'===============================================================================
========================
Function GetObjContext(ProdX,iContext,iSource)
On Error Resume Next
If iSource = 3 Then iContext = ProdX.Context
GetObjContext = iContext
End Function
'===============================================================================
========================
Function TranslateObjContext(iContext)
Dim sContext
On Error Resume Next
Select Case iContext
Case MSIINSTALLCONTEXT_USERMANAGED '1
sContext = "User Managed"
Case MSIINSTALLCONTEXT_USERUNMANAGED '2
sContext = "User Unmanaged"
Case MSIINSTALLCONTEXT_MACHINE '4
sContext = "Machine"
Case MSIINSTALLCONTEXT_ALL '7
sContext = "All"
Case MSIINSTALLCONTEXT_C2RV2 '8
sContext = "Machine C2Rv2"
Case Else
sContext = "Unknown"
End Select
TranslateObjContext = sContext
End Function
'===============================================================================
========================
Function GetObjGuid(ProdX,iSource)
Dim sGuid
On Error Resume Next
Select Case iSource
Case 0 'Registry
If (IsValidGuid(ProdX,GUID_COMPRESSED) OR fGuidCaseWarningOnly) Then
sGuid = GetExpandedGuid(ProdX)
Else
sGuid = ProdX
End If
Case 2 'WI 2.x
sGuid = ProdX
Case 3 'WI >=3.x
sGuid = ProdX.ProductCode
Case Else
End Select
GetObjGuid = sGuid
End Function
'===============================================================================
========================
Sub WritePLArrayEx(iSource,Arr,Obj,iContext,sSid)
Dim ProdX,Product,sProductCode,sProductName
Dim i, n, iDimCnt,iPosUMP
On Error Resume Next
If CheckObject(Obj) Or CheckArray(Obj) Then
i = 0
If CheckObject(Obj) Then
ReDim Arr(Obj.Count-1, UBOUND_MASTER)
Else
If UBound(Obj)>UBound(Arr) Then ReDim Arr(UBound(Obj), UBOUND_MASTER
)
Do While Not IsEmpty(Arr(i,0))
i=i+1
If i >= UBound(Obj) Then Exit Do
Loop
End If 'CheckObject
For Each ProdX in Obj
' preset Recordset with Default Error
For n = 0 to 4
Arr(i,n) = "Preset Error String"
Next 'n
' ProductCode
Arr(i,COL_PRODUCTCODE) = GetObjGUID(ProdX,iSource)
' ProductContext
Arr(i,COL_CONTEXT) = GetObjContext(ProdX,iContext,iSource)
Arr(i,COL_CONTEXTSTRING) = TranslateObjContext(Arr(i,COL_CONTEXT))
' SID
Arr(i,COL_USERSID) = GetObjUserSid(ProdX,sSid,iSource)
' ProductName
Arr(i,COL_PRODUCTNAME) = GetObjProductName(ProdX,Arr(i,COL_PRODUCTCO
DE),Arr(i,COL_CONTEXT),Arr(i,COL_USERSID),iSource)
' ProductState
Arr(i,COL_STATE) = GetObjProductState(ProdX,Arr(i,COL_CONTEXT),Arr(i
,COL_USERSID),iSource)
Arr(i,COL_STATESTRING) = TranslateObjProductState(Arr(i,COL_STATE))
' write to cache
CacheLog LOGPOS_RAW,LOGHEADING_NONE,Null,Arr(i,COL_PRODUCTCODE) & ",
" & Arr(i,COL_CONTEXT) & "," & Arr(i,COL_USERSID) & "," & _
Arr(i,COL_PRODUCTNAME) & "," & Arr(i,COL_STATE)
' ARP ProductName
Arr(i,COL_ARPPRODUCTNAME) = GetArpProductname(Arr(i,COL_PRODUCTCODE)
)
' Guid validation
If Not IsValidGuid(Arr(i,COL_PRODUCTCODE),GUID_UNCOMPRESSED) Then
If fGuidCaseWarningOnly Then
Arr(i,COL_NOTES) = Arr(i,COL_NOTES) & ERR_CATEGORYNOTE & ERR
_GUIDCASE & CSV
Else
Arr(i,COL_ERROR) = Arr(i,COL_ERROR) & ERR_CATEGORYERROR & sE
rror & CSV
Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATEGORYERROR,sE
rror & DSV & Arr(i,COL_PRODUCTCODE) & DSV & _
arrAllProducts(-1)
arrVirtProducts(-1)
arrVirt2Products(-1)
arrMProducts(-1)
arrMVProducts(-1)
arrUUProducts(-1)
arrUMProducts(-1)
'===============================================================================
========================
'Module Prerequisites
'===============================================================================
========================
Function CheckPreReq ()
On Error Resume Next
Dim sActiveSub, sErrHnd
Dim sPreReqError, sDebugLogName, sSubKeyName
Dim i, iFoo
Dim hDefKey, lAccPermLevel
Dim oCompItem, oWmiLocal, oItem
sActiveSub = "CheckPreReq" : sErrHnd = "_ErrorHandler"
fIsCriticalError = False
CheckPreReq = True : fIsAdmin = True : fIsElevated = True
sPreReqError = vbNullString
Err.Clear
'Create the WScript Shell Object
Set oShell = CreateObject("WScript.Shell"): CheckError sActiveSub,sErrHnd
sComputerName = oShell.ExpandEnvironmentStrings("%COMPUTERNAME%"): CheckErro
r sActiveSub,sErrHnd
sTemp = oShell.ExpandEnvironmentStrings("%TEMP%"): CheckError sActiveSub,sEr
rHnd
'Create the Windows Installer Object
Set oMsi = CreateObject("WindowsInstaller.Installer"): CheckError sActiveSub
,sErrHnd
iWiVersionMajor = Left(oMsi.Version,Instr(oMsi.Version,".")-1)
If (CheckPreReq = True And iWiVersionMajor < 2) Then CheckPreReq = False
'Create the FileSystemObject
Set oFso = CreateObject("Scripting.FileSystemObject"): CheckError sActiveSub
,sErrHnd
'Connect to WMI Registry Provider
Set oReg = GetObject("winmgmts:\\.\root\default:StdRegProv"): CheckError sAc
tiveSub,sErrHnd
'Needs to be done here already as registry access calls depend on it
Set oWmiLocal = GetObject("winmgmts:\\.\root\cimv2")
Set oCompItem = oWmiLocal.ExecQuery("Select * from Win32_ComputerSystem")
For Each oItem In oCompItem
sSystemType = oItem.SystemType
f64 = Instr(Left(oItem.SystemType,3),"64") > 0
Next
'Check registry access permissions
'Failure will not terminate the scipt but noted in the log
hDefKey = HKEY_LOCAL_MACHINE
sSubKeyName = "SOFTWARE\Microsoft\Windows"
For i = 1 To 4
Select Case i
Case 1 : lAccPermLevel = KEY_QUERY_VALUE
Case 2 : lAccPermLevel = KEY_SET_VALUE
Case 3 : lAccPermLevel = KEY_CREATE_SUB_KEY
Case 4 : lAccPermLevel = DELETE
End Select
If Not RegCheckAccess(hDefKey,sSubKeyName,lAccPermLevel) Then
fIsAdmin = False
Exit for
End If
Next 'i
If fIsAdmin Then
sSubKeyName = "Software\Microsoft\Windows\"
For i = 1 To 4
Select Case i
Case 1 : lAccPermLevel = KEY_QUERY_VALUE
Case 2 : lAccPermLevel = KEY_SET_VALUE
Case 3 : lAccPermLevel = KEY_CREATE_SUB_KEY
Case 4 : lAccPermLevel = DELETE
End Select
If Not RegCheckAccess(hDefKey,sSubKeyName,lAccPermLevel) Then
fIsElevated = False
Exit for
End If
Next 'i
End If 'fIsAdmin
Set ShellApp = CreateObject("Shell.Application")
If Not sPreReqError = vbNullString Then
If fQuiet = False Then
Msgbox "Script execution needs to terminate" & vbCrLf & vbCrLf & sPr
eReqError, vbOkOnly, _
"Critical Error in Script Prerequisite Check"
End If
CheckPreReq = False
End If ' sPreReqError = vbNullString
End Function 'CheckPreReq()
'===============================================================================
========================
Sub CheckPreReq_ErrorHandler
sPreReqError = sPreReqError & _
sDebugErr & " returned:" & vbCrLf &_
"Error Details: " & Err.Source & " " & Hex( Err ) & ": " & Err.Descripti
on & vbCrLf & vbCrLf
End Sub
'===============================================================================
========================
'Module ComputerProperties
'===============================================================================
========================
Sub ComputerProperties
Dim oOS, oWmi, oOsItem
Dim sOSinfo, sOSVersion, sUserInfo, sSubKeyName, sName, sValue, sOsMui, sOsL
cid, sCulture
Dim arrKeys, arrNames, arrTypes,arrVersion
Dim qOS, OsLang, ValueType
Dim iOSVersion, iValueName
Dim hDefKey
Const REG_SZ = 1
On Error Resume Next
sComputerName = oShell.ExpandEnvironmentStrings("%COMPUTERNAME%")
'Note 64 bit OS check was already done in 'Sub Initialize'
'OS
Set
Set
For
Next
sOSinfo = sOSinfo & CSV & "System Type: " & sSystemType
'Check for OS MUI languages
'The MUI registry location has been changed with Windows Vista
'Win 2000, XP and Server 2003: HKLM\System\CurrentControlSet\Control\Nls\MUI
Languages
'From Vista on: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MUI\UILa
nguages
========================
Sub WriteLog
Dim LogOutput
Dim i,n
Dim sScriptSettings
On Error Resume Next
'Add actual values for customizable settings
sScriptSettings = ""
If fListNonOfficeProducts Then sScriptSettings = sScriptSettings & "/All "
If fLogFull Then sScriptSettings = sScriptSettings & "/Full "
If fLogVerbose Then sScriptSettings = sScriptSettings & "/LogVerbose "
If fLogChainedDetails Then sScriptSettings = sScriptSettings & "/LogChainedD
etails "
If fFileInventory Then sScriptSettings = sScriptSettings & "/FileInventory "
If fFeatureTree Then sScriptSettings = sScriptSettings & "/FeatureTree "
If fBasicMode Then sScriptSettings = "/Basic "
If fQuiet Then sScriptSettings = sScriptSettings & "/Quiet "
If Not sPathOutputFolder = "" Then sScriptSettings = sScriptSettings & "/Log
folder: "&sPathOutputFolder
CacheLog LOGPOS_COMPUTER,LOGHEADING_NONE,"Script Settings",sScriptSettings
'Determine total scan time
tEnd = Time()
If NOT fBasicMode Then CacheLog LOGPOS_COMPUTER,LOGHEADING_NONE,"Total scan
time",Int((tEnd - tStart)*1000000 + 0.5)/10 & " s"
Set LogOutput = oFso.OpenTextFile(sLogFile, FOR_WRITING, True, True)
LogOutput.WriteLine "Microsoft Customer Support Services - Robust Office Inv
entory - " & Now
LogOutput.Write vbCrLf & String(160,"*") & vbCrLf
'Flush the prepared output arrays to the log
n = 2
'Enable raw output if an error was encountered
If NOT Len(arrLog(1)) = 32 AND NOT fBasicMode Then n = 3
For i = 0 to n
If i = 1 Then
If NOT Len(arrLog(i)) = 32 Then
LogOutput.Write arrLog(i)
LogOutput.Write vbCrLf & String(160,"*") & vbCrLf
End If
Else
LogOutput.Write arrLog(i)
If NOT (i = 2) Then LogOutput.Write vbCrLf & String(160,"*") & vbCrL
f
End If
Next 'i
LogOutput.Close
Set LogOutput = Nothing
'Copy the log to the fileinventory folder if needed
If fFileInventory Then oFso.CopyFile sLogFile,sPathOutputFolder&"ROIScan\",
TRUE
' write the xml log
WriteXmlLog
End Sub
'===============================================================================
========================
Sub WriteXmlLog
Dim XmlLogStream, mspSeq, key, lic
Dim sXmlLine, sText, sProductCode, sSPLevel, sFamily, sSeq
Dim i, iVPCnt, iItem, iArpCnt, iDummy, iPos, iPosMaster, iChainProd, iPosPat
ch, iColPatch
Dim iColISource, iLogCnt
Dim arrC2RPackages, arrC2RItems, arrTmp, arrTmpInner, arrLicData
Dim dicTmp
Dim fLogProduct
On Error Resume Next
Set dicTmp = CreateObject("Scripting.Dictionary")
Set XmlLogStream = oFso.CreateTextFile(sPathOutputFolder & sComputerName & "
_ROIScan.xml", True, True)
XmlLogStream.WriteLine "<?xml version=""1.0""?>"
XmlLogStream.WriteLine "<OFFICEINVENTORY>"
'c2r v2
If UBound(arrVirt2Products) > -1 Then
For iVPCnt = 0 To UBound(arrVirt2Products, 1)
sXmlLine = ""
sXmlLine = "<SKU "
' ProductName (heading)
sXmlLine = sXmlLine & "ProductName=" & chr(34) & arrVirt2Products(iV
PCnt,COL_PRODUCTNAME) & chr(34)
' ConfigName
sXmlLine = sXmlLine & " ConfigName=" & chr(34) & arrVirt2Products(iV
PCnt,VIRTPROD_CONFIGNAME) & chr(34)
sXmlLine = sXmlLine & " IsChainedChild=" & chr(34) & "FALSE" & chr(3
4)
' ProductCode
sXmlLine = sXmlLine & " ProductCode=" & chr(34) & "" & chr(34)
' ProductVersion
sXmlLine = sXmlLine & " ProductVersion=" & chr(34) & arrVirt2Product
s(iVPCnt,VIRTPROD_PRODUCTVERSION) & chr(34)
' SP Level
sXmlLine = sXmlLine & " ServicePackLevel=" & chr(34) & arrVirt2Produ
cts(iVPCnt,VIRTPROD_SPLEVEL) & chr(34)
' Architecture
sXmlLine = sXmlLine & " Architecture=" & chr(34) & arrVirt2Products(
iVPCnt,VIRTPROD_BITNESS) & chr(34)
' InstallType
sXmlLine = sXmlLine & " InstallType=" & chr(34) & "C2R" & chr(34)
' end line
sXmlLine = sXmlLine & " >"
'flush
XmlLogStream.WriteLine sXmlLine
' Child Packages
XmlLogStream.WriteLine "<ChildPackages>"
arrC2RPackages = Split(arrVirt2Products(iVPCnt,VIRTPROD_CHILDPACKAGE
S), ";")
For i = 0 To UBound(arrC2RPackages) - 1 'strip off last delimiter
arrC2RItems = Split(arrC2RPackages(i), " - ")
If UBound(arrC2RItems) = 1 Then
TNAME)
sXmlLine = sXmlLine & "ProductName=" & chr(34) & sText & chr(34)
' Configuration ProductName
sText = "" : sText = arrArpProducts(iArpCnt, COL_CONFIGNAME)
If InStr(sText,".") > 0 Then sText = Mid(sText, InStr(sText, ".") + 1)
sXmlLine = sXmlLine & " ConfigName=" & chr(34) & sText & chr(34)
sXmlLine = sXmlLine & " IsChainedChild=" & chr(34) & "FALSE" & chr(34)
' ProductCode
sXmlLine = sXmlLine & " ProductCode=" & chr(34) & "" & chr(34)
' ProductVersion
sXmlLine = sXmlLine & " ProductVersion=" & chr(34) & arrArpProducts(iArp
Cnt, ARP_PRODUCTVERSION) & chr(34)
' ServicePack
sSPLevel = ""
If NOT iPos = -1 AND NOT sProductCode = "" AND Len(arrArpProducts(iArpCn
t, ARP_PRODUCTVERSION)) > 2 Then
sSPLevel = OVersionToSpLevel(sProductCode, GetVersionMajor(sProductC
ode), arrArpProducts(iArpCnt, ARP_PRODUCTVERSION))
End If
sXmlLine = sXmlLine & " ServicePackLevel=" & chr(34) & sSPLevel & chr(3
4)
' Architecture
sXmlLine = sXmlLine & " Architecture=" & chr(34) & arrMaster(iPos, COL_A
RCHITECTURE) & chr(34)
' InstallType
sXmlLine = sXmlLine & " InstallType=" & chr(34) & arrMaster(iPos, COL_IN
STALLTYPE) & chr(34)
' InstallDate
sXmlLine = sXmlLine & " InstallDate=" & chr(34) & Left(Replace(arrMaster
(iPos, COL_INSTALLDATE), " ", ""), 8) & chr(34)
' ProductState
sXmlLine = sXmlLine & " ProductState=" & chr(34) & arrMaster(iPos, COL_S
TATESTRING) & chr(34)
' ConfigMsi
sXmlLine = sXmlLine & " ConfigMsi=" & chr(34) & arrMaster(iPos, COL_ORIG
INALMSI) & chr(34)
' BuildOrigin
sXmlLine = sXmlLine & " BuildOrigin=" & chr(34) & arrMaster(iPos, COL_OR
IGIN) & chr(34)
' end line
sXmlLine = sXmlLine & " >"
'flush
XmlLogStream.WriteLine sXmlLine
' Child Packages
XmlLogStream.WriteLine "<ChildPackages>"
For iChainProd = COL_LBOUNDCHAINLIST To UBound(arrArpProducts, 2)
If IsEmpty(arrArpProducts(iArpCnt, iChainProd)) Then Exit For
iPosMaster = GetArrayPosition(arrMaster,arrArpProducts(iArpCnt,i
ChainProd))
'Only run if iPosMaster has a valid index #
sXmlLine = "<ChildPackage"
'ProductCode
sText = "" : If NOT iPosMaster = -1 Then sText = arrMaster(iPosM
aster, COL_PRODUCTCODE)
sXmlLine = sXmlLine & " ProductCode=" & chr(34) & sText & chr(34
)
'ProductVersion
sText = "" : If NOT iPosMaster = -1 Then sText = arrMaster(iPosM
aster, COL_PRODUCTVERSION)
sXmlLine = sXmlLine & " ProductVersion=" & chr(34) & sText & chr
(34)
'ProductName
sText = "" : If NOT iPosMaster = -1 Then sText = arrMaster(iPosM
aster, COL_PRODUCTNAME)
sXmlLine = sXmlLine & " ProductName=" & chr(34) & sText & chr(34
)
' end line
sXmlLine = sXmlLine & " />"
'flush
XmlLogStream.WriteLine sXmlLine
Next 'iChainProd
XmlLogStream.WriteLine "</ChildPackages>"
'LicenseData
'----------XmlLogStream.WriteLine "<LicenseData>"
If NOT iPos = -1 Then
If arrMaster(iPos, COL_OSPPLICENSE) <> "" Then
XmlLogStream.WriteLine arrMaster(iPos, COL_OSPPLICENSEXML)
End If
End If
XmlLogStream.WriteLine "</LicenseData>"
' Patches
XmlLogStream.WriteLine "<PatchData>"
' PatchBaseLines
XmlLogStream.WriteLine "<PatchBaseline Sequence=" & chr(34) & arrArpProd
ucts(iArpCnt, ARP_PRODUCTVERSION) & chr(34) & " >"
dicTmp.RemoveAll
For iChainProd = COL_LBOUNDCHAINLIST To UBound(arrArpProducts, 2)
If IsEmpty(arrArpProducts(iArpCnt, iChainProd)) Then Exit For
iPosMaster = GetArrayPosition(arrMaster, arrArpProducts(iArpCnt, iCh
ainProd))
'Only run if iPosMaster has a valid index #
If Not iPosMaster = -1 Then
Set arrTmp = Nothing
arrTmp = Split(arrMaster(iPosMaster, COL_PATCHFAMILY), ",")
For Each MspSeq in arrTmp
arrTmpInner = Split(MspSeq, ":")
sFamily = "" : sSeq = ""
sFamily = arrTmpInner(0)
sSeq = arrTmpInner(1)
If (sSeq>arrMaster(iPosMaster,COL_PRODUCTVERSION)) Then
If dicTmp.Exists(sFamily) Then
If (sSeq > dicTmp.Item(sFamily)) Then dicTmp.Item(sF
amily)=sSeq
Else
dicTmp.Add sFamily,sSeq
End If
End If
Next 'MspSeq
End If 'Not iPosMaster = -1
Next 'iChainProd
For Each key in dicTmp.Keys
XmlLogStream.WriteLine "<PostBaseline PatchFamily=" & chr(34) & key
& chr(34) & " Sequence=" & chr(34) & dicTmp.Item(key) & chr(34) & " />"
Next 'key
XmlLogStream.WriteLine "</PatchBaseline>"
' PatchList
For iChainProd = COL_LBOUNDCHAINLIST To UBound(arrArpProducts, 2)
If IsEmpty(arrArpProducts(iArpCnt,iChainProd)) Then Exit For
iPosMaster = GetArrayPosition(arrMaster, arrArpProducts(iArpCnt, iCh
ainProd))
'Only run if iPosMaster has a valid index #
If Not iPosMaster = -1 Then
For iPosPatch = 0 to UBound(arrPatch, 3)
If Not IsEmpty (arrPatch(iPosMaster, PATCH_PATCHCODE, iPosPa
tch)) Then
sXmlLine = "<Patch PatchedProduct=" & chr(34) & arrMaste
r(iPosMaster, COL_PRODUCTCODE) & chr(34)
For iColPatch = PATCH_LOGSTART to PATCH_LOGCHAINEDMAX
If Not IsEmpty(arrPatch(iPosMaster, iColPatch, iPosP
atch)) Then
sXmlLine = sXmlLine & " " & Replace(arrLogForma
t(ARRAY_PATCH,iColPatch), ": ", "") & "=" & chr(34) & arrPatch(iPosMaster,iColPa
tch,iPosPatch) & chr(34)
End If
Next 'iColPatch
sXmlLine = sXmlLine & " />"
XmlLogStream.WriteLine sXmlLine
'
Set arrTmp = Nothing
'
arrTmp = Split(arrMaster(iPosMaster, COL_PATCHFAMIL
Y), ",")
'
For Each MspSeq in arrTmp
'
arrTmpInner = Split(MspSeq, ":")
'
XmlLogStream.WriteLine "<MsiPatchSequence Patch
Family=" & chr(34) & arrTmpInner(0) & chr(34) & " Sequence=" & chr(34) & arrTmpI
nner(1) & chr(34) & " />"
'
Next 'MspSeq
'
XmlLogStream.WriteLine "</Patch>"
End If 'IsEmpty
Next 'iPosPatch
End If ' Not iPosMaster = -1
Next 'iChainProd
XmlLogStream.WriteLine "</PatchData>"
'InstallSource
XmlLogStream.WriteLine "<InstallSource>"
For iColISource = IS_LOG_LBOUND To IS_LOG_UBOUND
If NOT iPos = -1 Then
If Not IsEmpty(arrIS(iPos, iColISource)) Then _
XmlLogStream.WriteLine "<Source " & Replace(arrLogFormat(ARRAY_I
S,iColISource)," ", "") & "=" & chr(34) & arrIS(iPos, iColISource) & chr(34) & "
/>"
End If
Next 'iColISource
XmlLogStream.WriteLine "</InstallSource>"
XmlLogStream.WriteLine "</SKU>"
Next 'iArpCnt
'Other Products
Err.Clear
For iLogCnt = 0 To 10
For iPosMaster = 0 To UBound(arrMaster)
fLogProduct = CheckLogProduct(iLogCnt, iPosMaster)
If fLogProduct Then
'arrMaster contents
sXmlLine = ""
sXmlLine = "<SKU "
' ProductName (heading)
sText = "" : sText = arrMaster(iPosMaster,COL_ARPPRODUCTNAME)
If sText = "" Then sText = arrMaster(iPosMaster,COL_PRODUCTNAME)
sXmlLine = sXmlLine & "ProductName=" & chr(34) & sText & chr(34)
sXmlLine = sXmlLine & " ConfigName=" & chr(34) & "" & chr(34)
Select Case iLogCnt
Case 1, 3, 5
sXmlLine = sXmlLine & " IsChainedChild=" & chr(34) & "TRUE"
& chr(34)
Case Else
sXmlLine = sXmlLine & " IsChainedChild=" & chr(34) & "FALSE"
& chr(34)
End Select
' ProductCode
sXmlLine = sXmlLine & " ProductCode=" & chr(34) & arrMaster(iPos
Master, COL_PRODUCTCODE) & chr(34)
' ProductVersion
sXmlLine = sXmlLine & " ProductVersion=" & chr(34) & arrMaster(i
PosMaster, COL_PRODUCTVERSION) & chr(34)
' ServicePack
sXmlLine = sXmlLine & " ServicePackLevel=" & chr(34) & arrMaster
(iPosMaster, COL_SPLEVEL) & chr(34)
' Architecture
sXmlLine = sXmlLine & " Architecture=" & chr(34) & arrMaster(iPo
sMaster, COL_ARCHITECTURE) & chr(34)
' InstallType
sXmlLine = sXmlLine & " InstallType=" & chr(34) & arrMaster(iPos
Master, COL_INSTALLTYPE) & chr(34)
' InstallDate
sXmlLine = sXmlLine & " InstallDate=" & chr(34) & Left(Replace(a
rrMaster(iPosMaster, COL_INSTALLDATE), " ", ""), 8) & chr(34)
' ProductState
sXmlLine = sXmlLine & " ProductState=" & chr(34) & arrMaster(iPo
sMaster, COL_STATESTRING) & chr(34)
' ConfigMsi
sXmlLine = sXmlLine & " ConfigMsi=" & chr(34) & arrMaster(iPosMa
ster, COL_ORIGINALMSI) & chr(34)
' BuildOrigin
sXmlLine = sXmlLine & " BuildOrigin=" & chr(34) & arrMaster(iPos
Master, COL_ORIGIN) & chr(34)
' end line
sXmlLine = sXmlLine & " >"
'flush
XmlLogStream.WriteLine sXmlLine
' Patches
XmlLogStream.WriteLine "<PatchData>"
' PatchBaseLines
XmlLogStream.WriteLine "<PatchBaseline Sequence=" & chr(34) & ar
rMaster(iPosMaster, COL_PRODUCTVERSION) & chr(34) & " >"
dicTmp.RemoveAll
Set arrTmp = Nothing
arrTmp = Split(arrMaster(iPosMaster, COL_PATCHFAMILY), ",")
For Each MspSeq in arrTmp
arrTmpInner = Split(MspSeq, ":")
sFamily = "" : sSeq = ""
sFamily = arrTmpInner(0)
sSeq = arrTmpInner(1)
If (sSeq>arrMaster(iPosMaster, COL_PRODUCTVERSION)) Then
If dicTmp.Exists(sFamily) Then
If (sSeq > dicTmp.Item(sFamily)) Then dicTmp.Item(sF
amily) = sSeq
Else
dicTmp.Add sFamily, sSeq
End If
End If
Next 'MspSeq
For Each key in dicTmp.Keys
XmlLogStream.WriteLine "<PostBaseline PatchFamily=" & chr(34
) & key & chr(34) & " Sequence=" & chr(34) & dicTmp.Item(key) & chr(34) & " />"
Next 'key
XmlLogStream.WriteLine "</PatchBaseline>"
For iPosPatch = 0 to UBound(arrPatch, 3)
If Not IsEmpty (arrPatch(iPosMaster, PATCH_PATCHCODE, iPosPa
tch)) Then
sXmlLine = "<Patch PatchedProduct=" & chr(34) & arrMaste
r(iPosMaster, COL_PRODUCTCODE) & chr(34)
For iColPatch = PATCH_LOGSTART to PATCH_LOGCHAINEDMAX
If Not IsEmpty(arrPatch(iPosMaster, iColPatch, iPosP
atch)) Then
sXmlLine = sXmlLine & " " & Replace(arrLogForma
t(ARRAY_PATCH, iColPatch), ": ", "") & "=" & chr(34) & arrPatch(iPosMaster, iCol
Patch, iPosPatch) & chr(34)
End If
Next 'iColPatch
sXmlLine = sXmlLine & " />"
XmlLogStream.WriteLine sXmlLine
End If 'IsEmpty
Next 'iPosPatch
XmlLogStream.WriteLine "</PatchData>"
'InstallSource
XmlLogStream.WriteLine "<InstallSource>"
For iColISource = IS_LOG_LBOUND To IS_LOG_UBOUND
If Not IsEmpty(arrIS(iPos, iColISource)) Then _
XmlLogStream.WriteLine "<Source " & Replace(arrLogFormat(ARR
AY_IS,iColISource)," ", "") & "=" & chr(34) & arrIS(iPosMaster, iColISource) & c
hr(34) & " />"
Next 'iColISource
XmlLogStream.WriteLine "</InstallSource>"
XmlLogStream.WriteLine "</SKU>"
End If 'fLogProduct
Next 'iPosMaster
Next 'iLogCnt
XmlLogStream.WriteLine "</OFFICEINVENTORY>"
End Sub 'WriteXmlLog
'===============================================================================
========================
Sub PrepareLog (sLogFormat)
iPosMaster = GetArrayPosition(arrMaster,arrArpProducts(iArpC
nt,iChainProd))
If iPosMaster = -1 AND NOT dicMissingChild.Exists(arrArpPro
ducts(iArpCnt,iChainProd)) Then Cachelog LOGPOS_REVITEM,LOGHEADING_NONE,ERR_CATE
GORYERROR,ERR_DATAINTEGRITY
'Only run if iPosMaster has a valid index #
If Not iPosMaster = -1 Then
sText = "" : sText = arrMaster(iPosMaster,COL_PRODUCTCOD
E) & DSV & arrMaster(iPosMaster,COL_PRODUCTVERSION) & DSV & arrMaster(iPosMaster
,COL_PRODUCTNAME)
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,sCategory,sText
sCategory = ""
Else
sText = "" : sText = arrArpProducts(iArpCnt,iChainProd)
& DSV & "Error - missing chained product!"
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,sCategory,sText
sCategory = ""
End If 'Not iPosMaster = -1
Next 'iChainProd
End If 'fBasicMode
'LicenseData
'----------If NOT iPos = -1 Then
If arrMaster(iPos,COL_OSPPLICENSE) <> "" Then
arrLicData = Split(arrMaster(iPos,COL_OSPPLICENSE),"#;#")
If CheckArray(arrLicData) Then
If NOT fBasicMode Then CacheLog LOGPOS_PRODUCT,LOGHEADIN
G_NONE,"",""
i = 0
For Each Lic in arrLicData
arrTmp = Split(Lic,";")
If LCase(arrTmp(0)) = "active license" Then i = 1
If i < 2 Then
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,arrTmp(0
),arrTmp(1)
Else
If NOT (fBasicMode AND i > 5) Then
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,"",a
rrTmp(0)&":"& Space(25-Len(arrTmp(0)))&arrTmp(1)
End If
End If
i = i + 1
Next 'Lic
End If 'arrLicData
End If 'arrMaster
End If 'iPos -1
If NOT fBasicMode Then
'Patches
'------CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,"",""
sCategory = "Patch Baseline"
sText = "" : If NOT iPos = -1 Then sText = arrMaster(iPos,COL_PR
ODUCTVERSION)
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,sCategory,sText
sCategory = "Post Baseline Sequences"
dicTmp.RemoveAll
For iChainProd = COL_LBOUNDCHAINLIST To UBound(arrArpProducts,2)
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,sCategor
y,RTrimComma(sText)
End If 'IsEmpty
Next 'iPosPatch
End If ' Not iPosMaster = -1
Next 'iChainProd
'InstallSource
'------------CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,"",""
For iColISource = IS_LOG_LBOUND To IS_LOG_UBOUND
If NOT iPos = -1 Then
If Not IsEmpty(arrIS(iPos,iColISource)) Then _
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,arrLogFormat(ARR
AY_IS,iColISource),arrIS(iPos,iColISource)
End If
Next 'iColISource
End If 'fBasicMode
Next 'iDummy
Next 'iArpCnt
If fLoggedMulti Then CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,"",vbCrLf & Str
ing(160,"*") & vbCrLf
End If 'CheckArray(arrArpProducts)
'Prepare Other Products
'======================
Err.Clear
For iLogCnt = 0 To 10
For iPosMaster = 0 To UBound(arrMaster)
fLogProduct = CheckLogProduct(iLogCnt, iPosMaster)
If fLogProduct Then
If NOT fLoggedSingle Then CacheLog LOGPOS_PRODUCT, LOGHEADING_H1
, Null, "Single .msi Products View"
fLoggedSingle = True
For iDummy = 1 To 1
'arrMaster contents
'-----------------sText = "" : sText = arrMaster(iPosMaster,COL_ARPPRODUCTNAME)
If sText = "" Then sText = arrMaster(iPosMaster,COL_PRODUCTNAME)
CacheLog LOGPOS_PRODUCT,LOGHEADING_H2,Null,sText
If arrMaster(iPosMaster,COL_STATE) = INSTALLSTATE_UNKNOWN Then
sText = arrMaster(iPosMaster,COL_PRODUCTCODE)
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,arrLogFormat(ARRAY_M
ASTER,COL_PRODUCTCODE),sText
sText = arrMaster(iPosMaster,COL_USERSID)
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,arrLogFormat(ARRAY_M
ASTER,COL_USERSID),sText
sText = arrMaster(iPosMaster,COL_CONTEXTSTRING)
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,arrLogFormat(ARRAY_M
ASTER,COL_CONTEXTSTRING),sText
sText = arrMaster(iPosMaster,COL_STATESTRING)
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,arrLogFormat(ARRAY_M
ASTER,COL_STATESTRING),sText
Exit For 'Dummy
End If 'arrMaster(iPosMster,COL_STATE) = INSTALLSTATE_UNKNOWN
For iPosOrder = 0 To UBound(arrOrder)
If fBasicMode AND iPosOrder > 1 Then Exit For
sText = "" : sText = arrMaster(iPosMaster,arrOrder(iPosOrder
))
If Not IsEmpty(arrMaster(iPosMaster,arrOrder(iPosOrder))) Th
en
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,arrLogFormat(ARR
AY_MASTER,arrOrder(iPosOrder)),sText
If arrMaster(iPosMaster,arrOrder(iPosOrder)) = "Unknown"
Then Exit For
End If
Next 'iPosOrder
If NOT fBasicMode Then
'Patches
'------CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,"",""
'First loop will take care of client side patches
'Second loop will log patches in the InstallSource
sCategory = "Patch Baseline"
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,sCategory,arrMaster(
iPosMaster,COL_PRODUCTVERSION)
sCategory = "Post Baseline Sequences"
dicTmp.RemoveAll
Set arrTmp = Nothing
arrTmp = Split(arrMaster(iPosMaster,COL_PATCHFAMILY),",")
For Each MspSeq in arrTmp
arrTmpInner = Split(MspSeq,":")
dicTmp.Add arrTmpInner(0),arrTmpInner(1)
Next 'MspSeq
For Each Key in dicTmp.Keys
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,sCategory,dicTmp
.Item(Key)&" - "&Key
sCategory = ""
Next
sCategory = "Client side patches"
bCspCondition = True
For iAip = 0 To 1
For iPosPatch = 0 to UBound(arrPatch,3)
If Not (IsEmpty (arrPatch(iPosMaster,PATCH_PATCHCODE
,iPosPatch))) AND (arrPatch(iPosMaster,PATCH_CSP,iPosPatch) = bCspCondition) The
n
sText = ""
For iColPatch = PATCH_LOGSTART to PATCH_LOGMAX
If Not IsEmpty(arrPatch(iPosMaster,iColPatch
,iPosPatch)) Then sText = sText & arrLogFormat(ARRAY_PATCH,iColPatch) & arrPatch
(iPosMaster,iColPatch,iPosPatch) & CSV
Next 'iColPatch
CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,sCategor
y,sText
sCategory = ""
End If 'IsEmpty
Next 'iPosPatch
sCategory = "Patches in InstallSource"
bCspCondition = False
Next 'iAip
'InstallSource
'------------CacheLog LOGPOS_PRODUCT,LOGHEADING_NONE,"",""
PARENTCOUNT)=0) ) AND _
IsEmpty(arrMaster(iPosMaster,COL_ARPPARENTCOUNT)) AND _
GetVersionMajor(arrMaster(iPosMaster,COL_PRODUCTCODE))=1
5
Case 3 'Office 14
fLogProduct = fLogChainedDetails AND arrMaster(iPosMaster,COL_ISOFFICEPR
ODUCT) AND GetVersionMajor(arrMaster(iPosMaster,COL_PRODUCTCODE))=14
Case 4 'Office 14 Single Msi Products
fLogProduct = NOT fLogChainedDetails AND _
arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) AND _
( (NOT arrMaster(iPosMaster,COL_SYSTEMCOMPONENT)=1) OR (
NOT arrMaster(iPosMaster,COL_SYSTEMCOMPONENT)=0 AND arrMaster(iPosMaster,COL_ARP
PARENTCOUNT)=0) ) AND _
IsEmpty(arrMaster(iPosMaster,COL_ARPPARENTCOUNT)) AND _
GetVersionMajor(arrMaster(iPosMaster,COL_PRODUCTCODE))=1
4
Case 5 'Office 12
fLogProduct = fLogChainedDetails AND arrMaster(iPosMaster,COL_ISOFFICEPR
ODUCT) AND GetVersionMajor(arrMaster(iPosMaster,COL_PRODUCTCODE))=12
Case 6 'Office 12 Single Msi Products
fLogProduct = NOT fLogChainedDetails AND _
arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) AND _
( (NOT arrMaster(iPosMaster,COL_SYSTEMCOMPONENT)=1) OR (
NOT arrMaster(iPosMaster,COL_SYSTEMCOMPONENT)=0 AND arrMaster(iPosMaster,COL_ARP
PARENTCOUNT)=0) ) AND _
IsEmpty(arrMaster(iPosMaster,COL_ARPPARENTCOUNT)) AND _
GetVersionMajor(arrMaster(iPosMaster,COL_PRODUCTCODE))=1
2
Case 7 'Office 11
fLogProduct = arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) AND GetVersionMa
jor(arrMaster(iPosMaster,COL_PRODUCTCODE))=11
Case 8 'Office 10
fLogProduct = arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) AND GetVersionMa
jor(arrMaster(iPosMaster,COL_PRODUCTCODE))=10
Case 9 'Office 9
fLogProduct = arrMaster(iPosMaster,COL_ISOFFICEPRODUCT) AND GetVersionMa
jor(arrMaster(iPosMaster,COL_PRODUCTCODE))=9
Case 10 'Non Office Products
fLogProduct = fListNonOfficeProducts AND NOT arrMaster(iPosMaster,COL_IS
OFFICEPRODUCT)
Case Else
End Select
CheckLogProduct = fLogProduct
End Function 'CheckLogProduct
'===============================================================================
========================
Function FormatCategory(sCategory)
Dim sTmp : Dim i
On Error Resume Next
Const iCATLEN = 30
sTmp = sTmp & Space(iCATLEN-Len(sCategory)-1)
FormatCategory = sCategory & sTmp
End Function
'===============================================================================
========================
Function FormatHeading(iHeading,sText)
Dim sTmp, sStyle
Dim i
On Error Resume Next
Select Case iHeading
Case LOGHEADING_H1: sStyle = "="
Case LOGHEADING_H2: sStyle = "-"
Case Else: sStyle =" "
End Select
sTmp = sTmp & String(Len(sText),sStyle)
FormatHeading = vbCrLf & vbCrLf & sText & vbCrlf & sTmp
End Function
'===============================================================================
========================
'Module Global Helper Functions
'===============================================================================
========================
'===============================================================================
========================
Sub RelaunchElevated
Dim Argument
Dim sCmdLine
Dim oShell,oWShell
Set oShell = CreateObject("Shell.Application")
Set oWShell = CreateObject("Wscript.Shell")
sCmdLine = Chr(34) & WScript.scriptFullName & Chr(34)
If Wscript.Arguments.Count > 0 Then
For Each Argument in Wscript.Arguments
If Argument = "UAC" Then Exit Sub
sCmdLine = sCmdLine & " " & chr(34) & Argument & chr(34)
Next 'Argument
End If
oShell.ShellExecute oWShell.ExpandEnvironmentStrings("%windir%") & "\system3
2\cscript.exe",sCmdLine & " UAC", "", "runas", 1
Wscript.Quit
End Sub 'RelaunchElevated
'===============================================================================
========================
Sub RelaunchAsCScript
Dim Argument
Dim sCmdLine
sCmdLine = oShell.ExpandEnvironmentStrings("%windir%") & "\system32\cscript.
exe " & Chr(34) & WScript.scriptFullName & Chr(34)
If Wscript.Arguments.Count > 0 Then
For Each Argument in Wscript.Arguments
sCmdLine = sCmdLine & " " & chr(34) & Argument & chr(34)
Next 'Argument
End If
oShell.Run sCmdLine,1,False
Wscript.Quit
End Sub 'RelaunchAsCScript
'===============================================================================
========================
'Launch a Shell command, wait for the task to complete and return the result
Function Command(sCommand)
Dim oExec
Dim sCmdOut
Set oExec = oShell.Exec(sCommand)
sCmdOut = oExec.StdOut.ReadAll()
Do While oExec.Status = 0
WScript.Sleep 100
Loop
Command = oExec.ExitCode & " - " & sCmdOut
End Function
'===============================================================================
========================
Sub CopyToZip (ShellNameSpace, fsoFile)
Dim fCopyComplete
Dim item,ShellFolder
Dim i
Set ShellFolder = ShellNameSpace
fCopyComplete = False
ShellNameSpace.CopyHere fsoFile.Path,COPY_OVERWRITE
For Each item in ShellFolder.Items
If item.Name = fsoFile.Name Then fCopyComplete = True
Next 'item
i = 0
While NOT fCopyComplete
WScript.Sleep 500
i = i + 1
For Each item in ShellFolder.Items
If item.Name = fsoFile.Name Then fCopyComplete = True
Next 'item
' hang protection
If i > 12 Then
fCopyComplete = True
fZipError = True
End If
Wend
End Sub
'===============================================================================
========================
'Function to compare to numbers of unspecified format
Function CompareVersion(sFile1, sFile2, bAllowBlanks)
'Return values:
'Left file version is lower than right file version
'Left file version is identical to right file version
'Left file version is higher than right file version
'Invalid comparison
Dim file1, file2
Dim sDelimiter
Dim iCnt, iAsc, iMax, iF1, iF2
-1
0
1
2
Dim bLEmpty,bREmpty
CompareVersion = 0
bLEmpty = False
bREmpty = False
'Ensure valid inputs values
On Error Resume Next
If IsEmpty(sFile1) Then bLEmpty = True
If IsEmpty(sFile2) Then bREmpty = True
If sFile1 = "" Then bLEmpty = True
If sFile2 = "" Then bREmpty = True
' don't allow alpha characters
If Not bLEmpty Then
For iCnt = 1 To Len(sFile1)
iAsc = Asc(UCase(Mid(sFile1,iCnt,1)))
If (iAsc>64) AND (iAsc<91) Then
CompareVersion = 2
Exit Function
End If
Next 'iCnt
End If
If Not bREmpty Then
For iCnt = 1 To Len(sFile2)
iAsc = Asc(UCase(Mid(sFile2,iCnt,1)))
If (iAsc>64) AND (iAsc<91) Then
CompareVersion = 2
Exit Function
End If
Next 'iCnt
End If
If bLEmpty AND (NOT bREmpty) Then
If bAllowBlanks Then CompareVersion = -1 Else CompareVersion = 2
Exit Function
End If
If (NOT bLEmpty) AND bREmpty Then
If bAllowBlanks Then CompareVersion = 1 Else CompareVersion = 2
Exit Function
End If
If bLEmpty AND bREmpty Then
CompareVersion = 2
Exit Function
End If
' if Files are identical we're already done
If sFile1 = sFile2 Then Exit Function
' split the VersionString
file1 = Split(sFile1,Delimiter(sFile1))
file2 = Split(sFile2,Delimiter(sFile2))
' ensure we get the lower count
iMax = UBound(file1)
CompareVersion = -1
If iMax > UBound(file2) Then
iMax = UBound(file2)
CompareVersion = 1
End If
' compare the file versions
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Case
Malay (Malaysia)
Marathi
Marathi (India)
Mongolian
Mongolian (Mongolia)
Norwegian
Norwegian (Bokml, Norway)
Norwegian (Nynorsk, Norway)
Polish
Polish (Poland)
Portuguese
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Punjabi (India)
Romanian
Romanian (Romania)
Russian
Russian (Russia)
Sanskrit
Sanskrit (India)
' Serbian (Serbia, Cyrillic)
' Serbian (Serbia, Latin)
Slovak
Slovak (Slovakia)
Slovenian
Slovenian (Slovenia)
Spanish (Argentina)
Spanish (Bolivia)
Spanish (Chile)
Spanish (Colombia)
Spanish (Costa Rica)
Spanish (Dominican Republic)
Spanish (Ecuador)
Spanish (El Salvador)
Spanish (Guatemala)
Spanish (Honduras)
Spanish (Mexico)
Spanish (Nicaragua)
Spanish (Panama)
Spanish (Paraguay)
Spanish (Peru)
Spanish (Puerto Rico)
Spanish (Spain)
Spanish (Uruguay)
Spanish (Venezuela)
Swahili
Swahili (Kenya)
Swedish
Swedish (Finland)
Swedish (Sweden)
Syriac
Syriac (Syria)
Tamil
Tamil (India)
Tatar
Tatar (Russia)
Telugu
Telugu (India)
+ 1),1)
- 1),1)
+ 1),1)
- 1),1)
End Function
'===============================================================================
========================
Function GetCompressedGuid (sGuid)
'Converts the GUID / ProductCode into the compressed format
Dim sCompGUID
Dim i
On Error Resume Next
sCompGUID = StrReverse(Mid(sGuid,2,8)) & _
StrReverse(Mid(sGuid,11,4)) & _
StrReverse(Mid(sGuid,16,4))
For i = 21 To 24
If i Mod 2 Then
sCompGUID = sCompGUID & Mid(sGuid, (i + 1), 1)
Else
sCompGUID = sCompGUID & Mid(sGuid, (i - 1), 1)
End If
Next
For i = 26 To 37
If i Mod 2 Then
sCompGUID = sCompGUID & Mid(sGuid, (i - 1), 1)
Else
sCompGUID = sCompGUID & Mid(sGuid, (i + 1), 1)
End If
Next
GetCompressedGuid = sCompGUID
End Function
'===============================================================================
========================
'Get Version Major from GUID
Function GetVersionMajor(sProductCode)
Dim iVersionMajor
On Error Resume Next
jor
jor
jor
jor
jor
jor
jor
jor
jor
jor
iVersionMajor = 0
iVersionMajor = oMsi.ProductInfo(sProductCode,"VersionMajor")
If Not Err = 0 OR iVersionMajor = 0 Then
If InStr(OFFICE_2000, UCase(Right(sProductCode,28))) > 0 Then
= 9
If InStr(ORK_2000,
UCase(Right(sProductCode,28))) > 0 Then
= 9
If InStr(PRJ_2000,
UCase(Right(sProductCode,28))) > 0 Then
= 9
If InStr(VIS_2002,
UCase(Right(sProductCode,28))) > 0 Then
= 10
If InStr(OFFICE_2002, UCase(Right(sProductCode,28))) > 0 Then
= 10
If InStr(OFFICE_2003, UCase(Right(sProductCode,28))) > 0 Then
= 11
If InStr(WSS_2,
UCase(Right(sProductCode,28))) > 0 Then
= 11
If InStr(SPS_2003,
UCase(Right(sProductCode,28))) > 0 Then
= 11
If InStr(PPS_2007,
UCase(Right(sProductCode,28))) > 0 Then
= 12
If InStr(OFFICEID,
UCase(Right(sProductCode,17))) > 0 Then
= Mid(sProductCode,4,2)
End If 'Err
iVersionMa
iVersionMa
iVersionMa
iVersionMa
iVersionMa
iVersionMa
iVersionMa
iVersionMa
iVersionMa
iVersionMa
GetVersionMajor = iVersionMajor
End Function
'===============================================================================
========================
'Obtain the ProductVersion from a .msi package
Function GetMsiProductVersion(sMsiFile)
Dim MsiDb,Record
Dim qView
On Error Resume Next
GetMsiProductVersion = ""
Set Record = Nothing
Set MsiDb = oMsi.OpenDatabase(sMsiFile,MSIOPENDATABASEMODE_READONLY)
sName = "LocalPackage"
End If 'iContext = MSIINSTALLCONTEXT_USERMANAGED
sSubKeyName = GetRegConfigKey(sProductCodeCompressed,iTmpContext,sSid,True)
& "InstallProperties\"
If RegKeyExists (hDefKey,sSubKeyName) Then
If RegValExists(hDefKey,sSubKeyName,sName) Then
GetRegProductState = 5 '"Installed"
Else
If InStr(sSubKeyName, REG_C2RVIRT_HKLM) > 0 Then
GetRegProductState = 8 '"Virtualized"
Else
GetRegProductState = 1 '"Advertised"
End If
End If 'RegValExists
Else
GetRegProductState = -1 '"Broken/Unknown"
End If 'RegKeyExists
End Function 'GetRegProductState
'===============================================================================
========================
'Check if the GUID has a valid structure
Function IsValidGuid(sGuid,iGuidType)
Dim i, n
Dim c
Dim bValidGuidLength, bValidGuidChar, bValidGuidCase
On Error Resume Next
'Set defaults
IsValidGuid = False
fGuidCaseWarningOnly = False
sError = "" : sErrBpa = ""
bValidGuidLength = True
bValidGuidChar = True
Select Case iGuidType
Case GUID_UNCOMPRESSED 'UnCompressed
If Len(sGuid) = 38 Then
IsValidGuid = True
For i = 1 To 38
bValidGuidCase = True
c = Mid(sGuid,i,1)
Select Case i
Case 1
If Not c = "{" Then
IsValidGuid = False
bValidGuidChar = False
Exit For
End If
Case 10, 15, 20, 25
If not c = "-" Then
IsValidGuid = False
bValidGuidChar = False
Exit For
End If
Case 38
If not c = "}" Then
IsValidGuid = False
bValidGuidChar = False
Exit For
End If
Case Else
n = Asc(c)
If Not IsValidGuidChar(n) Then
bValidGuidCase = False
fGuidCaseWarningOnly = True
IsValidGuid = False
n = Asc(UCase(c))
If Not IsValidGuidChar(n) Then
fGuidCaseWarningOnly = False
bValidGuidChar = False
Exit For
End If 'IsValidGuidChar (inner)
End If 'IsValidGuidChar (outer)
End Select
Next 'i
Else
'Invalid length for this GUID type
'Suppress error if passed in GUID matches 'compressed' length
If NOT (Len(sGuid)=32) Then bValidGuidLength = False
End If 'Len(sGuid)
Case GUID_COMPRESSED
If Len(sGuid)=32 Then
IsValidGuid = True
For i = 1 to 32
c = Mid(sGuid,i,1)
bValidGuidCase = True
n = Asc(c)
If Not IsValidGuidChar(n) Then
bValidGuidCase = False
fGuidCaseWarningOnly = True
IsValidGuid = False
n = Asc(UCase(c))
If Not IsValidGuidChar(n) Then
fGuidCaseWarningOnly = False
bValidGuidChar = False
Exit For
End If 'IsValidGuidChar (inner)
End If 'IsValidGuidChar (outer)
Next 'i
Else
'Invalid length for this GUID type
bValidGuidLength = False
End If 'Len
Case GUID_SQUISHED '"Squished"
'Not implemented
Case Else
'IsValidGuid = False
End Select
'Log errors
If (NOT bValidGuidLength) OR (NOT bValidGuidChar) OR (fGuidCaseWarningOnly)
Then
sError = ERR_INVALIDGUID & DOT
sErrBpa = BPA_GUID
End If
If fGuidCaseWarningOnly Then
sError = sError & ERR_GUIDCASE
End If 'fGuidCaseWarningOnly
If bValidGuidLength = False Then
sError = sError & ERR_INVALIDGUIDLENGTH
End If 'bValidGuidLength
If bValidGuidChar = False Then
sError = sError & ERR_INVALIDGUIDCHAR
End If 'bValidGuidChar
End Function 'IsValidGuid
'===============================================================================
========================
'Check if the character is in a valid range for a GUID
Function IsValidGuidChar (iAsc)
If ((iAsc >= 48 AND iAsc <= 57) OR (iAsc >= 65 AND iAsc <= 70)) Then
IsValidGuidChar = True
Else
IsValidGuidChar = False
End If
End Function
'===============================================================================
========================
Function GetContextString(iContext)
On Error Resume Next
Select Case iContext
Case MSIINSTALLCONTEXT_USERMANAGED
: GetContextString = "MSIINSTALL
CONTEXT_USERMANAGED"
Case MSIINSTALLCONTEXT_USERUNMANAGED
: GetContextString = "MSIINSTALL
CONTEXT_USERUNMANAGED"
Case MSIINSTALLCONTEXT_MACHINE
: GetContextString = "MSIINSTALL
CONTEXT_MACHINE"
Case MSIINSTALLCONTEXT_ALL
: GetContextString = "MSIINSTALL
CONTEXT_ALL"
Case MSIINSTALLCONTEXT_C2RV2
: GetContextString = "MSIINSTALL
CONTEXT_C2RV2"
Case Else
: GetContextString = iContext
End Select
End Function
'===============================================================================
========================
Function GetHiveString(hDefKey)
On Error Resume Next
Select Case hDefKey
Case HKEY_CLASSES_ROOT : GetHiveString = "HKEY_CLASSES_ROOT"
Case HKEY_CURRENT_USER : GetHiveString = "HKEY_CURRENT_USER"
Case HKEY_LOCAL_MACHINE : GetHiveString = "HKEY_LOCAL_MACHINE"
Case HKEY_USERS : GetHiveString = "HKEY_USERS"
Case Else : GetHiveString = hDefKey
End Select
End Function 'GetHiveString
'===============================================================================
========================
Function GetRegConfigPatchesKey(iContext,sSid,bGlobal)
Dim sTmpProductCode,sSubKeyName
On Error Resume Next
sSubKeyName = ""
Select Case iContext
Case MSIINSTALLCONTEXT_USERMANAGED
sSubKeyName = REG_CONTEXTUSERMANAGED
Case MSIINSTALLCONTEXT_USERUNMANAGED
If bGlobal OR NOT sSid = sCurUserSid
sSubKeyName = REG_GLOBALCONFIG &
Else
sSubKeyName = REG_CONTEXTUSER
End If
Case MSIINSTALLCONTEXT_MACHINE
If bGlobal Then
sSubKeyName = REG_GLOBALCONFIG &
Else
sSubKeyName = REG_CONTEXTMACHINE
End If
Case MSIINSTALLCONTEXT_C2RV2
If bGlobal Then
sSubKeyName = REG_C2RVIRT_HKLM &
"S-1-5-18\Patches\"
& "\Patches\"
s\"
Else
sSubKeyName = REG_C2RVIRT_HKLM & REG_CONTEXTMACHINE & "Patches\"
End If
Case Else
End Select
GetRegConfigPatchesKey = Replace(sSubKeyName,"\\","\")
End Function 'GetRegConfigPatchesKey
'===============================================================================
========================
Function GetRegConfigKey(sProductCode, iContext, sSid, bGlobal)
Dim sTmpProductCode,sSubKeyName
On Error Resume Next
sTmpProductCode = sProductCode
sSubKeyName = ""
If NOT sTmpProductCode = "" Then
If IsValidGuid(sTmpProductCode,GUID_UNCOMPRESSED) Then sTmpProductCode =
GetCompressedGuid(sTmpProductCode)
End If 'NOT sTmpProductCode = ""
Select Case iContext
Case MSIINSTALLCONTEXT_USERMANAGED
sSubKeyName = REG_CONTEXTUSERMANAGED & sSid & "\Installer\Products\" & s
TmpProductCode & "\"
Case MSIINSTALLCONTEXT_USERUNMANAGED
If bGlobal OR NOT sSid = sCurUserSid Then
sSubKeyName = REG_GLOBALCONFIG & sSid & "\Products\" & sTmpProductCo
de & "\"
Else
sSubKeyName = REG_CONTEXTUSER & "Products\" & sTmpProductCode & "\"
End If
Case MSIINSTALLCONTEXT_MACHINE
If bGlobal Then
sSubKeyName = REG_GLOBALCONFIG & "S-1-5-18\Products\" & sTmpProductC
RegValExists = False
If Not RegKeyExists(hDefKey,sSubKeyName) Then
Exit Function
End If
If oReg.EnumValues(hDefKey,sSubKeyName,arrValueNames,arrValueTypes) = 0 AND
CheckArray(arrValueNames) Then
For i = 0 To UBound(arrValueNames)
If LCase(arrValueNames(i)) = Trim(LCase(sName)) Then RegValExists =
True
Next
Else
Exit Function
End If 'oReg.EnumValues
End Function
'===============================================================================
========================
'Check access to a registry key
Function RegCheckAccess(hDefKey, sSubKeyName, lAccPermLevel)
Dim RetVal
Dim arrValues
RetVal = RegKeyExists(hDefKey,sSubKeyName)
RetVal = oReg.CheckAccess(hDefKey,sSubKeyName,lAccPermLevel)
If Not RetVal = 0 AND f64 Then RetVal = oReg.CheckAccess(hDefKey,Wow64Key(hD
efKey, sSubKeyName),lAccPermLevel)
RegCheckAccess = (RetVal = 0)
End Function 'RegReadValue
'===============================================================================
========================
'Read the value of a given registry entry
Function RegReadValue(hDefKey, sSubKeyName, sName, sValue, sType)
Dim RetVal
Dim arrValues
Select Case UCase(sType)
Case "1","REG_SZ"
RetVal = oReg.GetStringValue(hDefKey,sSubKeyName,sName,sValue)
If Not RetVal = 0 AND f64 Then RetVal = oReg.GetStringValue(hDefKey,
Wow64Key(hDefKey, sSubKeyName),sName,sValue)
Case "2","REG_EXPAND_SZ"
RetVal = oReg.GetExpandedStringValue(hDefKey,sSubKeyName,sName,sValu
e)
If Not RetVal = 0 AND f64 Then RetVal = oReg.GetExpandedStringValue(
hDefKey,Wow64Key(hDefKey, sSubKeyName),sName,sValue)
Case "7","REG_MULTI_SZ"
RetVal = oReg.GetMultiStringValue(hDefKey,sSubKeyName,sName,arrValue
s)
If Not RetVal = 0 AND f64 Then RetVal = oReg.GetMultiStringValue(hDe
fKey,Wow64Key(hDefKey, sSubKeyName),sName,arrValues)
If RetVal = 0 Then sValue = Join(arrValues,chr(34))
Case "4","REG_DWORD"
RetVal = oReg.GetDWORDValue(hDefKey,sSubKeyName,sName,sValue)
If Not RetVal = 0 AND f64 Then
RetVal = oReg.GetDWORDValue(hDefKey,Wow64Key(hDefKey, sSubKeyNam
e),sName,sValue)
End If
Case "3","REG_BINARY"
RetVal = oReg.GetBinaryValue(hDefKey,sSubKeyName,sName,sValue)
RetVal = oReg.GetBinaryValue(hDefKey,sSubKeyName,sName,sValue)
If Not RetVal = 0 AND f64 Then RetVal = oReg.GetBinaryValue(hDefKey,Wow64Key
(hDefKey, sSubKeyName),sName,sValue)
RegReadBinaryValue = (RetVal = 0)
End Function 'RegReadBinaryValue
'===============================================================================
========================
Function RegReadQWordValue(hDefKey,sSubKeyName,sName,sValue)
Dim RetVal
RetVal = oReg.GetQWORDValue(hDefKey,sSubKeyName,sName,sValue)
If Not RetVal = 0 AND f64 Then RetVal = oReg.GetQWORDValue(hDefKey,Wow64Key(
hDefKey, sSubKeyName),sName,sValue)
RegReadQWordValue = (RetVal = 0)
End Function 'RegReadQWordValue
'===============================================================================
========================
'Enumerate a registry key to return all values
Function RegEnumValues(hDefKey,sSubKeyName,arrNames, arrTypes)
Dim RetVal, RetVal64
Dim arrNames32, arrNames64, arrTypes32, arrTypes64
If f64 Then
RetVal = oReg.EnumValues(hDefKey,sSubKeyName,arrNames32,arrTypes32)
RetVal64 = oReg.EnumValues(hDefKey,Wow64Key(hDefKey, sSubKeyName),arrNam
es64,arrTypes64)
If (RetVal = 0) AND (Not RetVal64 = 0) AND IsArray(arrNames32) AND IsArr
ay(arrTypes32) Then
arrNames = arrNames32
arrTypes = arrTypes32
End If
If (Not RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrNames64) AND IsArr
ay(arrTypes64) Then
arrNames = arrNames64
arrTypes = arrTypes64
End If
If (RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrNames32) AND IsArray(a
rrNames64) AND IsArray(arrTypes32) AND IsArray(arrTypes64) Then
arrNames = RemoveDuplicates(Split((Join(arrNames32,"\") & "\" & Join
(arrNames64,"\")),"\"))
arrTypes = RemoveDuplicates(Split((Join(arrTypes32,"\") & "\" & Join
(arrTypes64,"\")),"\"))
End If
Else
RetVal = oReg.EnumValues(hDefKey,sSubKeyName,arrNames,arrTypes)
End If 'f64
RegEnumValues = ((RetVal = 0) OR (RetVal64 = 0)) AND IsArray(arrNames) AND I
sArray(arrTypes)
End Function 'RegEnumValues
'===============================================================================
========================
'Enumerate a registry key to return all subkeys
Function RegEnumKey(hDefKey,sSubKeyName,arrKeys)
Dim RetVal, RetVal64
Dim arrKeys32, arrKeys64
If f64 Then
RetVal = oReg.EnumKey(hDefKey,sSubKeyName,arrKeys32)
RetVal64 = oReg.EnumKey(hDefKey,Wow64Key(hDefKey, sSubKeyName),arrKeys64
)
If (RetVal = 0) AND (Not RetVal64 = 0) AND IsArray(arrKeys32) Then arrKe
ys = arrKeys32
If (Not RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrKeys64) Then arrKe
ys = arrKeys64
If (RetVal = 0) AND (RetVal64 = 0) Then
If IsArray(arrKeys32) AND IsArray (arrKeys64) Then
arrKeys = RemoveDuplicates(Split((Join(arrKeys32,"\") & "\" & Jo
in(arrKeys64,"\")),"\"))
ElseIf IsArray(arrKeys64) Then
arrKeys = arrKeys64
Else
arrKeys = arrKeys32
End If
End If
Else
RetVal = oReg.EnumKey(hDefKey,sSubKeyName,arrKeys)
End If 'f64
RegEnumKey = ((RetVal = 0) OR (RetVal64 = 0)) AND IsArray(arrKeys)
End Function 'RegEnumKey
'===============================================================================
========================
'Return the alternate regkey location on 64bit environment
Function Wow64Key(hDefKey, sSubKeyName)
Dim iPos
Dim fReplaced
fReplaced = False
If InStr(sSubKeyName, REG_C2RVIRT_HKLM) > 0 Then
sSubKeyName = Replace(sSubKeyName, REG_C2RVIRT_HKLM, "")
fReplaced = True
End If
Select Case hDefKey
Case HKCU
If Left(sSubKeyName,17) = "Software\Classes\" Then
Wow64Key = Left(sSubKeyName,17) & "Wow6432Node\" &
Name,Len(sSubKeyName)-17)
Else
iPos = InStr(sSubKeyName,"\")
Wow64Key = Left(sSubKeyName,iPos) & "Wow6432Node\"
eyName,Len(sSubKeyName)-iPos)
End If
Case HKLM
If Left(sSubKeyName,17) = "Software\Classes\" Then
Wow64Key = Left(sSubKeyName,17) & "Wow6432Node\" &
Name,Len(sSubKeyName)-17)
Else
iPos = InStr(sSubKeyName,"\")
Wow64Key = Left(sSubKeyName,iPos) & "Wow6432Node\"
eyName,Len(sSubKeyName)-iPos)
End If
Case Else
Wow64Key = "Wow6432Node\" & sSubKeyName
End Select 'hDefKey
If fReplaced Then
sSubKeyName = REG_C2RVIRT_HKLM & sSubKeyName
Right(sSubKey
& Right(sSubK
Right(sSubKey
& Right(sSubK
If RegEnumKey(HKLM,REG_CONTEXTUSERMANAGED,arrKeys) Then
n = 0
For i = 0 To UBound(arrKeys)
If Len(arrKeys(i)) > 8 Then
Redim Preserve arrUMSids(n)
arrUMSids(n) = arrKeys(i)
n = n + 1
End If 'Len(arrKeys)
Next 'i
End If 'RegEnumKey
Case Else
End Select
End Function
'===============================================================================
========================
Function GetArrayPosition (Arr,sProductCode)
Dim iPos
On Error Resume Next
GetArrayPosition = -1
'Need to allow exception for lower case only violations 'fGuidCaseWarningOnl
y'
If CheckArray(Arr) And (IsValidGuid(sProductCode,GUID_UNCOMPRESSED) OR fGuid
CaseWarningOnly) Then
For iPos = 0 To UBound(Arr)
If Arr(iPos,COL_PRODUCTCODE) = sProductCode Then
GetArrayPosition = iPos
Exit For
End If
Next 'iPos
End If 'CheckArray
End Function
'===============================================================================
========================
Function GetArrayPositionFromPattern (Arr, sProductCodePattern)
Dim iPos
On Error Resume Next
GetArrayPositionFromPattern = -1
'Need to allow exception for lower case only violations 'fGuidCaseWarningOnl
y'
If CheckArray(Arr) Then
For iPos = 0 To UBound(Arr)
If InStr(Arr(iPos,COL_PRODUCTCODE), sProductCodePattern) > 0 Then
GetArrayPositionFromPattern = iPos
Exit For
End If
Next 'iPos
End If 'CheckArray
End Function
'===============================================================================
========================
Sub InitMasterArray
On Error Resume Next
'Since ReDim cannot preserve the data on the first dimension determine the n
Exit Function
End If
If IsNull(Obj) Then
CheckObject = False
Exit Function
End If
If IsEmpty(Obj) Then
CheckObject = False
Exit Function
End If
If Not Obj.Count > 0 Then
If Not Err = 0 Then
Err.Clear
Set Obj = Nothing
End If 'Err
CheckObject = False
Exit Function
End If
End Function
'===============================================================================
========================
Sub CheckError(sModule,sErrorHandler)
Dim sErr
If Not Err = 0 Then
sErr = GetErrorDescription(Err)
If Not sErrorHandler = "" Then
sErrorHandler = sModule & sErrorHandler
ErrorRelay(sErrorHandler)
End If
End If 'Err = 0
Err.Clear
End Sub
'===============================================================================
========================
Sub ErrorRelay(sErrorHandler)
Select Case (sErrorHandler)
Case "CheckPreReq_ErrorHandler" : CheckPreReq_ErrorHandler
Case "FindAllProducts_ErrorHandler3x" : FindAllProducts_ErrorHandler3x
Case "FindProducts1","FindProducts2","FindProducts4" : FindProducts_Erro
rHandler Int(Right(sErrorHandler,1))
Case Else
End Select
End Sub
'===============================================================================
========================
Function GetErrorDescription (Err)
If Not Err = 0 Then
GetErrorDescription = "Source: " & Err.Source & "; Err# (Hex): " & Hex(
Err ) & _
"; Err# (Dec): " & Err & "; Description : " & Err.
Description & _
"; Stack: " & sStack
End If 'Err = 0
End Function
'===============================================================================
========================
Sub ParseCmdLine
Dim iCnt, iArgCnt
Dim oFso
'Handle settings from the .ini section
If fLogFull Then
fLogChainedDetails = True
fFileInventory = True
fFeatureTree = True
End If 'fLogFull
If Not sPathOutputFolder = "" Then
Set oFso = CreateObject("Scripting.FileSystemObject")
If Not oFso.FolderExists(sPathOutputFolder) Then sPathOutputFolder = ""
Set oFso = Nothing
End If 'Not sPathOutputFolder
If fLogVerbose Then
fLogChainedDetails = True
fFeatureTree = True
End If 'fLogVerbose
iArgCnt = Wscript.Arguments.Count
If iArgCnt>0 Then
For iCnt = 0 To iArgCnt-1
Select Case UCase(Wscript.Arguments(iCnt))
Case "/A","-A","/ALL","-ALL","ALL"
fListNonOfficeProducts = True
Case "/BASIC","-BASIC","BASIC"
fBasicMode = True
Case "/DCS","-DCS","/DISALLOWCSCRIPT","-DISALLOWCSCRIPT","DISALLOWCS
CRIPT"
fDisallowCScript = True
Case "/F","-F","/FULL","-FULL","FULL"
fLogFull = True
fLogChainedDetails = True
fFileInventory = True
fFeatureTree = True
Case "/FI","-FI","/FILEINVENTORY","-FILEINVENTORY","FILEINVENTORY"
fFileInventory = True
Case "/FT","-FT","/FEATURETREE","-FEATURETREE","FEATURETREE"
fFeatureTree = True
Case "/L","-L","/LOGFOLDER","-LOGFOLDER","LOGFOLDER"
If iArgCnt > iCnt Then
Set oFso = CreateObject("Scripting.FileSystemObject")
If oFso.FolderExists(Wscript.Arguments(iCnt+1)) Then sPathOu
tputFolder = Wscript.Arguments(iCnt+1)
Set oFso = Nothing
End If 'iArgCnt
Case "/LD","-LD","/LOGCHAINEDDETAILS","-LOGCHAINEDDETAILS"
fLogChainedDetails = True
Case "/LV","-LV","/L*V","-L*V","/LOGVERBOSE","-LOGVERBOSE","/VERBOSE
","-VERBOSE"
fLogVerbose = True
fLogChainedDetails = True
fFeatureTree = True
Case "/Q","-Q","/QUIET","-QUIET","QUIET"
fQuiet = True
Case "/?","-?","?"