Hyper-VでVagrant upできない人はこれを見てみて (Vagrant 2.1.1対応方法更新しました)

日頃、Windows上でLinux開発環境の立ち上げをVagrantやAnsibleで楽しく行っています。

WindowsだとVirtualBox + Vagrantの組み合わせで仮想サーバー立ち上げるのが一般的で無難に使用できるのですが、Dockerも使ってみたいとするとDocker for WindowsはHyper-V上で動くのでVirtualBoxと同時に使用することができません。

Windows ProにはHyper-VがありせっかくあるのでHyper-V + Vagrantという組み合わせでいけると思っていたのですが、Hyper-Vでvagrant使用したときになぜか `vagrant up` がうまく立ち上がらないというトラブルに見舞われてしまい、何とかその解決方法を見つけたので同じ現象になってしまった方に向けての投稿です。

----

> 2018/9/26現在 Vagrant はバージョンが 2.1.5になっており、 下記にも書いたIsuueは バージョン2.1.2に取り込まれたため Hyper-Vプロバイダーで  "既定のスイッチ" が日本語でも 正常に vagrant up できるようになりました。

v 2.1.5 では下記環境で確認しました。

----

> 本記事は Vagrant 2.0.2当時に書いたのものですが、 2018/5/7に Vagrant 2.1.1が出ていますので2.1.1での対応方法を追加します。

### 環境
Windows 10 Pro April 2018 Update(1803)
Vagrant ver 2.1.1 (64bit)

v2.1.1のCHANGELOGには以下のようにswitchnameを使わずswitchidを使う旨記載がありましたが、私の確認ではまた別の問題が生じておりvagrant upに失敗するようです。

```
provider/hyperv: Call import script with switchid instead of switchname [GH-9781]
```

