I'm adding WMI publishing to a .net framework 3.5 based windows service that is running under the 'network service' account.
According to a document I came across on MSDN, the 'network service' account should by default have WMI publishing permissions. ("By default, the following users and groups are allowed to publish data and events: ... Network Service, ...")
However, when the service calls Instrumentation.Publish(myStatusClassInstance), it throws a DirectoryNotFoundException;
System.IO.DirectoryNotFoundException was unhandled
Message: Could not find a part of the path 'C:\Windows\system32\WBEM\Framework\root\MyWMINamespace\MyService_SN__Version_1.0.3686.26280.cs'.
..so it looks like System.Management.Instrumentation tries to generate code on the fly, and when running under network service it targets a directory where network service has no permissions.
What is the best fix/workaround for this? Can I override the code-gen target dir in app.config or in code? I don't want to have to fiddle around with file system permissions when deploying the service...
Update: I think this is a 'feature' where older FX code clashes with newer security settings in Win7. Internally the WMI managed classes retrieves the WMI installation directory from registry, and uses that as the output path for generated code. Unfortunately a lot of users are not allowed to (or supposed to) write stuff under %SystemRoot%... ...I filed a connect bug (#530392) to see if MSFT can bring any clarity and/or provide a fix or workaround.
Update 2: I'm guessing that for normal user accounts this is not an issue, because UAC virtualization will kick in and store the files elsewhere. However, apparently the 'network service' account is not covered by UAC virtualization..(?)
Update 3: Added 550pt bounty. Simple constraints: .net framework 3.5 based windows service, running as network service, need to be able to publish data through WMI using System.Management.Instrumentation on Win7 and Win2008[RTM & R2] with default permissions/security settings and without resorting to modifying framework internal/private members using reflection. 'Out-of-the-box' but clean solutions welcome. Will open a second related bounty-Q as a placeholder for another 550pt if SO allows.
Bounty update: I intend to double the bounty for this Q through a second hand-in-hand question that will serve as a bounty placeholder:
https://stackoverflow.com/questions/2208341/bounty-placeholder ( <-- Apparently this was not allowed, so the bounty placeholder question got closed by the SO etiquette police.)
Update 4: This gets better and better. I noticed that installutil was writing the missing files to c:\windows\syswow64...etc..., so I realized that I was using the 32-bit version of installutil to install the service, but the service was running as a 64-bit process. The obvious side effect was that code generated when installutil was running ended up under syswow64 (the 32-bit system directory), while the service was looking for it under the 64-bit system directory (system32). (<-- off topic, but I really like how MSFT managed to switch around the names there... :) ).
So I tried installing the service with the 64-bit version of installutil. That failed miserably with permission errors in the %sysroot%\wbem\framework...etc... path. Next I recompiled the service as x86 and registered it again using the 32-bit version of installutil. That resulted in an entirely new exception:
System.Exception: The code generated for the instrumented assembly failed to compile.
at System.Management.Instrumentation.InstrumentedAssembly..ctor(Assembly assembly, SchemaNaming naming)
at System.Management.Instrumentation.Instrumentation.Initialize(Assembly assembly)
at System.Management.Instrumentation.Instrumentation.GetInstrumentedAssembly(Assembly assembly)
at System.Management.Instrumentation.Instrumentation.GetPublishFunction(Type type)
at System.Management.Instrumentation.Instrumentation.Publish(Object instanceData)
at SomeService.InstanceClass.PublishApp(String name) in e:\work\clientname\SomeService\SomeService\WMIProvider.cs:line 44
at SomeService.SomeServiceService..ctor() in e:\work\clientname\SomeService\SomeService\SomeServiceService.cs:line 26
at SomeService.Program.Main() in e:\work\clientname\SomeService\SomeService\Program.cs:line 17
...getting closer...