ご飯

すっきりしたコードってむつかしい

SQL文を使ってExcelのワークシートにデータを入力する

今回の試みは、SQL文を使ってExcelのワークシートにデータを入力するものです。このようなフォームがあり、追加ボタンを押すとデータが挿入されます。

 

f:id:uhoo:20181129223457g:plain

 

 

先日、ご紹介した、UQuery を使って簡単にできるんです。

uhoo.hatenablog.com

 

追加ボタンのクリックイベントは次のようになります。 

Private Sub 追加_Click()
    
    Dim q As New UQuery

    q.setCon con
    q.Sql.Add "INSERT INTO [ごはん$] (id,ごはん,種類,価格)"
    q.Sql.Add "VALUES (?, ?, ?, ?)"
    
    q.AddParam "id", get_last_id
    q.AddParam "ごはん", ごはん
    q.AddParam "種類", 種類
    q.AddParam "価格", 価格
    q.execute

    clear
    ごはん.SetFocus

End Sub

 

 

フォームを作る

コードウィンドウから、ユーザフォームを追加し、次のように、コントロールを配置します。

f:id:uhoo:20181129235646p:plain


コントロールの名前は次のようにします。

名前 コントロール
Fごはん フォーム
ごはん テキストボックス
種類 コンボボックス
価格 テキストボックス
追加 コマンドボタン
キャンセル コマンドボタン

 

フォームを初期化する

フォームに UConnection オブジェクトの参照を渡す必要があります。init というパブリックメソッドをフォームに追加します。

Public Sub init(con_ As UConnection)

    Set con = con_
    set種類

End Sub

 

コンボボックスの内容を設定する

コンボボックスのリストアイテムは、すでに入力されているデータから取ることにします。もちろん、新しい種類を入力することもできます。ここでも UQuery を使っています。

Private Sub set種類()
    
    Dim q As New UQuery, i%

    q.setCon con
    q.Sql.Add "SELECT DISTINCT 種類 FROM [ごはん$]"
    q.OpenRecordset

    種類.clear

    Do Until q.hasNext
        種類.AddItem q.Fields("種類")
        q.MoveNext
    Loop

End Sub 

 

id の最終番号を取得する

レコードを識別する id の最終番号を取得します。

Private Function get_last_id()
    
    Dim q As New UQuery, last_id
    
    q.setCon con
    q.Sql.Add "SELECT max(id) as last_id FROM [ごはん$]"
    q.OpenRecordset
    
    last_id = q.Fields("last_id")
    get_last_id = IIf(IsNull(last_id), 0, last_id) + 1

End Function

 

Module1.bas 

Uhoo というサブプロシージャでフォーム表示しています。

Option Explicit

Dim con As New UConnection

Sub Uhoo()

    Fごはん.init con
    Fごはん.Show

End Sub

 

ワークシートのボタンにマクロを登録しておいてください。

f:id:uhoo:20181129235840p:plain



Fごはん のコード全文

Option Explicit

Private con As UConnection

Public Sub init(con_ As UConnection)

    Set con = con_
    set種類

End Sub

Private Sub set種類()
    
    Dim q As New UQuery, i%

    q.setCon con
    q.Sql.Add "SELECT DISTINCT 種類 FROM [ごはん$]"
    q.OpenRecordset

    種類.clear

    Do Until q.hasNext
        種類.AddItem q.Fields("種類")
        q.MoveNext
    Loop

End Sub

Private Function get_last_id()
    
    Dim q As New UQuery, last_id
    
    q.setCon con
    q.Sql.Add "SELECT max(id) as last_id FROM [ごはん$]"
    q.OpenRecordset
    
    last_id = q.Fields("last_id")
    get_last_id = IIf(IsNull(last_id), 0, last_id) + 1

End Function

Private Sub UserForm_Activate()

    ごはん.SetFocus

End Sub

Private Sub 追加_Click()
    
    Dim q As New UQuery

    q.setCon con
    q.Sql.Add "INSERT INTO [ごはん$] (id,ごはん,種類,価格)"
    q.Sql.Add "VALUES (?, ?, ?, ?)"
    
    q.AddParam "id", get_last_id
    q.AddParam "ごはん", ごはん
    q.AddParam "種類", 種類
    q.AddParam "価格", 価格
    q.execute

    clear
    ごはん.SetFocus

End Sub

Private Sub clear()
    
    set種類
    
    ごはん.Text = ""
    種類.Value = ""
    価格.Text = ""

End Sub

Private Sub キャンセル_Click()
    
    Hide

End Sub

 

ご飯は、あまり高度なことはわかりません。ごめんなさい。

 

おしまい 

 

Powershell を使って、ネットワークを設定する (4)

では、少しずつメニューを完成させてゆきます。トップメニューは次のようになります。

 f:id:uhoo:20181119224505p:plain

コードは次のように書きます。

$root = new-object Menu(0, 0, "Windows Server 設定ツール")
$root.body += new-object MenuItem(7, 5, "ホスト名の設定", {sysdm.cpl})
$root.body += new-object MenuItem(7, 7, "ネットワークの設定", {ncpa.cpl})
$root.foot += new-object Caption(7, 10, "** S/N : $serial")
$root.exe()

 

