Ajax+ASP でスプーラの再起動(WMI) と外部実行

  IIS に、最初から管理者権限を持つ仮想ディレクトリを作成



USER0001 は Adminstrators グループに所属しています
( 画面は、Windows XP のものです )





  仮想ディレクトリに Spooler サービスの停止と実行コードを置く



Shift_JIS で記述している普通の ASP です。

Spooler に 依存するサービスが2つぶら下がっています。
( これを停止しないと Spooler の処理ができません )

どの処理も非同期なので、実行後完全に目的の状態になるまで待っています。
( Sleep を行う為に、Basp21 を使用していますが、WMI だけで書く事もできます )

関数にしたほうが良いように見えますが、そのほうが汎用性が無くなって余計
解りにくくなる可能性があります。WMI はなにがどうなるが予想が付かない
(これを使ってる時点で要求が複雑になるでしょう)ので、ベタで書いておいたほうが良いです。

また、この処理は完全ではありません。失敗する可能性もありますので
結局、サービスマネージャと似たようなものを作ったほうが良いのですが、
使う人が必ずしもシステムを理解しているとは限らないので。

  
<%

Set basp = Server.CreateObject("Basp21")

strComputer = "." 
strResult = ""

Set objWMIService = GetObject("winmgmts:" _ 
	& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") 

' **********************************************************
' TCP/IP プリンタサーバー
' **********************************************************
strQuery = "select * from Win32_Service where Name = 'LPDSVC'"
Set colRunningServices = objWMIService.ExecQuery(strQuery) 
For Each objService in colRunningServices 
	errReturnCode = objService.StopService() 
Next 

' 終了待ち
nCnt = 0
Do while true
	basp.Sleep 1

	Set colRunningServices = objWMIService.ExecQuery(strQuery) 
	For Each objService in colRunningServices 
		strResult = objService.State
	Next 

	if strResult = "Stopped" then
		Response.Write "LPDSVC Stopped"
		Exit Do
	end if

	nCnt = nCnt + 1
	if nCnt > 60 then
		Response.Write " -> Timeout"
		Response.End
	end if

Loop

' **********************************************************
' MacPrint
' **********************************************************
strQuery = "select * from Win32_Service where Name = 'MacPrint'"
Set colRunningServices = objWMIService.ExecQuery(strQuery) 
For Each objService in colRunningServices 
	errReturnCode = objService.StopService() 
Next 

' 終了待ち
nCnt = 0
Do while true
	basp.Sleep 1

	Set colRunningServices = objWMIService.ExecQuery(strQuery) 
	For Each objService in colRunningServices 
		strResult = objService.State
	Next 

	if strResult = "Stopped" then
		Response.Write " -> MacPrint Stopped"
		Exit Do
	end if

	nCnt = nCnt + 1
	if nCnt > 60 then
		Response.Write " -> Timeout"
		Response.End
	end if

Loop


' **********************************************************
' Spooler ( 停止 )
' **********************************************************
strQuery = "select * from Win32_Service where Name = 'Spooler'"
Set colRunningServices = objWMIService.ExecQuery(strQuery) 
For Each objService in colRunningServices 
	errReturnCode = objService.StopService() 
Next 

' 終了待ち
nCnt = 0
Do while true
	basp.Sleep 1

	Set colRunningServices = objWMIService.ExecQuery(strQuery) 
	For Each objService in colRunningServices 
		strResult = objService.State
	Next 

	if strResult = "Stopped" then
		Response.Write " -> Spooler Stopped"
		Exit Do
	end if

	nCnt = nCnt + 1
	if nCnt > 60 then
		Response.Write " -> Timeout"
		Response.End
	end if

Loop

' **********************************************************
' Spooler ( 開始 )
' **********************************************************
strQuery = "select * from Win32_Service where Name = 'Spooler'"
Set colRunningServices = objWMIService.ExecQuery(strQuery) 
For Each objService in colRunningServices 
	errReturnCode = objService.StartService() 
Next 

' 開始待ち
nCnt = 0
Do while true
	basp.Sleep 1

	Set colRunningServices = objWMIService.ExecQuery(strQuery) 
	For Each objService in colRunningServices 
		strResult = objService.State
	Next 

	if strResult = "Running" then
		Response.Write " -> Spooler Running"
		Exit Do
	end if

	nCnt = nCnt + 1
	if nCnt > 60 then
		Response.Write " -> Timeout"
		Response.End
	end if

Loop

' **********************************************************
' MacPrint
' **********************************************************
strQuery = "select * from Win32_Service where Name = 'MacPrint'"
Set colRunningServices = objWMIService.ExecQuery(strQuery) 
For Each objService in colRunningServices 
	errReturnCode = objService.StartService() 
Next 

' 終了待ち
nCnt = 0
Do while true
	basp.Sleep 1

	Set colRunningServices = objWMIService.ExecQuery(strQuery) 
	For Each objService in colRunningServices 
		strResult = objService.State
	Next 

	if strResult = "Running" then
		Response.Write " -> MacPrint Running"
		Exit Do
	end if

	nCnt = nCnt + 1
	if nCnt > 60 then
		Response.Write " -> Timeout"
		Response.End
	end if

Loop

' **********************************************************
' TCP/IP プリンタサーバー
' **********************************************************
strQuery = "select * from Win32_Service where Name = 'LPDSVC'"
Set colRunningServices = objWMIService.ExecQuery(strQuery) 
For Each objService in colRunningServices 
	errReturnCode = objService.StartService() 
Next 

' 終了待ち
nCnt = 0
Do while true
	basp.Sleep 1

	Set colRunningServices = objWMIService.ExecQuery(strQuery) 
	For Each objService in colRunningServices 
		strResult = objService.State
	Next 

	if strResult = "Running" then
		Response.Write " -> LPDSVC Running"
		Exit Do
	end if

	nCnt = nCnt + 1
	if nCnt > 60 then
		Response.Write " -> Timeout"
		Response.End
	end if

Loop


%>
  



  Ajax 呼び出し側

通常のページから Ajax で呼び出します。
そうする事によって、ユーザのページに容易に機能を追加できます
( ボタンが増えるだけ )
※ これを前提として、ASP に渡す文字列と戻す文字列に日本語を使っていません

実装 HTML を IFRAME で埋め込むとユーザのページは殆ど触らなくて済みますし、
JavaScript な環境を考慮せずに済みます。

  
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=Shift_JIS">
<STYLE type="text/css">

* {
	font-size: 14px;
	text-align: center;
}

INPUT {
	font-weight:normal;
}

</STYLE>
<SCRIPT language="JavaScript">

	var dom,bIE;
	var objXMLHttp;

	if ( document.all ) {
		bIE = true;
		dom = new ActiveXObject("Msxml2.DOMDocument.3.0");
		objXMLHttp = new ActiveXObject("Msxml2.XMLHTTP.3.0");
	}
	else {
		bIE = false;
		dom = document.implementation.createDocument("", "", null);
		objXMLHttp = new XMLHttpRequest();
	}

function GetStatus() {

	objXMLHttp.open(
		"GET",
		"http://piano/batch/spooler_status.asp"
		, false );
	objXMLHttp.send( "" );
	result = objXMLHttp.responseText;

	document.getElementById("spooler_status").innerHTML =
		 "スプーラのステータス : " + result

}

function RebootSpool( ) {

	document.getElementById("spooler_status").innerHTML = ""

	if ( !confirm( "処理を実行しますか?" ) ) {
		return;
	}

	objXMLHttp.open(
		"GET",
		"http://piano/batch/reboot_spool.asp"
		, false );
	objXMLHttp.send( "" );
	result = objXMLHttp.responseText;

	alert("再起動完了しました\n" + result + "   ")

}

</SCRIPT>
</HEAD>
<BODY>

<INPUT 
	id="spooler_reboot"
	type="button"
	value="スプーラ再起動"
	style='width:200px;'
	onClick='RebootSpool()'
><br>
<INPUT 
	id="spooler_getstatus"
	type="button"
	value="ステータス取得"
	style='width:200px;'
	onClick='GetStatus()'
><br>

<DIV id="spooler_control">
<br>
<DIV id="spooler_status">
</DIV>
</DIV>



</BODY>
</HTML>
  



  外部プログラムの起動について

WMI で出来ない場合、または WMI コードを書くより既存のスクリプトを実行したほうが
早い場合が多々あります。その場合は普通に WScript.Shell を使用して Run すれば
良いですが、いくつか注意しておくべき事があります。

1)
サービス起動・停止等のシステムにかかわる実行は、IIS 経由ではユーザが
Administrators グループでも実行できない。

