📘

Microsoft Intune 用に Web から MSI ファイルを取得&展開できるスクリプトを作った

2024/07/29に公開

これは何?

Intune ではアプリケーションの展開において、MSI インストーラ形式で配布されているアプリケーションを管理デバイスに展開することができます。

今回、運用のやりやすさを上げるために実施した取り組みをここにまとめます。

想定する読者

以下を満たす人を対象としています。

  • Intune で「Windows アプリ(Win32)」のアプリケーション登録ができる人
  • Intune のアプリケーション配布の手間を減らしたい人

課題1:アプリケーションのバージョンが上がるたびに配布パッケージを Intune に登録する必要がある

これは Intune に限らず MDM 関連ではあるあるな話ですが、アプリケーションの配布において MDM にインストーラを直接アップロードするとデバイスに配布されるアプリケーションのバージョンが固定化されてしまう課題があります。

アプリケーションによっては自動でアップデートされるにしても、バージョンが古くなったものを配布することはわずかながらもセキュリティのリスクを伴います。

これを解決するにはアプリケーションのバージョンが上がった際には都度 MDM にアップロードする必要があります。が、Intune においてはアップロードファイル(.intunewinファイルとか)を用意するのは手間ですよね……。

課題2:「Windows アプリ(Win32)」と「基幹業務アプリ」が同時利用できない

これ個人的には Intune の罠ポイントと思っているのですが、Intune では「Windows アプリ(Win32)」形式でアプリケーションを配布する場合、同じタイミングに別形式(基幹業務アプリなど)を使ったアプリケーションを配布することは非推奨とされています。

Win32 アプリを展開する場合、特に複数ファイルの Win32 アプリ インストーラーがある場合は、Intune 管理拡張機能の方法を排他的に使用することを検討してください。 Autopilot 登録中に Win32 アプリと基幹業務 (LOB) アプリのインストールを混在させる場合、アプリのインストールが失敗する可能性があります。

おそらくインストールの排他処理が正しく処理されていないのではと思っているのですが、AutoPilot などデバイスのセットアップにて多量のインストール処理をさせたいケースで排他処理が期待通りに動かないのはちょっと苦しいですね。

つまるところ、本問題を回避するには MSI 形式のインストーラでも「Windows アプリ(Win32)」で作成する必要があるわけです。結局、「基幹業務アプリ」だったら MSI をサクッと差し替えができるところが、課題1で挙げたように運用が重たい「Windows アプリ(Win32)」になってしまうわけです…。

本スクリプトでできること

この記事で紹介するスクリプトは以下の機能を有します。

  • 指定した URL から MSI インストーラを自動取得&インストール
  • アンインストール

事前準備で必要な情報

本スクリプトを使う場合は以下の情報が予め必要です。

MSI インストーラーの公開 URL

導入したいアプリケーションの MSI インストーラーの配布先です。
本スクリプトはこの URL からダウンロード、インストールを実行します。

この URL は気合いで探す必要がありますが、私が調査したものをいくつか紹介します。

アプリケーション 配布 URL
Google Chrome (64bit) https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi
Zoom (64bit) https://zoom.us/client/latest/ZoomInstallerFull.msi?archType=x64

アプリケーションの名称

本スクリプトを使用してアプリケーションをアンインストールするとき、アプリケーションの特定のために使用します。

MSI 形式でインストールした場合 Product ID と呼ばれる識別子が Windows に登録され、その識別子を用いてアンインストールをすることができます。しかし、アプリケーションがバージョンアップするごとに Product ID が変化するらしい(情報求む)ので、アプリケーション名を用いて Product ID を特定します。

Windows にインストールされたアプリケーション名をそのまま使います。厳密に名称を調べたいときは以下のレジストリキーを開いて DisplayName プロパティの値を調べます。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}

ここでも私が調査したものをいくつか紹介します。

アプリケーション アプリケーションの名称
Google Chrome (64bit) Google Chrome
Zoom (64bit) Zoom Workplace (64-bit)

アプリケーション本体のファイルパス

後述の「検出ルール」などで使うためにアプリケーション本体が保存されるパスを調べておきます。

スクリプトの作成

下記のスクリプトを作成して .intunewin 形式にパッケージングしてください。ファイル名、ファイル形式は以下で作成してください。

  • ファイル名:msiInstaller.ps1
  • 文字コード:UTF-8
  • 改行コード:CRLF
param(
  [string]$label = "",
  [string]$installerUrl = "",
  [switch]$uninstall = $false,
  [switch]$isDebug = $false
)

if (!$isDebug){
  $ProgressPreference = "SilentlyContinue"
}

