/build/static/layout/Breadcrumb_cap_w.png

Scripting Question


Generating Transform from MSI using PowerShell - Error coming while adding Registry but not in Component adding with same procedure -Help required

06/26/2019 755 views
$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

Comments


All Answers

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...

Answered 06/27/2019 by: VBScab
Red 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
}
...
Answered 07/01/2019 by: rad33k
Fourth Degree Brown Belt

  • Hi You have modified anything, Actually for me Registry is not coming its showing an SQL error(Openview,Sql,Exceptio calling).
    • 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?
 
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