Keshav
Keshav

Reputation: 2027

Set package code of MSI using vbscript

I am changing product code, upgrade code and product name of MSI by editing MSI database.

With reference :- http://www.codeproject.com/Articles/383481/Editing-an-MSI-Database

I am able to change all parameters above but unable to change Package Code.

Suggest a way to change package code.

Upvotes: 1

Views: 1133

Answers (5)

eduardomozart
eduardomozart

Reputation: 1454

I extended the Nikolay script for generating a random GUID automatically. The script also support drag and drop and be called through arguments (so you can easily automate it through cscript) and it checks if the file is writable before creating Windows Installer object (if the file is locked by some application, like InstEd, it will throw an error).

Set objArgs = Wscript.Arguments
Set objFso = CreateObject("scripting.filesystemobject")

'iterate through all the arguments passed
' https://community.spiceworks.com/scripts/show/1653-drag-drop-vbscript-framework
For i = 0 to objArgs.count
  on error resume next

  'try and treat the argument like a folder
  Set folder = objFso.GetFolder(objArgs(i))

  'if we get an error, we know it is a file
  If err.number <> 0 then
    'this is not a folder, treat as file
    ProcessFile(objArgs(i))
  Else

  'No error? This is a folder, process accordingly
    For Each file In folder.Files
      ProcessFile(file)
    Next
  End if
  On Error Goto 0
Next

Function ProcessFile(sFilePath)
 ' http://www.wisesoft.co.uk/scripts/vbscript_file_modified_date.aspx
 ' Set objFile = objFSO.GetFile(sFilePath)
 ' MsgBox "Now processing file: " & CDATE( objFile.DateLastModified)
 If Not IsWriteAccessible(sFilePath) Then WScript.Echo "Error persisting summary property stream" : Wscript.Quit 2
 'Do something with the file here...
 ' https://stackoverflow.com/questions/31536349/set-package-code-of-msi-using-vbscript
 Set installer = CreateObject("WindowsInstaller.Installer")
 Set summary = installer.SummaryInformation(sFilePath, 2)
 summary.Property(9) = CreateGuid()
 summary.Persist
End Function

' https://stackoverflow.com/questions/968756/how-to-generate-a-guid-in-vbscript
Function CreateGuid()
    CreateGuid = Left(CreateObject("Scriptlet.TypeLib").Guid,38)
End Function

' https://stackoverflow.com/questions/12300678/how-can-i-determine-if-a-file-is-locked-using-vbs
Function IsWriteAccessible(sFilePath)
    ' Strategy: Attempt to open the specified file in 'append' mode.
    ' Does not appear to change the 'modified' date on the file.
    ' Works with binary files as well as text files.

    ' Only 'ForAppending' is needed here. Define these constants
    ' outside of this function if you need them elsewhere in
    ' your source file.
    Const ForReading = 1, ForWriting = 2, ForAppending = 8

    IsWriteAccessible = False

    Dim oFso : Set oFso = CreateObject("Scripting.FileSystemObject")

    On Error Resume Next

    Dim nErr : nErr = 0
    Dim sDesc : sDesc = ""
    Dim oFile : Set oFile = oFso.OpenTextFile(sFilePath, ForAppending)
    If Err.Number = 0 Then
        oFile.Close
        If Err Then
            nErr = Err.Number
            sDesc = Err.Description
        Else
            IsWriteAccessible = True
        End if
    Else
        Select Case Err.Number
            Case 70
                ' Permission denied because:
                ' - file is open by another process
                ' - read-only bit is set on file, *or*
                ' - NTFS Access Control List settings (ACLs) on file
                '   prevents access

            Case Else
                ' 52 - Bad file name or number
                ' 53 - File not found
                ' 76 - Path not found

                nErr = Err.Number
                sDesc = Err.Description
        End Select
    End If

    ' The following two statements are superfluous. The VB6 garbage
    ' collector will free 'oFile' and 'oFso' when this function completes
    ' and they go out of scope. See Eric Lippert's article for more:
    '   http://blogs.msdn.com/b/ericlippert/archive/2004/04/28/when-are-you-required-to-set-objects-to-nothing.aspx

    'Set oFile = Nothing
    'Set oFso = Nothing

    On Error GoTo 0

    If nErr Then
        Err.Raise nErr, , sDesc
    End If
End Function

Upvotes: 0

Nikolay
Nikolay

Reputation: 12245

Found a way to do it with vbscript, just out of curiosity: The "property #9" is the package code (revision number).

Set wi = CreateObject("WindowsInstaller.Installer")
Set summary = wi.SummaryInformation("your.msi", 2)
summary.Property(9) = "{PUT-NEW-GUID-HERE}"
summary.Persist

Upvotes: 3

PhilDW
PhilDW

Reputation: 20780

I'm guessing that the requirement here is to install the same MSI multiple times, which means they need to change that set of guids. However the more normal way to solve that problem is with MSINEWINSTANCE.

https://msdn.microsoft.com/en-us/library/aa370326(v=vs.85).aspx

https://msdn.microsoft.com/en-us/library/aa369528(v=vs.85).aspx

so that you are not changing the base MSI file every time.

Upvotes: 1

Keshav
Keshav

Reputation: 2027

I needed it because MSI created cache in respective package code which restricts us to make another instance of application using MSI so I did this by

using (var database = new Database(@"D:\\Nirvana\\WorkingCopy\\trunk\\proj1\\installer.msi", DatabaseOpenMode.Direct))
{
     database.SummaryInfo.RevisionNumber = "{" +  Guid.NewGuid() + "}";
}   

Upvotes: 0

Kiran Hegde
Kiran Hegde

Reputation: 700

Why do you even have the need to set the package code?

Its auto generated during each build.

Take a look at the documentation of the Package element:

http://wixtoolset.org/documentation/manual/v3/xsd/wix/package.html

"The package code GUID for a product or merge module. When compiling a product, this attribute should not be set in order to allow the package code to be generated for each build. When compiling a merge module, this attribute must be set to the modularization guid."

Upvotes: 0

Related Questions