azukipochette's weblog

memory dump (mini)

いまどきの Vagrant (VMWare Workstation) で Windows の Box を作る方法

Vagrant の場合、Linux などの仮想マシンは簡単に入手できるはずです。

しかし、ライセンス問題がある Windows の仮想マシンはほとんど存在しません (人気が無いのかもしれませんが...)。 そこで、Windows の Box の作成方法を示します。

VM の作成

VM の設定

ディスクは [仮想ディスクを複数のファイルに分割] を選択します (既定)。

メモリは Vagrant の資料には 512MB と書かれていますが、Windows の場合はパフォーマンスの観点から 1 GB or 2GB が良いと思います。

Windows (OS) のインストール

普通に VMWare Workstation を使用して OS をインストールするだけです。

インストール完了後、ログインするユーザーとして次を設定します (Windows Server など、複雑なパスワードにしなくてはいけない場合は、一時的に別のパスワードに設定します)。

ユーザー名: vagrant パスワード: vagrant パスワードのヒント : パスワード以外の文字列

VMWare Tools のインストール

VMWare Tools をインストールします。通常のインストール方法と同じです。

インストール後、コンピューターを再起動します。

設定の変更

次の設定を変更する必要があります。

  1. UAC の無効化
  2. 複雑なパスワードの無効化
  3. シャットダウンの記録の無効化
  4. "サーバー マネージャーをログイン時に起動する"の無効化

UAC については、Windows 8/8.1 以降の環境では下記のレジストリで無効化する必要があります (バーを下げるだけでは UAC が無効にならないため)。 注意 : 管理者権限でコマンドプロンプトを起動する必要があります。

reg add HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System /v EnableLUA /d 0 /t REG_DWORD /f /reg:64

WinRMの構成

管理者権限でコマンドプロンプトを開き、次のコマンドを実行します。

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 config WinRM start= auto

なお、接続しているネットワークのタイプがパブリックの場合は quickconfig 時にエラーになるので事前にパブリック以外 (プライベート or ドメイン) に変更してください。

また、WinRM 1.1 (Windows Server 2008) 以前の場合は下記のコマンドも追加で必要。 ただし、Windows Server 2008R2, Windows 7 以降は不要です。

netsh firewall add portopening TCP 5985 "Port 5985"
winrm set winrm/config/listener?Address=*+Transport=HTTP @{Port="5985"}

リモート デスクトップの設定

RDP 接続したい場合は、システムのプロパティを開き、リモート接続を許可するように設定を変更してください。 また、念のためファイア ウォール設定で RDP のポートを開けておきます。

その他

Windows Update 、アプリケーションのインストールなどを行います。

マシンのシャットダウン

すべての作業を終了後、VM をシャットダウンさせます。

shutdown /s /t 0 /f

パッケージング (BOX 化)

仮想マシンを作成したフォルダに移動し、下記の作業を行います。

内容物の確認

NVRAM, VMSD, VMX, VMXF, VMDK ファイルが存在することを確認します。 それ以外のファイルは削除してしまって構いません。

ディスクの最適化

なるべく BOX のサイズを小さくするためにデフラグ (-d) とシュリンク (-k) を次の手順で最適化します。 なお、ディスクを分割している場合は、メインの仮想ディスク (-snnn が付与されていないもの) に対して実行します。

"C:\Program Files (x86)\VMware\VMware Workstation\vmware-vdiskmanager.exe" -d <main.vmdk> 
"C:\Program Files (x86)\VMware\VMware Workstation\vmware-vdiskmanager.exe" -k <main.vmdk>

metadata.json ファイルの作成

BOX FILE FORMAT に従って、metadata.json を用意します。 Windows 10 1607 のファイルを作成した例を示します。公式のものには、checksum などアップデートするための設定などが書かれていますが、動かすためには provider の設定があればいいだけです。

{
  "name": "en_win10_1607_x86",
  "description": "This box contains Windows 10 Pro 1607 (x86) English.",
  "provider": "vmware_desktop"
}

Vagrantfile ファイルの作成

