自動メンテナンス

プラットフォーム

クライアント – Windows 8
サーバー – Windows Server 2012

説明

Windows は、Windows Update、ディスクの自動最適化、ウイルス対策の更新プログラムやスキャンなど、付加価値の多くについて、受信トレイとサード パーティのメンテナンス アクティビティの実行に依存します。 さらに、企業では、ネットワーク アクセス保護 (NAP) スキャンなどのメンテナンス アクティビティを頻繁に使用して、すべてのエンタープライズ ワークステーションにセキュリティ標準を適用します。

Windows のメンテナンス アクティビティは、ユーザー操作が制限され、パフォーマンスとエネルギー効率への影響が最小限に抑えながらバックグラウンドで実行されるように設計されています。 ただし、Windows 7 以前のバージョンでは、Windows の複数のメンテナンス アクティビティの非決定論的かつ広範なスケジュールにより、パフォーマンスとエネルギー効率が引き続き影響を受けます。 ユーザーがコンピューターをアクティブに使用している間にメンテナンス アクティビティが実行されると、ユーザーに対する応答性が低下します。 また、アプリでは、ユーザーにソフトウェアの更新とバックグラウンド メンテナンスの実行を頻繁に求め、アクション センター、コントロール パネル、Windows Update、タスク スケジューラ MMC スナップイン、サード パーティ製のコントロールなど、複数のエクスペリエンスにユーザーを誘導します。

自動メンテナンスの目的は、Windows のすべてのバックグラウンド メンテナンス アクティビティを組み合わせ、サードパーティの開発者がパフォーマンスとエネルギー効率に悪影響を与えることなく、メンテナンス アクティビティを Windows に追加できるようにすることです。 さらに、自動メンテナンスを使用すると、ユーザーと企業は、メンテナンス アクティビティのスケジュールと構成を制御できます。

主な問題

自動メンテナンスは、Windows のメンテナンス アクティビティに関する次の問題に対処するように設計されています。

  • 期限のスケジュール設定
  • リソース使用率の競合
  • エネルギー効率
  • ユーザーに対する透過性

機能

自動メンテナンスにより、アイドル効率が向上し、すべてのアクティビティをタイムリーかつ優先順位の高い方法で実行できます。 また、メンテナンス アクティビティの一元的な可視性と制御を可能にし、サード パーティの開発者はパフォーマンスとエネルギー効率に悪影響を与えることなく、メンテナンス アクティビティを Windows に追加できます。 これを行うには、完全自動モード、ユーザー開始モード、自動停止、期限と通知、エンタープライズ制御が提供されます。 これらはそれぞれ以下で説明します。

全自動モード

この既定のモードでは、PC のアイドル時間とスケジュールされた時刻 (ユーザーの介入なしでメンテナンス アクティビティの実行と自動一時停止) のインテリジェントなスケジュール設定が可能になります。 ユーザーは、毎週または毎日のスケジュールを設定できます。 すべてのメンテナンス アクティビティは非対話型であり、サイレントで実行されます。

コンピューターは、システムが使用されていない可能性が高い場合に自動的にスリープ状態から再開されます。これは、ラップトップの場合は、AC 電源の場合にのみウェイクアップを許可する既定の電源管理ポリシーを考慮します。 高電力の完全なシステム リソースは、できるだけ早くメンテナンス アクティビティを完了するために使用されます。 システムが自動メンテナンスのためにスリープから再開された場合は、スリープ状態に戻るように要求されます。

構成などのアクティビティに関連する必要なユーザー操作は、自動メンテナンス実行の外部で実行されます。

ユーザー開始モード

ユーザーが旅行の準備をする必要がある場合、長時間バッテリ電源を使用する必要がある場合、またはパフォーマンスと応答性を最適化したい場合は、必要に応じて自動メンテナンスを開始するオプションがあります。 ユーザーは、自動実行スケジュールを含む自動メンテナンス属性を構成できます。 自動メンテナンス実行の現在の状態を表示でき、必要に応じて自動メンテナンスを停止できます。

