32

I'm writing a monitoring service that uses WMI to get information from remote machines. Having local admin rights on all these machines is not possible for political reasons.

Is this possible? What permissions/rights does my user require for this?

31

The following works on Window 2003 R2 SP 2, Windows Server 2012 R2

  1. Add the user(s) in question to the Performance Monitor Users group
  2. Under Services and Applications, bring up the properties dialog of WMI Control (or run wmimgmt.msc). In the Security tab, highlight Root/CIMV2, click Security; add Performance Monitor Users and enable the options : Enable Account and Remote Enable
  3. Run dcomcnfg. At Component Services > Computers > My Computer, in the COM security tab of the Properties dialog click "Edit Limits" for both Access Permissions and Launch and Activation Permissions. Add Performance Monitor Users and allow remote access, remote launch, and remote activation.
  4. Select Windows Management Instrumentation under Component Services > Computers > My Computer > DCOM Config and give Remote Launch and Remote Activation privileges to Performance Monitor Users Group.

Notes:

  • As an alternatively to step 3 and 4, one can assign the user to the group Distributed COM Users (Tested on Windows Server 2012 R2)
  • If the user needs access to all the namespaces, you can set the settings in 2. at the Root level, and recurse the permissions to the sub-namespaces via the Advanced window in Security
  • 1
    I've found steps 2 and 3 aren't necessary if you add the user to Distributed COM Users. – Nexus Feb 12 '10 at 0:53
  • Working on WinXP and Win7, I was not able to add the "Distributed COM Users" group - maybe this group is only accessible on servers? It would not resolve during name lookup when trying to add to the permissions. Also, I found that I had to set permissions for WMI on "Root" as well as "Root/CIMV2" and that I had to go into advanced permissions and apply the permission for the subnamespaces as well as the namespace. – Shannon Wagner Aug 3 '12 at 20:26
  • Works also for Windows 8! Also, does somebody know how to do the same from powershell or some other shell? – Bunyk Mar 24 '14 at 9:02
  • 1
    In the case that you want a user to be able to access all the namespace, you can grant the permission to Root and all the sub-namespaces by selecting Root, opening Security then Advanced and setting up the recursion. By default these settings apply only to the selected object and do not cascade. – Thomas Aug 22 '14 at 20:23
  • that doesn't work for MSCluster namespace – John Jan 13 '16 at 8:52
4

All I did on Windows 8 was added user to group "Remote Management Users", and remote WQL requests worked.

1

By default, only the local Administrators group has remote permissions to WMI. You will have to customise the WMI "Remote Enable" permissions.

1

You may also have to grant "DCOM remote access permissions" and/or "DCOM remote launch and activation permissions" depending on what exactly you are trying to do. This MSDN article gives the step-by-step procedures.

0

The following worked for me in a 2012 r2 domain environment although I only managed to do it per server and not the entire domain:

1) Add user to Performance Log Users Group. 2) Run wmimgmt.msc, right click "WMI Control (LOCAL), goto Security tab and grant the appropriate user "Enable Account" and "Remote Enable" on the desired namespace (usualy CIMV2).

If I manage to get it done for the entire domain I'll come back and update.

0

Based on the chosen answer, I modified the script from Microsoft to set the WMI security. My test user was a non-administrative domain user who was a member of the "Remote Management Users" on the local system for reasons not related to this issue. After granting my user the EnableAccount, RemoteEnable, and ExecuteMethods permissions on the target namespace, I was able to access WMI.

So, I did not add my user to the Performance Monitor Users or Distributed COM Users local groups.

A couple of notes regarding the script:

  1. You must specify the full path of the namespace. In my case, the namespace was Root/Microsoft/SqlServer
  2. Inheritance was wrong. Because there are no leaf objects you can't use $OBJECT_INHERIT_ACE_FLAG
  3. I got rid of the embedded function because it was too small and it was only used once.

The script is below. I named it Set-WMINamespaceSsecurity.ps1

Param ([Parameter(Mandatory=$true,Position=0)] [string]$Namespace,
       [Parameter(Mandatory=$true,Position=1)] [ValidateSet("Add","Remove")] [string]$Operation,
       [Parameter(Mandatory=$true,Position=2)] [string] $Account,
       [Parameter(Mandatory=$false,Position=3)] [ValidateSet("EnableAccount","ExecuteMethods","FullWrite","PartialWrite","ProviderWrite","RemoteEnable","ReadSecurity","WriteSecurity")] [string[]] $Permissions=$null,
       [Parameter(Mandatory=$false)] [switch]$AllowInherit,
       [Parameter(Mandatory=$false)] [switch]$Deny,
       [Parameter(Mandatory=$false)] [string]$ComputerName=".",
       [Parameter(Mandatory=$false)] [System.Management.Automation.PSCredential]$Credential=$null)

$OBJECT_INHERIT_ACE_FLAG    = 0x1
$CONTAINER_INHERIT_ACE_FLAG = 0x2
$ACCESS_ALLOWED_ACE_TYPE    = 0x0
$ACCESS_DENIED_ACE_TYPE     = 0x1

