Files
gsadmin 8889f41c7c Refactor to script template and toolkit flow with PS7 compatibility
- Adopt the standardized Toolkit layout (Toolkit.ps1 + Functions/Modules/Libraries/Tools)
- Replace the legacy NLog-era Registry.dll with Eric Zimmerman Registry 2026.5.0 (netstandard2.0) for offline hive parsing without mounting; libraries are loaded into memory in dependency order (byte load on Windows PowerShell 5.1, dedicated AssemblyLoadContext stream load on PowerShell 7)
- Rewrite Invoke-RegistryHiveAction with a case-insensitive ValueTable contract for direct value name indexing
- Rewrite Invoke-FileDownloadWithProgress with automatic system proxy detection and progress reporting
- Convert Copy-ItemWithProgress, Get-InstalledSoftware, and the MSI helper functions to the toolkit logging and error handling patterns
- Add opt-in QEMU guest agent installation from the mounted ISO (full operating system only, version-aware, REBOOT=ReallySuppress)
- Remove the task sequence variable parameters from the script surface while retaining the toolkit functionality
- Update README with structure, usage, and OS deployment guidance (DeployR/MDT/SCCM two-pass flow, pwsh.exe for DeployR boot images)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 14:38:29 -04:00

76 lines
3.0 KiB
PowerShell

#region Get-MSIProductList
Function Get-MSIProductList
{
<#
.SYNOPSIS
Retrieves the list of installed MSI products from the Windows Installer database.
.DESCRIPTION
Uses the 'WindowsInstaller.Installer' COM object to enumerate the installed product codes and return the associated product information attributes as objects.
.PARAMETER ContinueOnError
Continue processing even if an error occurs.
.EXAMPLE
Get-MSIProductList
.NOTES
Attributes that cannot be read for a given product will be returned as null.
.LINK
Place any useful link here where your function or cmdlet can be referenced
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$False)]
[Switch]$ContinueOnError
)
Try
{
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
$ComObject = New-Object -ComObject 'WindowsInstaller.Installer'
$ComObjectType = $ComObject.GetType()
[String[]]$AttributeList = @('Language', 'ProductName', 'PackageCode', 'Transforms', 'AssignmentType', 'PackageName', 'InstalledProductName', 'VersionString', 'RegCompany', 'RegOwner', 'ProductID', 'ProductIcon', 'InstallLocation', 'InstallSource', 'InstallDate', 'Publisher', 'LocalPackage', 'HelpLink', 'HelpTelephone', 'URLInfoAbout', 'URLUpdateInfo') | Sort-Object
$ProductList = $ComObjectType.InvokeMember('Products', [System.Reflection.BindingFlags]::GetProperty, $Null, $ComObject, $Null)
ForEach ($Product In $ProductList)
{
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$OutputObjectProperties.Add('ProductCode', $Product)
For ($AttributeListIndex = 0; $AttributeListIndex -lt $AttributeList.Count; $AttributeListIndex++)
{
[String]$AttributeName = $AttributeList[$AttributeListIndex]
Switch ($OutputObjectProperties.Contains($AttributeName))
{
{($_ -eq $False)}
{
$OutputObjectProperties.Add($AttributeName, $Null)
}
}
Try {$OutputObjectProperties."$($AttributeName)" = $ComObjectType.InvokeMember('ProductInfo', [System.Reflection.BindingFlags]::GetProperty, $Null, $ComObject, @($Product, $AttributeName))} Catch {}
}
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
$Null = $OutputObjectList.Add($OutputObject)
}
Write-Output -InputObject ($OutputObjectList)
}
Catch
{
$ErrorHandlingDefinition.Invoke($Error[0], 2, $ContinueOnError.IsPresent)
}
}
#endregion