2)
バッチファイルの起動は cmd.exe /c で実行するが、Run のオプション無しだと
非同期になって実行されない(想像はつくが、理由不明)。

厳密に全てのテストをし、Microsoft のドキュメントを調べたわけではありませんが、
時間を無駄にする可能性が高いので、避けて通ったほうが無難です。

特に 2) に関してのトラブルは良く聞くのですが、cmd.exe の実行権限とのあわせ技の場合もあるので、
聞かれるほうの立場としても現象だけでは判断付きかねる場合が多いです。

※ 実行に cmd.exe /c を使用しているのは、新たなバッチファイルを作りたく無いので & で対応する為です


サーバ側
  
<%

Set WshShell = Server.CreateObject( "WScript.Shell" )

if Request.QueryString("pass") <> "password" then
	Response.Write "1"
	Response.End
end if


if Request.QueryString("id") = "1" then
	strCommand = _
	"cmd.exe /c cd \ & d: & cd \ & cd 目的のパス & cscript.exe 転送1.wsf"

	' コマンドプロンプトを開かない非同期実行
	Call WshShell.Run( strCommand, 0, False )
	Response.Write "OK"
	Response.End

end if

if Request.QueryString("id") = "2" then
	strCommand = _
	"cmd.exe /c cd \ & d: & cd \ & cd 目的のパス & cmd /c 転送2.bat"

	' コマンドプロンプトを開かない同期実行
	Call WshShell.Run( strCommand, 0, True )
	Response.Write "OK"
	Response.End

