0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PowerShellでmsiを編集

Posted at

Visual Studioで作成したmsiは編集が必要

Visual Studio のセットアッププロジェクトで作成したmsiは編集が必要です。
(セットアッププロジェクトはVisual Studio 2012からサポートされなくなりました)

exeをバージョンアップするときは、既存のexeに上書きするのが普通です。
msiの編集は、上書きを可能にするために行います。

msiの編集について

PowerShellでmsiを編集

orca.ps1
# MSIファイルのパス
$msiPath = Join-Path $PSScriptRoot "[ここにmsiのパスを描く]"
try {
    # Windows Installerオブジェクトを作成
    $installer = New-Object -ComObject WindowsInstaller.Installer
    
    # データベースを開く
    $database = $installer.OpenDatabase($msiPath, 1)
    
    try {
        # CustomActionテーブルに追加
        $record = $installer.CreateRecord(4)
        $record.StringData(1) = "fix_reinstall".Trim()
        $record.IntegerData(2) = 51
        $record.StringData(3) = "REINSTALL".Trim()
        $record.StringData(4) = "{}".Trim()
        
        $view = $database.OpenView("INSERT INTO CustomAction (Action, Type, Source, Target) VALUES (?, ?, ?, ?)")
        $view.Execute($record)
        
        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($view) | Out-Null
        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($record) | Out-Null

        # InstallExecuteSequenceテーブルに追加
        $record = $installer.CreateRecord(3)
        $record.StringData(1) = "fix_reinstall".Trim()
        $record.StringData(2) = "NOT Installed".Trim()
        $record.IntegerData(3) = 999
        
        $view = $database.OpenView("INSERT INTO InstallExecuteSequence (Action, Condition, Sequence) VALUES (?, ?, ?)")
        $view.Execute($record)
        
        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($view) | Out-Null
        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($record) | Out-Null
        
        # InstallUISequenceテーブルに追加
        $record = $installer.CreateRecord(3)
        $record.StringData(1) = "fix_reinstall".Trim()
        $record.StringData(2) = "NOT Installed".Trim()
        $record.IntegerData(3) = 999
        
        $view = $database.OpenView("INSERT INTO InstallUISequence (Action, Condition, Sequence) VALUES (?, ?, ?)")
        $view.Execute($record)
        
        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($view) | Out-Null
        [System.Runtime.Interopservices.Marshal]::ReleaseComObject($record) | Out-Null
        
        $database.Commit()
        
        # 確認クエリ
        Write-Host "`n[結果]"
        
        Write-Host "`nCustomAction:"
        $view = $database.OpenView("SELECT * FROM CustomAction WHERE Action = 'fix_reinstall'")
        $view.Execute()
        $record = $view.Fetch()
        while ($record -ne $null) {
            Write-Host "  Action: $($record.StringData(1))"
            Write-Host "  Type: $($record.IntegerData(2))"
            Write-Host "  Source: $($record.StringData(3))"
            Write-Host "  Target: $($record.StringData(4))"
            $record = $view.Fetch()
        }
        
        Write-Host "`nInstallExecuteSequence:"
        $view = $database.OpenView("SELECT * FROM InstallExecuteSequence WHERE Action = 'fix_reinstall'")
        $view.Execute()
        $record = $view.Fetch()
        while ($record -ne $null) {
            Write-Host "  Action: $($record.StringData(1))"
            Write-Host "  Condition: $($record.StringData(2))"
            Write-Host "  Sequence: $($record.IntegerData(3))"
            $record = $view.Fetch()
        }
        
        Write-Host "`nInstallUISequence:"
        $view = $database.OpenView("SELECT * FROM InstallUISequence WHERE Action = 'fix_reinstall'")
        $view.Execute()
        $record = $view.Fetch()
        while ($record -ne $null) {
            Write-Host "  Action: $($record.StringData(1))"
            Write-Host "  Condition: $($record.StringData(2))"
            Write-Host "  Sequence: $($record.IntegerData(3))"
            $record = $view.Fetch()
        }
    }
    finally {
        Write-Host "`n"
        if ($record -ne $null) {
            [System.Runtime.Interopservices.Marshal]::ReleaseComObject($record) | Out-Null
        }
        if ($view -ne $null) {
            [System.Runtime.Interopservices.Marshal]::ReleaseComObject($view) | Out-Null
        }
        if ($database -ne $null) {
            [System.Runtime.Interopservices.Marshal]::ReleaseComObject($database) | Out-Null
        }
        if ($installer -ne $null) {
            [System.Runtime.Interopservices.Marshal]::ReleaseComObject($installer) | Out-Null
        }
    }
}
catch {
    Write-Host "エラーが発生しました: $_"
}
finally {
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()
}

バッチからPowerShellのスクリプトを呼び出す

バッチからPowerShellのスクリプトを呼び出すときは、powershell [ps1ファイル名] では動かないのでオプションを追加します。

msi.bat

powershell -NoProfile -ExecutionPolicy Bypass .\orca.ps1

顛末

Visual Studioで作成したmsiは、通常のmsiとは違うようです。

orcaを使って手動で編集する以外に、セットアッププロジェクトのプロパティPostBuildEventや、VBscriptを使用することで自動化することができるはずですが、うまくいきませんでした。

手動で編集して間違えるとインストーラが動きません。
自動化するのが一番です

関連リンク

なつかしの Visual Studio Installer(の後継)を現役のVisual Studioで使用する

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?