最初に、Menu クラスのインスタンスを作成し、容器を作っておきます。さらに、MenuItem クラスのインスタンスを作成し、Menuオブジェクトに追加します。お皿におかずをトッピングするようなイメージです。最後の行の exe メソッドによりメニューが実行されます。

 

コード全文 (tool.ps1)

add-type -AssemblyName System.Windows.Forms
$kmp = [Windows.Forms.Keys]
$rui = $host.UI.RawUI
. ".\def.ps1"
# メニュー表示 function show_menu($head, $body, $foot) { $init = $true $i = 0 do { if($init) { clear foreach($s in $head) {mv_cur $s.x $s.y; write-host $s.caption} foreach($s in $body) {mv_cur $s.x $s.y; write-host $s.caption} foreach($s in $foot) {mv_cur $s.x $s.y; write-host $s.caption} $init = $false; } $s = $body[$i] mv_cur $s.x $s.y write-host $s.caption -F "Black" -B "White" mv_cur $s.x $s.y $kif = $rui.ReadKey("NoEcho,IncludeKeyDown") $kcd = $kif.VirtualKeyCode if($kcd -in ($kmp::Up, $kmp::Left)) { write-host $s.caption; $i-=1 if($i -lt 0) { $i = $body.length - 1 } } if($kcd -in ($kmp::Down, $kmp::Right)) { write-host $s.caption; $i+=1 if($i -ge $body.length) { $i = 0; } } if($kcd -eq $kmp::Enter) { $s.exe() $init = $true; } } until($kcd -in ($kmp::Escape, $kmp::Q)) clear } # カーソル移動 function mv_cur($x, $y) { $cd = New-Object System.Management.Automation.Host.Coordinates $x, $y $rui.CursorPosition = $cd } class Caption { $x; $y; $caption Caption($x, $y, $caption) { $this.x = $x; $this.y = $y; $this.caption = $caption } } class Menu : Caption { $head = @(); $body = @(); $foot = @() Menu($x, $y, $caption) : base ($x, $y, $caption) { $title = "** "+ $caption + " **" $this.head += new-object Caption(7, 2, $title) } exe() { show_menu $this.head $this.body $this.foot } } class MenuItem : Caption { $cmd MenuItem($x, $y, $caption, $cmd) : base($x, $y, $caption) { $this.cmd = $cmd } exe() { &($this.cmd) } } $root = new-object Menu(0, 0, "Windows Server 設定ツール") $root.body += new-object MenuItem(7, 5, "ホスト名の設定", {sysdm.cpl}) $root.body += new-object MenuItem(7, 7, "ネットワークの設定", {ncpa.cpl}) $root.foot += new-object Caption(7, 10, "** S/N : $serial") $root.exe()

 

Powershell 画面から、.\tool.ps1 とたたいて実行してみてください。メニューが表示されましたでしょうか?

このメニューは、Enter キーを押すと、コントロールパネルのアプレットが起動するようになっています(まだ完成ではないですが、完成に限りなく近いです。ごめんなさい)。

 

こんどは、Enter キーを押すと、さらにサブメニューが表示されるように変更してみます。

 

サブメニューを作る

サブメニューを作るには、まず Menu クラスを継承します。ここではホスト名を変更する Host クラスを作ります。

class Host : Menu {
  Host($x, $y, $param) : base($x, $y, "ホスト名の設定") {
    $s = gwmi win32_computersystem
    $this.body += new-object MenuItem(7, 5, "設定確認", {sysdm.cpl})
    $this.body += new-object MenuItem(7, 7, "設定実行", $this.config)
    $this.foot += new-object Caption(7, 11, "* 現在の設定")
    $this.foot += new-object Caption(7, 13, ("ホスト名       : "+$s.name))
    $this.foot += new-object Caption(7, 14, ("ワークグループ : "+$s.domain))
    $this.foot += new-object Caption(7, 17, "* 変更後の設定")
    $this.foot += new-object Caption(7, 19, ("ホスト名       : "+$param.host_name))
    $this.foot += new-object Caption(7, 20, ("ワークグループ : "+$param.domain))
    $this.foot += new-object Caption(7, 23, "* 実行後、再起動します")
  }

  $config = {
    clear
    $ch = $false
    $s = gwmi win32_computersystem
    if($s.name -ne $param.host_name) {
      $s.rename($param.host_name)
      $ch = $true
    }
    if($s.domain -ne $param.domain) {
      Add-Computer -WorkgroupName $param.domain
      $ch = $true
    }
    if($ch -eq $true) {
      restart-computer
    }
  }
}

 

 画面は次のようになります。

 f:id:uhoo:20181119231122p:plain

 

メニュー画面に、設定値や説明などを加えたため、コードがぐじゃぐじゃしてきてしまいました。Host クラスの $cocnfig というインスタンス変数には、ホスト名を変更するスクリプトブロックが代入されています。

$config = {
  clear
  $ch = $false
  $s = gwmi win32_computersystem
  if($s.name -ne $param.host_name) {
    $s.rename($param.host_name)
    $ch = $true
  }
  if($s.domain -ne $param.domain) {
    Add-Computer -WorkgroupName $param.domain
    $ch = $true
  }
  if($ch -eq $true) {
    restart-computer
  }
}

 

