Softwarevirtualisierung mit App V 5 192Unser Buch "Softwarevirtualisierung mit App-V 5"

Das deutsche App-V 5 Buch: 496 Seiten Wissen zu Microsoft App-V 5 (5.1 bis HF6). Ab Windows 7 bis Server 2016 mit Zusatzinhalten zu App-V mit VDI, Terminalservern, XenDesktop und SCCM Mit Fragestellungen zum Contentstore, Skripting, Hochverfügbarkeit usw.
3 minutes reading time (598 words)

MSP Productcode mit Powershell auslesen

MSPPS 180x180Ein Windows Installer-Patch (MSP-Datei) ist eine Paketdatei, ein die Updates für eine bestimmte Anwendung enthält und beschreibt, welche Versionen der Anwendung gepatcht werden kann. Der Vorteil eines MSPs ist, dass nur die Dateien enthalten sind, die sich zu einem MSI ändern. MSP werden für Minor Releases eingesetzt (i.d.R. kleine Updates). Ich selber habe ein Tool in der Hinterhand, dass  binäre Differenzen für extrem kleine Patches verteilen kann (wird denn demnächst veröffentlicht).

In dem Patch enthalten ist u.a. ein Productcode und ein Patchcode für die zu ändernde Anwendung. Passt der Productcode zu einer installierten Anwendung, kann gepatched werden. Es ist also praktisch, diesen Code schon vor einer Installation zu ermitteln, um eine Softwareverteilung zu optimieren. Im Folgenden werden zwei Lösungen mit Powershell gezeigt.


Wie bekommt man den Productcode heraus? Eine Variante ist die Installation auf Codeplex: MSI Powershell Module. Der Nachteil dieses Modules ist, dass dafür auch wieder ein MSI installiert werden muss. Dies beinhaltet wiederum Komponenten des Windows Installer XML. Also nichts, was einfach in ein Paket eingebunden werden kann.Das MSI Powershell Module ist im übrigen sehr gut und ich kann das sehr empfehlen für komplexere Dinge. Nach der Installation bekommt man beispielsweise so die Daten einer MSI Datei:

get-msicomponentinfo `
    | where { $_.Path -like 'C:\Program Files\*\Common7\IDE\devenv.exe'} `
    | get-msiproductinfo

Vor kurzen habe ich nach einer Möglichkeit, gesucht, den Productcode eines eines MSP auszulesen, ohne diesen Overhead. Das COM Object "WindowsInstaller.Installer" bietet diese Möglichkeit. Der Vorteil ist, dass diese Funktionen leicht bei Installationen eingesetzt werden können. Also zum Abgleich, ob ein Patch für ein System geeigent ist. Demnächst baue ich das genau so in unseren Citrix XenApp Patcher ein.

Auslesen des "Display Name" des Patches mit Powershell. Achtung, dieser ist nicht immer im MSP enthalten:

function Get-MSPDisplayName {
<# 
.SYNOPSIS 
    Get the Display Name from an Microsoft Installer Patch MSP
.DESCRIPTION 
    Get Display Name from an Microsoft Installer Patch MSP (Andreas Nick 2015)
.NOTES 
    $NULL for an error
.LINK
.RETURNVALUE
  [String] Display Name
.PARAMETER
  [IO.FileInfo] Path to the msp file
#>
function Get-MSPDisplayName {
	param (
		[IO.FileInfo] $patchnamepath
	)
	try {
		$wi = New-Object -com WindowsInstaller.Installer
		$mspdb = $wi.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $Null, $wi, $($patchnamepath.FullName, 32))
		$su = $mspdb.GetType().InvokeMember("SummaryInformation", "GetProperty", $Null, $mspdb, $Null)
		[String] $displayName = $su.GetType().InvokeMember("Property", "GetProperty", $Null, $su, 6)
		return $displayName
	}
	catch {
		Write-Output $_.Exception.Message
		return $NULL
	}
}

Auslesen des Productcodes eines Microsoft Patches (MSP) mit Powershell:

