読者です 読者をやめる 読者になる 読者になる

harry’s memorandum

おれおれメモ

Win32OLEをつかってWindowsのサービスをリモートから起動停止してみる

ruby monitoring

Win32OLEがすごく面白かったのでWindowsのサービスをリモートから起動停止するコードを書いてみました。

Win32OLEを使ったrubyのコード

require 'win32ole' すれば後はvbsで書くのとあまりかわりはありません。vbsと違い強力なrubyのHashやArrayやイテレータで遊べます。

locator = WIN32OLE.new( "WbemScripting.SWbemLocator" )
service = locator.ConnectServer(hostname ,"root/cimv2", account, password)
service.InstancesOf("Win32_Service").each {|v| p v.class: p v }

使い方

 ruby foo.rb -h hostname -a accout -p password -c {stop|start}

下のほうにある svcList に起動/停止したいサービスを書いて実行してください。

#!/usr/bin/ruby

require 'win32ole'
require 'optparse'
require 'socket'

opt = OptionParser.new
o = {}

def usage
  puts 
  puts " usage: #{__FILE__} -h hostname -a accout -p password -c {stop|start}"
  puts "    -h hostname"
  puts "    -a accout"
  puts "    -p password"
  puts "    -c {stop|start}"
  exit
end

begin
  opt.on('-h [hostname]') {|v| o[:hostname] = v }
  opt.on('-a [account]') {|v| o[:account] = v }
  opt.on('-p [password]') {|v| o[:password] = v }
  opt.on('-c [ctl]') {|v| o[:service_ctl] = v }
  opt.on("--help") {|v| o[:help] = v}
  opt.parse!(ARGV)
rescue
  puts  "#{__FILE__}: unrecognized option"
  usage
end

# usage ...
usage if o.size == 0
usage if o[:help] 
usage unless o[:service_ctl] == "stop" || o[:service_ctl] == "start"

class ServiceCtl
  def initialize()
    @h = Hash.new{|h,k| h[k]=[]}
    @table ={}
  end
  def getdata(service)
    service.InstancesOf("Win32_Service").each {|v| @h[v.name] = v }
    @h
  end
  def start(service,svcList)
    @table = getdata(service)
    svcList[:start].each {|s|
      if @table.key?(s) == true
          r = @table[s].StartService 
          puts statusmsg(r, s, :ctl => 0)
      end
    }
  end
  def stop(service,svcList)
    @table = getdata(service)
    svcList[:stop].each {|s|
      if @table.key?(s) == true
        r = @table[s].StopService
        puts statusmsg(r, s, :ctl => 1)
      end
    }
  end
  def statusmsg(r, s, opt ={})
    opt[:ctl] == 0 ? msg = "startng a service" : msg = "stopping a service"
    case r
    when 0
      "#{msg} (#{s}) - status:(success)"
    when 5
      "#{msg} (#{s}) - status:(stopped)"
    when 8
      "#{msg} (#{s}) - status:(abort)"
    when 10
      "#{msg} (#{s}) - status:(running)"
    else
      "#{msg} (#{s}) - status:(illegal)"
    end
  end
end

# main
svcList = {
  :stop => ["wuauserv" ,"Themes" ,"WebClient"],
  :start => ["wuauserv", "Themes", "WebClient"]
}

locator = WIN32OLE.new( "WbemScripting.SWbemLocator" )
if Socket.gethostname == o[:hostname] || 'localhost' == o[:hostname]
  service = locator.ConnectServer()
else
  service = locator.ConnectServer( o[:hostname] ,"root/cimv2", o[:account], o[:password] )
end

so = ServiceCtl.new

case o[:service_ctl]
when "stop"
  so.stop(service,svcList)
when "start"
  so.start(service,svcList)
else
  usage
end

参考

Microsoft の Hey, Scripting Guy! にvbsやwshやwmiのサンプルがたくさんあるので参考になります。また WMI Administrative Tools(CIM Studio) を使うとオブジェクトツリーを参照できてとても便利です。

  • Hey, Scripting Guy!

http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/default.mspx

  • WMI Administrative Tools

http://www.microsoft.com/downloads/details.aspx?familyid=6430F853-1120-48DB-8CC5-F2ABDC3ED314&displaylang=en