Generating Transform from MSI using PowerShell - Error coming while adding Registry but not in Component adding with same procedure -Help required
$msiOpenDatabaseModeReadOnly = 0
$msiOpenDatabaseModeTransact = 1
$msiTransformErrorNone = 0
$msiTransformValidationNone = 0
$msiFolder = "C:\Test\"
$database1Path = $msiFolder + "ELMSDesktopApplication.msi"
$database2Path = $database1Path + "_bak"
$MSTPath = $msiFolder + "New_MST.mst"
#If backup doesn't already exist, make a copy to make our changes to
if (!(Test-Path -Path $database2Path))
{
Copy-Item -Path $database1Path -Destination $database2Path
}
#Remove MST if already exists
If (Test-Path $MSTPath){
Remove-Item $MSTPath
}
#open original MSI in ReadOnly mode
$windowsInstaller = New-Object -ComObject WindowsInstaller.Installer
$database1 = $windowsInstaller.GetType().InvokeMember(
"OpenDatabase",
"InvokeMethod",
$Null,
$windowsInstaller,
@($database1Path, $msiOpenDatabaseModeReadOnly)
)
#open 'backup' MSI in transact mode
$database2 = $windowsInstaller.GetType().InvokeMember(
"OpenDatabase",
"InvokeMethod",
$Null,
$windowsInstaller,
@($database2Path, $msiOpenDatabaseModeTransact)
)
#Insert a test Feature Component
$query = "INSERT INTO ``FeatureComponents`` (``Feature_``,``Component_``) VALUES ('BulkLoaderInstaller_Files','AAA_AddReg')"
$View = $database2.GetType().InvokeMember(
"OpenView",
"InvokeMethod",
$Null,
$database2,
($query)
)
$View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null)
$View.GetType().InvokeMember("Close", "InvokeMethod", $Null, $View, $Null)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($View) | Out-Null
#Insert a test Component
$queryCom = "INSERT INTO ``Component`` (``Component``,``ComponentId``,``Directory_``,``Attributes``,``Condition``,``KeyPath``) VALUES ('AAA_AddReg','','INSTALLDIR',0,'','')"
$ViewCom = $database2.GetType().InvokeMember(
"OpenView",
"InvokeMethod",
$Null,
$database2,
($queryCom)
)
$ViewCom.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $ViewCom, $Null)
$ViewCom.GetType().InvokeMember("Close", "InvokeMethod", $Null, $ViewCom, $Null)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ViewCom) | Out-Null
#Insert a Registry
$queryReg = "INSERT INTO ``Registry`` (``Registry``,``Root``,``Key``,``Name``,``Value``,``Component_``) VALUES ('Registry1',2,'Software\Chiranjit','Installed','1','AAA_AddReg')"
$ViewReg = $database2.GetType().InvokeMember(
"OpenView",
"InvokeMethod",
$Null,
$database2,
($queryReg)
)
$ViewReg.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $ViewReg, $Null)
$ViewReg.GetType().InvokeMember("Close", "InvokeMethod", $Null, $ViewReg, $Null)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ViewReg) | Out-Null
#Commit the changes to our backup database
$database2.GetType().InvokeMember("Commit", "InvokeMethod", $Null, $database2, $Null)
#Generate a transform (the difference between our original MSI and our Backup MSI)
$transformSuccess = $database2.GetType().InvokeMember(
"GenerateTransform",
"InvokeMethod",
$Null,
$database2,
@($database1,$MSTPath)
)
#Create a Summary Information Stream for the MST
$transformSummarySuccess = $database2.GetType().InvokeMember(
"CreateTransformSummaryInfo",
"InvokeMethod",
$Null,
$database2,
@($database1,$MSTPath, $msiTransformErrorNone, $msiTransformValidationNone)
)
#Release objects from memory
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($database1) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($database2) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($windowsInstaller) | Out-Null
#Delete backup database
If (Test-Path $database2Path){
Remove-Item $database2Path
}
0 Comments
[ + ] Show comments
Answers (2)
Please log in to answer
Posted by:
anonymous_9363
1 year ago
Posted by:
rad33k
1 year ago
Does the Registry table exist in your MSI?
Your code is working fine for me only if the Registry table is present in the source MSI.
Here is an example how to handle it for CustomAction table:
https://www.alkanesolutions.co.uk/blog/2014/10/30/powershell-windows-installer-msi-transforms-mst/
...
#use the TablePersist method to see if the CustomAction table exists
$tableExists = $database2.GetType().InvokeMember(
"TablePersistent",
"GetProperty",
$Null,
$database2,
"CustomAction"
)
#If CustomAction table does not exist
if ([int]$tableExists -ne 1)
{
#Create CustomAction table
$query = "CREATE TABLE ``CustomAction`` ( ``Action`` CHAR(72) NOT NULL, ``Type`` SHORT NOT NULL, ``Source`` CHAR(64), ``Target`` LONGCHAR PRIMARY KEY ``Action``)"
$View = $database2.GetType().InvokeMember(
"OpenView",
"InvokeMethod",
$Null,
$database2,
($query)
)
$View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null)
$View.GetType().InvokeMember("Close", "InvokeMethod", $Null, $View, $Null)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($View) | Out-Null
}
...
Comments:
-
Hi You have modified anything, Actually for me Registry is not coming its showing an SQL error(Openview,Sql,Exceptio calling). - Mr. Jeet 1 year ago
-
I did not change anything - I just copied your code and ran it against my MSI.
I tested it on Win10 machine.
Have you tried to test it with few different MSIs? Does the Registry table exist in your base MSI? - rad33k 1 year ago