$WBEM_ENABLE            = 0x01
$WBEM_METHOD_EXECUTE    = 0x02
$WBEM_FULL_WRITE_REP    = 0x04
$WBEM_PARTIAL_WRITE_REP = 0x08
$WBEM_WRITE_PROVIDER    = 0x10
$WBEM_REMOTE_ACCESS     = 0x20
$WBEM_RIGHT_SUBSCRIBE   = 0x40
$WBEM_RIGHT_PUBLISH     = 0x80
$READ_CONTROL           = 0x20000
$WRITE_DAC              = 0x40000
$WBEM_S_SUBJECT_TO_SDS  = 0x43003

$ErrorActionPreference = "Stop"

$InvokeParams=@{Namespace=$Namespace;Path="__systemsecurity=@";ComputerName=$ComputerName}
if ($PSBoundParameters.ContainsKey("Credential")) { $InvokeParams+= @{Credential=$Credential}}

$output = Invoke-WmiMethod @InvokeParams -Name "GetSecurityDescriptor"
if ($output.ReturnValue -ne 0) { throw "GetSecurityDescriptor failed:  $($output.ReturnValue)" }

$ACL = $output.Descriptor

if ($Account.Contains('\')) {
  $Domain=$Account.Split('\')[0]
  if (($Domain -eq ".") -or ($Domain -eq "BUILTIN")) { $Domain = $ComputerName }
  $AccountName=$Account.Split('\')[1]
}
elseif ($Account.Contains('@')) {
  $Somain=$Account.Split('@')[1].Split('.')[0]
  $AccountName=$Account.Split('@')[0]
}
else {
  $Domain = $ComputerName
  $AccountName = $Account
}

$GetParams = @{Class="Win32_Account" ;Filter="Domain='$Domain' and Name='$AccountName'"}
$Win32Account = Get-WmiObject @GetParams
if ($Win32Account -eq $null) { throw "Account was not found: $Account" }

# Add Operation
if ($Operation -eq "Add") {
  if ($Permissions -eq $null) { throw "Permissions must be specified for an add operation" }

  # Construct AccessMask
  $AccessMask=0
  $WBEM_RIGHTS_FLAGS=$WBEM_ENABLE,$WBEM_METHOD_EXECUTE,$WBEM_FULL_WRITE_REP,$WBEM_PARTIAL_WRITE_REP,$WBEM_WRITE_PROVIDER,$WBEM_REMOTE_ACCESS,$READ_CONTROL,$WRITE_DAC
  $WBEM_RIGHTS_STRINGS="EnableAccount","ExecuteMethods","FullWrite","PartialWrite","ProviderWrite","RemoteEnable","ReadSecurity","WriteSecurity"
  $PermissionTable=@{}
  for ($i=0; $i -lt $WBEM_RIGHTS_FLAGS.Count; $i++) { $PermissionTable.Add($WBEM_RIGHTS_STRINGS[$i].ToLower(), $WBEM_RIGHTS_FLAGS[$i]) }
  foreach ($Permission in $Permissions) { $AccessMask+=$PermissionTable[$Permission.ToLower()] }

  $ACE=(New-Object System.Management.ManagementClass("Win32_Ace")).CreateInstance()
  $ACE.AccessMask=$AccessMask
  # Do not use $OBJECT_INHERIT_ACE_FLAG.  There are no leaf objects here.
  if ($AllowInherit.IsPresent) { $ACE.AceFlags=$CONTAINER_INHERIT_ACE_FLAG }
  else { $ACE.AceFlags=0 }

  $Trustee=(New-Object System.Management.ManagementClass("Win32_Trustee")).CreateInstance()
  $Trustee.SidString = $Win32Account.SID
  $ACE.Trustee=$Trustee

  if ($Deny.IsPresent) { $ACE.AceType = $ACCESS_DENIED_ACE_TYPE } else { $ACE.AceType = $ACCESS_ALLOWED_ACE_TYPE }
  $ACL.DACL+=$ACE
}
#Remove Operation
else {
  if ($Permissions -ne $null) { Write-Warning "Permissions are ignored for a remove operation" }
  [System.Management.ManagementBaseObject[]]$newDACL = @()
  foreach ($ACE in $ACL.DACL) {
    if ($ACE.Trustee.SidString -ne $Win32Account.SID) { $newDACL+=$ACE }
  }
  $ACL.DACL = $newDACL
}

$SetParams=@{Name="SetSecurityDescriptor"; ArgumentList=$ACL}+$InvokeParams

$output = Invoke-WmiMethod @SetParams
if ($output.ReturnValue -ne 0) { throw "SetSecurityDescriptor failed: $($output.ReturnValue)" }
-1

We did this for PRTG: We created a new domain user: Created a GPO Dit to put his user in the group "Performnce Log Users" and used a powershell script to add this user to WMI Control. thanks to:

https://live.paloaltonetworks.com/t5/Management-Articles/PowerShell-Script-for-setting-WMI-Permissions-for-User-ID/ta-p/53646

  • Please include relevant information directly in your answers. Answers posted should be able to stand alone, and just use links for reference. – Cory Knutson Jun 2 '17 at 18:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.