Google

2013-10-16

Permissions to access WMI remotely

Accessing WMI on a remote machine is pretty mundane for System Admins. They do not even think about it, they have Administrator rights, and it works (for the most part).

In my case, I needed to run a script with a service account and connect from one Windows 2008 R2 Server to another. I needed to figure out what permissions that account should have on the server, short of making the service account an admin. How difficult this can be? Well, it proved to be more difficult to find information on this than I thought it would be.

Here is what happens if the service (domain) account I use tries to access remote server, where it does not have any permissions:

PS> gwmi win32_ComputerSystem -ComputerName test.adilhindistan.com
gwmi : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:1 char:1
+ gwmi win32_ComputerSystem -ComputerName test.adilhindistan.com
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
I looked at several resources including venerable StackOverflow, where I have found several responses to this type of questions but none worked for my case.

There are many KB articles on the subject. This dated MSDN article claimed that you need to be admin on the target box. WMI Troubleshooting, Connecting to WMI on a Remote Computer by Using Windows PowerShell,

I asked in PowerShell Community Group chat, where Joel "Jaykul" Bennett pointed me to this article.

All of them helped, but in the end, I had to find my own solution to it:

1) Add the user to 'Distributed DCOM Users' group on the target server
2) Grant WMI permissions to user by following the steps below:

  • Launch compmgmt.msc and connect to target server
  • Right click on Services and Applications > WMI Control and select "Properties"
  • Click Root (CIMV2 did not seem to work but see update below) and then "Security"
  • Add the domain user and click on "Advanced"
  • Double click on user name
  • Change Applies to to "This namespace and subnamespaces"
  • Click on "Remote Enable" checkbox and hit "OK"
See screenshots below.



Note that I only needed read access. If you need to write or execute WMI methods, then additional checkboxes (Execute Methods, * write) will need to be added.

Update 2013-10-17:
I got an e-mail from Colyn, who had helped answering the question on StackOverflow thread asking me if  adding user to "WinRMRemoteWMIUsers__" group would work for me.

I did not have that option because that group did not exist on the server, which had PowerShell version 2. CIM cmdlets became available with PowerShell v3, so I guess that explained why.

However, I had access to another Windows 2008 R2 server with PowerShell3. Sure enough, that server had the group. the group definition says:
"Members of this group can access WMI resources over management protocols (such as WS-Management via the Windows Remote Management service). This applies only to WMI namespaces that grant access to the user."

On target server:
1) I added domain test user to  "WinRMRemoteWMIUsers__".
2) I granted both "Enable Account" & "Remote Enable" access to  Root/CIMV2 namespace

FAILURE:
Get-WMIObject call failed with the same access denied error:

PS D:\> get-wmiobject win32_ComputerSystem -Computer TEST01
gwmi : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:1 char:1
+ gwmi win32_ComputerSystem -Computer TEST01
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Similarly, Get-CimInstance with DCOM protocol fails as well

PS D:\> $cimoption = New-CimSessionOption -Protocol Dcom
PS D:\> new-cimsession -computername wstwsdcpvm001.nyumc.org -SessionOption $cimoption
new-cimsession : Access is denied.
   + FullyQualifiedErrorId : HRESULT 0x80070005,Microsoft.Management.Infrastructure .CimCmdlets.NewCimSessionCommand


SUCCESS:
But Get-CimInstance cmdlet which uses WS-MAN protocol succeeded:

PS D:\> get-ciminstance -classname win32_ComputerSystem -ComputerName TEST01

Name             PrimaryOwn Domain     TotalPhysi Model     Manufactu PSCompute
                 erName                calMemory            rer       rName
----             ---------- ------     ---------- -----     --------- ---------
TEST01    Windows...   4026064896 VMware... VMware... TEST01...

NO ALIAS PLEASE!
Here is another twist to this story. If I use the dns alias instead of actual hostname, Get-CimInstance too returned an error, but return code is different (0x80070035).

WMI SERVICE GOTCHA
Another note: if you will be playing with the WMI permissions, you may sometimes see unexpected results if you do not restart WMI service (get-service winmgmt | restart-service -force)  after making a change. For example: I wanted to test removing "Remote Enable" permission and see if I would still be able to use Get-CimInstance. To my surprise it worked for a while...until I restarted the service. Then I started to get errors (HRESULT 0x80041004). I had to add back the "Remote Enable" and restart WMI service to get it back up.

Finally, here are a couple more useful links:

2013-10-08

Detecting and Fixing Duplicate SPN

If you search internet, you will find tons of people trying to find an answer why and how a computer trust relationship is broken and as a result Windows rudely refuses to log them in.

The error message: "The security database on the server does not have a computer account for this workstation trust relationship"


Seeing the message, the first suspicion is that something is wrong with the secure channel that the computer uses to communicate with Active Directory.

I logged into the computer using a local account, launched PowerShell to check the status of Secure Channel:

PS> Test-ComputerSecureChannel
True

OK. That is not the issue then! If it had returned "False", I could have used the -repairChannel parameter to fix it (need to run that in PowerShell Admin console).

PS> Test-ComputerSecureChannel -Repair