自動停止

自動メンテナンスは、ユーザーがコンピューターとの対話を開始すると、現在実行中のメンテナンス アクティビティを自動的に停止します。 システムがアイドル状態に戻ると、メンテナンス アクティビティが再開されます。

注意

自動メンテナンスのすべてのアクティビティは、2 秒以内の停止をサポートする必要があります。 アクティビティが停止されたことをユーザーに通知する必要があります。

 

期限と通知

重要なメンテナンス アクティビティは、事前に定義された時間枠内で実行する必要があります。 重要なタスクが指定された時間内に実行できなかった場合、自動メンテナンスは、次に使用可能なシステムアイドル状態の機会に自動的に実行を開始します。 ただし、タスクの状態が期限を過ぎたままの場合、自動メンテナンスはアクティビティについてユーザーに通知し、自動メンテナンスを手動で実行するためのオプションを提供します。 メンテナンスのためにスケジュールされたすべてのタスクが実行されますが、最も不足しているタスクが優先されます。 このアクティビティは、システムの応答性とパフォーマンスに影響を与える可能性があります。そのため、自動メンテナンスでは、重要なメンテナンス アクティビティが実行されていることをユーザーに通知します。

エンタープライズ コントロール

エンタープライズ IT プロフェッショナルは、Windows システムで自動メンテナンスがいつ実行されるかを判断し、標準化された管理インターフェイスを使用してそのスケジュールを適用し、自動メンテナンス実行の試行の状態に関するイベント データを取得できる必要があります。 さらに、IT プロフェッショナルは、標準管理インターフェイスを介して特定の自動メンテナンス アクティビティをリモートで呼び出すことができる必要があります。 自動メンテナンスが実行されるたびに、ユーザーがアクティビティを手動で一時停止したために自動メンテナンスを実行できなかった場合の通知を含む状態レポートが実行されます。 IT プロフェッショナルは、ユーザーのログオン エクスペリエンスを迅速に行うために、ログオン スクリプトを自動メンテナンスに移行することを検討する必要があります。

自動メンテナンス タスクの作成

このセクションでは、開発者が XML または C 言語のタスク定義を使用してタスクを作成する方法について詳しく説明します。 自動メンテナンスは完全にサイレントであり、ユーザーが存在しないときに実行されるため、メンテナンス アクティビティはユーザー操作を必要とするユーザー インターフェイスを起動しないように注意してください。 実際、自動メンテナンス中にユーザーがコンピューターと対話した場合、処理中のすべてのタスクは次のアイドル期間まで終了します。

XML の使用

タスク スケジューラには、XML 形式でタスク定義をインポートできる、schtasks.exe組み込みのコマンド ライン ツールが含まれています。 タスク定義のスキーマについては、 を参照 https://msdn.microsoft.com/library/aa383609(v=VS.85).aspxしてください。 XML で定義されている自動メンテナンス タスクの例を次に示します。

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2011-07-01T11:34:31</Date>
    <Author>IT Deptartment</Author>
  </RegistrationInfo>
  <Principals>
    <Principal id="Author">
      <RunLevel>LeastPrivilege</RunLevel>
      <GroupId>NT AUTHORITY\SYSTEM</GroupId>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <MaintenanceSettings>
      <Period>P2D</Period>
      <Deadline>P14D</Deadline>
    </MaintenanceSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
    <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>P3D</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>cmd</Command>
      <Arguments>/c timeout -t 60</Arguments>
    </Exec>
  </Actions>
</Task> 

タスクを Windows コンピューターに保存するには、上記の XML をテキスト ファイルとして保存し、次のコマンド ラインを使用します。

Schtasks.exe /create /tn <task name> /xml <text file name>

C の使用

自動メンテナンス タスクは、C コードを使用して作成することもできます。 タスクの自動メンテナンス設定を構成するために使用できるコード サンプルを次に示します。

/********************************************************************
This sample creates a maintenance task to start cmd window during maintenance opportunities with periodicity of 2 days and deadline 0f 14 days.
********************************************************************/

