DOBON.NET DOBON.NETプログラミング掲示板過去ログ

開始、停止させる任意のサービス名を引数として渡したい

環境/言語:[OS : Windows XP Professional / 言語 : Visual Basic .NET / .NET Framework : 1.1]
分類:[.NET]

【解決したい問題】

現在バッチファイルに組み込んで使用するのを前提と
してConsole上から任意のサービス名を引数として渡し
サービスを開始、停止させるプログラムを作成しています。

大部分をどぼん!様作成のSapleを参考にさせて頂きました。

Imports System.ServiceProcess
Module Module1

Sub Main(ByVal CmdArgs() As String)
Dim cmd As String
For Each cmd In CmdArgs
Next
'ServiceControllerオブジェクトの作成
Dim sc As New ServiceController("cmd", ".")
If cmd = "" Then
Console.WriteLine("サービス名を指定して下さい")
'サービスが停止していれば、開始する
ElseIf sc.Status = ServiceControllerStatus.Stopped Then
sc.Start()
Console.WriteLine("サービスを開始します")
ElseIf sc.Status = ServiceControllerStatus.StartPending Then
'サービスが開始するまで3分待機する
sc.WaitForStatus(ServiceControllerStatus.Running, New TimeSpan(0, 0, 180))
ElseIf sc.Status = ServiceControllerStatus.StartPending Then
Console.WriteLine("サービスを開始出来ませんでした")
Else
'サービスが開始していれば、停止する
If sc.CanStop Then
sc.Stop()
Console.WriteLine("サービスを停止します")
'サービスが停止するまで3分待機する
sc.WaitForStatus(ServiceControllerStatus.Stopped, New TimeSpan(0, 0, 180))
ElseIf sc.Status = ServiceControllerStatus.StopPending Then
Console.WriteLine("サービスを停止出来ませんでした")
End If
End If
End Sub
End Module

引数を指定せず実行した場合は意図した通りになります。
しかし引数にサービス名(例:Telnet)を指定して実行する
とエラーになります。

書籍などで自分なりに調べたのですが

> Dim sc As New ServiceController("cmd", ".")

の部分のcmdに変数は使えないような(弱気)サービス名
そのものを指定するとエラーも無く動作致します。

齢37にしてプログラムの勉強を始めたおじさんに
助力を頂ければ大変嬉しいです。

長文になってしまいましたがよろしくお願いいたします。
> 現在バッチファイルに組み込んで使用するのを前提と
> してConsole上から任意のサービス名を引数として渡し
> サービスを開始、停止させるプログラムを作成しています。

net start コマンドを使うのではダメなのでしょうか?
> net start コマンドを使うのではダメなのでしょうか?

はい・・それを言われてしまうとその通りと言うしかありません・・・。
バッチファイル+VBSで組んだ方が簡単なのはわかってるのですが・・・。
■No11600に返信(ぱそこんオヤジさんの記事)
>>net start コマンドを使うのではダメなのでしょうか?
>
> はい・・それを言われてしまうとその通りと言うしかありません・・・。
> バッチファイル+VBSで組んだ方が簡単なのはわかってるのですが・・・。

「net start コマンド」は OS 荷標準で付属するコマンドラインツールです。
VBS とは一切関係ありませせん。

とりあえず、Windows のヘルプで net start コマンドについて調べてみてはいかがですか?
> 「net start コマンド」は OS 荷標準で付属するコマンドラインツールです。
> VBS とは一切関係ありませせん。

いやいや、バッチファイルの中に"net start XXX"を書いて
開始、又は停止したかステータスをチェックするスクリプト
をVBSで書いた方が簡単だなぁと。そう言う意味です。

・・・もう少しVB.NETを勉強して出直して来ます。
■No11597に返信(ぱそこんオヤジさんの記事)
> 書籍などで自分なりに調べたのですが
> > Dim sc As New ServiceController("cmd", ".")
> の部分のcmdに変数は使えないような(弱気)サービス名
> そのものを指定するとエラーも無く動作致します。

sc の宣言子に記述されている「"cmd"」は、リテラル式です。リテラル式は、
リテラルで表現された値に評価されます。文字列リテラルは、文字列の値その
ものをソースコード上に表現したものですから、ServiceController 型のコン
ストラクタには「『cmd』という文字列」が渡されます。

ぱそこんオヤジさんが渡したいのは、「cmd に格納された文字列」ですよね。
cmd に格納された値に評価される式は、ぱそこんオヤジさんも If ステートメ
ントの式に記述しているローカル変数式です。

早い話が、

Dim sc As New ServiceController(cmd, ".")

でしょう。