$config は、メニューアイテム「設定実行」で使われます。

$this.body += new-object MenuItem(7, 5, "設定確認", {sysdm.cpl})
$this.body += new-object MenuItem(7, 7, "設定実行", $this.config)

 

では、メニューを完成させます。ルートメニューの前に Host クラスの記述を追加して、ルートメニューを次のように変更します。2行目の new-object Host(7, 5, $param) という文で、サブメニューが追加されます。 

$root = new-object Menu(0, 0, "Windows Server 設定ツール")
$root.body += new-object Host(7, 5, $param)
$root.body += new-object MenuItem(7, 7, "ネットワークの設定", {ncpa.cpl})
$root.foot += new-object Caption(7, 10, "** S/N : $serial")
$root.exe()

 

ついでに、ルートメニューもクラスにしてしまいましょう。

class Root : Menu {
  Root($param, $serial) : base(0, 0, "Windows Server 設定ツール") {
    $this.body += new-object Host(7, 5, $param)
    $this.body += new-object MenuItem(7, 7, "ネットワークの設定", {ncpa.cpl})
    $this.foot += new-object Caption(7, 10, "** S/N : $serial")
  }
}

$root = new-object Root($param, $serial)
$root.exe()

 

同じ要領でネットワーク設定についても見てゆきます。

 

ネットワーク設定

ネットワーク設定もまたサブメニューです。サブメニューの中に、種々のサブメニューを追加しています。

class Network : Menu {
  Network($x, $y, $nw) : base($x, $y, "ネットワーク設定") {
    $this.body += new-object RenameIfs(7, 5, $nw)
    $this.body += new-object Lbfo(7, 7, $nw)
    $this.body += new-object Binding(7, 9, $nw)
    $this.body += new-object IPAddr(7, 11, $nw)
    $this.body += new-object MenuItem(7, 13, "ncpa.cpl", {ncpa.cpl})
  }
}

 

f:id:uhoo:20181120101955p:plain

 

NICのポート名の変更

class RenameIfs : Menu {
  RenameIfs($x, $y, $nw) : base ($x, $y, "NICのポート名の変更") {
    $this.body += new-object MenuItem(7, 5, "設定実行", $this.config)
    $this.foot += new-object Caption(7, 8, "* 次の名前に変更します*")
    $i = 10
    foreach($r in $nw.rename_ifs) {
      $this.foot += new-object Caption(7, $i, ($r.name +" => "+ $r.newname)); $i+=1
    }
  }

  $config = {
    clear
    foreach($r in $param.nw.rename_ifs) {
      rename-netadapter @r
    }
    pause
  }
}

 

f:id:uhoo:20181120102103p:plain

  

チーミング

class Lbfo : Menu {
  Lbfo($x, $y, $nw) : base($x, $y, "チーミング") {
    $this.body += new-object MenuItem(7, 5, "設定確認", $this.confirm)
    $this.body += new-object MenuItem(7, 7, "設定実行", $this.config)
    $this.foot += new-object Caption(7, 10, "* 次の値を追加します")
    $this.foot += new-object Caption(9, 12, ("チーム名         : " + $nw.lbfo1.Name))
    $this.foot += new-object Caption(9, 13, ("メンバー         : " + $nw.lbfo1.TeamMembers))
    $this.foot += new-object Caption(9, 14, ("チーミングモード : " + $nw.lbfo1.TeamingMode))
    $this.foot += new-object Caption(9, 15, ("不可分散モード   : " + $nw.lbfo1.LoadBalancingAlgorithm))
    $this.foot += new-object Caption(9, 16, ("スタンバイポート : " + $nw.lbfo2.Name))
  }

  $config = {
    clear
    $lbfo1 = $param.nw.lbfo1
    $lbfo2 = $param.nw.lbfo2
    New-NetLbfoTeam @lbfo1
    Set-NetLbfoTeamMember @lbfo2
    pause
  }

  $confirm = {
    lbfoadmin
  }
}

 

f:id:uhoo:20181120102228p:plain

 

 

バインディング

class Binding : Menu {
  Binding($x, $y, $nw) : base($x, $y, "バインディング") {
    $this.body += new-object MenuItem(7, 5, "設定実行", $this.config)
    $this.foot += new-object Caption(7, 8, "* 次の値に設定します")
    $i=10
    foreach($r in $nw.ifs) {
      $this.foot += new-object Caption(9, $i, ("接続名 : "+ $r.name)); $i+=2
      foreach($x in $r.bindings) {
        $this.foot += new-object Caption(9, $i, ($nw.binding_dscr[$x.ComponentID]+" : "+$x.Enabled)); $i+=1
      }$i+=2
    }
  }

  $config = {
    clear
    foreach($r in $param.nw.ifs) {
      foreach($x in $r.bindings) {
        set-netadapterbinding -Name $r.name @x
      }
    }
    pause
  }
}

 

f:id:uhoo:20181120102312p:plain

 

 

IPアドレス 

