先日Vagrant 1.8.0がリリースされたのでサクッと手元の環境を更新しました。
本エントリではVagrant 1.8.0で追加された新機能のうち、vagrant powershell
コマンドについて詳しく触れていきたいと思います。
Vagrant 1.8.0の新機能について
https://hashicorp.com/blog/vagrant-1-8.htmlで公式にアナウンスされています。
チェンジログはここです。
結構な数のバグフィックスといくつかの機能改善、機能追加がなされています。
機能追加は、
vagrant powershell
コマンドの追加vagrant port
コマンドの追加vagrant snapshot
コマンドの追加ansible_local
プロビジョナーの追加- Linked Cloneサポートの追加(VirtualBox/VMware)
- IPV6ネットワークサポートの追加(VirtualBox/VMware)
がされているとの事です。
vagrant snapshot
コマンドもかなり気になりますが、今回はvagrant powershell
コマンドに絞った話をします。
Vagrant 1.8.0のインストール
インストール手順はこれまでのバージョンと特に変わりませんでした。
Windowsであれば、
のエントリの内容そのままの手順で問題ないと思います。
本バージョンからVagrantのインストール時にVirtualBoxの自動インストール*1もサポートされたそうなのですが今回は試せませんでした。
ちなみに今回の環境は、
- Windows 8.1 Pro(64bit版)
- VirtualBox 5.0.10 + Extension Pack
- Vagrant 1.8.0
になります。
既知の問題について
のエントリで書いたネットワークアダプタ名が日本語名称("イーサネット"等)の場合にIPアドレスに失敗する件については本バージョンで解決した様です。
パッチを当てなくても問題なくIPアドレスの設定ができました。
vagrant up --debug
コマンドでデバックログを出力してみると
# デバッグログを一部抜粋 # 日本語ネットワークアダプタ名がUnicodeエスケープされた形で渡されている。 # "\u30A4\u30FC\u30B5\u30CD\u30C3\u30C8" => イーサネット DEBUG configure_networks: nic: {:index=>10, :mac_address=>"08:00:27:86:80:4E", :net_connection_id=>"\u30A4\u30FC\u30B5\u30CD\u30C3\u30C8", :interface_index=>12} DEBUG configure_networks: nic: {:index=>13, :mac_address=>"08:00:27:1B:D1:29", :net_connection_id=>"\u30A4\u30FC\u30B5\u30CD\u30C3\u30C8 2", :interface_index=>15} DEBUG configure_networks: vm_interface_map: {1=>{:net_connection_id=>"\u30A4\u30FC\u30B5\u30CD\u30C3\u30C8", :mac_address=>"08002786804E", :interface_index=>12, :index=>10}, 2=>{:net_connection_id=>"\u30A4\u30FC\u30B5\u30CD\u30C3\u30C8 2",:mac_address=>"0800271BD129", :interface_index=>15, :index=>13}} INFO guestnetwork: Configuring NIC イーサネット 2 using static ip 192.168.1.100 # netsh interface ipコマンドに日本語ネットワークアダプタ名(イーサネット 2)が文字化けせず渡されて実行されている。 DEBUG winrmshell: powershell executing: $ProgressPreference='SilentlyContinue'; netsh interface ip set address "イーサネット 2" static 192.168.1.100 255.255.255.0 if ($?) { exit 0 } else { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }
な感じのログが出力され、文字化けすることなくnetsh interface ip
コマンドが実行されてIPアドレスが設定されているのがわかります。
vagrant powershellコマンドの基本
ここから本題に入ります。
コマンドの基本
vagrant powershell
コマンドは一言でいってしまうとvagrant ssh
コマンドのWindows版です。
ホストからPSRemotingでWindowsゲストに接続することができます。
公式なドキュメントはこちらになります。
コマンドのヘルプを見てみると以下の様な感じです。
PS C:\> vagrant powershell --help Usage: vagrant powershell [-- extra powershell args] Options: -c, --command COMMAND Execute a powershell command directly -h, --help Print this help
vagrant powershell [VM名(複数VMある場合)]
が基本で、単一のコマンドを実行させるだけの場合は--command
オプションを指定します。
[-- extra powershell args]
の部分はこのコマンドで起動するホスト側のpowershell.exeに追加のオプションを指定する場合に使います。
コマンド実行例
適当なWindowsゲストVMを作成しvagrant powershell
を実行すると以下の図の様になりゲストVM(127.0.0.1)にvagrantユーザーで接続していることがわかります。
--command
オプションを指定した場合はこんな感じで指定されたコマンドを実行して直ちに終了しているのがわかります。
ゲストのVagrantfileは以下。特に特別な設定は必要ありません。
# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don't change it unless you know what # you're doing. Vagrant.configure(2) do |config| config.vm.box = "Win2012R2" config.vm.guest = :windows config.vm.communicator = "winrm" # config.vm.network "private_network", ip: "192.168.1.100" # config.vm.provider "virtualbox" do |vb| # Display the VirtualBox GUI when booting the machine vb.gui = true # Customize the amount of memory on the VM: vb.memory = "4096" vb.customize ["modifyvm", :id, "--cpus", "2"] vb.customize ["modifyvm", :id, "--paravirtprovider", "hyperv"] end end
vagrant powershellコマンドの詳細
コマンドの実体は[インストール先]\embedded\gems\gems\vagrant-1.8.0\plugins\commands\powershell\command.rb
になります。
--commandオプションを指定した場合
--command
オプションを指定した場合は、WinRM Communicator([インストール先]\embedded\gems\gems\vagrant-1.8.0\plugins\communicators\winrm\communicator.rb
)の機能を直接使って単一のコマンドを実行します。
まだ未検証なのですが、WinRMの通信のみを行うので、--command
オプションを使う場合は非Windowsホストでも実行可能だと思います。
【2015/12/23追記】
Mac OS X(Yosemite)にVagrant 1.8.0をインストールしてvagrant powershell --command "ほげ"
なコマンドを試してみましたが以下のエラーメッセージが出てしまい実行できませんでした。
vagrant powershell
コマンドはWindowsホスト専用でした。
ただ、command.rb
ファイルの41行目でコマンドの実行ホストをチェックしている部分をコメントアウトしてしまうと、
# command.rb # 41行目の以下の部分をコメントアウトして実行ホストのチェックをしない様にしてしまう # Check if the host even supports ps remoting raise Errors::HostUnsupported if !@env.host.capability?(:ps_client) ↓ # Check if the host even supports ps remoting #raise Errors::HostUnsupported if !@env.host.capability?(:ps_client)
以下の図の様にvagrant powershell --command "ほげ"
なコマンドを無理やり実行することはできますw
当然オススメはできませんが自己責任でやるのはアリかもしれません。
また、Vagrantで使っているWinRMライブラリのロケールがen-US
、コードページが65001(UTF8)
で固定*2されているため、--command
オプションを指定した場合はシェルの言語が英語になります。
このため日本語の取り扱いに難があるっぽく、コマンドの実行結果に日本語が混じると即エラーとなったりしました...
【追記ここまで】
--commandオプションを指定しない場合
--command
オプションを指定しない場合、ゲストVMに対してEnter-PSSesssion
コマンドレットを使いリモート接続する流れとなります。
リモート接続の前にPSRemotingが有効か否かのチェックなどを行います。
こちらはホストからpowershell.exeを別途起動するため、非Windowsホストでは実行できません。
【2015/12/23追記】
例えばMacから実行した場合、--command
オプションを指定した場合と同じエラーになります。
【追記ここまで】
最初に[インストール先]\embedded\gems\gems\vagrant-1.8.0\plugins\commands\powershell\scripts\enable_psremoting.ps1
を呼び出し、ここでゲストVMに対してPSRemotingが有効になっているかのチェックとホスト側のTrustedHostの設定変更*3を行っています。
ゲストにPSRemotingで接続できる様になったのを確認した後で、[インストール先]\embedded\gems\gems\vagrant-1.8.0\plugins\hosts\windows\cap\ps.rb
を呼び出し、Enter-PSSesssion
を呼ぶスクリプトブロックを組み立て、powershell.exeを-NoProfile -ExecutingPolicy Bypass -NoExit
で呼び出しています。
ps.rb
から該当する部分を抜粋すると以下になります。
# ps.rbより抜粋 # powershell.exeで実行するコマンド(BASE64エンコードされる) command = <<-EOS $plain_password = "#{ps_info[:password]}" $username = "#{ps_info[:username]}" $port = "#{ps_info[:port]}" $hostname = "#{ps_info[:host]}" $password = ConvertTo-SecureString $plain_password -asplaintext -force $creds = New-Object System.Management.Automation.PSCredential ("$hostname\\$username", $password) function prompt { kill $PID } Enter-PSSession -ComputerName $hostname -Credential $creds -Port $port EOS # powershell.exe呼び出し args = ["-NoProfile"] args << "-ExecutionPolicy" args << "Bypass" args << "-NoExit" args << "-EncodedCommand" args << ::WinRM::PowershellScript.new(command).encoded if ps_info[:extra_args] args << ps_info[:extra_args] end # Launch it Vagrant::Util::Subprocess.execute("powershell", *args)
これをPowerShellのコードに直すとこんな感じになります。(あくまで疑似コードです)
# powershell.exeで実行するコマンド(BASE64エンコードされる) $Command = { $plain_password = "平文パスワード" $username = "接続ユーザー名(vagrant)" $port = "接続ポート" $hostname = "接続先ホスト(127.0.0.1)" $password = ConvertTo-SecureString $plain_password -asplaintext -force $creds = New-Object System.Management.Automation.PSCredential ("$hostname\\$username", $password) function prompt { kill $PID } Enter-PSSession -ComputerName $hostname -Credential $creds -Port $port }.ToString() $EncodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Command)) # powershell.exe呼び出し powershell.exe -NoProfile -ExecutingPolicy Bypass -NoExit -EncodedCommand $EncodedCommand
接続先がゲストVMなだけでよくあるEnter-PSSession
の呼び出しです。
ちょっと面白いのがfunction prompt { kill $PID }
の部分で、Enter-PSSession
が終了した次のプロンプト呼び出し時点で自分自身を殺してpowershell.exeを終了させているところでしょうか。
苦労のあとが見られます。
とりあえずこんなところです。
まだ軽く使った程度ですが、かなり便利で良い感じです。