<# 
.SYNOPSIS 
    Get the Product Code from an Microsoft Installer Patch MSP
.DESCRIPTION 
    Get a Product Code from an Microsoft Installer Patch MSP (Andreas Nick 2015)
.NOTES 
    $NULL for an error
.LINK
.RETURNVALUE
  [String] Product Code
.PARAMETER
  [IO.FileInfo] Path to the msp file
#>
function Get-MSPProductcode {
	param (
		[IO.FileInfo] $patchnamepath
	)
	try {
		$wi = New-Object -com WindowsInstaller.Installer
		$mspdb = $wi.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $Null, $wi, $($patchnamepath.FullName, 32))
		$su = $mspdb.GetType().InvokeMember("SummaryInformation", "GetProperty", $Null, $mspdb, $Null)
		#$pc = $su.GetType().InvokeMember("PropertyCount", "GetProperty", $Null, $su, $Null)
		
		[String] $productcode = $su.GetType().InvokeMember("Property", "GetProperty", $Null, $su, 7)
		return $productcode
	}
	catch {
		Write-Output $_.Exception.Message
		return $NULL
	}
}

Auslesen des Patchcodes eines MSP Patches mit Powershell:

<# 
.SYNOPSIS 
    Get the Patch Code from an Microsoft Installer Patch MSP
.DESCRIPTION 
    Get a Patch Code from an Microsoft Installer Patch MSP (Andreas Nick 2015)
.NOTES 
    $NULL for an error
.LINK
.RETURNVALUE
  [String] Product Code
.PARAMETER
  [IO.FileInfo] Path to the msp file
#>
function Get-MSPPatchcode {
	param (
		[IO.FileInfo] $patchnamepath
		
	)
	try {
		$wi = New-Object -com WindowsInstaller.Installer
		$mspdb = $wi.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $Null, $wi, $($patchnamepath.FullName, 32))
		$su = $mspdb.GetType().InvokeMember("SummaryInformation", "GetProperty", $Null, $mspdb, $Null)
		$pc = $su.GetType().InvokeMember("PropertyCount", "GetProperty", $Null, $su, $Null)
		#Write-Host $pc
		[String] $patchcode = $su.GetType().InvokeMember("Property", "GetProperty", $Null, $su, 9)
		return $patchcode
	}
	catch {
		Write-Output $_.Exception.Message
		return $NULL
	}
}

 

Citrix Studio XenDesktop startet langsam und mit d...
NITCtxPatcher a patchmanager for Citrix XenApp and...

Ähnliche Beiträge

 

Kommentare 5

Gäste - Frank am Montag, 06. Juni 2016 14:33

Hi,

