Windows サンドボックスを使ってみた

概要

WSL上のLinuxを利用してある程度GUIアプリを動かせる環境ができましたが、Pro以上のWindowsにて利用可能なWindows サンドボックスを利用してUSBを含めた試験環境を作ってみました。

Windows サンドボックスとは?

Windows サンドボックス
Windows サンドボックス概要

Windows 10 Pro および Enterprise以降にて利用できる機能です。仮想環境のWindowsを立ち上げて動かすことができます。特徴としてはログアウトか閉じると初期化される環境となります。毎回完全な新規状態で立ち上がるので動作確認などがしやすいとは思います。

注意点としては毎回初期化されるので、ある程度環境を自動構築するスクリプトなどを併用する必要があると思いました。

Windows サンドボックスの有効化

デフォルトでは有効化されていませんので、コントロールパネルにある「Windowsの機能の有効化または無効化」をつかって有効化をする必要があります。

WSLのときと同じようにHyper-Vも有効化したほうが通信周りは安定すると思います。

とりあえず立ち上げてみる

さくっとたちあがりますが、残念ながら英語です。

設定から変更すると日本語になりますが、ここで表記のとおりにサインアウトするとサンドボックスが終了され、初期化されます。この状態で再起動をするのが正解になります。

再起動をすると左上にあるゴミ箱が日本語になっているのがわかります。ただ毎回これをやるのは面倒なので自動化をしたいと思います。

自動化の仕組み

Windows サンドボックス構成
Windows サンドボックス構成

上記に書いてあるのですが、構成用のファイルを作成して実行することで環境をある程度事前設定することが可能です。以下設定可能な項目の概要です。

そして残念ながらデフォルトの機能ではUSBの共有がありません。どうにかがんばって自分で共有する必要があります。

vGPU (仮想 GPU)

GPUの設定ですが、通常はさわらなくて大丈夫だと思います。通常はvGPUサポートが有効になっているのですが、サンドボックス無いで重い処理を動かすとホスト側にも影響がでるので無効に設定可能です。

ネットワーク

デフォルトはNAT経由での接続になります。Hyper-Vがインストールしてあれば直結でホストのWindowsに接続可能です。あとはブリッジと完全無効が選択できそうです。

マップ済みフォルダー

ホスト側のフォルダをサンドボックスに共有することができます。クリップボード経由でファイルのやり取りは可能ですが、基本的なファイルは共有をしたほうが楽だと思います。

Logon コマンド

起動時に実行されるコマンドを指定できます。1つしか指定できないのでバッチファイルなどを作成して指定することになります。

オーディオ入力

オーディオ入力(マイク)はデフォルトで有効になっていました。無効にすることができます。

ビデオ入力

デフォルトで無効になっており、有効化が可能なようです。

保護されたクライアント

保護レベルの設定です。デフォルトは通常モードで起動しており、さらに保護を強化することができるようです。

プリンターのリダイレクト

デフォルトで無効になっており、有効化が可能なようです。

クリップボードのリダイレクト

デフォルトで有効になっていました。無効にすることができます。

メモリ (MB 単位)

デフォルトは自動設定で、私の環境だと4GBが割り当てられていました。

実際の設定方法

構成ファイル(Ja.wsb)

<Configuration>
  <MappedFolders>
    <MappedFolder>
      <HostFolder>C:\Users\%USERNAME%\Dropbox\Sandbox</HostFolder>
      <SandboxFolder>C:\Sandbox</SandboxFolder>
      <ReadOnly>true</ReadOnly>
    </MappedFolder>
    <MappedFolder>
      <HostFolder>C:\Work</HostFolder>
      <SandboxFolder>C:\Work</SandboxFolder>
      <ReadOnly>false</ReadOnly>
    </MappedFolder>
  </MappedFolders>
  <LogonCommand>
    <Command>powershell 
        -executionpolicy unrestricted 
        -command "start powershell {-noexit -file C:\Sandbox\Ja.ps1}"</Command>
  </LogonCommand>
</Configuration>

2つのフォルダを共有して、1つのスクリプトを自動時に設定しています。wsb拡張子のファイルをDropbox上においています。

共有フォルダ

ホスト上のパスサンドボックス上のパス権限
C:\Users\%USERNAME%\Dropbox\SandboxC:\Sandbox読み込みのみ
C:\WorkC:\Work読み書き

共有フォルダは読み込みのみのスクリプトをおいてあるSandboxフォルダと、各種ファイル共有用のWorkフォルダの2つを準備しました。