#define _WIN32_DCOM

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <comdef.h>
#include <wincred.h>
//  Include the task header file.
#include <taskschd.h>
//#pragma comment(lib, "taskschd.lib")
//#pragma comment(lib, "comsupp.lib")

int __cdecl 
MainteanceTask( )
{
    //  ------------------------------------------------------
    //  Initialize COM.
    HRESULT hr;

    //  ------------------------------------------------------
    //  Create a name for the task.
    LPCWSTR wszTaskName = L"MaintenanceTask";

    ITaskService *pService = NULL;
    ITaskFolder *pRootFolder = NULL;
    ITaskDefinition *pTask = NULL;
    ITaskSettings *pSettings = NULL;
    IRegistrationInfo *pRegInfo= NULL;
    IPrincipal *pPrincipal = NULL;
    ITaskSettings3 *pSettings3 = NULL;
    IMaintenanceSettings* pMaintenanceSettings = NULL;
    IActionCollection *pActionCollection = NULL;
    IAction *pAction = NULL;
    IExecAction *pExecAction = NULL;
    IRegisteredTask *pRegisteredTask = NULL;

    wprintf(L"\nCreate Maintenance Task %ws", wszTaskName );

    hr = CoInitializeEx( NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        wprintf(L"\nCoInitializeEx failed: %x", hr );
        return 1;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity( NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);

    if( FAILED(hr) )
    {
        wprintf(L"\nCoInitializeSecurity failed: %x", hr );
        goto CleanUp;
    }

    //  ------------------------------------------------------
    //  Create an instance of the Task Service. 
    hr = CoCreateInstance( CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           IID_ITaskService,
                           (void**)&pService );  
    if (FAILED(hr))
    {
        wprintf(L"\nFailed to create an instance of ITaskService: %x", hr);
        goto CleanUp;
    }
        
    //  Connect to the task service.
    hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
    if( FAILED(hr) )
    {
        wprintf(L"\nITaskService::Connect failed: %x", hr );
        goto CleanUp;
    }

    //  ------------------------------------------------------
    //  Get the pointer to the root task folder.  This folder will hold the
    //  new task that is registered.
    hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot get Root folder pointer: %x", hr );
        goto CleanUp;
    }
    
    //  If the same task exists, remove it.
    ( void ) pRootFolder->DeleteTask( _bstr_t(wszTaskName), 0  );
    
    //  Create the task definition object to create the task.
    hr = pService->NewTask( 0, &pTask );
    if (FAILED(hr))
    {
        wprintf(L"\nFailed to CoCreate an instance of the TaskService class: %x", hr);
        goto CleanUp;
    }
        
    //  ------------------------------------------------------
    //  Get the registration info for setting the identification.
    hr = pTask->get_RegistrationInfo( &pRegInfo );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot get identification pointer: %x", hr );
        goto CleanUp;
    }
    
    hr = pRegInfo->put_Author( _bstr_t(L"Author Name") );    
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot put identification info: %x", hr );
        goto CleanUp;
    }

    // The task needs to grant explicit FRFX to LOCAL SERVICE (A;;FRFX;;;LS)
    hr = pRegInfo->put_SecurityDescriptor( _variant_t(L"D:P(A;;FA;;;BA)(A;;FA;;;SY)(A;;FRFX;;;LS)") );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot put security descriptor: %x", hr );
        goto CleanUp;
    }

    //  ------------------------------------------------------
    //  Create the principal for the task - these credentials
    //  are overwritten with the credentials passed to RegisterTaskDefinition
    hr = pTask->get_Principal( &pPrincipal );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot get principal pointer: %x", hr );
        goto CleanUp;
    }
    
    //  Set up principal logon type to interactive logon
    hr = pPrincipal->put_LogonType( TASK_LOGON_INTERACTIVE_TOKEN );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot put principal info: %x", hr );
        goto CleanUp;
    }  

    //  ------------------------------------------------------
    //  Create the settings for the task
    hr = pTask->get_Settings( &pSettings );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot get settings pointer: %x", hr );
        goto CleanUp;
    }

    hr = pSettings->QueryInterface( __uuidof(ITaskSettings3), (void**) &pSettings3 );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot query ITaskSettings3 interface: %x", hr );
        goto CleanUp;
    }

    hr = pSettings3->put_UseUnifiedSchedulingEngine( VARIANT_TRUE );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot put_UseUnifiedSchedulingEngine: %x", hr );
        goto CleanUp;
    }

    hr = pSettings3->CreateMaintenanceSettings( &pMaintenanceSettings );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot CreateMaintenanceSettings: %x", hr );
        goto CleanUp;
    }

    hr = pMaintenanceSettings->put_Period ( _bstr_t(L"P2D") );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot put_Period: %x", hr );
        goto CleanUp;
    }

    hr = pMaintenanceSettings->put_Deadline ( _bstr_t(L"P14D") );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot put_Period: %x", hr );
        goto CleanUp;
    }

    //  ------------------------------------------------------
    //  Add an action to the task. This task will execute cmd.exe.     
    //  Get the task action collection pointer.
    hr = pTask->get_Actions( &pActionCollection );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot get Task collection pointer: %x", hr );
        goto CleanUp;
    }
    
    //  Create the action, specifying that it is an executable action.
    hr = pActionCollection->Create( TASK_ACTION_EXEC, &pAction );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot create the action: %x", hr );
        goto CleanUp;
    }

    //  QI for the executable task pointer.
    hr = pAction->QueryInterface( IID_IExecAction, (void**) &pExecAction );
    if( FAILED(hr) )
    {
        wprintf(L"\nQueryInterface call failed for IExecAction: %x", hr );
        goto CleanUp;
    }

    //  Set the path of the executable to cmd.exe.
    hr = pExecAction->put_Path( _bstr_t(L"cmd") );
    if( FAILED(hr) )
    {
        wprintf(L"\nCannot put action path: %x", hr );
        goto CleanUp;
    }  
    
    //  ------------------------------------------------------
    //  Save the task in the root folder.
    hr = pRootFolder->RegisterTaskDefinition(
            _bstr_t(wszTaskName),
            pTask,
            TASK_CREATE_OR_UPDATE, 
            _variant_t(), 
            _variant_t(), 
            TASK_LOGON_INTERACTIVE_TOKEN,
            _variant_t(L""),
            &pRegisteredTask);
    if( FAILED(hr) )
    {
        wprintf(L"\nError saving the Task : %x", hr );
        goto CleanUp;
    }
    
    wprintf(L"\nSuccess!\n----------------------------------" );

