/build/static/layout/Breadcrumb_cap_w.png

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)

Posted by: anonymous_9363 1 year ago
Red Belt
0

Personally, I'd be using the proven Wix toolset to generate the transform but, as a casual observation, your code doesn't seem to create the 'BulkLoaderInstaller_Files' feature...

Posted by: rad33k 1 year ago
Fourth Degree Brown Belt
0

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
 
This website uses cookies. By continuing to use this site and/or clicking the "Accept" button you are providing consent Quest Software and its affiliates do NOT sell the Personal Data you provide to us either when you register on our websites or when you do business with us. For more information about our Privacy Policy and our data protection efforts, please visit GDPR-HQ