Recently I was asked to create an inventory process that would query active directory for servers and gather data on their hardware.
I said “No problem”, fired up my trusty domain admin account and ran a bunch of WMI calls against the servers. Of course, for a script that is to be run on a daily basis, a domain admin is NOT the account of choice.
So, I needed to create a domain user account that could access WMI on all the servers.
Additionally, on a certain percentage of remote servers, my domain admin account was getting an error that I traced to DCOM not allowing access. When I cleared that up, using dcomcnfg, I realized the domain user would also need remote DCOM privileges.
So, my problem was two-fold:
1) Allow remote WMI for a domain user.
2) Allow remote DCOM for a domain user.
I thought I was going to have to modify the firewalls on my servers, but that was already done when they were built.
We have 557 Windows servers in the department, so I wasn’t about to do this by hand.
Of those 557 servers, only 56 are Server 2008 or newer. Now I had a third criteria:
3) My script needs to work against Server 2000, 2003, 2008, 2008 R2
I did some searching, and asked around, and wasn’t getting very far – starting to get desperate, I enabled remote DCOM on a test machine, found out what registry keys it changed, and thought I’d use this:
(From Shay Levi’s "Stand alone registry functions library")
This has problems though – If the target server had other than default DCOM permissions I’d overwrite them.
For the second part of the problem, enabling remote WMI, I thought I found a solution on this blog:
https://blogs.msdn.com/wmi/archive/2009/07/27/scripting-wmi-namespace-security-part-3-of-3.aspx – I mean how perfect, “Scripting WMI Namespace Security” right?
Well, it turns out that I needed to read this on Part 1 of his post: “In each namespace, there is a singleton instance that controls namespace security: __SystemSecurity=@. It exposes several methods, but in this case, we are only interested in two (available on Vista+): GetSecurityDescriptor and SetSecurityDescriptor. On older systems, these two methods are not available and you would have to use GetSD and SetSD which work on SECURITY_DESCRIPTOR structs represented as binary arrays. Discussion on how to use those methods (which is only really possible with C/C++) is outside of the scope of this blog post.”
Wow – Bummer. But, I don’t give up easily. So, off to Bing some more. I DID find a C# project on “The Code Project” called WMI Namespace Security, (http://www.codeproject.com/KB/system/WmiSecurity.aspx) and when I downloaded and compiled it, it granted the permissions I needed. However, the groups that own the servers wanted a script, not a compiled program. They wanted to see what the script was doing, and besides, I wanted to do it in PowerShell!
But, between Steve Lee’s blog on Scripting WMI Namespace Security, and J_Madden’s C# program, I had some clues.
I searched the web for information and found this:
Close, but I don’t want to add the built in users group.
I searched for a method to retrieve a SID and found Adam Bell’s excellent script on:
Now I have a SID, I know what registry value I need to modify for the DCOM permissions, and what I have to do to set WMI permissions, so I need to read and write registry values. I could have continued to use Shay’s excellent functions from above, but found this page:
OK, I’m starting to tie it all together, and have a working script in 31 lines of PowerShell: