Question:
I can’t seem to be able to set WMI ACLs via Powershell. An invocation of
1 2 |
Invoke-WmiMethod -Name "SetSecurityDescriptor" -Path "__systemsecurity=@" -ArgumentList $acl.psobject.immediateBaseObject |
returns this exception:
1 2 3 4 5 6 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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:
1 2 |
$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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# 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 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. |
Answer:
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:
1 2 3 4 5 6 |
$invokeparams = @{Namespace=$namespace;Path="__systemsecurity=@"} $setparams = @{Name="SetSecurityDescriptor";ArgumentList=$acl.psobject.immediateBaseObject} + $invokeParams $output = Invoke-WmiMethod @setparams |
Source:
Setting WMI ACLs via SetSecurityDescriptor by stackoverflow.com licensed under CC BY-SA | With most appropriate answer!
"}
$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.
Answer:
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:
1 |