下記のような Vagrantfile を用意します。特に guest と communicator が重要で、これが正しくないと起動もしません。

# -*- 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.guest = :windows
  config.vm.define "vagrant-windows-10"
  config.vm.box = "windows_10"
  config.vm.communicator = "winrm"

  # Admin user name and password
  config.winrm.username = "vagrant"
  config.winrm.password = "vagrant"

  config.windows.halt_timeout = 15

  config.vm.network :forwarded_port, guest: 3389, host: 3389, id: "rdp", auto_correct: true
  config.vm.network :forwarded_port, guest: 22, host: 2222, id: "ssh", auto_correct: true
  config.vm.network :forwarded_port, guest: 5985, host: 5985, id: "winrm", auto_correct: true

  config.vm.provider :vmware_workstation do |v, override|
    #v.gui = true
    v.vmx["memsize"] = "2048"
    v.vmx["numvcpus"] = "2"
    v.vmx["ethernet0.virtualDev"] = "vmxnet3"
    v.vmx["RemoteDisplay.vnc.enabled"] = "false"
    v.vmx["RemoteDisplay.vnc.port"] = "5900"
    v.vmx["scsi0.virtualDev"] = "lsisas1068"
  end
end

パッキング

残念ながら、vagrant package コマンドは VirtualBox 専用なので、GZIP などの形式に圧縮します。

私は、公式のサイト通り、tar コマンドを使用して圧縮しています。