BTW, good old 'nltest' can be used to test and reset secure channel too, as shown below, but no need to bother when you have PowerShell?

PS H:\> nltest /sc_query:adilhindistan.com
Flags: 30 HAS_IP  HAS_TIMESERV
Trusted DC Name \\MyDCName.adilhindistan.com
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully

Similarly, the following would reset it.

nltest /sc_reset:adilhindistan.com


Looking at Event logs revealed that this was related to an Service Principal Name issue:

WORKSTATION:
Log Name:      System
Source:        Microsoft-Windows-Security-Kerberos
Date:          10/7/2013 3:59:14 PM
Event ID:      3
Task Category: None
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      testcomputer.adilhindistan.com
Description:
A Kerberos Error Message was received:
on logon session 
 Client Time: 
 Server Time: 20:59:14.0000 10/7/2013 Z
Error Code: 0x7  KDC_ERR_S_PRINCIPAL_UNKNOWN
Extended Error: 0xc0000035 KLIN(0) <===== STATUS_OBJECT_NAME_COLLISION (Object Name Already Exists)
Client Realm: 
 Client Name: 
 Server Realm: adilhindistan.com
Server Name: host/testcomputer.adilhindistan.com
Target Name: host/testcomputer.adilhindistan.com@adilhindistan.com
Error Text: 
 File: 9
Line: f09
Error Data is in record data.


DOMAIN CONTROLLER:
Log Name:      System
Source:        Microsoft-Windows-Kerberos-Key-Distribution-Center
Date:          10/7/2013 3:59:14 PM
Event ID:      11
Task Category: None
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      mydc.adilhindistan.com
Description:
The KDC encountered duplicate names while processing a Kerberos authentication request. The duplicate name is host/testcomputer.adilhindistan.com (of type DS_SERVICE_PRINCIPAL_NAME). This may result in authentication failures or downgrades to NTLM. In order to prevent this from occuring remove the duplicate entries for host/testcomputer.adilhindistan.com in Active Directory.

I ran setspn command to show me the duplicate SPNs:

setspn.exe -X -P

Looked at results, yet the computername I was concerned was not listed. By the way, there is a detailed Microsoft article on SPN and setspn.exe usage here.

setspn.exe -Q HOST/testcomputer

Checking domain DC=adilhindistan,DC=com
CN=testcomputer,OU=Workstations,DC=adilhindistan,DC=com
        TERMSRV/testcomputer.adilhindistan.com
        WSMAN/testcomputer.adilhindistan.com
        RestrictedKrbHost/testcomputer.adilhindistan.com
        HOST/testcomputer.adilhindistan.com
        TERMSRV/testcomputer
        WSMAN/testcomputer
        RestrictedKrbHost/testcomputer
        HOST/testcomputer

Existing SPN found!

That showed me the current SPN and it looked right but did not help with detecting the computer that's causing the conflict. This did the trick:

setspn.exe -Q HOST/testcomputer.adilhindistan.com

Checking domain DC=adilhindistan,DC=com
CN=testcomputer1,OU=Workstations,DC=adilhindistan,DC=com
        HOST/testcomputer.adilhindistan.com
        HOST/testcomputer1

Checking domain DC=adilhindistan,DC=com
CN=testcomputer,OU=Workstations,DC=adilhindistan,DC=com
        TERMSRV/testcomputer.adilhindistan.com
        WSMAN/testcomputer.adilhindistan.com
        RestrictedKrbHost/testcomputer.adilhindistan.com
        HOST/testcomputer.adilhindistan.com
        TERMSRV/testcomputer
        WSMAN/testcomputer
        RestrictedKrbHost/testcomputer
        HOST/testcomputer

Existing SPN found!

So, 'testcomputer1' was incorrectly claiming the SPN HOST/testcomputer.adilhindistan.com and causing the issue.

While on the subject here is another link that might help in other relevant cases:
Kerberos Error Code: 0x7 KDC_ERR_S_PRINCIPAL_UNKNOWN

2013-10-05

The server is unwilling to process the request

I was working on a script that reads the information about printers on a print server and creates AD groups for each share name if it does not exist. Script is part of a process to manage shared printers for users.

So, the part of code goes like this:

try {
    New-AdGroup -Path "OU=Printers,OU=Groups,DC=XYZ,dc=org" -Name $PrinterGroupName -GroupScope DomainLocal -GroupCategory Security -Description $Description -OtherAttributes @{Info=$Comment}
    }
catch { $_ }

There is a line above that code to get all printers on the Print Server:
 Get-Printer -ComputerName $PrintServer   ## Available on Win8+
 

Then this code retrieves Printer Group Name, Printer Location as Description 'AND' a comment field out of 'Get-Printer' cmdlet results and populates relevant fields in the new group.

This code was failing to create some groups and the error message was quite unhelpful: "The server is unwilling to process the request"

I looked at the groups and realized that New-ADGroup was not happy when $comment did not include anything.

So, I added a couple of lines before try/catch block to make sure I would have something for both Active Directory Group's Description and  Notes fields to fix the issue:

$Description = $Comment = $printer.name

if ($printer.location) {

   $Description = $printer.location

}

If ($Printer.Comment) {

  $Comment = $Printer.Comment

}