CleanUp:

    if ( pService != NULL ) pService->Release();
    if ( pRootFolder != NULL ) pRootFolder->Release();
    if ( pTask != NULL ) pTask->Release();
    if ( pSettings != NULL ) pSettings->Release();
    if ( pRegInfo != NULL ) pRegInfo->Release();
    if ( pPrincipal != NULL ) pPrincipal->Release();
    if ( pSettings3 != NULL ) pSettings3->Release();
    if ( pMaintenanceSettings != NULL ) pMaintenanceSettings->Release();
    if ( pActionCollection != NULL ) pActionCollection->Release();
    if ( pAction != NULL ) pAction->Release();
    if ( pExecAction != NULL ) pExecAction->Release();
    if ( pRegisteredTask != NULL ) pRegisteredTask->Release();

    CoUninitialize();
    return SUCCEEDED ( hr ) ? 0 : 1;
}

タスクの検証

タスクが正常に作成され、メンテナンスの一環として実行されていることを確認します。

タスクの作成の検証

このコマンド ラインを使用して、タスク定義をファイルにエクスポートし、タスク定義が想定どおりに行われるようにします。

Schtasks.exe /Query /tn<task name> /xml <text file name>

タスクの実行の検証

このコマンド ラインを実行してタスクを起動し、タスク スケジューラ UI (taskschd.msc) にタスクが実行されたことを確認します。

Schtasks.exe /Run /tn<task name>

リソース