あぁ!!そうか!"cmd"だと文字列だから、cmdっていう文字が渡され
ちゃうのか。ご丁寧な解説ありがとうございます。

無事にコマンドラインから指定したサービスを開始、停止出来る
ようになりました。しかし、新たな問題が。今度は引数に何も指定
しない場合にエラーが出るようになってしまいました。

>If cmd = "" Then
>Console.WriteLine("サービス名を指定して下さい")

cmdの中が空(引数無し)の場合はこれで良いはずだと思ったのですが・・・。
う〜ん、難しい。もう少し頑張ってみます。

おおた様、ありがとうございました。
■No11609に返信(ぱそこんオヤジさんの記事)
> ... しかし、新たな問題が。今度は引数に何も指定
> しない場合にエラーが出るようになってしまいました。
> >If cmd = "" Then
> >Console.WriteLine("サービス名を指定して下さい")
> cmdの中が空(引数無し)の場合はこれで良いはずだと思ったのですが・・・。

エラーが出るというのは、ServiceController オブジェクトの作成で、例外が
発生するということでいいですよね。

ServiceController オブジェクトの作成は、sc のローカル宣言ステートメン
トの位置で行われます。ServiceController 型のコンストラクタが呼び出され
てしまった後で、cmd の値の正当性を調べても手遅れですよね。
おおた様、こんばんは。

> ServiceController オブジェクトの作成は、sc のローカル宣言ステートメン
> トの位置で行われます。ServiceController 型のコンストラクタが呼び出され
> てしまった後で、cmd の値の正当性を調べても手遅れですよね。

な、なるほど。ServiceControllerのオブジェクトを生成してからでは遅い
という事ですね。おおた様のヒントを頼りに自分なりに調べ書籍を読みあさり
最初のステップを以下のように修正しました。

Imports System.ServiceProcess
Module Module1

Sub Main(ByVal CmdArgs() As String)
Dim cmd As String
For Each cmd In CmdArgs
Next
If cmd = "" Then
Console.WriteLine("サービス名を指定して下さい")
Exit Sub
End If
'ServiceControllerオブジェクトの作成
Dim sc As New ServiceController(cmd, ".")
(以下略)

・・・見事動作しました。引数無しでもエラーにはなりませんし、引数で
指定したサービスの開始、停止もOKでした。後はバッチで使う事を前提に
作成しているのでサービスが開始、停止出来なかった場合に環境変数
「%ERRORLEVEL%」に終了コードをセットするようなステップを追加して
完成です。

おおた様、本当にありがとうございました。感謝です。
解決済み!
■No11645に返信(ぱそこんオヤジさんの記事)
> 「%ERRORLEVEL%」に終了コードをセットするようなステップを追加して
> 完成です。

今ごろは、もう完成しているかもしれませんが、落ち穂拾いを少し。

コマンドライン引数に、無効なサービス名を指定されると、例外が発生して終
了します。サービス名を指定されなかった場合との、一貫性がないですよね。

コマンドライン引数に、複数のサービス名を指定されても、エラーの報告を行
いません。代わりに、最後の引数で指定されたサービスに対してのみ、処理を
行います。このままでも、構わないとは思いますが、このプログラムの実装を
忘れてしまった頃に利用すると、困惑することになるかもしれませんね。

指定されたサービスの、開始や停止に時間がかかると、例外が発生して終了し
ます。意図して用意してあるエラーメッセージを表示できないのですから、こ
れはバグといってよさそうですね。ServiceController.WaitForStatus メソッ
ドは、指定した待機時間が経過すると、TimeoutException の例外を発生させ
ます。単純に呼び出し側に制御を戻すわけではないです。
解決済み!
おおた様

> コマンドライン引数に、無効なサービス名を指定されると、例外が発生して終
> 了します。サービス名を指定されなかった場合との、一貫性がないですよね。

あ!確かに・・・これは気がつきませんでした。

> 指定されたサービスの、開始や停止に時間がかかると、例外が発生して終了し
> ます。意図して用意してあるエラーメッセージを表示できないのですから、こ
> れはバグといってよさそうですね。ServiceController.WaitForStatus メソッ
> ドは、指定した待機時間が経過すると、TimeoutException の例外を発生させ
> ます。単純に呼び出し側に制御を戻すわけではないです。

はい。おおた様のご指摘通りの問題が発生しております。今までVBSを少し
弄った事があるくらいで本格的なプログラミングは初めての経験で少々
浮かれてしまったようです。完成はまだまだ先ですね(笑

何とか完成まで持って行きたいと思います。ご指摘ありがとうございました。

DOBON.NET | プログラミング道 | プログラミング掲示板