Scripting WMI Namespace Security (part 2 of 3)

In the first part of this series, we discussed what WMI
namespace security was and why it is something you would want to change.For
this blog post, I’ll show a Powershell script for retrieving the current
security descriptor of a WMI namespace.Note that everything I’m doing in the Powershell script can be done in
vbscript, but I’ll leave that as an exercise to the reader.Here’s the entire script.I’ll discuss the various sections to explain
why I did something.Note that this is
not intended to be a discussion about Powershell, so I’m focusing on the WMI
specific parts.

Internally, all OS Security Descriptors, ACLs, ACEs, etc…
are just represented by numbers.I would
not expect that an admin would remember that the Remote Enable permission has
the numerical value of 0x20 (decimal 32).So the internal function Get-PermssionFromAccessMask was created to
translate the “magic numbers” into human readable form.

Here I store all the numerical values into descriptive
variables.If you’re wondering where I
got these values from, they are from wbemcli.h and winnt.h (for the last two
related to permissions for reading and writing to the ACL).

Function
Get-PermissionFromAccessMask($accessMask) {

$WBEM_ENABLE= 1

$WBEM_METHOD_EXECUTE= 2

$WBEM_FULL_WRITE_REP= 4

$WBEM_PARTIAL_WRITE_REP= 8

$WBEM_WRITE_PROVIDER= 0x10

$WBEM_REMOTE_ACCESS= 0x20

$READ_CONTROL = 0x20000

$WRITE_DAC = 0x40000

Next, I store the values and text representations in
arrays.Each element maps to the
corresponding index of the other.I can
then simply see which permissions are included in the access mask and create a
new array that contains the text of the permission.

The next section takes advantage of Powershell 2.0 splatting
so I can store commonly used parameters in a single variable.In this script, I don’t reuse the parameters,
but I tend to make it a habit.If
credentials were not specified I don’t want the credential prompt to come up
since this script can be used locally or remotely.

Finally, I want to output the result as an object, not
simply as text so that it can be piped to another cmdlet for further
processing.So I do the actual call to
__SystemSecurity::GetSecurityDescriptor() and get back a
Win32_SecurityDescriptor (checking the ReturnValue first).I walk through each ACE (Access Control
Entry) and store the username, permission set, and whether it’s inherited into
my new object, then I send that object to the pipeline.

$output = Invoke-WmiMethod @invokeparams
@credparams

if ($output.ReturnValue -ne 0) {

throw "GetSecurityDescriptor
failed: $($output.ReturnValue)"

}

$acl = $output.Descriptor

foreach ($ace in $acl.DACL) {

$user = New-Object
System.Management.Automation.PSObject

$user | Add-Member -MemberType
NoteProperty -Name "Name" `

-Value
"$($ace.Trustee.Domain)\$($ace.Trustee.Name)"

$user | Add-Member -MemberType
NoteProperty -Name "Permission" `

-Value
(Get-PermissionFromAccessMask($ace.AccessMask))

$user | Add-Member -MemberType
NoteProperty -Name "Inherited" `

-Value (($ace.AceFlags -band
$INHERITED_ACE_FLAG) -gt 0)

$user

}

Next time, we’ll look at setting namespace security which is
a bit more complicated.

Ok, I found a W2k8R2 VHD and I copied and pasted the text from above to 'test.ps1' and ran it in PowerShell and it worked for me. $PSVersionTable.PSVersion tells me I'm running PowerShell 2.0. What version of PowerShell are you running?

Steve, These scripts (Get & Set) works perfectly locally on a server; however I'm getting errors when attempting to use this script to get (and, i assume Set) the security descriptor from a remote system (Testing from 2008R2 to 2008R2). The script works fine when run locally on each of the test boxes, but not when running from one to the other.

I think you've missed something when updating this post. In the first block you add 10 values to the $WBEM_RIGHTS_FLAGS, but only define 8 actual flags. This will produce an error due to the 2 missing variable definitions.

In the later block you define 8 values in $WBEM_RIGHTS_FLAGS and 8 flags. This block will work.