bei mir funzen deine scripts nicht. Schade: Idee?
Exception calling "InvokeMember" with "5" argument(s): "Type mismatch. (Exception from HRESULT: 0x80020005
(DISP_E_TYPEMISMATCH))"
At E:\!neu\!PS\ReadMSPFile.ps1:19 char:92
+ ... $Null, $wi, ($($MSPFile.FullName, 32)))
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: ( [], MethodInvocationException
+ FullyQualifiedErrorId : COMException

You cannot call a method on a null-valued expression.
At E:\!neu\!PS\ReadMSPFile.ps1:20 char:9
+ $su = $mspdb.GetType().InvokeMember("SummaryInformation", "GetProperty", ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ( [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At E:\!neu\!PS\ReadMSPFile.ps1:23 char:9
+ [String] $productcode = $su.GetType().InvokeMember("Property", "GetPrope ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ( [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

Hi, bei mir funzen deine scripts nicht. Schade: Idee? Exception calling "InvokeMember" with "5" argument(s): "Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))" At E:\!neu\!PS\ReadMSPFile.ps1:19 char:92 + ... $Null, $wi, ($($MSPFile.FullName, 32))) + ~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : COMException You cannot call a method on a null-valued expression. At E:\!neu\!PS\ReadMSPFile.ps1:20 char:9 + $su = $mspdb.GetType().InvokeMember("SummaryInformation", "GetProperty", ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull You cannot call a method on a null-valued expression. At E:\!neu\!PS\ReadMSPFile.ps1:23 char:9 + [String] $productcode = $su.GetType().InvokeMember("Property", "GetPrope ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
Andreas Nick am Montag, 06. Juni 2016 15:04

Mal ein Schnelltest mit einem MSP aus c:\windows\installer. Alles mit 32/64 Bit und PowerShell V2 und V5. Alles ok. Ich vermute es liegt am msp. Möglich ist auch, dass die COM Komponente fehlt oder eingeschränkt ist? Antivirus, AppSense Application Manager? Kannst Du die msp Datei bereitstellen?

Get-MSPProductcode -patchnamepath c:\Windows\Installer\105ece52.msp
Get-MSPPatchcode -patchnamepath c:\Windows\Installer\105ece52.msp

>> Debugging (Get-MSPProductcode.ps1) Script...
>> Platform: V5 32Bit (STA)
{89F4137D-6C26-4A84-BDB8-2E5A4BB71E00}
{413EB1DF-7973-4D2C-8317-E520032EBD27}
>> Script Ended

Mal ein Schnelltest mit einem MSP aus c:\windows\installer. Alles mit 32/64 Bit und PowerShell V2 und V5. Alles ok. Ich vermute es liegt am msp. Möglich ist auch, dass die COM Komponente fehlt oder eingeschränkt ist? Antivirus, AppSense Application Manager? Kannst Du die msp Datei bereitstellen? Get-MSPProductcode -patchnamepath c:\Windows\Installer\105ece52.msp Get-MSPPatchcode -patchnamepath c:\Windows\Installer\105ece52.msp >> Debugging (Get-MSPProductcode.ps1) Script... >> Platform: V5 32Bit (STA) {89F4137D-6C26-4A84-BDB8-2E5A4BB71E00} {413EB1DF-7973-4D2C-8317-E520032EBD27} >> Script Ended
Gäste - Frank am Montag, 06. Juni 2016 15:21

Hi,

habe dir eine email gesendet.
Frank

Hi, habe dir eine email gesendet. Frank
Andreas Nick am Montag, 06. Juni 2016 15:56

Hallo Frank,

Hier die Lösung. Ich hatte das Skript noch liegen und irgendwann einmal im Internet herausgesucht. Damit kann man Datenbankfelder in einem MSI oder MSP auslesen. Unten schon mit den Feldern, die Du benötigst.

function Get-MsiDatabaseValue
{
param (
[IO.FileInfo]$FilePath,
$Table,
$Tableproperty
)

try
{
$windowsInstaller = New-Object -com WindowsInstaller.Installer

$database = $windowsInstaller.GetType().InvokeMember(
"OpenDatabase", "InvokeMethod", $Null,
$windowsInstaller, @($FilePath.FullName, 32)
)

$q = "SELECT Value FROM $Table WHERE Property = '$TableProperty'"

$View = $database.GetType().InvokeMember(
"OpenView", "InvokeMethod", $Null, $database, ($q)
)

$View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null)



$record = $View.GetType().InvokeMember(
"Fetch", "InvokeMethod", $Null, $View, $Null
)

$TableValue = $record.GetType().InvokeMember(
"StringData", "GetProperty", $Null, $record, 1
)

return $TableValue

}
catch
{
# throw "Failed to get MSI file version the error was: {0}." -f $_
}
}


Get-MsiDatabaseValue -FilePath c:\temp\aout\policytips-x-none.msp MsiPatchMetadata TargetProductName
Get-MsiDatabaseValue -FilePath c:\temp\aout\policytips-x-none.msp MsiPatchMetadata Release

>> Platform: V2 64Bit (STA)
Microsoft Office 2016
3114694
>> Script Ended

Hallo Frank, Hier die Lösung. Ich hatte das Skript noch liegen und irgendwann einmal im Internet herausgesucht. Damit kann man Datenbankfelder in einem MSI oder MSP auslesen. Unten schon mit den Feldern, die Du benötigst. function Get-MsiDatabaseValue { param ( [IO.FileInfo]$FilePath, $Table, $Tableproperty ) try { $windowsInstaller = New-Object -com WindowsInstaller.Installer $database = $windowsInstaller.GetType().InvokeMember( "OpenDatabase", "InvokeMethod", $Null, $windowsInstaller, @($FilePath.FullName, 32) ) $q = "SELECT Value FROM $Table WHERE Property = '$TableProperty'" $View = $database.GetType().InvokeMember( "OpenView", "InvokeMethod", $Null, $database, ($q) ) $View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null) $record = $View.GetType().InvokeMember( "Fetch", "InvokeMethod", $Null, $View, $Null ) $TableValue = $record.GetType().InvokeMember( "StringData", "GetProperty", $Null, $record, 1 ) return $TableValue } catch { # throw "Failed to get MSI file version the error was: {0}." -f $_ } } Get-MsiDatabaseValue -FilePath c:\temp\aout\policytips-x-none.msp MsiPatchMetadata TargetProductName Get-MsiDatabaseValue -FilePath c:\temp\aout\policytips-x-none.msp MsiPatchMetadata Release >> Platform: V2 64Bit (STA) Microsoft Office 2016 3114694 >> Script Ended
Andreas Nick am Mittwoch, 08. Juni 2016 20:37

Hier noch eine Variante zum Auslesen von Metadaten, die für MSI und MSP Pakete funktioniert. Das Paket ist mir gerade aus der letzten Debug-Aktion zugeschickt worden... Viele Dank!

Es wird eine Excel Tabelle mit Informationen zu allen Office Updates erstellt. Bitte den Pfad zu den Patch-Dateien anpassen.

# Ausgabe der MetaDaten einer MSP Datei
# FG 2016

Function Get-MsiDatabaseValue {
param ( [IO.FileInfo]$FilePath, $Table, $Tableproperty )

$windowsInstaller = New-Object -com WindowsInstaller.Installer
$database = $windowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $Null, $windowsInstaller, @($FilePath.FullName, 32))
$q = "SELECT Value FROM $Table WHERE Property = '$TableProperty'"
$View = $database.GetType().InvokeMember("OpenView", "InvokeMethod", $Null, $database, ($q))
$View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null)
$record = $View.GetType().InvokeMember("Fetch", "InvokeMethod", $Null, $View, $Null )
$TableValue = $record.GetType().InvokeMember( "StringData", "GetProperty", $Null, $record, 1)
return $TableValue
}

$FolderPath = "R:\APP\Office\2016\Updates"
$MSPList =@()

$Shell=New-Object -ComObject Shell.Application
$Folder = $Shell.namespace( $FolderPath )
$FileItems = $Folder.Items()

foreach ($FileItem in $FileItems) {
If (Test-Path -PathType Leaf $FileItem.Path) { # Only process files (not folders)
# Get-MsiDatabaseValue -FilePath D:\2\policytips-x-none.msp MsiPatchMetadata TargetProductName
$FileName = ( $FileItem.Name ).Trim("`t")
$Release = Get-MsiDatabaseValue -FilePath $FileItem.Path MsiPatchMetadata Release
$Release = [System.String] $Release
$Release = ($Release).Trim("`t")
$Description = Get-MsiDatabaseValue -FilePath $FileItem.Path MsiPatchMetadata Description
$Description = [System.String] $Description
$Description = ($Description).Trim("`t")
#$Row = $Release + "," + $FileName + "," + $Description #$Row = $Row.ToString() # -replace "`t|`n|`r",""
$newrow = New-Object PSObject -Property @{
Description = ($Description)
HotfixID = ( $Release )
FileName = ( $FileName )
}
}
$MSPList += $newrow
}

# Sortierte Ausgabe in einer anderen Variablen speichern
$MSPlist | sort HotfixID | select HotfixID, FileName,Description | export-csv -path ($FolderPath +"\msp.csv") -Force -NoTypeInformation

Hier noch eine Variante zum Auslesen von Metadaten, die für MSI und MSP Pakete funktioniert. Das Paket ist mir gerade aus der letzten Debug-Aktion zugeschickt worden... Viele Dank! :D Es wird eine Excel Tabelle mit Informationen zu allen Office Updates erstellt. Bitte den Pfad zu den Patch-Dateien anpassen. # Ausgabe der MetaDaten einer MSP Datei # FG 2016 Function Get-MsiDatabaseValue { param ( [IO.FileInfo]$FilePath, $Table, $Tableproperty ) $windowsInstaller = New-Object -com WindowsInstaller.Installer $database = $windowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $Null, $windowsInstaller, @($FilePath.FullName, 32)) $q = "SELECT Value FROM $Table WHERE Property = '$TableProperty'" $View = $database.GetType().InvokeMember("OpenView", "InvokeMethod", $Null, $database, ($q)) $View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null) $record = $View.GetType().InvokeMember("Fetch", "InvokeMethod", $Null, $View, $Null ) $TableValue = $record.GetType().InvokeMember( "StringData", "GetProperty", $Null, $record, 1) return $TableValue } $FolderPath = "R:\APP\Office\2016\Updates" $MSPList =@() $Shell=New-Object -ComObject Shell.Application $Folder = $Shell.namespace( $FolderPath ) $FileItems = $Folder.Items() foreach ($FileItem in $FileItems) { If (Test-Path -PathType Leaf $FileItem.Path) { # Only process files (not folders) # Get-MsiDatabaseValue -FilePath D:\2\policytips-x-none.msp MsiPatchMetadata TargetProductName $FileName = ( $FileItem.Name ).Trim("`t") $Release = Get-MsiDatabaseValue -FilePath $FileItem.Path MsiPatchMetadata Release $Release = [System.String] $Release $Release = ($Release).Trim("`t") $Description = Get-MsiDatabaseValue -FilePath $FileItem.Path MsiPatchMetadata Description $Description = [System.String] $Description $Description = ($Description).Trim("`t") #$Row = $Release + "," + $FileName + "," + $Description #$Row = $Row.ToString() # -replace "`t|`n|`r","" $newrow = New-Object PSObject -Property @{ Description = ($Description) HotfixID = ( $Release ) FileName = ( $FileName ) } } $MSPList += $newrow } # Sortierte Ausgabe in einer anderen Variablen speichern $MSPlist | sort HotfixID | select HotfixID, FileName,Description | export-csv -path ($FolderPath +"\msp.csv") -Force -NoTypeInformation
Bereits registriert? Hier einloggen
Gäste
Donnerstag, 21. November 2019

Sicherheitscode (Captcha)

Kontakt

Nick Informationstechnik GmbH
WEB : http://www.nick-it.de
TEL : +49 511 165.810.190
MAIL: info(at)nick-it.de

@nickinformation Tweets

MAD Newsletter


Unser Modern Application Deployment Newsletter. Ihre Daten werden auf Grundlage der DSGVO gespeichert. Dazu auch der Link Datenschutz. Sie können sich jederzeit abmelden.


Empfange HTML?

Joomla Extensions powered by Joobi

Most Popular Post

04. Mai 2015
NITCtxPatcher a patchmanager for Citrix XenApp and XenDesktop 7.xMay 2017 The NITCtxPatchManager is back, after some changes from Citrix on the websit...
02. April 2015
NIT-GPOSearch is a free tool to search in the Group Policy (admx, adml) definitions for a specific setting. New in Version 1.2 - search in the domain ...
14. März 2015
Attention: We have completed a new version 2.0. This version is not longer free (Version 1.4 is it). In DACH you can request a conversion with the con...
Cookies erleichtern die Bereitstellung unserer Dienste. Mit der Nutzung unserer Dienste erklären Sie sich damit einverstanden, dass wir Cookies verwenden.
Weitere Informationen Ok