Windows SandboxでのMSIインストーラーが遅すぎる場合の対処法、細かい問題修正など

:::note info
この記事は、複数のライセンス不明の記事のまとめです

Windowsサンドボックスはproなどでしか利用できません。
また、Windowsサンドボックスは有効化はワンクリックですが、無効化は恐ろしいほど複雑なので気軽に試すのはお勧めしません。
:::

Windowsサンドボックス、セットアップ、wsbで自動化していますか？
[Windowsサンドボックスのissue](https://github.com/microsoft/Windows-Sandbox/issues)を[漁っていたところ](https://github.com/microsoft/Windows-Sandbox/issues/68#issuecomment-2684473932)、インストーラが5分ぐらいかかる問題の回避先を見つけました。
次のpowershellを実行します。

# インストーラが5分ぐらいかかる(遅い)のを直す

:::note warn
実機、仮想環境がわからない場合、絶対に実行しないでください。
実行した場合、スマート アプリ コントロールを無効になり、あなたのパソコンがウイルスに対して弱くなります
:::

:::note alert 
スマート アプリ コントロールの簡単に無効化はできますが、再度有効化するにはwindowsの再インストール([おそらく公式インストーラーによるインプレースアップグレード](https://www.microsoft.com/ja-jp/software-download/windows11))が必要です。
そのため、実機では絶対にスマート アプリ コントロールを無効化しないでください。

:::

powershellを起動して次のコマンドを実行してください

```powershell
# 実機ガード
$path = "C:\Users\WDAGUtilityAccount"

if (!(Test-Path -Path $path -PathType Container)) {
    Write-Error "Error: Required directory '$path' not found."
    exit 1
}

# 回避策

Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\CI\Policy" -Name "VerifiedAndReputablePolicyState" -Value "0"
echo "" | C:\Windows\System32\CiTool.exe -r
```

そうすると、msiインストーラが爆速になります。

# おまけ

# wsbファイルから自動で構成する場合

:::note info
wsbファイルの構文については公式ドキュメントをお勧めします
:::

https://learn.microsoft.com/ja-jp/windows/security/application-security/application-isolation/windows-sandbox/windows-sandbox-configure-using-wsb-file

wsbで`d:\drivers\`を`C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\`にマウンドしたうえで、LogonCommandから魔法のコマンドでpowershellファイル`C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\general\general.ps1`を管理者サンドボックスで実行(LogonCommandは1つしか許可されてない)してください。

:::note info
使用しているパスは自由に変更できます
:::


general.wsbファイルの例は次の通りです。
```xml
<Configuration>
    <Networking>Disable</Networking>
    <MappedFolders>
        <MappedFolder>
            <HostFolder>d:\drivers\</HostFolder>
            <SandboxFolder>C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\</SandboxFolder>
            <ReadOnly>true</ReadOnly>
        </MappedFolder>
    </MappedFolders>
    <vGPU>Enable</vGPU>
    <MemoryInMB>4000</MemoryInMB>
    <LogonCommand>
        <Command>powershell -executionpolicy unrestricted -command "start powershell {-file "C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\general\general.ps1"}"</Command>
    </LogonCommand>
    <AudioInput>Disable</AudioInput>
    <VideoInput>Disable</VideoInput>
</Configuration>

```

この場合、`C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\general\general.ps`、つまり`d:\drivers\general\general.ps`を作り、テキストエディタで上のコマンドを追加します


# Windowsサンドボックスでファイアウォールを有効化し、ローカル通信を拒否する
引用元

https://note.com/serasora/n/nfc004894b1c5

サンドボックスで使われるアカウントが管理者権限なので意味はありませんが、ファイアウォールでローカルネットワークへの通信を拒否しておいて問題はないでしょう。
```powershell
#実機ガード
$path = "C:\Users\WDAGUtilityAccount"

if (!(Test-Path -Path $path -PathType Container)) {
    Write-Error "Error: Required directory '$path' not found."
    exit 1
}

# サンドボックス内のファイアウォールで通信遮断

    New-NetFirewallRule -DisplayName "Block-Outbound-Private1" -Profile Private,Public -Direction Outbound -RemoteAddress 192.168.0.0/16 -Action Block
    New-NetFirewallRule -DisplayName "Block-Outbound-Private2" -Profile Private,Public -Direction Outbound -RemoteAddress 172.16.0.0/12 -Action Block
    New-NetFirewallRule -DisplayName "Block-Outbound-Private3" -Profile Private,Public -Direction Outbound -RemoteAddress 10.0.0.0/8 -Action Block
    Get-NetAdapter | Set-DnsClientServerAddress -ServerAddresses 8.8.8.8
    # ファイアウォール有効化
    Set-NetFirewallProfile -Enabled true
```

# 一部のソフトが日本語で文字化けするのを直す

引用元

https://qiita.com/mmake/items/adb02df7c6dea8a10922



Windowsサンドボックスのwin11最新バージョンはシステムの再起動をサポートしているので、システム言語を変更できます！
これにより、アプリが文字化けしなくなります！
再起動すると、設定によっては~~ProtectedClientがオンになってるときなどは~~もう一回スクリプトが実行されるので、実行ガードが必要です。

:::note info
最新バージョンであるかは、ウインドウのxを押したときに、青いボタンが出るかどうかで判別できます。最新バージョンではない場合、マイクロソフトストアで更新したのち、何回か起動すると更新されます。
:::


```powershell
#実機ガード
$path = "C:\Users\WDAGUtilityAccount"

if (!(Test-Path -Path $path -PathType Container)) {
    Write-Error "Error: Required directory '$path' not found."
    exit 1
}

# 2重実行ガード
$path1 = "C:\Windows\Temp\KJFLSH.txt"

if (!(Test-Path -Path $path1 -PathType Leaf)) {
    New-Item -Path $path1 -ItemType File -Force | Out-Null

    # ほかの処理

    Set-WinUserLanguageList -Force ja-JP      # 言語リストとプロパティを日本語に設定
    Set-WinSystemLocale -SystemLocale ja-JP   # システムロケールを 日本 に変更
    Set-WinUILanguageOverride -Language ja-JP # 表示言語と地域設定を 日本語 に変更
    Set-WinHomeLocation 122                   # 国と地域を 日本 に変更
    Set-Culture -CultureInfo ja-JP            # 地域設定を「日本語」に変更
    Restart-Computer                          # システムを再起動
    exit 0
}

# 再起動後の処理 (<ProtectedClient>Enable</ProtectedClient>とかではおそらくもういっかいスクリプトが実行されるので、それ専用)
```


## エクスプローラーなどを使いやすくする
引用元

https://henjinkutsu.com/text/pc/autounattend/


```powershell
# 実機ガード
$path = "C:\Users\WDAGUtilityAccount"

if (!(Test-Path -Path $path -PathType Container)) {
    Write-Error "Error: Required directory '$path' not found."
    exit 1
}

# レジストリ設定

# 右クリックをWindows10以前のものに戻す
reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /ve /d "" /f
# タスクバーを左揃えにする
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "TaskbarAl" /t REG_DWORD /d "0" /f
# 拡張子を常に表示
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "HideFileExt" /t REG_DWORD /d "0" /f
# すべてのフォルダーを表示
reg add "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "NavPaneShowAllFolders" /t REG_DWORD /d "1" /f
# タイトルバーに完全なパスを表示
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState" /v "FullPath" /t REG_DWORD /d "1" /f
#  Windows を最大限に活用するためのデバイス設定の完了方法を提案する　「オフ」
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\UserProfileEngagement" /v "ScoobeSystemSettingEnabled" /t REG_DWORD /d 0 /f
#  Windows を使う上でのヒントやお勧めの方法を取得する　「オフ」
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338389Enabled" /t REG_DWORD /d 0 /f
# 新機能とおすすめを確認するために～をオフ
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-310093Enabled" /t REG_DWORD /d "0" /f
# シフトを連打すると出てくる固定キーを無効化(上のように再起動がいる)
reg add "HKCU\Control Panel\Accessibility\StickyKeys" /v Flags /t REG_SZ /d "506" /f

# Explorerの再起動
Stop-Process -Name explorer -Force

```

# ps1の出力が文字化けするのを直す

```powershell
$OutputEncoding = [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
```

# 環境変数を即時更新する
```powershell
# 追加したいパス
$newPath = "C:\Users\WDAGUtilityAccount\Desktop\Data\test"

# 即時更新
$oldPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine)
# 環境変数を更新 (管理者権限が必要)
[System.Environment]::SetEnvironmentVariable("Path", $newPath, [System.EnvironmentVariableTarget]::Machine)
# 変更を即時適用
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine)

```

## vscodeをインストールして固定の設定を追加する

:::note info
C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\VSCodeUserSetup-x64-1.96.4.exeは自分で取得してwsbで構成してください
:::

引用元

https://zenn.dev/nuits_jp/articles/silent-installation-of-vs-code

```powershell
# 実機ガード
$path = "C:\Users\WDAGUtilityAccount"

if (!(Test-Path -Path $path -PathType Container)) {
    Write-Error "Error: Required directory '$path' not found."
    exit 1
}

Write-Output "Installing vscode`n"
Start-Process -FilePath "C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\VSCodeUserSetup-x64-1.96.4.exe" `
    -ArgumentList "/VERYSILENT /NORESTART /MERGETASKS=!runcode,desktopicon,addcontextmenufiles,addcontextmenufolders,associatewithfiles" `
    -NoNewWindow -Wait
Write-Output "VSCode installation completed."

Write-Output "vscode setting`n"

$settingsPath = "C:\Users\WDAGUtilityAccount\AppData\Roaming\Code\User\settings.json"

# 設定する内容
$jsonContent = '{
    "editor.unicodeHighlight.ambiguousCharacters": false,
    "editor.unicodeHighlight.invisibleCharacters": false,
    "editor.unicodeHighlight.includeComments": false,
    "editor.unicodeHighlight.includeStrings": false,
    "editor.unicodeHighlight.nonBasicASCII": false,
    "files.autoSave": "afterDelay"
}'

# ディレクトリが存在しない場合は作成
$dir = Split-Path -Path $settingsPath -Parent
if (!(Test-Path $dir)) {
    New-Item -ItemType Directory -Path $dir -Force
}

# JSON ファイルを書き込み
$jsonContent | Set-Content -Path $settingsPath -Encoding UTF8

Write-Output "VSCode settings.json has been updated."
```

# vc_redistを入れる
vc_redistは上の回避策を実行しないとインストールに10分かかるので実行します


:::note info
C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\vc_redist.x64.exe, VC_redist.x86.exeは自分で取得してwsbで構成してください
:::

https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170

```powershell
# 実機ガード
$path = "C:\Users\WDAGUtilityAccount"

if (!(Test-Path -Path $path -PathType Container)) {
    Write-Error "Error: Required directory '$path' not found."
    exit 1
}

# 回避策実行
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\CI\Policy" -Name "VerifiedAndReputablePolicyState" -Value "0"
echo "" | C:\Windows\System32\CiTool.exe -r

# vc_redist両方入れる

$basePath = "C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files"

# 64bit VC再頒布パッケージを実行して待機
$proc64 = Start-Process -FilePath "$basePath\vc_redist.x64.exe" -ArgumentList "/quiet", "/norestart" -Wait -PassThru

# 32bit VC再頒布パッケージを実行して待機
$proc86 = Start-Process -FilePath "$basePath\VC_redist.x86.exe" -ArgumentList "/quiet", "/norestart" -Wait -PassThru
```

# ほかのps1スクリプトを実行する
処理を1つのpsにまとめておけば、実際のスクリプトはすっきりするはず。
```powershell
powershell -ExecutionPolicy Bypass -File "C:\Users\WDAGUtilityAccount\Desktop\Sandbox-Files\vclib.ps1"
```


# サンドボックス内のより低い権限(ファイアウォール操作できないetc)でアプリを実行する(上級者向け)
サンドボックスの管理者権限で実行するとサンドボックス内ではやりたい放題できるのはけしからんので、より下級のアカウントownerを作ってそこで実行するようにしてみましょう。
こうすれば、owner権限からはファイアウォールはいじれません

## 制約
- プログラムはパブリック等に置く必要があります。OwnerからWDAGUtilityAccountのユーザーフォルダにはアクセスできません。
- 引数には対応していますが、未知のバグがあるかもしれません。自己責任で実行してください
- 絶対に実機では実行しないでください。私は実機で実行したらパソコンがどうなっても知りません
- カレントディレクトリはプログラムのexeがあるフォルダにしておいてください。ファイルの不整合が発生することがあります。アクセス拒否された場合`c:/`で実行されます
- cmdやpowershellが多重起動しますが仕様です
- **runasOwner.ps1**ファイルのエンコードは**UTF-8 BOM**です。ホストマシンのメモ帳や、virtual studio codeなどを入れて保存してください
- 引数から任意cmdインジェクションできますが仕様です

## 使い方
runasOwner.cmdにパブリック等にあるファイルを投げ込むか、管理者権限(サンドボックス内)で引数1はプログラム名、それ以外は引数を指定して実行すればokです

## runasOwner.cmd
```bat
@echo off
rem setlocal

echo %*

powershell -ExecutionPolicy Bypass -File %~dp0RunAsOwner.ps1 %*
```

## runasOwner.ps1
```powershell
# 実機ガード
$path = "C:\Users\WDAGUtilityAccount"

if (!(Test-Path -Path $path -PathType Container)) {
    Write-Error "Error: Required directory '$path' not found."
    exit 1
}
# すべての引数は $args に格納されている
if ($args.Count -lt 1) {
    Write-Host "Usage: RunAsOwner.ps1 <AppPath> [arg1] [arg2] ..."
    exit 1
}

$AppPath = $args[0]
$AppArgs = $args[1..($args.Count - 1)]

# 残りの処理はこれまでと同じ
$username = "Owner"
$passwordPlain = "MyP@ssw0rd"
$securePassword = ConvertTo-SecureString $passwordPlain -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($username, $securePassword)

# ユーザー確認
$user = Get-LocalUser -Name $username -ErrorAction SilentlyContinue
if (-not $user) {
    New-LocalUser -Name $username -Password $securePassword -PasswordNeverExpires -UserMayNotChangePassword
    Add-LocalGroupMember -Group "Users" -Member $username
}

# コマンドスクリプト生成
$cmdPath = "C:\Users\Public\run_temp.ps1"

$quotedApp = '"' + $AppPath + '"'
$quotedArgs = @()
if ($AppArgs.Count -gt 0) {
    $quotedArgs = $AppArgs | ForEach-Object {
        if ($_ -match '\s|\*|\?|"') {
            '"' + $_.Replace('"', '""') + '"'
        } else {
            $_
        }
    }
}

$fullCommand = if ($args.Count -gt 1) {
    "$quotedApp $($quotedArgs -join ' ')"
} else {
    "$quotedApp"
}

# pwd (エイリアス) を使って現在のディレクトリを取得
$currentDir = pwd

# 変数の中身を表示
$path1 = $currentDir.Path

@"
cd $path1
cmd.exe /c $fullCommand
pause
Remove-Item $cmdPath
"@ | Out-File -Encoding ASCII -FilePath $cmdPath -Force

# 実行
 #非同期実行にしたい場合「-wait」を削除する
Start-Process -FilePath "powershell.exe" -ArgumentList "-ExecutionPolicy Bypass -File ", $cmdPath -Credential $credential  -Wait
```