I can't seem to be able to set WMI ACLs via Powershell. An invocation of
Invoke-WmiMethod -Name "SetSecurityDescriptor" -Path "__systemsecurity=@" -ArgumentList $acl.psobject.immediateBaseObject
returns this exception:
Invoke-WmiMethod : Invalid method Parameter(s)
At line:1 char:17.
+ Invoke-WmiMethod <<<< -Name "SetSecurityDescriptor" -Path "__systemsecurity=@" -ArgumentList $acl.psobject.immediateBaseObject
+ CategoryInfo : InvalidOperation: (:) [Invoke-WmiMethod], ManagementException
+ FullyQualifiedErrorId : InvokeWMIManagementException,Microsoft.PowerShell.Commands.InvokeWmiMethod
SetSecurityDescriptor takes exactly one parameter of the __SecurityDescriptor type and the $acl
object itself I am using in -Arguments
seems alright:
PS C:\Windows\system32> $acl | gm
TypeName: System.Management.ManagementBaseObject#\__SecurityDescriptor
Name MemberType Definition
---- ---------- ----------
ControlFlags Property System.UInt32 ControlFlags {get;set;}
DACL Property System.Management.ManagementObject#__ACE[] DACL ...
Group Property System.Management.ManagementObject#__ACE Group {...
Owner Property System.Management.ManagementObject#__ACE Owner {...
SACL Property System.Management.ManagementObject#__ACE[] SACL ...
TIME_CREATED Property System.UInt64 TIME_CREATED {get;set;}
__CLASS Property System.String __CLASS {get;set;}
__DERIVATION Property System.String[] __DERIVATION {get;set;}
__DYNASTY Property System.String __DYNASTY {get;set;}
__GENUS Property System.Int32 __GENUS {get;set;}
__NAMESPACE Property System.String __NAMESPACE {get;set;}
__PATH Property System.String __PATH {get;set;}
__PROPERTY_COUNT Property System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH Property System.String __RELPATH {get;set;}
__SERVER Property System.String __SERVER {get;set;}
__SUPERCLASS Property System.String __SUPERCLASS {get;set;}
From what I can get off the docs, I am invoking the Parameter Set: path
overload, so the parameter set seems not to be missing required arguments.
I am basically ripping the code off this MSDN blog post on the very same topic and while GetSecurityDescriptor using a similar invocation gives the desired results:
$output = Invoke-WmiMethod -Path "__systemsecurity=@" -Name GetSecurityDescriptor
the SetSecurityDescriptor keeps throwing exceptions on me. How do I get it working?
The code in context, for reference:
# connect to SystemSecurity
$invokeparams = @{Path="__systemsecurity=@"}
# get SecurityDescriptor with ACL
$output = Invoke-WmiMethod @invokeparams -Name GetSecurityDescriptor
if ($output.ReturnValue -ne 0) {
throw "GetSecurityDescriptor failed: $($output.ReturnValue)"
}
# ACL object reference is in the .Descriptor property
$acl = $output.Descriptor
$ace = (New-Object System.Management.ManagementClass("win32_Ace")).CreateInstance()
# AccessMask is WBEM_ENABLE, $WBEM_METHOD_EXECUTE, $WBEM_WRITE_PROVIDER, $WBEM_REMOTE_ACCESS
$ace.AccessMask = 1 + 2 + 0x10 + 0x20
# AceFlags are $OBJECT_INHERIT_ACE_FLAG, $CONTAINER_INHERIT_ACE_FLAG
$ace.AceFlags = 0x01 + 0x2
# AceType is ACCESS_ALLOWED_ACE_TYPE
$ace.AceType = 0x1
# get user SID
$getparams = @{Class="Win32_Account";Filter="Domain='MYDOMAIN' and Name='SERVER$'"}
$win32account = Get-WmiObject @getparams
# and build a new Trustee object
$trustee = (New-Object System.Management.ManagementClass("win32_Trustee")).CreateInstance()
$trustee.SidString = $win32account.Sid
$ace.Trustee = $trustee
# Add ACE to ACL
$acl.DACL += $ace.psobject.immediateBaseObject
# apply new ACL
$setparams = @{Name="SetSecurityDescriptor";ArgumentList=$acl.psobject.immediateBaseObject} + $invokeParams
$output = Invoke-WmiMethod @setparams
if ($output.ReturnValue -ne 0) {
throw "SetSecurityDescriptor failed: $($output.ReturnValue)"
}
I also already have tried playing with the .AceFlags property as suggested in comments to the aforementioned blog post by Steve Lee - to no avail.
In the article you refer to the call is different and those differences could well be important - the params are a single hashtable built up to include all the params as name/value pairs:
$invokeparams = @{Namespace=$namespace;Path="__systemsecurity=@"}
$setparams = @{Name="SetSecurityDescriptor";ArgumentList=$acl.psobject.immediateBaseObject} + $invokeParams
$output = Invoke-WmiMethod @setparams
I got this to work by changing the this line
# AceFlags are $OBJECT_INHERIT_ACE_FLAG, $CONTAINER_INHERIT_ACE_FLAG
$ace.AceFlags = 0x01 + 0x2
to
# AceFlags are $CONTAINER_INHERIT_ACE_FLAG
$ace.AceFlags = 0x2
I wish I could tell you why this change is necessary, but I don't really know. I also changed the invokeparams to equal @{Path="__systemsecurity=@"; Namespace="root"} so that the script sets the permissions at the root level instead of the cimv2 level. The permission seems to be inherited as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With