Microsoft Intuneとwingetを組み合わせて自動で最新版のアプリケーションを展開してみた

おはようこんにちはこんばんは！

さて、今回は自宅の環境でMicrosoft Azure ADとMicrosoft Intuneを使えるようにしたので、せっかくなのでwingetと組み合わせて自動でwinget経由で最新版のアプリケーションを展開出来るようにしてみました。

(今回の記事ではMicrosoft 365のプランやライセンスについては解説しませんが、検証にはMicrosoft 365 F1を使用しています)

## winget(Windows Package Manager)とは
Windows Package Manager(winget)とは、Windows10およびWindows11向けのオープンソースのパッケージ管理システムのことです。
ChocolateyやScoopを使ったことがある人ならば、それのMicrosoft公式から出ているようなものだと思ってもらえると分かりやすいと思います。

ちなみに、Windows11以降には標準でインストールされているので特に何もすることなく、`winget`コマンドを叩けば使用出来ます。

## 下準備 
https://github.com/Microsoft/Microsoft-Win32-Content-Prep-Tool よりIntuneWinAppUtilを用意しておきましょう。

IntuneではWin32アプリケーションを展開するには `.intunewin` 形式の1つのファイルにインストーラーやスクリプトがまとめられたものを使う必要があるので、この `.intunewin` ファイルをIntuneWinAppUtilを使って準備します。

といっても、インストールコマンドはIntuneの画面上からカスタマイズ出来るのと、毎回これを作るのはあまりにも非効率すぎるので、使い回せるwinget経由のインストール用の`.intunewin`を作っていきます。

### wingetを操作するスクリプトを用意する
Intuneでは基本的にインストールとアンインストールを操作できれば何とかなるので、一旦それを満たせるスクリプトを作ります。

```ps:winget-installer/winget-installer.ps1
param(
    [string]$package = "",
    [switch]$uninstall = $false
)

if ($uninstall)
{
    winget uninstall -e --accept-source-agreements --silent --id $package
}
else
{
    winget install -e --accept-package-agreements --accept-source-agreements --silent --id $package
}
```

コツは、 `--accept-source-agreements` と `--accept-package-agreements` ですが、これがないと利用規約の同意のプロンプトで操作が止まってしまってインストール中に固まってしまうので、予めオプションで指定してそれを同意させるようにします。(必ず利用規約は事前に確認しておきましょう)

スクリプトが完成したら、IntuneWinAppUtilを使ってパッケージをビルドしましょう。

```ps
.\IntuneWinAppUtil.exe -c .\winget-installer -s winget-installer.ps1 -o .\build -q
```

完了するとbuildディレクトリの中に `winget-installer.intunewin` が完成しているはずなので、今後はこれを使って展開の設定を作っていきます。

## インストールする対象のアプリケーションの検出スクリプトを組む
Intuneではアプリケーションがインストールされているかどうかを、ファイルやレジストリが存在するかどうかとカスタムのスクリプトの実行結果を元に判定することができます。

設定必須の項目なので、これもwingetコマンドを用いて検出する形で作っていきます。

今回は例として、Docker.DockerDesktopを扱います。

```ps:docker-desktop-detect.ps1
winget list --accept-source-agreements --exact Docker.DockerDesktop
exit $LastExitCode
```

対象のパッケージが入っているかどうかを検索して、なければ0以外の終了コードが返ってくるのでそれをそのまま返すようにしています。(異常終了するとその対象はないものとしてIntuneから扱われます)

## 最後にIntuneの展開設定をポチポチ入れて完了
ここからはGUIメインの操作になりますが、基本的には先程作ったスクリプトを割り当てるだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41743/17b19eaf-ece6-71ee-01ba-75b2ff7769f2.png)

ホーム > Windows のアプリ > 追加 からWindowsアプリ(Win32)を選択して...

ウィザード形式の設定画面が出てくるので、各項目を以下の設定値で埋めましょう。

- ファイルの選択(アプリパッケージファイル): `winget-installer.intunewin`を指定
- 名前: 何でも良いです
- 説明: 何でも良いです
- 発行元: 何でも良いです
- インストールコマンド: `powershell.exe -executionpolicy bypass -windowstyle hidden .\winget-installer.ps1 Docker.DockerDesktop`
    - `Docker.DockerDesktop` の所は適宜アプリケーションのパッケージ名に合わせてください
- アンインストールコマンド: `powershell.exe -executionpolicy bypass -windowstyle hidden .\winget-installer.ps1 Docker.DockerDesktop -uninstall`
    - `Docker.DockerDesktop` の所は適宜アプリケーションのパッケージ名に合わせてください
- インストールの処理: ユーザー
    - 必ずユーザーを選択しましょう。UACはログインユーザで昇格された状態で実行されます。
    - システムにするとIntuneのシステムユーザによって実行されるため、正しくwingetが実行出来ません
- 必要条件: 各アプリケーションに合わせて設定しましょう
- 検出ルール: カスタム検出スクリプトを使用する
    - 先程作成した検出スクリプトを指定してください
- 割り当て: 環境に合わせて適宜設定してください
    - 今回は必須ではなく利用可能に設定しておきましたが、必須にするとドメインに参加した時点で自動的に強制的にインストールされます

## 動作確認をする
動作確認はポータルサイト(Microsoftストアからダウンロード出来ます)のアプリケーションから確認出来るのでそちらで確認しましょう。

必須のアプリケーションの場合は「同期」することで、そうでないアプリケーションはポータルサイトからインストールすることで確認出来ます。

また、上手く行かないときは一回手動でwingetコマンドを実行してみることでエラーの手がかりが得られることがあります。

よくあるのがインストーラのハッシュ値の不一致ですが、これはGoogle Chromeのようなインストーラの配布URLが常に最新版を配るようになっているものの場合は顕著に起こります。これを回避する `-force` オプションはUAC昇格状態では使えないので、現状その場合は諦めて手動で入れるなどで対応しましょう。

## さいごに
さて、勘が良い人ならば既にwinget初期状態で入ってないからこの手法使えなくね？ということに気づくと思います。
はい、その通りです。(Windows11の端末に展開するなら話は別ですが)

英語の記事にはなりますが、以下のサイトが参考になりますのでビジネス向けMicrosoft Storeを使った展開もしくはPowershellを使った展開で入れるようにしましょう。

https://call4cloud.nl/2021/05/cloudy-with-a-chance-of-winget/

また、Chocolateyでもwingetを使った今回の手法と同様の事は出来るので、興味がある方はやってみてください！

それでは、良いIntune生活を！