しばたテックブログ

気分で書いている技術ブログです。

WindowsでVagrantを扱う私的まとめ (Windows OSのBox作成編 Part.1)

前回に引き続き、今回はWindows OSのBoxファイルを自分で作る手順について説明します。

参考にしたサイト

本エントリの内容は以下のサイトの手順を参考にしています。

Creating a Base Box - Vagrant by HashiCorp

GitHub - WinRb/vagrant-windows

VagrantでWindowsゲストのBoxを作成 | dsp74118の補完庫

Boxの作成手順

参考にしたサイトでの手順を生かしつつ、極力PowerShellからCUIでBoxを作成する手順を説明していきます。
残念ながら現時点ではローカルグループポリシーを設定する箇所のみGUIで行わざるを得ず全ての手順をCUI化することは出来てません。
いずれすべての手順をCUI化し、スクリプトで一発設定できる様にしたいです...

0. はじめに

以降の手順は管理者権限を持つユーザーで行ってください。

作成するBoxのOSは基本Windows Server 2012 R2を想定していますが他のOSでも大体同じ手順でBoxを作ることが出来ます。
一応、Windows Server 2012 R2、Windows Server 2008 R2、Windows 7、Windows 8.1で動作を確認しています。

1. ベースとなるゲストVM(Windows OS)の作成

VirtualBoxマネージャーからベースとなるゲストVMを作成し、OSをインストールします。
VMの構成は環境に応じて適宜設定してください。

2. WinRMの設定

VagrantではWinRMを使用してゲストVMのWindowsを操作します。このため、ゲスト上で以下のコマンドを実行しWinRMを有効化します。
vagrant-windowsのサイトではCmd.exeから実行する手順が記載されていますが、本エントリではPowerShellから実行する手順に書き換えています。*1

# このコマンドはPowerShellから実行してください。
winrm quickconfig -q
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="512"}'
winrm set winrm/config '@{MaxTimeoutms="1800000"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
winrm set winrm/config/service/auth '@{Basic="true"}'
sc.exe config WinRM start= auto

また、WinRMのバージョンが1.1(Windows Server 2008 R2以前)の場合は以下のコマンドを実行する必要があります。

# このコマンドはPowerShellから実行してください。
netsh firewall add portopening TCP 5985 "Port 5985"
winrm set winrm/config/listener?Address=*+Transport=HTTP '@{Port="5985"}'

ちなみにWinRMのバージョンは以下のコマンドで取得することができます。

(-Split (( winrm id | where {$_ -like '*ProductVersion*'}) -Split '=')[1])[5]

3. パスワードの複雑性の無効化

次の手順で作るvagrantユーザーに対して単純なパスワードを設定するためにパスワードの複雑性を無効化します。
こちらのエントリの内容を参考にseceditコマンドを使用してパスワードの複雑性を無効化します。

PowerShellから以下の様にコマンドを実行してください。

# このコマンドはPowerShellから実行してください。
$TempCfgFile = ".\_secpol_{0}.inf" -F [System.IO.Path]::GetRandomFileName()
# Export temp file
secedit /export /cfg $TempCfgFile
# Disable PasswordComplexity and Change password age.
( Get-Content $TempCfgFile -Encoding Unicode ) -replace 'PasswordComplexity = 1','PasswordComplexity = 0' -replace 'MaximumPasswordAge = 42','MaximumPasswordAge = -1' | Out-File $TempCfgFile
# Update security policy
secedit /configure /db $env:windir\security\database\secedit-new.sdb /cfg $TempCfgFile /areas SECURITYPOLICY
# Delete temp file
If( Test-Path -Path $TempCfgFile -PathType Leaf ) {
    Remove-Item -Path $TempCfgFile
}

4. Vagrantユーザーの追加

ローカルユーザーにVagrantユーザーを追加し、Administratorsグループに参加させます。
ユーザーのパスワードは"vagrant"にしています。

ユーザーの追加方法はいろいろありますが、ここではADSIを使用して作成します。

# このコマンドはPowerShellから実行してください。
# Create Vagrant User
$Computer = [ADSI]"WinNT://$Env:COMPUTERNAME,Computer"
$NewUser = $Computer.Create("user","vagrant")
$NewUser.SetPassword("vagrant")
$NewUser.SetInfo()
$NewUser.FullName = "Vagrant"
$NewUser.UserFlags = 65536 # ADS_UF_DONT_EXPIRE_PASSWD
$NewUser.SetInfo()
# Join Administrators Group
$AdminGroup = [ADSI]"WinNT://$Env:COMPUTERNAME/Administrators,group"
$AdminGroup.Add($NewUser.Path)

5. UACの無効化

レジストリを変更してUACを無効化します。
実際にUACの無効化が反映されるのはOSの再起動後になるので、一連の手順を終えた後にOSを再起動する必要があります。

# このコマンドはPowerShellから実行してください。
$RegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system"
If ( Test-Path $RegPath -PathType Container ) {
    Set-ItemProperty $RegPath -name EnableLUA -Type DWord -value 0
}

6. シャットダウンイベントの追跡ツールの無効化(Server Core以外)

vagrant haltコマンド実行時にシャットダウンの問い合わせを出さない様にするためにシャットダウンイベントの追跡ツールの無効化を行います。
この手順はGUIから行います。

コマンドプロンプトまたはPowerShellからgpedit.mscと入力し、ローカルグループポリシーエディタを起動します。
グループポリシーエディタを起動したら、コンピュータ\管理用テンプレート\システムの順に選択し、シャットダウンイベント追跡ツールの表示無効に設定します。

