Vagrant で起動したゲスト Windows のネットワーク設定

最初に結論を書いとくと、一部しか実現できていない。

[Vagrant で Windows もゲストOSに - Qiita](http://qiita.com/toruuetani/items/d86408113b18344e62c4)で書いた通り、Windowsでも好きなように作ったり壊したりできるようになりました。そこからいろいろ試してみたところ欲が出てきて、製品のデモ環境も  Vagrant で作れるんじゃ？と考えたのが運のつき。

やろうとした環境は以下の通り。ゲストOSにいろいろ仕込んで、外部からアクセスできる環境を構築しつつ、ホストは汚さない環境を構築したかった。

外部PC（192.168.2.100）
↑
ブリッジアダプター
↓
ゲストOS（192.168.2.1）
ゲストOS（192.168.56.100）
↑
ホストオンリーアダプター
↓
ホストOS（192.168.56.1）

`vagrant up` してからゲストOSでネットワーク設定を変更すればいいんだけど、面倒なのでそれも自動化しようとしてみた。

まずは [Private Networks - Networking - Vagrant Documentation](http://docs.vagrantup.com/v2/networking/private_network.html) を参考に `private_network` を設定する。これがホストオンリーアダプターに相当する。今回は DHCP でなく static で指定したいので IP アドレスを設定。次に [Public Networks - Networking - Vagrant Documentation](http://docs.vagrantup.com/v2/networking/public_network.html) を参考に `public_network` を設定する。これがブリッジアダプターに相当する。 ~~あとは IP アドレス、と思ったらこっちは DHCP しか設定できないらしい・・・~~ → ドキュメントに記載がないけど、今は設定できるらしい。

仕方ないので以下のように設定した。

```rb:Vagrantfile
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.network "private_network", ip: "192.168.2.1"
  config.vm.network "public_network", ip: "192.168.56.100"
end
```

これで `vagrant up` すると、ネットワークアダプターを３つ持った VM が起動する（１つはポートフォワーディングした NAT ）。なんだけどアダプターの IP アドレスは設定されていない。

これはなぜかと言うと、文字コードのせいで WinRM 経由の `netsh` が失敗しているため。試しにホストオンリーアダプターの名前を「ローカル エリア接続 2」から「local network」のようにASCII文字列オンリーに変更すれば正しく IP アドレスが `192.168.2.1` に設定される。
もちろんホストOS側を `192.168.2.1` 以外にしておく前提。

ちなみにエラーはこんな感じ。

```bat
Shell: powershell
Command: netsh interface ip set address "ローカル エリア接続 2" static 192.168.2.1 255.255.255.0
Message: U+30ED from UTF-8 to ASCII-8BIT>
ERROR vagrant: An error occurred executing a remote WinRM command.
```

2014/04/06 追記
Vagrant-Windows が依存してる [WinRb/WinRM](https://github.com/WinRb/WinRM) が ASCII に決め打ちでエンコードしてるのが原因っぽい。 `script = script.encode('ASCII-8BIT')` を `Windows-31J` に変えたらエラーは出なくなった。ただし正常に設定変更できたわけではないので、まだ何か問題があるっぽい。

```rb:winrm/winrm_service.rb
    def run_powershell_script(script_file, &block)
      # if an IO object is passed read it..otherwise assume the contents of the file were passed
      script = script_file.kind_of?(IO) ? script_file.read : script_file

      script = script.chars.to_a.join("\x00").chomp
      script << "\x00" unless script[-1].eql? "\x00"
      if(defined?(script.encode))
        script = script.encode('ASCII-8BIT')
        script = Base64.strict_encode64(script)
      else
        script = Base64.encode64(script).chomp
      end

      shell_id = open_shell
      command_id = run_command(shell_id, "powershell -encodedCommand #{script}")
      command_output = get_command_output(shell_id, command_id, &block)
      cleanup_command(shell_id, command_id)
      close_shell(shell_id)
      command_output
    end
    alias :powershell :run_powershell_script
```

2014/04/09 追記
powershell に `-encodedCommand` オプションを指定しているので、 `Windows-31J` を指定しても意味はなさそう。エラーを避けつつ Base64 で送信するには以下のようにすればいいと思うんだけど、まだ解決できていない。

```diff
-script = script.encode('ASCII-8BIT')
+script = script.force_encoding('ASCII-8BIT').encode('ASCII-8BIT')
```

2014/06/26 追記
この件に関しては [Configurating network adapter failed when NON-ASCII adapter name used. · Issue #182 · WinRb/vagrant-windows](https://github.com/WinRb/vagrant-windows/issues/182) として issue 登録済み。
また、Vagrant-Windowsが依存しているWinRMに対して [Fix PowerShell encoding from ASCII-8BIT to UTF-16LE for NON-ASCII string... by toruuetani · Pull Request #70 · WinRb/WinRM](https://github.com/WinRb/WinRM/pull/70) としてPR済み

PRしている変更をWinRMに対して適用すれば、正しくネットワーク設定できることを確認済みです。ただ、十分テストできているとは言えないので、試してみたらGitHub上で報告してもらえると助かります。