既にissue [vagrant up fails after selecting network adapter on hyperv](https://github.com/hashicorp/vagrant/issues/9818)が出ており、次のアップデート v2.1.2で修正が入るようですがアップデートまで待てない方は、以下のPRで出ている変更を適用させると良いです。
[PR#9813 Reference Hyper-V switch by ID instead of name](https://github.com/hashicorp/vagrant/pull/9813/files)

この適用で私の環境では無事 `vagrant up` 成功しました。

----
以下、 初稿記事 v2.0.2 での対応です。

# 環境
Windows 10 Pro Fall Creators Update(1709)
Vagrant ver 2.0.2 (64bit)

# 見舞われた現象
普通にごくごくシンプルな設定でVagrantを使ってHyper-VにCentos7を立ち上げてみます。

``` ruby:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
end
```

``` shell:実行結果
PS D:\servers\centos7> vagrant up --provider=hyperv
Bringing machine 'default' up with 'hyperv' provider...
==> default: Verifying Hyper-V is enabled...
==> default: Importing a Hyper-V instance
    default: Cloning virtual hard drive...
    default: Creating and registering the VM...
An error occurred while executing a PowerShell script. This error
is shown below. Please read the error message and see if this is
a configuration error with your system. If it is not, then please
report a bug.

Script: import_vm_xml.ps1
Error:

Hyper-V\New-VM : Hyper-V で、"譌｢螳壹・繧ｹ繧､繝・メ" という名前の仮想スイッチが見つかりませんでした。
発生場所 C:\HashiCorp\Vagrant\embedded\gems\gems\vagrant-2.0.2\plugins\providers\hyperv\scripts\import_vm_xml.ps1:127
文字:7
+ $vm = Hyper-V\New-VM @vm_params
+       ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [New-VM]、VirtualizationException
    + FullyQualifiedErrorId : InvalidParameter,Microsoft.HyperV.PowerShell.Commands.NewVM

PS D:\servers\centos7>
```
エラーの内容的にはHyper-Vで用意している「既定のスイッチ」が文字化けして認識してくれない模様です。
この仮想スイッチ「既定のスイッチ」っていうのは、Hyper-Vが用意してくれている仮想スイッチでNAT接続できるのでゲストから簡単に外のネットに接続できとても便利なのですが、下の画像のように名前が灰色になって名前の変更すらさせてくれないし、削除すらさせてくれないので、他の仮想スイッチを作ってNAT接続できる自前のスイッチも作成できないのです。

![switch.png](https://qiita-image-store.s3.amazonaws.com/0/24418/88fdddeb-3fc9-5e3d-1f66-91ce34db37c3.png)

# たどり着いた解決法

何かしらコマンドレットで変更すればよいのではと思っていたのですができませんでした。

``` shell:Failure　Rename-VMSwitch
PS D:\servers\centos7> Rename-VMSwitch -Name 既定のスイッチ -NewName "DefaultSwitch"
Rename-VMSwitch : 仮想イーサネット スイッチの変更中にエラーが発生しました。
仮想イーサネット スイッチの設定の変更中にエラーが発生しました。
自動インターネット接続共有スイッチは変更できません。
発生場所 行:1 文字:1
+ Rename-VMSwitch -Name 既定のスイッチ -NewName "DefaultSwitch"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Rename-VMSwitch]、VirtualizationException
    + FullyQualifiedErrorId : InvalidParameter,Microsoft.HyperV.PowerShell.Commands.RenameVMSwitch
```

もう、アレしかない．．．

**レジストリエディターという黒魔術**

ということで、 "既定のスイッチ" が書かれているレジストリを探してみました。

**見つけた...**

ただし、レジストリ触るのは自己責任でお願いします。

レジストリ触りたくない方は、この下の方に別の方法も紹介しますのでそちらを試してください。

該当するレジストリのキーはこれです。

```
\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\vmsmp\parameters\SwitchList
```
ここに、Hyper-Vに設定してある仮想スイッチの一覧があります。

![friendname.png](https://qiita-image-store.s3.amazonaws.com/0/24418/77812679-6fe8-93d4-dff9-3d0d9e026d7b.png)

"FriendlyName"をダブルクリックして"既定のスイッチ"と書いてある箇所を"DefaultSwitch"に変更します。（半角英文字であればOK）
変更後はWindowsを再起動することで設定が反映されます。

![newswitch.png](https://qiita-image-store.s3.amazonaws.com/0/24418/38415a21-b15e-8884-f30a-bfa72418faba.png)

ここで、再度 vagrant upに挑戦してみます。

``` shell:Success
PS D:\servers\centos7> vagrant up --provider=hyperv
Bringing machine 'default' up with 'hyperv' provider...
==> default: Verifying Hyper-V is enabled...
==> default: Importing a Hyper-V instance
    default: Cloning virtual hard drive...
    default: Creating and registering the VM...
    default: Setting VM Integration Services
    default: Successfully imported a VM with name: centos-7-1-1.x86_64
==> default: Starting the machine...
==> default: Waiting for the machine to report its IP address...
    default: Timeout: 120 seconds
    default: IP: 172.27.14.216
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 172.27.14.216:22
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
```
NATもちゃんと機能しているようです。

``` shell
PS D:\servers\centos7> vagrant ssh
Last login: Sat Mar  3 14:09:13 2018 from 172.27.14.209
[vagrant@localhost ~]$ ping yahoo.co.jp
PING yahoo.co.jp (183.79.135.206) 56(84) bytes of data.
64 bytes from f1.top.vip.kks.yahoo.co.jp (183.79.135.206): icmp_seq=1 ttl=49 time=26.1 ms
64 bytes from f1.top.vip.kks.yahoo.co.jp (183.79.135.206): icmp_seq=4 ttl=49 time=25.1 ms
64 bytes from f1.top.vip.kks.yahoo.co.jp (183.79.135.206): icmp_seq=5 ttl=49 time=21.0 ms
64 bytes from f1.top.vip.kks.yahoo.co.jp (183.79.135.206): icmp_seq=6 ttl=49 time=24.7 ms
64 bytes from f1.top.vip.kks.yahoo.co.jp (183.79.135.206): icmp_seq=7 ttl=49 time=93.2 ms

--- yahoo.co.jp ping statistics ---
7 packets transmitted, 5 received, 28% packet loss, time 6006ms
rtt min/avg/max/mdev = 21.072/38.079/93.246/27.637 ms
[vagrant@localhost ~]$
```

レジストリ触るのは負けた感があるので上記の方法を見つけた後にvagrantのIssueを探してみましたが、今のところはこれしか方法はなさそうでした。

## 関連するGithubのIssue
i have a same question, and i found a reason! if you have a non-english environment, the win10 with Fall Creators Update,it may have a default switch with your own language in Hyper-V setting and you can create new switch one with english name,It's useful to me！hope can help you~

https://github.com/hashicorp/vagrant/issues/8255#issuecomment-352393729

# レジストリは触りたくない人には
さすがにレジストリはと思い直し、もう少し粘ってVagrantのソースコードを見てみました。VagrantのHyper-VにおいてはPowerShellとrubyを使って動いてるようですが、PowerShellよくわからないしとりあえず、日本語(Shift_Jis)のことだけ考えてしまうのなら触ったこともあるrubyで何とかしちゃうのが手っ取り早そうでした。

エラーメッセージでは _import_vm_xml.ps1_ の中でエラーになっていますが、仮想スイッチの名前はこのスクリプトに引数として渡されています。
そこで Vagrant\embedded\gems\gems\vagrant-2.0.2\plugins\providers\hyperv\driver.rb
の84行目にある関数importの中で_import_vm_xml.ps1_ に渡すオプションの中にある `switchname` の文字コードをShift_JISに変更して渡してしまいます。

``` ruby:driver.rb
def import(options)
  config_type = options.delete(:vm_config_type)
  if config_type === "vmcx"
　  execute('import_vm_vmcx.ps1', options)
  else
    options.delete(:data_path)
    options.delete(:source_path)
    options.delete(:differencing_disk)
    options[:switchname].encode!('Shift_JIS') # ここで無理やりShift_JISに変換してしまう
    execute('import_vm_xml.ps1', options)
  end
end
```

これで「既定のスイッチ」という名称を変更することなく _vagrant up_ で立ち上げることができました。
もちろん修正後の再起動も不要です。

どちらの方法もあくまでも一時的な対処方法ですが、本家で修正が入るまではこの方法でやっていこうと思っています。

Windowsでも良きVagrantライフを！！