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.