class IPAddr : Menu {
  IPAddr($x, $y, $nw) : base($x, $y, "IPアドレス") {
    $this.body += new-object MenuItem(7, 5, "設定実行", $this.config)
    $this.foot += new-object Caption(7, 8, "* 次の値を追加します")
    $i=10
    foreach($r in $nw.ifs) {
      if($r.ip -ne $null) {
        $this.foot += new-object Caption(9, $i, ("接続名     : "+ $r.name)); $i+=1
        $this.foot += new-object Caption(9, $i, ("IPアドレス : "+ $r.ip.IPAddress + "/"+ $r.ip.PrefixLength)); $i+=1
        $this.foot += new-object Caption(9, $i, ("デフォゲ   : "+ $r.ip.DefaultGateway)); $i+=1
        $this.foot += new-object Caption(9, $i, ("DNSサーバ  : "+ $r.dns.ServerAddress)); $i+=1
      }
      if($r.register -eq $false) {
        $this.foot += new-object Caption(9, $i, "* この接続のアドレスをDNSに登録する のチェックを外します"); $i+=1
      }
    }
    if($nw.enablewins -eq $false) {
       $i+=3
       $this.foot += new-object Caption(9, $i, "* LMHOSTSの参照を有効にする のチェックを外します")
    }
  }