スクリプトの指定

共有したフォルダ上にあるスクリプトを実行しています。コマンドプロンプトのバッチファイルも実行可能ですが、環境設定ができるPowerShell用のファイルにしてあります。デフォルトだと権限の問題で実行できないので-executionpolicy unrestrictedなどのオプションを追加して呼び出しています。

自動実行スクリプト(Ja.ps1)

# mklink
cmd /c "mklink" /D "%USERPROFILE%\Desktop\Sandbox" "C:\Sandbox"
cmd /c "mklink" /D "%USERPROFILE%\Desktop\Work" "C:\Work"

# set Language ja-JP
Set-WinUserLanguageList -Force ja-JP
shutdown /r /t 0

いろいろ指定が可能ですが、共有したフォルダをデスクトップ上にリンクで配置しています。また、言語設定はSet-WinUserLanguageListで指定して、反映させるために再起動をしています。

これで共有ファイルがデスクトップにあり、日本語化された状態で起動しました。

wingetを入れる

# mklink
cmd /c "mklink" /D "%USERPROFILE%\Desktop\Sandbox" "C:\Sandbox"
cmd /c "mklink" /D "%USERPROFILE%\Desktop\Work" "C:\Work"

# winget install
$progressPreference = 'silentlyContinue'
Write-Information "Downloading WinGet and its dependencies..."
Invoke-WebRequest -Uri https://aka.ms/getwinget -OutFile Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx
Invoke-WebRequest -Uri https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx -OutFile Microsoft.UI.Xaml.2.8.x64.appx
Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx
Add-AppxPackage Microsoft.UI.Xaml.2.8.x64.appx
Add-AppxPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle

# set Language ja-JP
Set-WinUserLanguageList -Force ja-JP
shutdown /r /t 0

実際のところ環境構築をするときにwingetがあると便利なので追加してみます。自動スクリプトの真ん中にあるコマンドになります。

WinGet ツールを使用したアプリケーションのインストールと管理
WinGet コマンド ライン ツールを使用すると、開発者は Windows コンピューター上でアプリケーションを検出、インストール、アップグレード、削除、および構成することができます。

上記にてサンドボックスにwingetを実行するときのコマンドがあったので使っています。

Arduino IDEを入れてみる

# mklink
cmd /c "mklink" /D "%USERPROFILE%\Desktop\Sandbox.lnk" "C:\Sandbox"
cmd /c "mklink" /D "%USERPROFILE%\Desktop\Work.lnk" "C:\Work"

# winget install
$progressPreference = 'silentlyContinue'
Write-Information "Downloading WinGet and its dependencies..."
Invoke-WebRequest -Uri https://aka.ms/getwinget -OutFile Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx
Invoke-WebRequest -Uri https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx -OutFile Microsoft.UI.Xaml.2.8.x64.appx
Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx
Add-AppxPackage Microsoft.UI.Xaml.2.8.x64.appx
Add-AppxPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle

winget install ArduinoSA.IDE.stable --accept-package-agreements --accept-source-agreements

# hide taskbar 
$regp = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3"
$regv = (get-item $regp).getvalue("Settings")
if(($regv[8] -band 0x01) -eq 0x00){
  $regv[8] = $regv[8] -bor 0x01
}else{
  $regv[8] = $regv[8] -band 0xFE
}
set-itemproperty $regp -name "Settings" -value $regv -type "binary"
stop-process -name "explorer"

# set Language ja-JP
Set-WinUserLanguageList -Force ja-JP
shutdown /r /t 0

winget installでアプリを追加します。初回は承認をしないとすすまないはずなので–accept-package-agreements –accept-source-agreementsをつけて実行しています。

あとは下にあるタスクバーが邪魔だったので自動的に隠す設定を追加しています。

USBの共有

デフォルトではUSBを共有することができません。これはかなり困っていて、Arduino IDEを起動しても実際に転送することができないので意味がありません。

GitHub - cezanne/usbip-win: USB/IP for Windows
USB/IP for Windows. Contribute to cezanne/usbip-win development by creating an account on GitHub.

そこで上記のアプリを利用します。WSLのときに利用していたwingetで入手可能なのはusbipd-winでサーバー側の共有する機能のみで、利用するクライアント側になることができません。ホスト側はusbipd-winを動かして、サンドボックス側はusbip-winを利用することになります。最後のdの有無でかなり紛らわしいです。

ホスト側は上記の記事を参考にして、usbipd-winで該当のUSBを共有状態にしておきます。