end if

Response.Write "id error"

%>
  


クライアント側
  
<HTML>
<HEAD>
<TITLE>バッチ処理特別</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=Shift_JIS">
<STYLE type="text/css">

* {
	font-size: 14px;
}

INPUT {
	font-weight:bold;
}

</STYLE>
<SCRIPT language="JavaScript">

	var dom,bIE;
	var objXMLHttp;

	if ( document.all ) {
		bIE = true;
		dom = new ActiveXObject("Msxml2.DOMDocument.3.0");
		objXMLHttp = new ActiveXObject("Msxml2.XMLHTTP.3.0");
	}
	else {
		bIE = false;
		dom = document.implementation.createDocument("", "", null);
		objXMLHttp = new XMLHttpRequest();
	}

function ExecCommand( nID ) {

	if ( !confirm( "処理を実行しますか?" ) ) {
		return;
	}

	var strPass = document.getElementsByName("pass")[0].value;

	objXMLHttp.open(
		"GET",
		"http://layla/batch/asp/go.asp?id=" + nID + "&pass=" + strPass
		, false );
	objXMLHttp.send( "" );
	result = objXMLHttp.responseText;

	if ( result == "1" ) {
		alert("パスワードが一致しません:"+result+"   ");
		return;
	}

	alert("バッチ処理を登録しました。結果はメールで返されます:"+result+"   ");

}

</SCRIPT>
</HEAD>
<BODY style='background-color:gainsboro'>

<TABLE cellpadding="3">
<TR>
	<TD>
	パスワード
	</TD>
	<TD>
	<INPUT type="password" name="pass" style='ime-mode:disabled'>
	</TD>
</TR>
<TR>
	<TD colspan="2">
		<INPUT 
			type="button"
			value="転送1"
			style='width:200px;'
			onClick='ExecCommand(1)'
		>
	</TD>
</TR>
<TR>
	<TD colspan="2">
		<INPUT 
			type="button"
			value="転送2"
			style='width:200px;'
			onClick='ExecCommand(2)'
		>
	</TD>
</TR>
</TABLE>

</BODY>
</HTML>
  










  infoboard   管理者用   
このエントリーをはてなブックマークに追加





フリーフォントWEBサービス
SQLの窓WEBサービス

SQLの窓フリーソフト

素材

一般WEBツールリンク

SQLの窓

フリーソフト

JSライブラリ