  $config = {
    clear
    foreach($r in $param.nw.ifs) {
      if($r.ip -ne $null) {
        $ip = $r.ip
        New-NetIPAddress -IfAlias $r.name @ip
        if($r.register -eq $false) {
          $cmd = "netsh int ip set dnsservers name=`"" + $r.name + "`" source=dhcp register=none"
          invoke-expression $cmd
        }
        if($r.dns -ne $null) {
          $dns = $r.dns
          Set-DnsClientServerAddress $r.name @dns
        }
      }
    }
    if($param.nw.enablewins -eq $false) {
      $nicClass = Get-WmiObject -list Win32_NetworkAdapterConfiguration
      $nicClass.enablewins($false,$false)
    }
    pause
  }
}

 

f:id:uhoo:20181120102414p:plain

 

仕上げ

ルートクラスの前に種々のメニュークラスの記述を追加して、次のように修正すれば完成です。

class Root : Menu {
  Root($param, $serial) : base(0, 0, "Windows Server 設定ツール") {
    $this.body += new-object Host(7, 5, $param)
    $this.body += new-object Network(7, 7, $param.nw)
    $this.foot += new-object Caption(7, 10, "** S/N : $serial")
  }
}

$root = new-object Root($param, $serial)
$root.exe()

 

多少ぐじゃぐじゃしてしまいましたが、クラスに押し込んでおけば、すっきりします。ご飯のおうちの押入れもぐじゃぐじゃしたものでいっぱいですが、ふすまを閉めてしまえばすっきりします。ただ、お部屋も手がつけられないほど散らかっていて。。。

 

お話はこれでおしまいです。

 

Powershell を使って、ネットワークを設定する (3)

パラメータファイル def.ps1 をインポートして、Windows Server を設定するスクリプト tool.ps1 を作成してゆきます。使いやすさを考慮して、メニュー画面による対話形式のスクリプトに仕上げてみたいと思います。 *1

 

メニューの仕様は、つぎのようなものです。

  • メニューは、ヘッダーとフッターおよびメニューアイテムからなる
  • メニューアイテムの最初の行にカーソルが止まり、矢印キーで移動できる
  • 選択したメニューアイテムにおいて Enterキーを押すと、設定コマンドが実行される
  • Escキーを押すと終了する

 

まず、ベースとなる関数やクラスを作ります。

  

 

show_menu 関数の作成

show_menu 関数は、メニューを表示します。

add-type -AssemblyName System.Windows.Forms
$kmp = [Windows.Forms.Keys] $rui = $host.UI.RawUI . ".\def.ps1" # メニュー表示 function show_menu($head, $body, $foot) { $init = $true $i = 0 do { if($init) { clear foreach($s in $head) {mv_cur $s.x $s.y; write-host $s.caption} foreach($s in $body) {mv_cur $s.x $s.y; write-host $s.caption} foreach($s in $foot) {mv_cur $s.x $s.y; write-host $s.caption} $init = $false; } $s = $body[$i] mv_cur $s.x $s.y write-host $s.caption -F "Black" -B "White" mv_cur $s.x $s.y $kif = $rui.ReadKey("NoEcho,IncludeKeyDown") $kcd = $kif.VirtualKeyCode if($kcd -in ($kmp::Up, $kmp::Left)) { write-host $s.caption; $i-=1 if($i -lt 0) { $i = $body.length - 1 } } if($kcd -in ($kmp::Down, $kmp::Right)) { write-host $s.caption; $i+=1 if($i -ge $body.length) { $i = 0; } } if($kcd -eq $kmp::Enter) { $s.exe() $init = $true; } } until($kcd -in ($kmp::Escape, $kmp::Q)) clear } # カーソル移動 function mv_cur($x, $y) { $cd = New-Object System.Management.Automation.Host.Coordinates $x, $y $rui.CursorPosition = $cd }

 

メニューの表示

次のコードは、メニュー全体を表示する箇所です。$head と $body および $foot を読み出し、指定された座標に移動し、Write-Host コマンドレットでメニューの内容を表示しているところです。

foreach($s in $head) {mv_cur $s.x $s.y; write-host $s.caption}
foreach($s in $body) {mv_cur $s.x $s.y; write-host $s.caption}
foreach($s in $foot) {mv_cur $s.x $s.y; write-host $s.caption}

 

メニューカーソル 

次のコードは、メニューカーソルです。現在のメニューアイテムを反転表示させています。

$s = $body[$i]

mv_cur $s.x $s.y
write-host $s.caption -F "Black" -B "White"
mv_cur $s.x $s.y

$body は、メニューアイテムが格納された配列です。$i は行番号です。最初はメニューアイテムの1番目の要素が取り出され、$x, $y 座標の位置でメニューアイテムの内容が反転表示されます。矢印キーが押されるたびに $i をインクリメント、またはデクリメントさせて、メニューカーソルを移動させる仕掛けです。

 

キー入力の受付

$rui.ReadKey メソッドでキー入力を受付る状態になります。$kcd の値を評価すると、押されたキーを知ることができます。

$kif = $rui.ReadKey("NoEcho,IncludeKeyDown")
$kcd = $kif.VirtualKeyCode

 

上矢印キーが押されたとき

行番号をデクリメントします。メニューの先頭のときは、行番号を最終行にセットします。

if($kcd -in ($kmp::Up, $kmp::Left)) {
  write-host $s.caption; $i-=1 
  if($i -lt 0) { $i = $body.length - 1 }
}

 

下矢印キーが押されたとき

行番号をインクリメントします。メニューの最後のときは、行番号を先頭行にセットします。

if($kcd -in ($kmp::Down, $kmp::Right)) {
  write-host $s.caption; $i+=1
  if($i -ge $body.length) { $i = 0; }
}

 

Enterキーが押されたとき

コマンドを実行します。

if($kcd -eq $kmp::Enter) {
  $s.exe()
  $init = $true;
}

 

Escキーが押されたとき

メニューを終了します。

until($kcd -in ($kmp::Escape, $kmp::Q)

 

Caption クラス

Caption クラスは、メニューの内容を保持するためのオブジェクトです。座標とキャプションをフィールドに持ちます。

class Caption {
  $x; $y; $caption

  Caption($x, $y, $caption) {
    $this.x = $x; $this.y = $y; $this.caption = $caption
  }
}

 

Menu クラスは、メニュー本体のオブジェクトです。ヘッダーとフッターおよびメニューアイテムのリストをフィールドに持ちます。メニューを表示するには、exe メソッドを実行します。

class Menu : Caption {
  $head = @(); $body = @(); $foot = @()

  Menu($x, $y, $caption) : base ($x, $y, $caption) {
    $title = "** "+ $caption + " **"
    $this.head += new-object Caption(7, 2, $title)
  }

  exe() {
    show_menu $this.head $this.body $this.foot
  }
}

コンストラクターでは、メニュータイトルが表示されるようにひと工夫加えました。 

MenuItem クラスは、メニューアイテムの座標とキャプションを保持するオブジェクトです。さらに、コマンドを入れるための cmd フィールドを持ちます。メニューアイテムで Enter キーが押されると、exe メソッドが起動し、&($this.cmd) によりコマンドが実行されます。

class MenuItem : Caption {
  $cmd

  MenuItem($x, $y, $caption, $cmd) : base($x, $y, $caption) {
    $this.cmd = $cmd
  }

  exe() {
    &($this.cmd)
  }
}

 

次回は、具体的な設定コマンドを作っていきます。

 

uhoo.hatenablog.com

*1:f:id:uhoo:20181123140025g:plain

Powershell を使って、ネットワークを設定する (2)

パラメータファイル def.ps1 をインポートして、サーバのネットワークを設定するスクリプトを作成します。

その前に、設定に必要なコマンドレットを整理しておきます。

 

ホスト名とワークグループ名の変更

ホスト名の変更は、Win32_ComputerSystemクラスの WMIオブジェクトを取得し、rename メソッドを実行します。

$s = gwmi win32_computersystem
$s.rename($param.host_name)

 

ワークグループは、Add-Computer コマンドレットを使用します。

Add-Computer -WorkgroupName $param.domain

 

設定後に再起動が必要なので、変更されたかどうかを記憶しておきます。変更ありなら restart-computer コマンドレットを実行します。

$ch = $false
$s = gwmi win32_computersystem

if($s.name -ne $param.host_name) {
  $s.rename($param.host_name)
  $ch = $true
}

if($s.domain -ne $param.domain) {
  Add-Computer -WorkgroupName $param.domain
  $ch = $true
}

if($ch -eq $true) {
  restart-computer
}

 

NICのポート名を変更する

Rename-NetAdapter コマンドレットを使用します。

foreach($r in $param.nw.rename_ifs) {
  rename-netadapter @r
}

 

@r という記述は、ハッシュのキーと値をコマンドレットの引数として展開してくれます。foreach で $r に代入される値は、たとえば次のようなものです。

@{Name = "Ethernet0"   ; NewName = "Eth1"}

 

rename-netadapter @r は、次のような文に展開します。

rename-netadapter -Name "Ethernet0" -NewName "Eth1"

素敵だと思います。

 

チーミングを設定する

つぎのコマンドレットを使用します。

  • チーミングの作成…New-NetLbfoTeam
  • スタンバイポートの設定…Set-NetLbfoTeamMember 
$lbfo1 = $param.nw.lbfo1
$lbfo2 = $param.nw.lbfo2
New-NetLbfoTeam @lbfo1
Set-NetLbfoTeamMember @lbfo2

 

ここでも @lbfo1 という記述が見られます。チーミングのパラメータは、このようなものです。

lbfo1 = @{
  Name = $team_name
  TeamMembers  = ("Eth1","Eth5")
  TeamingMode  = "SwitchIndependent"
  LoadBalancingAlgorithm = "Dynamic"
  Confirm = $false
}

lbfo2 = @{
  Name = "Eth5"
  AdministrativeMode = "Standby"
}

 

これだけ多くのパラメータをコマンドラインの引数に展開したら、かなりぐじゃぐじゃになることでしょう。考えただけでも恐ろしいです。すっきりしたコードを書くということがいかに大切かがわかります。

なお、@param.nw.lbfo1 とすることができなかったので、いったん平べったい変数に代入してから @演算子が有効となります。

 

バインディングを設定する

バインディングとは、 ネットワークのプロパティの赤枠のチェックボックスをつけるところです。

f:id:uhoo:20181109032211p:plain

 

これを Powershell でコントロールするには、Set-NetAdapterBinding コマンドレットを使用します。

foreach($r in $param.nw.ifs) {
  foreach($x in $r.bindings) {
    set-netadapterbinding -Name $r.name @x
  }
}

 

IPv4プロパティを設定する

IPv4アドレスの追加

New-NetIPAddress コマンドレットを使います。

New-NetIPAddress -IfAlias $r.name @ip

 

DNSサーバの追加

Set-DnsClientServerAddress コマンドレットを使います。

$dns = $r.dns
Set-DnsClientServerAddress $r.name @dns

 

「この接続のアドレスをDNSに登録する」 のチェックを外す

次の画面がそれにあたります。

 f:id:uhoo:20181109060226p:plain

 

$cmd = "netsh int ip set dnsservers name=`"" + $r.name + "`" source=dhcp register=none"
invoke-expression $cmd

これだけコマンドレットがありませんでした。仕方ないので冗長な netsh を使います。💢💢💢

 

「LMHOSTSの参照を有効にする」 のチェックを外す 

次の画面がそれにあたります。

f:id:uhoo:20181109060104p:plain

 

$nicClass = Get-WmiObject -list Win32_NetworkAdapterConfiguration
$nicClass.enablewins($false,$false)

 

まとめると次のようになります。

foreach($r in $param.nw.ifs) {
  if($r.ip -ne $null) {

    $ip = $r.ip
    New-NetIPAddress -IfAlias $r.name @ip

    if($r.register -eq $false) {
      $cmd = "netsh int ip set dnsservers name=`"" + $r.name + "`" source=dhcp register=none"
      invoke-expression $cmd
    }

    if($r.dns -ne $null) {
      $dns = $r.dns
      Set-DnsClientServerAddress $r.name @dns
    }
  }
}

if($param.nw.enablewins -eq $false) {
  $nicClass = Get-WmiObject -list Win32_NetworkAdapterConfiguration
  $nicClass.enablewins($false,$false)
}

 

次回は、メニュー画面を作成し、メニュー項目の Enterキーが押されたら、設定を実行するように書き換えてみます。

 

uhoo.hatenablog.com

 

VMware に Windows Server 2012 R2 をインストールする

今回は UbuntuVMwareWindows Server 2012 R2 をインストールしてみます。まず、以下のサイトからWindows Server 2012 R2 の 180日評価版をダウンロードします。

Microsoft Evaluation Center

 

4.3GB 残り 5時間と表示されたので、ご飯は朝までやっているお店でカラオケでも歌ってきます。

 

家に帰ってきました。いつもの面々に会えてうれしかったので、つい飲みすぎてしまいました。やはり、孤独に生きていると、無性にだれかと一緒にいたくなってしまいます。ご飯の内面はたぶん優しいと思います。反面、さびしがりやで、自尊心も低く、ちょっとしたことに傷つき、いつもくじけて泣いています。この世から消えてしまいたいとさえ思うことがあります。ご飯のまわりの人たちも、人知れず悲しみを抱えているのだろうと思います。大切にしなければいけない人たちです。

 

さて、ダウンロードができたところで、VMware を起動し、Create a New Virtual Machine をクリックします。

f:id:uhoo:20181109012444p:plain

 

Use ISO image: を選択し、さきほどダウンロードした ISOファイルを指定し、Next をクリックします。

f:id:uhoo:20181109013046p:plain

 

Microsoft Windows が選択されています。そのまま Next をクリックします。

f:id:uhoo:20181109013240p:plain

 

なにも変更せずに Next をクリックします。

f:id:uhoo:20181109013658p:plain

 

60GBもあれば十分でしょう。Next をクリックします。

f:id:uhoo:20181109013845p:plain

 

Finish をクリックします。

f:id:uhoo:20181109013925p:plain

 

Close をクリックします。

f:id:uhoo:20181109014030p:plain

 

よくわからない画面が出てきましたが、OKをクリック。

f:id:uhoo:20181109014209p:plain

 

次へをクリックします。

f:id:uhoo:20181109014426p:plain

 

今すぐインストールをクリック

f:id:uhoo:20181109014604p:plain

 

Windows Server 2012 R2 Standard 評価版 (GUI 使用サーバ) を選択し次へをクリックします。

f:id:uhoo:20181109014837p:plain

 

同意しますにチェックを入れて、次へをクリックします。

f:id:uhoo:20181109014947p:plain

 

カスタムをクリック。

f:id:uhoo:20181109015036p:plain

 

パーティションは作成せずに、次へをクリック。

f:id:uhoo:20181109015229p:plain

 

インストールが始まります。

f:id:uhoo:20181109015310p:plain

 

数回再起動します。

f:id:uhoo:20181109015651p:plain

適宜パスワードを入力し、完了をクリックします。

f:id:uhoo:20181109020101p:plain

 

もうこんな時間か。寝なくては。Ctrl + Alt + Del でログオンします。

f:id:uhoo:20181109020359p:plain

パスワードを入力します。

f:id:uhoo:20181109020604p:plain

 

サインインできました。

f:id:uhoo:20181109020758p:plain

 

今日はこのへんで寝ることにします。

 

Powershell を使って、ネットワークを設定する (1)

今回の試みは、Windows Server の設定を、Powershellスクリプトで実行するというものです。サーバは複数台存在し、それぞれ異なるIPアドレスやホスト名を設定します。設定項目は、次の通りです。

 

f:id:uhoo:20181123140025g:plain

 

すっきりしたコードにするため、スクリプトはパラメータファイルと実行用ファイルに分けたいと思います。前者が def.ps1 という名前で、後者が tool.ps1 です。

 

では、def.ps1 から作っていきます。

 

ハッシュ $params を作成する 

def.ps1 に次のコードを追加します。

$params = @{
  "XYZ123S2C5" = @{host_name = "hostname4" ; ipaddr1 = "192.168.1.64"; gw1 = "192.168.1.1"}
  "XYZ123S2C9" = @{host_name = "hostname3" ; ipaddr1 = "192.168.1.94"; gw1 = "192.168.1.1"}
  "XYZ123S2C6" = @{host_name = "hostname2" ; ipaddr1 = "192.168.1.84"; gw1 = "192.168.1.1"}
  "XYZ123VDED" = @{host_name = "hostname1" ; ipaddr1 = "192.168.1.74"; gw1 = "192.168.1.1"}
}

 

$params というハッシュは、左辺がサーバ固有のシリアルナンバー、右辺が、サーバに設定すべき固有のパラメータのテーブルです。シリアルナンバーは、サーバ本体のバーコードをスキャンするとよいでしょう。Excelの一覧表にしてIPアドレスやホスト名などの情報を紐付けます。

 

Powershell から次のように入力すると $params の内容が表示されます。

PS /home/uhoo> . ".\def.ps1"
PS /home/uhoo> $params

Name                           Value
----                           -----
XYZ123S2C9                     {host_name, gw1, ipaddr1}
XYZ123VDED                     {host_name, gw1, ipaddr1}
XYZ123S2C6                     {host_name, gw1, ipaddr1}
XYZ123S2C5                     {host_name, gw1, ipaddr1}

 

シリアルナンバーが、XYZ123S2C9 であると仮定すると、次のようにして $params の要素を取り出すことができます。

PS /home/uhoo> $params["XYZ123S2C9"]

Name                           Value
----                           -----
ipaddr1                        192.168.1.94
gw1                            192.168.1.1
host_name                      hostname3

 

シリアルナンバーを取得する

自身のサーバのシリアルナンバーを取得するには、 (gwmi win32_bios).SerialNumber とします。

def.ps1 に次のコードを追加します。

$serial    = (gwmi win32_bios).SerialNumber  # このコンピュータのシリアル№
$uhoo      = $params[$serial]
$host_name = $uhoo.host_name       # ホスト名
$ipaddr1   = $uhoo.ipaddr1         # IPv4アドレス -1
$gw1       = $uhoo.gw1             # デフォゲ -1
$team_name = "team_" + $host_name  # チーム名

コードは、取得したシリアルナンバーを $serial に代入し、$params から該当するレコードを取り出しています。そしてフィールドを使いやすい形式の変数に代入しています。

 

なお、ここでは便宜上、一番目のレコードのシリアルナンバーを取得したことにしておきます。

#$serial    = (gwmi win32_bios).SerialNumber  # コメントアウト
$serial    = "XYZ123S2C9" # 便宜上の値に変更  

 

ハッシュ $param を作成する

$param というハッシュを定義して、使いやすい形式に整えます。

コード全文(def.ps1)

$params = @{
  "XYZ123S2C5" = @{host_name = "hostname4" ; ipaddr1 = "192.168.1.64"; gw1 = "192.168.1.1"}
  "XYZ123S2C9" = @{host_name = "hostname3" ; ipaddr1 = "192.168.1.94"; gw1 = "192.168.1.1"}
  "XYZ123S2C6" = @{host_name = "hostname2" ; ipaddr1 = "192.168.1.84"; gw1 = "192.168.1.1"}
  "XYZ123VDED" = @{host_name = "hostname1" ; ipaddr1 = "192.168.1.74"; gw1 = "192.168.1.1"}
}

#$serial    = (gwmi win32_bios).SerialNumber  # このコンピュータのシリアル№
$serial    = "XYZ123S2C9"
$uhoo      = $params[$serial]
$host_name = $uhoo.host_name       # ホスト名
$ipaddr1   = $uhoo.ipaddr1         # IPv4アドレス -1
$gw1       = $uhoo.gw1             # デフォゲ -1
$team_name = "team_" + $host_name  # チーム名

$param = @{

  # ホスト名
  host_name = $host_name
  domain    = "WORKGROUP"

  # ネットワークのプロパティ
  nw = @{

    # ポート名の変更
    rename_ifs = @(
       @{Name = "Ethernet0" ; NewName = "Eth1"}
       @{Name = "Ethernet1" ; NewName = "Eth5"}
     )

    # チーミングの設定
    lbfo1 = @{
      Name = $team_name
      TeamMembers  = ("Eth1","Eth5")
      TeamingMode  = "SwitchIndependent"
      LoadBalancingAlgorithm = "Dynamic"
      Confirm = $false
    }

    lbfo2 = @{
      Name = "Eth5"
      AdministrativeMode = "Standby"
    }

    # 接続の設定
    ifs = @(
      # インタフェイス-1 
      @{
        name = $team_name
     
        # バインディング (既定値を変更する ComponentID だけ追加し、enabled 属性を与えてください)
        bindings  = @(
          @{ComponentID = "ms_tcpip6"; Enabled = $false}
        )
     
        # IPv4アドレス (個別パラメータの $ipaddr1 を参照しています)
        ip = @{IPAddress = $ipaddr1; PrefixLength = 24; DefaultGateway = $gw1}
     
        # DNSサーバ
        dns = @{ServerAddress = @('192.168.0.2','192.168.0.1')}
     
        # $false を指定すると「この接続のアドレスをDNSに登録する」のチェックを外します
        register = $false
      }
    )

    # false を指定すると「LMHOSTS の参照を有効にするチェック」のを外します
    enablewins = $true

    # コンポーネントIDとその説明
    binding_dscr = @{
      ms_rspndr    = "Link-Layer Topology Discovery Responder"
      ms_lltdio    = "Link-Layer Topology Discovery Mapper I/O Driver"
      ms_implat    = "Microsoft Network Adapter Multiplexor Protocol"
      ms_msclient  = "Microsoft ネットワーク用クライアント"
      ms_netftflt  = "Microsoft Failover Cluster Virtual Adapter Performance Filter"
      ms_bridge    = "Microsoft MAC Bridge"
      ms_lbfo      = "Microsoft Load Balancing/Failover Provider"
      ms_pacer     = "QoS パケット スケジューラ"
      ms_server    = "Microsoft ネットワーク用ファイルとプリンター共有"
      ms_tcpip6    = "インターネット プロトコル バージョン 6 (TCP/IPv6)"
      ms_tcpip     = "インターネット プロトコル バージョン 4 (TCP/IPv4)"
    }
  }
}

 

以上で準備ができました。

 

次回は、パラメータファイルを使って設定を実行するスクリプトを作成します。 

 

uhoo.hatenablog.com

 

Ubuntu に VMware Player をインストールする

UbuntuVMWare をインストします。

  1. VMWare をダウンロード。

    VMware-Player-15.0.0-10134415.x86_64.bundle というファイルがダウンロードされます

  2. ダウンロードしたファイルを実行します。次のように入力
    uhoo@miyu:~$ sudo sh ./VMware-Player-15.0.0-10134415.x86_64.bundle 
    [sudo] uhoo のパスワード: 
    Extracting VMware Installer...done.
    [AppLoader] Use shipped Linux kernel AIO access library.
    An up-to-date "libaio" or "libaio1" package from your system is preferred.
    Gtk-Message: 21:46:48.840: Failed to load module "canberra-gtk-module"
    
    (vmware-installer.py:31940): IBUS-WARNING **: 21:46:51.327: The owner of /home/uhoo/.config/ibus/bus is not root!
  3. I accept にチェックを入れて Next をクリック

    f:id:uhoo:20181108220445p:plain

  4. I accept にチェックを入れて Next をクリック

    f:id:uhoo:20181108220547p:plain

  5. スタートアップ時にアップデートをチェックする場合 Yes にチェックを入れて Next をクリック

    f:id:uhoo:20181108220639p:plain

  6. カスタマーエクスペリエンスは No にチェックを入れて Next をクリック

    f:id:uhoo:20181108220803p:plain

  7. ライセンスキーはなにも入れないで Next をクリック

    f:id:uhoo:20181108220915p:plain

  8. 準備ができたので Install をクリック

    f:id:uhoo:20181108220952p:plain

  9. インストール中

    f:id:uhoo:20181108221400p:plain

  10. close をクリック

    f:id:uhoo:20181108221420p:plain

 

こんどは VMware  に Windows Server 2012 R2 をインストールしてみます。

uhoo.hatenablog.com