# mklink
cmd /c "mklink" /D "%USERPROFILE%\Desktop\Sandbox.lnk" "C:\Sandbox"
cmd /c "mklink" /D "%USERPROFILE%\Desktop\Work.lnk" "C:\Work"

# winget install
$progressPreference = 'silentlyContinue'
Write-Information "Downloading WinGet and its dependencies..."
Invoke-WebRequest -Uri https://aka.ms/getwinget -OutFile Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx
Invoke-WebRequest -Uri https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx -OutFile Microsoft.UI.Xaml.2.8.x64.appx
Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx
Add-AppxPackage Microsoft.UI.Xaml.2.8.x64.appx
Add-AppxPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle

winget install ArduinoSA.IDE.stable --accept-package-agreements --accept-source-agreements

# install usbip
\Sandbox\usbip-win-0.3.6-dev\usbip install

# hide taskbar 
$regp = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3"
$regv = (get-item $regp).getvalue("Settings")
if(($regv[8] -band 0x01) -eq 0x00){
  $regv[8] = $regv[8] -bor 0x01
}else{
  $regv[8] = $regv[8] -band 0xFE
}
set-itemproperty $regp -name "Settings" -value $regv -type "binary"
stop-process -name "explorer"

# set Language ja-JP
Set-WinUserLanguageList -Force ja-JP
shutdown /r /t 0

Sandboxフォルダに最新版のusbip-win-0.3.6-devを展開しておき、それを初回起動のスクリプトからインストールコマンドを実行しています。

GitHub - vadimgrn/usbip-win2: USB/IP Client for Windows
USB/IP Client for Windows. Contribute to vadimgrn/usbip-win2 development by creating an account on GitHub.

ちなみにusbip-winは古く、現在は別の作者でusbip-win2の開発が進んでいます。ただしこちらの方はテスト署名済みドライバーを許可する必要などがありサンドボックスで動かすのには適していませんでした。

サンドボックス上からUSBバインド

C:\Sandbox>ipconfig

Windows IP Configuration


Ethernet adapter イーサネット:

   Connection-specific DNS Suffix  . : mshome.net
   Link-local IPv6 Address . . . . . : fe80::32df:7851:5b4f:e8e4%202
   IPv4 Address. . . . . . . . . . . : 172.28.26.85
   Subnet Mask . . . . . . . . . . . : 255.255.240.0
   Default Gateway . . . . . . . . . : 172.28.16.1

C:\Sandbox>cd usbip-win-0.3.6-dev

C:\Sandbox\usbip-win-0.3.6-dev>usbip list -r 172.28.16.1
Exportable USB devices
======================
 - 172.28.16.1
        5-1: unknown vendor : unknown product (303a:1001)
           : USB\VID_303A&PID_1001\DC:54:75:C8:95:2C
           : Miscellaneous Device / ? / Interface Association (ef/02/01)
           :  0 - Communications / Abstract (modem) / None (02/02/00)
           :  1 - CDC Data / unknown subclass / unknown protocol (0a/02/00)
           :  2 - Vendor Specific Class / Vendor Specific Subclass / unknown protocol (ff/ff/01)


C:\Sandbox\usbip-win-0.3.6-dev>usbip attach -b 5-1 -r 172.28.16.1
succesfully attached to port 0

usbip installでドライバを入れておくことでusbipが利用可能になります。まずはipconfigでDefault Gatewayを調べます。Hyper-Vをインストールしてある場合、このIPがホスト側のIPアドレスとなります。

「usbip list -r 172.28.16.1」で共有可能なデバイスの一覧を確認をしてから「usbip attach -b 5-1 -r 172.28.16.1」でアタッチしています。

これでシリアルポートが増えれば成功です。ちなみにサンドボックス上でのArduino IDEビルドはホスト側より遅いです。あと転送速度が早すぎると通信の取りこぼしがあるようですので、転送中にエラーが出た場合には少し遅い速度にすることで安定すると思います。

まとめ

開発環境として利用するのには遅すぎるのでおすすめしません。ただし画面キャプチャや構築手順書の作成などではかなり便利に利用可能だと思います。

あとはwingetなどでセットアップが可能なアプリを一時的に使ってみたい場合や、ちょっと怪しいアプリを実行する場合にはかなり便利そうです。

WSL上のLinuxとサンドボックス上のWidows環境があればmacOS以外の環境をサクッと検証できるので今後活用していきたいと思います。

コメント