Scheduling a Storage Report using WMI

Starting with Windows Server 2012 FSRM uses WMI to schedule reports to run.

The following C++ example shows how to schedule a storage report using WMI.

#include "main.h"

void __cdecl wmain()
{
    MI_Result          result                 = MI_RESULT_OK;
    MI_Application     application            = MI_APPLICATION_NULL;
    MI_Session         session                = MI_SESSION_NULL;
    MI_Operation       createScheduleResult   = MI_OPERATION_NULL;
    MI_Operation       createReportResult     = MI_OPERATION_NULL;
    MI_Instance       *pSchedule              = NULL;
    MI_Instance       *pStorageReport         = NULL;
    const MI_Instance *pScheduleResult        = NULL;
    const MI_Instance *pStorageReportResult   = NULL;
    MI_Instance       *pScheduledTaskInParams = NULL;
    MI_Boolean         moreResults            = MI_TRUE;

    MI_Value           value;
    ::ZeroMemory(&value, sizeof(MI_Value));

    static const unsigned int aDaysOfTheWeek[] = {0, 6};
    static const MI_Datetime time = {1 /* is a timestamp */, {2012, 1, 1, 1, 0, 0, 0, 1}};
    static PCWSTR pwszNamespace = L"Root\\Microsoft\\Windows\\FSRM";
    static PCWSTR aNamespaces[] = {L"P:\\namespace1", L"P:\\namespace2"};

    // 1 - Large files report
    // 3 - Least recently accessed report
    static const unsigned int aReportTypes[] = {1, 3};

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    wprintf(L"\nInitializing ...\n");

    CheckResultAndExit( "MI_Application_Initialize", 
                        MI_Application_Initialize(0, NULL, NULL, &application) );

    assert( application.ft );

    CheckResultAndExit( "MI_Application_NewSession", 
                        MI_Application_NewSession(&application, NULL, NULL, NULL, NULL, NULL, &session) );

    assert( session.ft );

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    wprintf(L"\nCreating a scheduled task ...\n");

    CheckResultAndExit( "MI_Application_NewParameterSet for method to create schedule", 
                        MI_Application_NewParameterSet(&application, NULL, &pScheduledTaskInParams) );

    assert( pScheduledTaskInParams );

    // Set the day of the week to trigger the scheduled task
    // 0 - Sunday
    // 6 - Saturday
    // This means schedule will run every weekend
    value.uint32a.data = (MI_Uint32 *) aDaysOfTheWeek;
    value.uint32a.size = ARRAYSIZE(aDaysOfTheWeek);
    CheckResultAndExit( "MI_Instance_AddElement for day of the week for schedule", 
                        MI_Instance_AddElement(pScheduledTaskInParams, L"Weekly", &value, MI_UINT32A, MI_FLAG_ANY) );

    // Set the time of the day to trigger the scheduled task
    // Time stamp used is 1:00:00 AM on 1:1:2012 in UTC.
    // This means schedule will run at 1 AM on the scheduled days in UTC time.
    value.datetime = time;
    CheckResultAndExit( "MI_Instance_AddElement for time of the day for schedule", 
                        MI_Instance_AddElement(pScheduledTaskInParams, L"Time", &value, MI_DATETIME, MI_FLAG_ANY) );

    MI_Session_Invoke(&session, 
                      0, 
                      NULL, 
                      pwszNamespace, 
                      L"MSFT_FSRMScheduledTask", 
                      L"CreateScheduledTask", 
                      NULL, 
                      pScheduledTaskInParams, 
                      NULL, 
                      &createScheduleResult);

    while (moreResults == MI_TRUE)
    {
        // MI_Session_Invoke results should be obtained using 
        // MI_Operation_GetInstance until there are no more results left
        const MI_Char *errorMessage = NULL;
        CheckResultAndExit( "MI_Operation_GetInstance for schedule", 
                            MI_Operation_GetInstance(&createScheduleResult, 
                                                     &pScheduleResult, 
                                                     &moreResults, 
                                                     &result, 
                                                     &errorMessage, 
                                                     NULL) );

        if (result != MI_RESULT_OK)
        {
            fwprintf(stderr, 
                     L"MI_Session_Invoke to create a scheduled task sent back failure with MI Result = %d and error message = \n", 
                     result, 
                     errorMessage);
            goto end;
        }

        assert( pScheduleResult );

        MI_Type type;
        ::ZeroMemory(&type, sizeof(MI_Type));

        // Extract the scheduled task instance from the output using MI_Instance_GetElement
        CheckResultAndExit( "MI_Instance_GetElement", 
                            MI_Instance_GetElement(pScheduleResult, L"ScheduledTask", &value, &type, NULL, NULL) );

        assert( type == MI_INSTANCE );

        pSchedule = value.instance;
        assert( pSchedule );
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    wprintf(L"Creating a storage report ...\n");

    CheckResultAndExit( "MI_Application_NewInstance for storage report", 
                        MI_Application_NewInstance(&application, L"MSFT_FSRMStorageReport", NULL, &pStorageReport) );

    assert( pStorageReport );

    // Set name for the storage report
    value.string = L"Storage Report 1";
    CheckResultAndExit( "MI_Instance_AddElement for name", 
                        MI_Instance_AddElement(pStorageReport, L"Name", &value, MI_STRING, MI_FLAG_KEY) );

    // Set namespaces for the storage report
    value.stringa.data = (MI_Char **) aNamespaces;
    value.stringa.size = ARRAYSIZE(aNamespaces);
    CheckResultAndExit( "MI_Instance_AddElement for namespace", 
                        MI_Instance_AddElement(pStorageReport, L"Namespace", &value, MI_STRINGA, MI_FLAG_ANY) );

    // Set report types for the storage report
    value.uint32a.data = (MI_Uint32 *) aReportTypes;
    value.uint32a.size = ARRAYSIZE(aReportTypes);
    CheckResultAndExit( "MI_Instance_AddElement for report type", 
                        MI_Instance_AddElement(pStorageReport, L"ReportType", &value, MI_UINT32A, MI_FLAG_ANY) );

    // Set least accessed minimum bar to 100 days for the least recently accessed report in the storage report
    value.uint32 = 100;
    CheckResultAndExit( "MI_Instance_AddElement for least accessed minimum", 
                        MI_Instance_AddElement(pStorageReport, L"LeastAccessedMinimum", &value, MI_UINT32, MI_FLAG_ANY) );

    // Set file pattern to *.mp3 for the large files report in the storage report
    value.string = L"*.mp3";
    CheckResultAndExit( "MI_Instance_AddElement for large file pattern", 
                        MI_Instance_AddElement(pStorageReport, L"LargeFilePattern", &value, MI_STRING, MI_FLAG_ANY) );

    // Set schedule for the storage report
    value.instance = pSchedule;
    CheckResultAndExit( "MI_Instance_AddElement for schedule", 
                        MI_Instance_AddElement(pStorageReport, L"Schedule", &value, MI_INSTANCE, MI_FLAG_ANY) );

    MI_Session_CreateInstance(&session, 0, 0, pwszNamespace, pStorageReport, NULL, &createReportResult);

    moreResults = MI_TRUE;

    while (moreResults == MI_TRUE)
    {
        const MI_Char *errorMessage;

        // MI_Session_CreateInstance results should be obtained using 
        // MI_Operation_GetInstance until there are no more results left
        MI_Operation_GetInstance(&createReportResult, &pStorageReportResult, &moreResults, &result, &errorMessage, NULL);

        if (result != MI_RESULT_OK)
        {
            fwprintf(stderr, 
                     L"MI_Session_CreateInstance for storage report sent back failure with MI Result = %d and error message = \n", 
                     result, 
                     errorMessage);
            goto end;
        }
    }

end:
    if (createReportResult.ft)
    {
        CheckResult( "MI_Operation_Close for operation result", MI_Operation_Close(&createReportResult) );
        // This frees objects in the operation
    }

    if (createScheduleResult.ft)
    {
        CheckResult( "MI_Operation_Close for operation result", MI_Operation_Close(&createScheduleResult) );
        // This frees objects in the operation including pSchedule
    }

    if (pStorageReport)
    {
        CheckResult( "MI_Instance_Delete for pStorageReport", MI_Instance_Delete(pStorageReport) );
        pStorageReport = NULL;
    }

    if (pScheduledTaskInParams)
    {
        CheckResult( "MI_Instance_Delete for pScheduledTaskInParams", MI_Instance_Delete(pScheduledTaskInParams) );
        pScheduledTaskInParams = NULL;
    }

    if (session.ft)
    {
        CheckResult( "MI_Session_Close", MI_Session_Close(&session, NULL, NULL) );
    }

    if (application.ft)
    {
        CheckResult( "MI_Application_Close", MI_Application_Close(&application) );
    }

    wchar_t chTemp = L'\0';
    ::wprintf(L"\nDone.\nPress \"Enter\" to quit");
    ::wscanf_s(L"%c", &chTemp, 1);
}

This is the header named Main.h used by the example above.

#pragma once

#include <stdio.h>
#include <objbase.h>
#include <assert.h>
#include <tchar.h>
#include <crtdbg.h>

#define MI_CHAR_TYPE 2 // Maps MI_CHAR to wchar_t

#include <mi.h>

inline
bool
CheckResult(
    __in PCSTR pwszOperation, 
    __in MI_Result Result
    )
{
    if (Result != MI_RESULT_OK)
    {
        fwprintf(stderr, L"%s failed with MI Result = %d\n", pwszOperation, Result);
        return false;
    }

    return true;
}

#define CheckResultAndExit(Operation, Result) { if (!CheckResult(Operation, Result)) { goto end; } }

FSRM

MSFT_FSRMScheduledTask

CreateScheduledTask

MSFT_FSRMStorageReport

WMI

MI_Application_Close

MI_Application_Initialize

MI_Application_NewInstance

MI_Application_NewParameterSet

MI_Application_NewSession

MI_Instance_AddElement

MI_Instance_Delete

MI_Instance_GetElement

MI_Operation_Close

MI_Operation_GetInstance

MI_Session_Close

MI_Session_CreateInstance

MI_Session_Invoke