また、ローカルグループポリシーエディタ上のGUIの表示と設定値の整合性を犠牲にしても構わないのであれば、HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Reliability配下のレジストリキーを更新することで無効化することもできます。

# このコマンドはPowerShellから実行してください。
# このコマンドからシャットダウンイベントの追跡ツールを無効化した場合、ローカルグループポリシーエディタ上に反映されません。

# デフォルト状態ではReliabilityキーは存在していません。
$RegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Reliability"
If ( ! (Test-Path $RegPath -PathType Container) ) {
    New-Item $RegPath
}
Set-ItemProperty $RegPath -name ShutdownReasonOn -Type DWord -value 0
Set-ItemProperty $RegPath -name ShutdownReasonUI -Type DWord -value 0

7. サーバーマネージャがログオン時に表示されないようにする(Server Core以外)

この手順はサーバー系OSでのみ行います。

前の手順と同様にローカルグループポリシーエディタを起動します。
コンピュータ\管理用テンプレート\システム\サーバーマネージャーの順に選択し、ログオン時にサーバーマネージャーを自動的に表示しない有効に設定します。

この手順はレジストリ操作からも行うことができるのですが、ユーザーごとの設定のためグループポリシーで無効化したほうが確実です。

OSインストール直後でAdministrator以外のユーザーがいない場合であれば、以下のコマンドを実行することで現在のユーザー(Administrator)とデフォルトのユーザー設定を更新してサーバーマネージャーを自動的に表示しない様にすることができます。

# このコマンドはPowerShellから実行してください。
# 現在ログオンしているユーザーと、`Default`ユーザーの設定を更新します。
# この更新により新しくユーザープロファイルが作られる際にサーバーマネージャーを自動的に表示しない様にしています。

# Change Current User Setting
$RegPath = "HKCU:\SOFTWARE\Microsoft\ServerManager"
If ( Test-Path $RegPath -PathType Container ) {
    Set-ItemProperty $RegPath -name DoNotOpenServerManagerAtLogon -Type DWord -value 1
}

# Change 'Default' User Setting
$DefaultRegFile = Join-Path (Split-Path $env:USERPROFILE -Parent) 'default\NTUSER.dat'
try {
    reg load HKLM\DefaultUser "$DefaultRegFile"
    $RegPath = "HKLM:\DefaultUser\SOFTWARE\Microsoft\ServerManager"
    If ( Test-Path $RegPath -PathType Container ) {
        Set-ItemProperty $RegPath -name DoNotOpenServerManagerAtLogon -Type DWord -value 1
    }
} finally {
    reg unload HKLM\DefaultUser
}

8. ログイン時に初期構成ツールを起動しない様にする(Windows Server 2008/2008 R2のみ)

Windows Server 2008/2008 R2の場合はログイン時に初期構成タスクが表示されるので、以下のレジストリを更新して表示しない様にします。

# このコマンドはPowerShellから実行してください。
$RegPath = "HKLM:\SOFTWARE\Microsoft\ServerManager\oobe"
If ( Test-Path $RegPath -PathType Container ) {
    Set-ItemProperty $RegPath -name DoNotOpenInitialConfigurationTasksAtLogon -Type DWord -value 1
}

9. RDPの有効化(オプション)

必須の手順ではないですが、大抵の場合はRDPを使用しますので以下のコマンドで有効化しておきます。

# このコマンドはPowerShellから実行してください。
# RDPの有効化+Firewallの例外設定を行います。
(gwmi -Class Win32_TerminalServiceSetting -Namespace root\cimv2\TerminalServices).SetAllowTSConnections(1, 1)

10.その他(オプション)

その他VirtualBox Guest Additionsのインストール等を必要に応じて行ってください。
この時点でWindows Updateなどをしておくと良いでしょう。

11.Vagrantユーザープロファイルの作成

最後にVagrantユーザーでログインし、ユーザープロファイルを作成します。
同時にログイン時に起動するツールが無効化されているかも確認しておくと良いでしょう。

Boxファイルの作成

ゲストVMの設定が終わったらVMをシャットダウンしてBoxファイルを作成します。
vagrant packageコマンドで以下の様にしてBoxファイルを作成します。

# --output先に同一ファイルがある場合はエラーとなるので注意
vagrant package --base "VirtualBoxのマシン名(VirtualBoxマネージャー上の名称)" --output "Boxファイルのパス"

実行例

vagrant package --base "Win2012R2" --output "C:/Temp/Win2012R2.box"

Boxファイルの登録

作成したBoxファイルをvagrant box addコマンドで登録します。
登録し終わったら作ったBoxファイルは(再利用しない場合)不要になります。ディスクの容量が足りない場合は削除してしまっても良いかもしれません。

vagrant box add "Box名" "Boxファイルのパス"

実行例

vagrant box add "Win2012R2" "C:\Temp\Win2012R2.box"

Sysprepの有無

Windows OSのBoxを作る際にSysprepを行うかどうかはBoxの用途次第だと思います。
私個人としては、Box作成時や運用時の手間を考えると、基本Sysprepは行わずBoxを作成しSysprepを行う必要があるときに都度行うのが良いのではないかと考えています。

ちなみに、Sysprepをかけた場合はvagrantユーザーで一度ログインしなおす必要があります。
しなおさないとユーザープロファイルが更新されず、vagrant rdpコマンドを実行した際に内部エラーが発生してしまいます。

2015/06/11ちょっと追記
Sysprepする際のコマンドはこんな感じで。

C:\Windows\System32\Sysprep\Sysprep.exe /oobe /generalize /reboot /mode:vm

*1:@の部分を文字列化したり、scコマンドをsc.exeに書き換えています。