harry’s memorandum

おれおれメモ

rubyでWindowsのIPアドレスを変更してみる

vbsのサンプルがたくさんあるのでそれを参考にWIN32OLEで書いてみました。
書いたのですが、vbのErrオブジェクトをWIN32OLEでどうやって使えばいいのかわからない。。。まあいいか。

#!/usr/bin/ruby 

require 'win32ole'
require 'optparse'
require 'pp'

# usage
def usage
  puts "Usage: #{__FILE__} [OPTIONS...]"
  puts "Try `#{__FILE__} --help' for more information."
  exit
end

# is numeric?
def is_num(x)
  begin
    x.integer?
  rescue
    false
  end
end

# is ipaddress? 
def is_ipaddr(str)
  return false if str.nil? || str.empty?
  array = str.split(".")
  return false unless array.size == 4 #ipv4 only
  array.each {|n|
    return false if is_num(n) 
    return false if n.to_i > 256
  }
  true
end

#It borrowed from activesupport.
class Hash
  # hash with all keys converted to strings.
  def stringify_keys
    inject({}) do |options, (key, value)|
      options[key.to_s] = value
      options
    end
  end
  # Destructively convert all keys to strings.
  def stringify_keys!
    keys.each do |key|
      self[key.to_s] = delete(key)
    end
    self
  end
end

opts = {}
opt = OptionParser.new
opt.on('--ip      ipaddr', 'set the ip address') {|v| opts[:ip] = v }
opt.on('--netmask netmask', 'set the ip network mask') {|v| opts[:netmask] = v }
opt.on('--gateway gateway', 'set the default gateway') {|v| opts[:gateway] = v }
opt.on('--dns     dnsserver', 'set the dns server')  {|v| opts[:dns] = v }

usage if ARGV.size == 0

begin
  opt.parse!(ARGV)
rescue
  usage
end

list = %w(ip netmask gateway dns)
opts.stringify_keys!
list.each {|key|
   unless is_ipaddr(opts[key])
     puts "#{key}(#{opts[key]}) is illegal value"
     exit
   end
}

errno = {}
host = "."
service = WIN32OLE.connect("winmgmts://#{host}/root/cimv2")
adapters = service.ExecQuery("Select * from Win32_NetworkAdapterConfiguration where IPEnabled=TRUE")
adapters.each {|ifc|
  if ifc.IPEnabled then
    errno[:ip] = ifc.EnableStatic(opts["ip"].to_a, opts["netmask"].to_a)
    errno[:gateways] = ifc.SetGateways(opts["gateway"].to_a, [1])
    errno[:dns] = ifc.SetDNSServerSearchOrder(opts["dns"].to_a)
    #puts "Index=#{ifc.Index}, Caption=#{ifc.Caption}"
    break
  end
}

if errno.values.max == 0 then
  puts "The IP address has been changed."
else
  puts "The IP address could not be changed."
  errno.each_pair {|key,val|
    puts " - errnor: #{key} == #{val}" unless val == 0 
  }
end 

最初のINDEXのネットワークカードのしか変更していないので、
複数のNICやオープンソース版XenPVドライバなどのインストールしている場合はうまくいかない場合があります。