【Windowsサービス】Windowsサービス ~ Hello World編 ~

■ はじめに

https://blogs.yahoo.co.jp/dk521123/31706797.html
の頃は、無料版 Visual Studioでは簡単には作れなかったが
Visual Studio Community 2017 だと、簡単に作れそうなので、メモする。

■ 環境

 * Visual Studio Community 2017 (C#)
 * Windows 10

■ 手順

【1】プロジェクト 作成
【2】Windowsサービス の 実装 および ビルド
【3】Windowsサービス の インストール
【4】動作確認

以下、詳細。

【1】プロジェクト 作成

[1] Visual Studio を立ち上げて、[ファイル]-[新規作成]-[プロジェクト]を選択
[2] [Visual C#]-[Windows デスクトップ]-[Windowsサービス(.NET Framework)]を選択し、
    任意の名前、.NET Frameworkなどを入力・指定して「OK」ボタン押下
 => とりあえず、今回は、そのままで。

【2】Windowsサービス の 実装 および ビルド

[1] 「Service1.cs」 を ダブルクリック で開く

[2] 右クリックし、[インストーラーの追加] を選択
 => 「serviceProcessInstaller1」「serviceInstaller1」が追加される

[3] 「serviceInstaller1」を選択し、プロパティを変更
~~~~~
 * Description:サービスの説明(例:「はじめの一歩」)
 * DisplayName:サービスの表示名(例:「ハローワールド」)
 * ServiceName:システムがサービスを識別するための名称(例:「HelloWorldService」)
 * StartType  :サービスの開始方法(例:「Manual」「Automatic」など)
~~~~~

[4] 「serviceInstaller11」を選択し、プロパティを変更
~~~~~
 * Account:サービスが実行されるアカウント
 (例:「LocalSystem」。 以下「※ 注意:「Account:LocalService」を指定しないこと」を参照。)
~~~~~
 * Account プロパティの詳細は、以下の「■ 補足:Account プロパティについて」を参照のこと。

[5] 「Service1.cs」を右クリック、[コードの表示] を選択し、コーディングする
 => 今回は、以下の「サンプル」のように実装

[6] ビルドする
 => bin/Debug 配下にexeファイル(今回は、「WindowsService1.exe」)ができる
補足:サービス名の変更(「Service1」⇒「任意のサービス名」)するには...
 * Service1.cs をファイル名(クラス名)変更するだけじゃ不十分
 => イベントログに出力した際に「Service1」のままになっていた

【変更手順】
[1] Service1.cs をデザインビューで表示する
[2] デザインビューを右クリックし、[プロパティ]を選択
[3] ServiceNameの「Service1」を任意のサービス名(ex HelloWorldService)に変更する
※ 注意:「Account:LocalService」を指定しないこと
 「Account:LocalService」を指定すると、
Webサービス開始時に「エラー 5: アクセスが拒否されました。」が表示されてしまう。
詳細は、以下の関連記事を参照。
https://blogs.yahoo.co.jp/dk521123/14491769.html
サンプル:Service1.cs
using System;
using System.Diagnostics;
using System.ServiceProcess;

namespace WindowsService1
{
  public partial class Service1 : ServiceBase
  {
    public Service1()
    {
      InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
      EventLog.WriteEntry(String.Format("Hello World, OnStart: {0}", DateTime.Now));
    }

    protected override void OnStop()
    {
      EventLog.WriteEntry(String.Format("Hello World, OnStop: {0}", DateTime.Now));
    }
  }
}

【3】Windowsサービス の インストール

[1] [スタートメニュー]-[Visual Studio 2017]-[開発者コマンドプロンプト for VS2017]を右クリックし、
    [その他]-[管理者として実行]を選択
[2] 「開発者コマンドプロンプト for VS2017」で「installutil [exeファイル]」を実行する
~~~~~~~~~~
cd C:\source\repos\WindowsService1\WindowsService1\bin\Debug
installutil WindowsService1.exe

 => 「トランザクション インストールが完了しました。」が表示
~~~~~~~~~~

【4】動作確認

[1] Windowsの「サービス」の一覧から、作成したサービス「ハローワールド」を右クリックし、
    「開始」を選択し、Windowsサービスをスタートする

[2] Windowsの「イベントビューアー」を立ち上げて、
    [イベントビューアー(ローカル)]-[Windowsログ]-[Application]を選択し
    以下のようなログを探す。
    ~~~~~~
    Hello World, OnStart: 2019/02/XX XX:XX:XX
    ~~~~~~

[3] Windowsの「サービス」の一覧から、作成したサービス「ハローワールド」を右クリックし、
    「停止」を選択し、Windowsサービスをストップする

[4] Windowsの「イベントビューアー」から、以下のようなログを探す。
    ~~~~~~
    Hello World, OnStop: 2019/02/XX XX:XX:XX
    ~~~~~~

後片付け

Windowsサービス の アンインストール するには...
https://docs.microsoft.com/ja-jp/dotnet/framework/windows-services/how-to-install-and-uninstall-services
 * 「installutil /u [exeファイル]」を実行する

~~~~~~~~~~
cd C:\source\repos\WindowsService1\WindowsService1\bin\Debug
installutil /u WindowsService1.exe
~~~~~~~~~~
https://docs.microsoft.com/ja-jp/dotnet/framework/windows-services/how-to-install-and-uninstall-services

■ 補足:Account プロパティについて

https://docs.microsoft.com/ja-jp/dotnet/framework/windows-services/how-to-specify-the-security-context-for-services
の公式サイトより抜粋
User
 システムは、サービスのインストール時に有効なユーザー名とパスワードの指定を要求し、
ネットワーク上の 1 人のユーザーによって指定されたアカウントのコンテキストで実行します。
LocalService
 ローカル コンピューター上で非特権ユーザーとして機能し、
リモート サーバーに匿名の資格情報を提示するアカウントのコンテキストで実行します。
LocalSystem
 広範なローカル特権を提供し、リモート サーバーにコンピューターの
資格情報を提示するアカウントのコンテキストで実行します。
NetworkService
ローカル コンピューター上で非特権ユーザーとして機能し、
リモート サーバーにコンピューターの資格情報を提示するアカウントのコンテキストで実行します。

LocalSystem アカウントについて

https://docs.microsoft.com/ja-jp/dotnet/framework/windows-services/walkthrough-creating-a-windows-service-application-in-the-component-designer
LocalSystem アカウントには、イベント ログへの書き込みを含む、幅広いアクセス許可が設定されています。
このアカウントは悪意のあるソフトウェアから攻撃されるリスクが高いため、使用する場合は注意が必要です。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
その他のタスクについては、ローカル コンピューターで非特権ユーザーとして機能し、
リモート サーバーには匿名の資格情報を渡す LocalService アカウントの使用を検討してください。  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
この例は、 LocalService アカウントを使用しようとすると失敗します。
これは、イベント ログに書き込むアクセス許可が必要になるためです。

■ 次の課題

 * プロセス間通信(IPC:Inter Process Communication)を実現できる WCF を使って、
   「Windowsサービス - 他のアプリ」とのやり取りをする
 => 詳細は、以下の関連記事を参照。
Windowsサービス ~ WCFでクライアント側と通信する ~
https://blogs.yahoo.co.jp/dk521123/37953369.html


関連記事

Windowsサービス

Windowsサービス ~ 基礎知識編 ~
https://blogs.yahoo.co.jp/dk521123/31702889.html
Windowsサービス ~ WCFでクライアント側と通信する ~
https://blogs.yahoo.co.jp/dk521123/37953369.html
Windowsサービス ~ サービスのインストール etc ~
https://blogs.yahoo.co.jp/dk521123/29631029.html
VS Express で Windowsサービス のテンプレート作成
https://blogs.yahoo.co.jp/dk521123/31706797.html
ServiceControllerクラス ~サービスをコントロールする~
https://blogs.yahoo.co.jp/dk521123/31737290.html
Windowsサービスに関するトラブルシューティング
https://blogs.yahoo.co.jp/dk521123/14491769.html

WCF

WCF ~ 基礎知識編 ~
https://blogs.yahoo.co.jp/dk521123/22254537.html
WCF ~ Hello World編 ~
https://blogs.yahoo.co.jp/dk521123/31872515.html

Windowsサービス / Java

JavaWindowsサービス化する ~ Apache Commons Daemon
https://blogs.yahoo.co.jp/dk521123/37752105.html