cd "E:\Virtual Machines\en_windows_10_1607_x86_vmware"
tar cvzf my.box ./*

Windows に tar コマンドは普通存在しないので、GitHub Desktop などを導入して、Linux のコマンドを呼び出すのが簡単です。ZIP でも問題ないので、そこまでするかどうかは好みの問題です (私は圧縮効率で選択)。

テスト

よい子はテストしましょう。

vagrant box add <box name> <box path>
vagrant init <box name>
vagrant up --debug

参考情報

Selenium を使って Microsoft Edge の UI テストをする

はじめに

Selenium は Firefox との相性がとても良い。WebDriver のインストールは不要、テストもなるべく失敗しようなような動きをしてくれる。 だが、ほかのブラウザーではそうはいかない。そこで、今回は Microsoft Edge におけるテストについて説明する。

Selenium を使うためにインストールが必要な NuGet パッケージ

Visual Studio の好きな言語で単体テストのプロジェクトを作成し、次の NuGet パッケージをインストールすればよい。

  • Selenium.Support
  • Selenium.WebDriver

Microsoft Edge Web Driver のインストール

Microsoft Edge Web Driver は下記からダウンロードできる。

注意してほしいのは、使用されている Windows 10 のバージョンによってインストールするドライバーが違うということだ。 自分自身が使っているバージョンをしっかり確認したほうがいい。

コード記述例

後は下記のようなテストを書くだけだ。 下記のテストは、amazon.co.jp に移動し、いくつかの検索条件で検索したあと、その画面をキャプチャするものである。 テキストの入力、ボタンのクリック、検索後の遅延待ちや、画面取得というのはよくある話なので、その辺を理解するのに役に立つと思う。

using System;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Edge;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Interactions;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.Extensions;
using OpenQA.Selenium.Support.UI;

namespace SeleniumTests
{
    public static class WebDriverExtensions
    {
        public static void SaveScreenshot(this IWebDriver driver, string fileName, ImageFormat format)
        {
            Screenshot screenshot = driver.TakeScreenshot();
            screenshot.SaveAsFile(fileName, format);
        }
    }

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void AmazonSearchTest()
        {
            RemoteWebDriver driver = null;
            try
            {
                var list = new[] { "Visual Studio", "Windows 10", "ビール", "少年ジャンプ" };

                string serverPath = "Microsoft Web Driver";
                serverPath = Path.Combine(Environment.ExpandEnvironmentVariables(Environment.Is64BitOperatingSystem ? "%ProgramFiles(x86)%" : "%ProgramFiles%"), serverPath);
                EdgeOptions options = new EdgeOptions { PageLoadStrategy = EdgePageLoadStrategy.Normal };
                driver = new EdgeDriver(serverPath, options);

                // 暗黙的待機 (要素を検索するときに、見つけられるまで指定時間分だけ待つ)
                driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));

                foreach (var keyword in list)
                {
                    driver.Url = "http://www.amazon.co.jp";

                    // 本当はこれで検索ボックスに文字列を入力できるが...
                    //IWebElement element = driver.FindElement(By.Name("field-keywords"));
                    //element.SendKeys(keyword);

                    // Edge は 日本語 を SendKeys すると Unknown Error になるので、ExecuteScript で回避
                    driver.ExecuteScript($"document.getElementsByName('field-keywords')[0].value = \"{keyword}\"");

                    // 検索ボタンをクリック
                    IWebElement element2 = driver.FindElementByClassName("nav-input");
                    element2.Submit();

                    // 検索結果のページが読み込み完了するまで待機する
                    WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));
                    wait.Until(_ => driver.ExecuteScript("return document.readyState").Equals("complete"));

                    // 画面ショットを取る
                    driver.SaveScreenshot($"{keyword}.png", ImageFormat.Png);
                }
            }
            finally
            {
                driver?.Quit();
            }
        }
    }
}

テストのコツ

実際に動かしてみるとわかるが、Microsoft Edge の Web Driver は、Edge が起動していると一度すべて閉じてしまう。なので、インターネットで調べ物をしながらコードを書いているなら Microsoft Edge を使わない方がいい。 また、Edge を起動したままにしていると、どうもテストの失敗率が高くなるので、テスト前には Microsoft Edge 自体を落としておくほうがよい。

Edge が起動しなくなったときの対処

上記のコードにも Try-finally で EdgeDriver.Quite() を呼び出しているが、このメソッドがちゃんと呼び出されないと次回以降の起動ができなくなることがよくある。 ただ、上記コードを書いていても、デバッグなどで途中停止したりすると同じ現象になることがある。 その場合はコンピューターを再起動する、または sihost.exe (Shell Infrastructure Host) を Kill するとよい (当然、自己責任で)。

Atom for Windows のシェル統合部分を削除する

atom をインストールすると、自動的に Shell 統合が行われて、context menu に atom で開く項目が追加される。 表示が鬱陶しい場合は、以下のようにしてシェル統合部分を削除できる (ただし、アップデートの度に実行が必要)。

REG DELETE HKCR*\shell\Atom /f

REG DELETE HKCR\Directory\Background\shell\Atom /f

REG DELETE HKCR\Directory\shell\Atom /f

# 早くオプションになりますように...。

Outlook の多重起動をやめたい

Windows 10 にしてからスタートメニューにピン止めした Outlook のアイコンで起動しているわけですが、気が付くと Outlook.exe が 3 つも 4 つも起動している...ということが良くあります。

Outlook の多重起動をやめるには、ピン止めしている Outlook のショートカットに /recycle オプションを付与するだけです。

以下に例を示します

"C:\Program Files (x86)\Microsoft Office\root\Office16\OUTLOOK.EXE" /recycle

WinDbg の覚え書き (その 2)

コマンド ウィンドウにデバッグ出力を表示させたい

ドライバーのデバッグ出力を WinDbg のコマンド ウィンドウに表示したいときは、次のようにして nt!kd_default_mask を有効にする。

eb nt!Kd_Default_Mask f

なお、マスクはいろいろあり、x nt!kd_*_mask で確認することができる。 次の資料が詳しい。

変数を使いたい

デバッガーで変数のようなものを使いたいときがある。その時は、疑似レジスタ (pseudo register) を使うとよい。 $t0 - $t19 まで用意されており、次のように使用することができる。

r $t0 = 123

たとえば、とある変数が持つハンドルからプロセス情報を表示するには次のようにすることで表示が可能。

** 現在ブレークしている地点で参照可能な handle という変数があるという前提
** handle はハンドルのポインターなので、poi() によってポインターが指し示す先から値を取得する
r $t0 = poi(handle)
!process $t0 0

Kindle を活用するまでの長い道のり

電子書籍を購入する

残念ながら amazon.co.jp のような流通のサイトで全ての電子書籍が購入できると良いのだが、amazon.co.jp には無いが出版社直営の e-book ストアには販売していることが多々ある。一般的な技術書の販売サイトを以下にまとめておく。

amazon.co.jp

http://amazon.co.jp/

ネット流通大手、amazon.co.jp のサイト。Kindle 本のところから、コミック、雑誌などもを購入することができる。 Kindle 向けに最適化されているので、DRM は付いてしまうが、Kindle で見るならここで買うのが一番無難。

O'Reilly Media

http://shop.oreilly.com/

英語の技術書籍を購入するなら、まずは O'Reilly Media で購入を検討するほうがいい。 理由は DRM Free なので、Kindle 端末に限らず、様々なデバイスで見ることができること、そして DRM Free に多い、PDF のみということが少なく、mobi や epub 形式も提供していることが多い。

たまに ALL BOOKS 50% OFF というキャンペーンをしているので、その手のタイミングを狙っても良いだろう。

達人出版会

http://tatsu-zine.com/

日本語の書籍で DRM Free な書籍を販売している。主に PDF 形式しか提供していないのは残念だが、割引などもあるので、出版社直営を見る前に同じ書籍がないかどうかを見るのは良いと思う。

O'Reilly Japan Ebook Store

http://www.oreilly.co.jp/ebook/

日本のオライリーが提供している e-book ストア。日本語のオライリーの書籍はここで買うのが一番良い様子。

オーム社 eStore

http://estore.ohmsha.co.jp/

オーム社が提供している e-book ストア。オーム社の書籍を買うならここ。

技術評論社の電子書籍サイト

https://gihyo.jp/dp

技術評論社が提供している e-book ストア。技術評論社の書籍を買うならここ。

翔泳社 (amazon 経由で購入することになる)

https://www.shoeisha.co.jp/book/ebooks

技術評論社が提供している e-book ストア。技術評論社の書籍を買うならここ。

ThinkPad Keyboard で Fn キーを押さずに ファンクション キー (F1 など) を押したいという願いをかなえる方法

ThinkPad Bluetooth ワイヤレス・トラッキング・キーボード を買いました

Lenovo 直販の 30% キャンペーンの値段と、amazon.co.jp の売価がほとんど変わらないことがわかり、amazon.co.jp で "ThinkPad Bluetooth ワイヤレス・トラッキング・キーボード - 英語 (0B47189)" を購入することにした。

ファンクション キーは Fn キーを押しながら、が既定

amazon.co.jp のコメント欄に大量に書かれているので既知の上で購入したのだが、ThinkPad キーボードの上部にあるファンクション キーは、ミュートやボリューム調整などのアクションが割り当てられており、そのアクションが既定になっている。 このため、ヘルプのために F1 キーを押したいと思った場合には、Fn を押しながら、 F1 キーを押下しなくてはならない。

もちろん、この問題は Lenovo も認識していて、ThinkPad Keyboard Suite をインストールした上で、Fn+Esc を押下することで、ファンクション ロックとなり、動作が逆転する (アクションを実行したければ Fn キーを押す)。

しかし、ThinkPad Keyboard Suite はあまり良くない常駐アプリケーションなので、可能ならば入れずにこの動作を実現したい。

解決策: レジストリ キーを変更しましょう

Bluetooth でデバイスを認識させると、ThinkPad キーボード用の HID ドライバーがインストールされる。その上で、Think Pad Keyboard Suite Updater が起動し、最新のアプリケーションをインストールしますか、と聞かれるので、ここで、"無視" を選んだ上で、次のレジストリを設定する。

名前 設定値
キー名 HKEY_CURRENT_USER\Software\Lenovo\fnlock
値の名前 state
値の種類 REG_DWORD
値のデータ 1

これで Thinkpad Keyboard Suite をインスト-ルして、ファンクション ロックした状態だとドライバーが認識してくれるようになる。