WMI Provider EvtWmiInstanceSetInstance not called if class has string members

I had a WMI provider class working fine with user space such that it could read and write members of the provider class. I then needed to add a couple members of type string. Once I added these new members to the class my EvtWmiInstanceQueryInstance callback still works fine, but my EvtWmiInstanceSetInstance callback doesn’t get called any more. If I set a breakpoint on the call to this callback it never gets hit.

What would cause this behavior? And better yet, how do I resolve it?

Here’s how I’m attempting to modify my WMI object:

$ci = get-ciminstance My_WMIClass -Namespace "root/wmi"

$ci.NormalMember= 10
Set-CimInstance -CimInstance $ci -PassThru

This works just fine if my class doesn’t have any members of type string. When I add a string member I get the following error when I call Set-CimInstance -CimInstance $ci -PassThru:

Set-CimInstance : Generic failure 
At line:5 char:1
+ Set-CimInstance -CimInstance $ci -PassThru
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (My_WMIClass...5&7047288&8...):CimInstance) [Set-CimInsta 
   nce], CimException
    + FullyQualifiedErrorId : HRESULT 0x80041001,Microsoft.Management.Infrastructure.CimCmdlets.SetCimIns 
   tanceCommand

How are you providing the string data to WMI ?

See: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdfwmi/nf-wdfwmi-wdf_wmi_buffer_append_string.

My query call is working fine. The strings have the read attribute set in the .mof like so:

    [WmiDataId(8),
     read,
     Description("Description"),
     MaxLen(511)]
    string Description;

I can set my description in my driver and read it in PowerShell with this command just fine:

get-ciminstance My_WMIClass -Namespace "root/wmi"

The problem I’m facing now is that I can’t write to ANY members of my class. For example I have another member defined in the .mof as:

    [WmiDataId(4),
     read,
     write,
     Description("Scratch value to practice reading and writing")]
    uint32 scratch;

If I don’t add Description to my class I can read/write scratch from PowerShell just fine. If I add Description to my class I can read scratch fine, but I can no longer write a new scratch value. It results in the error I have shown in my previous post.

From my understanding, if your WMI class contains a read-only item, then you will have to set a single item everytime, when modifying a field, instead of setting the entire instance.

Please setup a EvtWmiInstanceSetItem function and try again.

I have other read only items in the class that are of type uint32 and I am still able to set the entire instance. It’s only since I added the string members that things fell apart. I suppose I can try that though.

Any idea how to set a single item from PowerShell? No matter what I do it seems to call the EvtWmiInstanceSetInstance callback.

You might want to share some code that is related to your issue, otherwise it is going to be like your last post in March asking about the same issue.
It is a problem with your code (obviously). We can’t do anything without knowing even the most basics parts of your wmi config structure setup.

https://community.osr.com/discussion/291918/use-powershell-to-call-wmi-evtwmiinstancesetitem

Here’s the .mof

#PRAGMA AUTORECOVER

[WMI,
 Dynamic,
 Provider("WmiProv"),
 Locale("MS\\0x409"),
 Description("My WMI Class with confidential info removed") : amended,
 guid("82DE1B9F-C0EC-4BA4-B81E-D6B9C9EDD2D3")]
class My_WMIClass 
{
    [key, read]
    string InstanceName;

    [read]
    boolean Active;

    [WmiDataId(1),
     read,
     write,
     Description("R/W integer values")]
    uint32 NormalMember;

    [WmiDataId(2),
     read,
     Description("Description"),
     MaxLen(511)]
    string Description;
};

Here’s the header:

// WMI method
#define My_WMIClass _GUID)\
    { 0x82de1b9f,0xc0ec,0x4ba4, { 0xb8,0x1e,0xd6,0xb9,0xc9,0xed,0xd2,0xd3 } }

#if ! (defined(MIDL_PASS))
DEFINE_GUID(My_WMIClass _GUID), \
   0x82de1b9f, 0xc0ec, 0x4ba4, 0xb8, 0x1e, 0xd6, 0xb9, 0xc9, 0xed, 0xd2, 0xd3);
#endif

typedef struct _My_WMIClass
{
   // Normal integer member
   ULONG NormalMember;
#define My_WMIClass_NormalMember_SIZE sizeof(ULONG)
#define My_WMIClass_NormalMember_ID 1

   // Description
   WCHAR Description[511 + 1];
#define My_WMIClass_Description_ID 2
}My_WMIClass, *PMy_WMIClass;

#define My_WMIClass_SIZE (FIELD_OFFSET(My_WMIClass, NormalMember) + sizeof(WCHAR)*512)
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(My_WMIClass, MyWmiGetData);

Here’s the registration:

NTSTATUS register_wmi_provider(
   _In_ WDFDEVICE device
)
{
   NTSTATUS status;
   WDF_OBJECT_ATTRIBUTES woa;
   WDF_WMI_PROVIDER_CONFIG providerConfig;
   WDF_WMI_INSTANCE_CONFIG instanceConfig;
   DECLARE_CONST_UNICODE_STRING(mofResourceName, MOFRESOURCENAME);

   PAGED_CODE();
   
   //
   // Register the MOF resource names of any customized WMI data providers
   // that are not defined in wmicore.mof.
   //
   status = WdfDeviceAssignMofResourceName(device, &mofResourceName);
   if (!NT_SUCCESS(status)) {
      TraceEvents(TRACE_LEVEL_ERROR, TRACE_WMI,
         "WdfDeviceAssignMofResourceName failed 0x%x", status);
      return status;
   }

   WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, &My_WMIClass_GUID);
   providerConfig.MinInstanceBufferSize = My_WMIClass_SIZE;

   WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig);
   instanceConfig.Register = TRUE;
   instanceConfig.EvtWmiInstanceQueryInstance = wmi_instance_query;
   instanceConfig.EvtWmiInstanceSetInstance = wmi_instance_set;
   instanceConfig.EvtWmiInstanceSetItem = wmi_item_set;

   WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&woa, My_WMIClass );

   //
   // No need to get the newly created handle because we just reference data
   // from our device extension directly.
   //
   status = WdfWmiInstanceCreate(device,
      &instanceConfig,
      &woa,
      WDF_NO_HANDLE);
   if (!NT_SUCCESS(status)) {
      TraceEvents(TRACE_LEVEL_ERROR, TRACE_WMI,
         "WdfWmiInstanceCreate failed 0x%x", status);
      return status;
   }

   return status;
}

If I remove the Description property, the following PowerShell works:

$x = get-ciminstance MY_WMIClass -Namespace "root/wmi"

$x.NormalMember = 42
Set-CimInstance -CimInstance $x -PassThru

As stated previously, as soon as I add the Description property any attempt to update the instance fails. I have tried changing providerConfig.MinInstanceBufferSize and that doesn’t change the observed behavior.

I still haven’t figured out how to use PowerShell such that it calls my EvtWmiInstanceSetItem callback.

Have you tried playing with the Toaster and WMI? It has read/write members with descriptions. If you get the same problems there you’ll at least know it’s not you.

https://github.com/microsoft/Windows-driver-samples/tree/master/general/toaster/toastDrv/kmdf/func/featured