if ($label -eq "") {
  echo "アプリケーション名を指定してください。"
  exit 1
}

#
# アンインストール処理ここから
#
if ($uninstall)
{
  # MSI の製品ID(Product ID)を取得する
  $productId32bit = (Get-ChildItem -Path "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | Get-ItemProperty | Where-Object DisplayName -eq $label | Select-Object -ExpandProperty PSChildName)
  $productId64bit = (Get-ChildItem -Path "Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | Get-ItemProperty | Where-Object DisplayName -eq $label | Select-Object -ExpandProperty PSChildName)

  if ($productId32bit -eq "" -and $productId64bit -eq ""){
    echo "レジストリにアプリケーションが登録されていません。"
    exit 1
  }

  $productId = ""
  if (!($productId32bit -ne "" -or $productId64bit -ne "")){
    echo "32bit と 64bit 両方にアプリケーションが登録されています。64bit を優先します。"
    $productId = $productId64bit
  }else{
    $productId = (echo $productId32bit$productId64bit)
  }

  # 取得した製品ID(Product ID)を使ってアンインストール実行
  Start-Process -NoNewWindow -PassThru -Wait -FilePath "msiexec" -ArgumentList "/x", $productId, "/qn"

  # なぜか30秒ほど待機いれないとエラーになる
  Start-Sleep -Seconds 30

  exit 0
}
#
# アンインストール処理ここまで
#

#
# 以下インストール処理
#
if ($installerUrl -eq "") {
  echo "アプリケーションの配布先 URL を指定してください。"
  exit 1
}

$installerLabel = $label.replace(" ","")
$installerName = "$installerLabel.msi"

# MSI ファイルのダウンロード
Invoke-WebRequest -UseBasicParsing -Uri $installerUrl -OutFile $installerName

# MSI ファイルのインストールをサイレントモードで実行
Start-Process -NoNewWindow -PassThru -Wait -FilePath "msiexec" -ArgumentList "/i", $installerName, "/qn"

# なぜか30秒ほど待機いれないとエラーになる
Start-Sleep -Seconds 30

exit 0

Intune の配布設定

上記スクリプトを格納した .intunewin ファイルを Intune にアップロードします。

配布設定は以下のように設定します。

プログラム

プログラム画面の入力例

インストールコマンド

下記文字列を入力します。一部書き換えないといけない箇所があるので下表から置き換えてください。

powershell -ExecutionPolicy Bypass ".\msiInstaller.ps1 'Label' 'URL'"
コマンド内の文字列 置き換える値
Label 事前準備で確認した「アプリケーションのタイトル」
URL 事前準備で確認した「MSI インストーラーの公開 URL」

例えば、例に挙げた Google Chrome や Zoom ではこんな感じです。

アプリケーション コマンド例
Google Chrome (64bit) powershell -ExecutionPolicy Bypass ".\msiInstaller.ps1 'Google Chrome' 'https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi'"
Zoom (64bit) powershell -ExecutionPolicy Bypass ".\msiInstaller.ps1 'Zoom Workplace (64-bit)' 'https://zoom.us/client/latest/ZoomInstallerFull.msi?archType=x64'"

アンインストールコマンド

下記文字列を入力します。一部書き換えないといけない箇所があるので、「インストールコマンド」項で挙げた対応表と同じものを入れてください。

powershell -ExecutionPolicy Bypass ".\msiInstaller.ps1 'Label' -uninstall"

例えば、例に挙げた Google Chrome や Zoom ではこんな感じです。

アプリケーション コマンド例
Google Chrome (64bit) powershell -ExecutionPolicy Bypass ".\msiInstaller.ps1 'Google Chrome' -uninstall"
Zoom (64bit) powershell -ExecutionPolicy Bypass ".\msiInstaller.ps1 'Zoom Workplace (64-bit)' -uninstall"

インストールの処理

事前準備で確認した「アプリケーション本体のファイルパス」によって値を変えます。

  • パスが C:¥Users¥ 配下である場合:ユーザー
  • パスが上記以外の場合:システム

検出ルール

前述の通り、アプリケーションのバージョンアップで Product ID が変わるので MSI ではなくファイルの有無で検出するように設定します。

その他の設定

特に特筆することがないので割愛します。

最後に

というわけで、MSI ファイルを Intune にアップロードすることなく、自動で配布先から取得できるようにする方法を紹介しました。

ここまで書いて気づいたんですが、PowerShell を実行できる環境なら Intune じゃなくても動きますね…w。

記載した内容について何かありましたら記事コメントか X/Twitter までご連絡ください。

GitHubで編集を提案

Discussion