My Entry for the Advanced Event #4 of the 2013 Scripting Games

by Ryan 21. May 2013 12:35

We're on the downhill stretch now. Honestly I'm kind of glad.  These scripts are fun to write, and great practice, but it's work.  I can tell that I'm not the only one loosing steam, as the number of votes on other people's entries has gone way down.  Anyway, about the script I wrote: I like that the #Requires -Modules statement at the top automatically loads the AD module for you if it's not already loaded. I still didn't do the BEGIN/PROCESS/END blocks this time either, which I fail to see how it matters at all, since I'm not dealing with pipeline input... but I'm sure I'll still get crowd scores of 1 and 2 stars for it.  That and dudes with 640x480 monitors going "some of your code goes off the screen why don't you splat!?"  :P

#Requires -Version 3
#Requires -Modules ActiveDirectory
Function Get-RandomADUser
{
<#
.SYNOPSIS
    Retrieves random users from Active Directory and generates an HTML report.
.DESCRIPTION
    Retrieves random users from Active Directory, generates an HTML report,
    and then returns the users to the pipeline. 
    Use the -Verbose switch if you want to see console output.
    This Cmdlet requires PS 3 and the Active Directory module. The AD module
    will be loaded automatically if it isn't already.
.PARAMETER Count
    The number of random users to get from Active Directory. Minimum is 1,
    maximum is Int16.MaxValue (32767) and the default is 20.
.PARAMETER Filename
    The filename to write the HTML report to. The filename must end in
    html or htm. The default is .\RandomADUsers.html.
.EXAMPLE
    Get-RandomADUser
 
    Gets 20 random users from AD, outputs a report to .\RandomADUsers.html.
.EXAMPLE
    Get-RandomADUser -Count 100 -Filename C:\reports\rpt.html.
 
    Gets 100 random users from AD, outputs a report to C:\reports\rpt.html.
#>
 
    [CmdletBinding()]
    Param([Parameter()]
            [ValidateRange(1, [Int16]::MaxValue)]
            [Int16]$Count = 20,
          [Parameter()]
            [ValidateScript({($_.ToLower().Split('.')[-1] -EQ "html" -OR $_.ToLower().Split('.')[-1] -EQ "htm") -AND (Test-Path -IsValid $_)})]
            [String]$Filename = ".\RandomADUsers.html") 
 
    Try
    {
        Write-Verbose "Retrieving users from Active Directory..."
        $Users = Get-ADUser -Filter * -Properties Department, Title, LastLogonDate, PasswordLastSet, Enabled, LockedOut -ErrorAction Stop | Get-Random -Count $Count
        Write-Verbose "$($Users.Count) users retrieved from Active Directory."
    }
    Catch
    {
        Write-Error "Unable to retrieve users from Active Directory: $($_.Exception.Message)"
        Return
    }   
    Try
    {
        Write-Verbose "Generating report $Filename..."
        $Header = @'
        <title>Random Active Directory User Audit</title>
            <style type=""text/css"">
                <!--
                    TABLE { border-width: 1px; border-style: solid;  border-color: black; }
                    TD    { border-width: 1px; border-style: dotted; border-color: black; }
                -->
            </style>
'@
        $Pre  = "<p><h2>Random Active Directory User Audit for $Env:USERDNSDOMAIN</h2></p>"
        $Post = "<hr><p style=`"font-size: 10px; font-style: italic;`">This report was generated on $(Get-Date)</p>"
        $Users | ConvertTo-HTML -Property SamAccountName, Department, Title, LastLogonDate, PasswordLastSet, Enabled, LockedOut -Head $Header -PreContent $Pre -PostContent $Post | Out-File $Filename     
        Return $Users
    }
    Catch
    {
        Write-Error "Unable to generate report: $($_.Exception.Message)"
    }
}

Active Directory List Object Mode

by Ryan 20. May 2013 12:00

This is something I've been wanting to blog about for a long time, but have been putting it off because I knew it might turn in to a long, time-consuming post. Well it's time to bite the bullet and get started.

We were facing a bit of a problem in one of our managed hosting environments. We had this high-volume, multitenant Active Directory being used by dozens of different customers. There was a business requirement in this domain that customers not be able to read from one another's organization units for the sake of the mutual privacy of the customers. Things seemed to be working well for a while, but one day, it appeared that customer users logging on to many of the client computers were failing to process Group Policy upon logon:

Event ID: 1101
Source: Userenv
User: NT Authority\System
Description: Windows cannot access the object OU=Customers, DC=contoso, DC=com in Active Directory. The access to the object may be denied. Group Policy processing aborted.

To start troubleshooting, I copied one of the affected user accounts and used it to log in to one of their machines, and I was able to reproduce the issue. Upon trying to update Group Policy with gpupdate.exe, I noticed that the computer configuration was updating fine, while only the user portion of the update failed, and the event 1101 was produced.

The basic layout of the OU structure in the domain was this:

    
CONTOSO.COM
    |
    + Customers (OU)
          |
          + Customer1 (OU)
          |
          + Customer2 (OU)
          |
          + ...

Still using my customer-level user account, I noticed that I was able to browse the contents of my own Customer1 OU, but I was not able to browse the contents of any other OU. The permissions on these OUs had certainly been modified.

In fact, it was that the read permission for the Authenticated Users security group had been removed from the access control list on the Customers OU. That explains the event 1101s and the GPO processing failures. From Microsoft:

[GPO processing fails] when the Group Policy engine cannot read one of the OUs.

The Group Policy engine must be able to read all OUs from the level of the user object or the computer object to the level of the domain root object. Also, the Group Policy engine must be able to read the domain root object and the site object of the computer. This is because these objects may contain links to group policies. If the Group Policy engine cannot read one of these OUs, the events that are mentioned in the "Symptoms" section will be logged.

So in satisfying the business requirement that no customer be allowed to list the contents of another customer's OU, Group Policy processing had been broken. But simply giving Authenticated Users their read permissions back on the Customers OU, they get to browse all the other customers OUs as well.

We needed the best of both worlds.

This Microsoft article would lead you to believe that if a security principal just had the Read gpLink and Read gpOptions access control entries, then GPO processing should work fine:

But that's not enough. The four ACEs that were needed on the Customers OU were:

  • Read gpLink
  • Read gpOptions
  • Read cn
  • Read distinguishedName

Now we're making progress, but we're still not out of the woods. Giving Authenticated Users the List Contents permission on the Customers OU would allow them to see the names of all the other customer's OUs, although now they show up as "Unknown" object types and can't have their respective contents listed. But that's a messy solution in my opinion and doesn't fully satisfy the requirement. Customer1 shouldn't even be aware of Customer2's existence.

There's one last piece of the puzzle missing, and that brings me to List Object Mode.

List Object Mode is one strategy available to Active Directory administrators to allow for hiding certain bits of data from certain users. List Object mode has to be enabled manually; it's turned off by default. To enable it, set the value of the dsHeuristics property in the Configuration partition to 001 using ADSI Edit, like so:

dsHeuristics

Now you will have a new access control entry in the list on objects in your forest: List Object. The ACE was actually there before, but Active Directory doesn't enforce it by default.

List Object Mode is a form of Access Based Enumeration, (not to be confused with file system ABE,) where items are not displayed to users that do not have List Object permissions to them. By default, when a user has the List Contents permission on an OU, and queries that OU, he or she is given a list of all child OUs in that parent OU, even if the user doesn't have read access to those other child OUs.  They show up in ADUC as "Unknown" object types and get that little blank page for an icon which is the Microsoft universal symbol for "wth is this?"

By using List Object permissions after having enabled it as just described, Active Directory evaluates the permissions of all the child objects under the object that was queried before returning the results to the user. Unless the user has the List Object permission on the object, it is omitted from the results. So now we have a customer user who is able to read just his or her own OU, and the other Customer OUs are completely hidden from view.

And no more Group Policy failures due to access denied, either.

So are there disadvantages to enabling and using List Object mode in your domain? Yes there are. So even though it may be appropriate for your environment, List Object Mode is not for everybody and it's not a decision that should be made lightly:

  • Significantly increased access control checks on LDAP queries = busier domain controllers.
  • You may need to rethink your entire User and Computer organization strategy to accommodate for how the new permissions work.
  • It's a less common configuration that fewer people are familiar with. Administrative complexity++. You need to fully document the change and make sure every administrator is aware of it.

So there you have it. Now go impress your friends with your knowledge of AD List Object Mode!

AD Recycle Bin and a Eulogy for the Infrastructure Master

by Ryan 13. April 2013 19:45

Ruminate with me a while, won't you?

Ah, the Infrastructure Master.  Probably the least-appreciated FSMO role of all.  In discussions such as technical job interviews, most people can list the five FSMOs for me... maybe even tell me which are per-forest and which are per-domain... but if you then start asking for specifics about what each one of them actually does, the interviewee usually gets a bit more wobbly.  And I think the Infrastructure Master in particular is probably the most difficult of all to grasp.  I know it was certainly the last one for me to really "get."

I won't spill it all out here on what exactly the IM does - there's plenty of documentation out there if you're really interested. I would also direct you to this ServerFault post wherein I give a real-world example of what the IM does and what might happen if the IM is on the wrong domain controller.

This brings me to the Active Directory Recylce Bin.  The AD Recycle Bin was introduced in 2008 R2, and was a long time coming.  Before, restoring AD objects was a lot more arcane and cumbersome than it is with a good ole' Recycle Bin.  Considering the AD Recycle Bin is going on 5 years old now, even though it's an optional feature, there's less and less of an excuse as time goes on for you to not have it enabled in your AD domain.

(You don't, do you?)

So here's the interesting bit that you might not have known: (sorry for wasting your time if you did know) once you've enabled the AD Recycle Bin, your Infrastructure Master no longer has anything to do.  Nothing.  Not even in an environment where some domain controllers are not also global catalogs.

From Technet:

When the Recycle Bin optional feature is enabled, every DC is responsible for updating its cross-domain object references in the event that the referenced object is moved, renamed, or deleted. In this case, there are no tasks associated with the Infrastructure FSMO role, and it is not important which domain controller owns the Infrastructure Master role.

So as the AD Recycle Bin becomes more and more commonplace in Active Directory environments, it seems that the Infrastructure Master may slowly dwindle away until only the old guard even remembers what it was, and budding young IT pros will only have 4 FSMOs to remember.

Why Does It Say <Unknown Contact> When Viewing Network Share Permissions?

by Ryan 31. March 2013 10:15

I only get to work with Active Directory trusts every so often. I think multi-domain forests seem to be falling out of fashion. At least for those of us who've heard of federation. Regardless, here's an interesting issue I ran into the other day:

So I have this domain, contoso.com.  In contoso.com, there is a one-way forest trust established with fabrikam.com, such that contoso.com trusts fabrikam.com.  This way, users in fabrikam.com can access resources in contoso.com.

On pc1.contoso.com, I create a network file share. I add permissions for my own user account, contoso\ryan, to it.  Then, I add permissions for fabrikam\steve to access the file share also.  The operation was successful and the file share appears to be set correctly.  However, when I go back and view the permissions for the file share again, it takes a very long time, as if it were waiting on something to time out, and then eventually, this is what I see:

File Share Permissions

So why is fabrikam\steve showing up as <Unknown Contact> when viewed from the contoso.com domain?  What we have here, is a SID translation failure.  But why?  First, a little background.  Here is what Microsoft says about users in your forest who are members of another forest:

"When a trust is established between a domain in a forest and a domain outside of that forest, security principals from the external domain can access resources in the internal domain. Active Directory creates a foreign security principal object in the internal domain to represent each security principal from the trusted external domain. These foreign security principals can become members of domain local groups in the internal domain. Directory objects for foreign security principals are created by Active Directory and should not be manually modified. You can view foreign security principal objects from Active Directory Users and Computers by enabling advanced features." [ Source ]

So if you go look in the ForeignSecurityPrincipals container in contoso.com, you'll see an object that represents the user account of fabrikam\steve, but his friendly name or samAccountName is not part of that record. It's just a SID.  When we pull up a permissions file dialog box like the one above, Windows attempts a SID to name translation... but it fails.  There's a little bit of technical documentation on how SID translation occurs:

"LSA on the computer that the call is sent to (using the LSA RPC interface) will resolve the SIDs it can map and send on the remaining unresolved SIDs to a domain controller in the primary domain. The domain controller will resolve additional SIDs to account names from the local database, including SIDs found in SidHistory on a global catalog.

If SIDs cannot be resolved there, the domain controller will send remaining SIDs to domain controllers in a trusted domain where the domain part of the SID matches the trust information." [ Source ]

There are many functions regarding SID lookups, and I don't know exactly which ones are used at each location, but the general concept is the same and you can see how this procedure could take a while to time out. And when it fails, you see <Unknown Contact>.  Or maybe just the unresolved SID of security principal.  Depends on which version of Windows you're using and exactly which dialog box you're looking at.

The reason it happens in our scenario is because of the one-way trust. Contoso.com cannot call upon fabrikam to translate SIDs from its forest, because fabrikam does not trust contoso.

To fix it, we could allow anonymous SID translation in fabrikam... but for many that is an unacceptable security risk.  Or we could make the trust two-way.  Or, if you're unable to do either of those things, you could at least create a security group in contoso, add the individuals from fabrikam to that group, and just assign the group to the network share ACL.  The functionality would be the same but at least you wouldn't have to look at "<Unknown Contact>" every time you opened that dialog box.

Mystery solved.

For more information on this, see the ServerFault question that I answered here, as well as the much better Ask the Directory Services team blog post here.

Signing Powershell Scripts

by Ryan 8. March 2013 13:19

Hi guys,
 
Something you might know about me is that I think Powershell is just about the best thing to ever happen to Windows Server.  And even if you don't agree... well, you don't really have a choice because there are already tasks that must be done in Powershell and there is no GUI alternative, and that trend will only continue.
 
Powershell will become part of your life if you plan on continuing to work with Windows Server. PS is very powerful, and it makes many tasks much faster and more automatable.  But with that power, comes the side-effect that PS also makes many nefarious activities faster and easier as well.  An attacker has many more tools and methods (no pun intended) available to him or her if they have unrestricted access to Powershell on your server. You could restrict all Powershell usage on your servers, but that means losing an extremely valuable tool for administrators. There must be a compromise...

One effective way to mitigate this risk is to digitally sign your Powershell scripts with a certificate. By setting the execution policy of PS scripts on your servers to AllSigned, Powershell will not run scripts unless it can successfully validate the signature that is in the script.  That also means that the script cannot be modified after being signed, as the signature will no longer match the modified script.  This is much better than the RemoteSigned execution policy, which only mandates that scripts downloaded through an Attachment Execution Service-compliant application need to be signed, which is extremely easy to bypass. (e.g. just clear the alternate NTFS data stream.)
 
Good news is that code signing, especially in Powershell, is actually pretty easy to do.
 
First, as an administrator of an Active Directory domain with an Enterprise Certificate Authority, you need to make a code signing certificate for your users to use.  On your CA, open the Certificate Templates MMC snap-in.  You can also get there in the CA snap-in by right-clicking on Certificate Templates and choosing Manage.

Cert Templates

Duplicate the Code Signing template, so that you don't modify the original template.  Configure all the properties of this template as desired, including allowing Authenticated Users (or whichever users you desire) the ability to enroll in your new certificate template.

Cert Templates

I very creatively named my template "Code Signing Template v1."  Now go back to your Certificate Authority snap-in, and choose New -> Certificate Template to Issue.  Choose your new code signing cert.

Cert Templates

Keep in mind that this information is being uploaded to Active Directory, so make sure AD replication has taken effect before wondering why the certificate isn't already available at your location as soon as you issue it.

Now, on your workstation, where you are logged in as a regular user, you want to enroll for one of those new code signing certs.  You could do this in the Certificates MMC snap-in:

Cert Enrollment

But, since we like to save time, let's go ahead and instead submit the certificate request via Powershell:

Powershell

You have to take the spaces out of the certificate template name.  But you'll know the certificate request was successful if the status is Issued.  You'll also notice that the public key of your new code signing cert is now published publicly in your Active Directory user account.  This is so everyone else in the domain can access your public key so that they can validate that you did, in fact, sign that exact Powershell script, so we can figure that it's safe to run.

Powershell

Signing a Powershell script with your new code signing certificate is simple:

Powershell script sign

Just Set-AuthenticodeSignature $script $certificate, and it's signed.  The signature is actually a block of cipher-text that appears at the bottom of your newly signed script.

 

Script Signed

Your identity is also encoded in those comments, but is not encrypted.  So Powershell can tell who signed the script right off the bat.  Then, Powershell retrieves the public key of that identity (from AD for example.)  The script was signed using your private key, which you do not share, and can only be decrypted with your public key, which you do share.  So if Powersell is able to decode the signature with your public key, it can be reasonably assured that it was signed by you.  If the script changes by even a single character, then that hashed with your private key would result in an entirely different signature, therefore modification of the script means Powershell will not run it unless it is re-signed by another authorized user, and we would be able to tell who that was.
 
Alright, that's enough out of me.  Hopefully I've been able to at least pique your interest in the potential security benefits of code signing!

(And sorry for all the cheesy pixellation.)

Why Are You Talking To THAT Domain Controller!?

by Ryan 9. February 2013 11:05

I was in Salt Lake City most of this week. Being surrounded by stark snow-covered mountains made for some wonderful scenery... it could not be more different than it is here in Texas. Plus I got to meet and greet with a bunch of Novell and NetIQ people. And eat an enormous bone-in ribeye that no human being has any business eating in one sitting.

But anyway, here's a little AD mystery I ran in to a couple weeks ago, and it may not be as simple as you first think.

As Active Directory admins, something we're probably all familiar with is member servers authenticating with the "wrong" domain controller. By wrong, I mean a DC that is in a different site than the member server, when there's a perfectly fine DC right there in the same site as the member server, and so the member server is incurring cross-site communication when it doesn't need to be. Everything might still function well enough as long as the communication between DC and member server is successful, but now you're saturating your slower inter-site WAN links with AD traffic when you don't need to be. You should want your AD replication, group policy application, DFS referrals, etc., to run like a well-oiled machine.

I often work in a huge environment with AD sites in many countries and on multiple continents, and thousands of little /26 subnets that can't always be easily grouped into a predictable supernet for the purposes of linking subnets to sites in AD Sites & Subnets. So I'm always alert to the fact that if I log on to a server, and I notice that logon takes an abnormally long time, I very well could be logging on to the wrong DC. First, I run set log to see which DC I have logged on to:

set log*DC01 is in Amsterdam*

So in this case, I noticed that while I had logged on to a member server in Dallas, that server's logon server was a DC in Europe. :(

You immediately think "The server's IP subnet isn't defined in AD Sites & Services or is associated to the wrong site," don't you?  Yeah, me too. So I went and checked. Lo and behold, the server's IP subnet was properly defined and associated to the correct site in AD.

Now we have a puzzle. Back on the member server, I run nltest /dsgetsite to verify that the domain member does know to which site it belongs. (Which the domain member's NetLogon service stores in the registry in the DynamicSiteName value once it's discovered.)

I also ran nltest /dsgetdc:domain.com /Account:server01$ to essentially emulate the DC locator and selection process for that server, which basically just confirmed what we already knew:

C:\Users\Administrator>nltest /dsgetdc:domain.com /Account:server01$ 
           DC: \\DC01.DOMAIN.COM (In Amsterdam) 
      Address: \\10.0.2.55 
     Dom Guid: blah-blah-blah 
     Dom Name: DOMAIN.COM 
  Forest Name: DOMAIN.COM 
 Dc Site Name: Amsterdam 
Our Site Name: Arlington 
        Flags: GC DS LDAP KDC TIMESERV WRITABLE DNS_DC DNS_DOMAIN DNS_FOREST FUL
L_SECRET WS 
The command completed successfully

So where do we look next if there's no problem with the IP subnets in AD Sites & Services?  I'm going with DNS. We know that domain controllers register site-specific SRV records so that clients who know to which site they belong will know what DNS query to make to find domain controllers specific to their own site.  So what DNS records did we find for the Arlington site?

Forward Lookup Zones
    _msdcs.domain.com
        dc
            _sites
                Arlington
                    _kerberos SRV NewYorkDC
                    _kerberos SRV SanDiegoDC
                    _kerberos SRV MadridDC
                    _kerberos SRV ArlingtonDC
                    _ldap     SRV NewYorkDC
                    _ldap     SRV SanDiegoDC
                    _ldap     SRV MadridDC
                    _ldap     SRV ArlingtonDC

OK, now things are getting weird.  All of these other domain controllers that are not part of the Arlington site have registered their SRV records in the Arlington site.  The only way I can imagine that happening is because of Automatic Site Coverage, whereby domain controllers will register their own SRV records into sites where it is detected that the site has no domain controllers of its own... combined with the fact that scavenging is turned off for the DNS server, including the _msdcs zone.  So someone, once upon a time, must have created the Arlington site in AD before the actual domain controllers for Arlington were ready.  What's more is that Automatic Site Coverage is supposed to intelligently use site link costing so that only the domain controllers in the next closest site provide "coverage" for the site with no DCs, not every DC in the domain. Turns out the domain did not have a site link strategy either - it used DEFAULTIPSITELINK for everything - the entire global infrastructure. So even after Arlington did get some domain controllers, the SRV records from all the other DCs stayed there because of no scavenging.

Here's the thing though - did you notice that almost every other domain controller in the domain had SRV records registered in the Arlington site, except for the domain controller in Amsterdam that our member server actually authenticated to!?

This is getting kinda' nuts.  So what else, besides the DNS query, does a member server perform in order to locate a suitable domain controller?

So after a client does a DNS query for _ldap._tcp.SITENAME._sites.ForestDnsZones.domain.com, and gets a response, the client then begins to do LDAP queries against the DCs given in the DNS response to make sure that the DCs are alive and servicing requests. If you want to see this for yourself, I recommend starting Wireshark, and then restarting the NetLogon service while the capture is running. If it turns out that none of the DCs in the list that was returned by the site-specific DNS query is responding to your LDAP queries, then the client has to back up and try again with a domain-wide query.

And that is what was happening. The client, server01, was getting a list of DCs for its site, even ones that were erroneously there, but I confirmed that it was unable to contact any of those domain controllers over port 389. So after that failed, the server was forced to try again with a domain-wide query, where it finally found one domain controller that it could perform an LDAP query on... a domain controller in Amsterdam.

Moral of the story: Always blame the network guys.

 

An Interesting DFSR Change (that probably everyone knew about but me)

by Ryan 9. January 2013 19:28

First, wooo I hit 5K on ServerFault today.

I'm embarrassed to say that something I read about recently but didn't pay enough attention to at the time officially just bit me in the butt.  

A significant change occurred in January 2012 in the way that DFS Replication behaves.  Windows Server 2008 R2 SP1 post KB2663685 and Windows Server 2012 have changed the default behavior of DFSR.  Auto-recovery of DFSR replicated folders after unexpected shutdown is now disabled.  In other words, if a computer that hosts a DFSR replicated folder experiences an unexpected shutdown, DFSR will not automatically resume upon reboot.  (This includes Sysvol!

On older versions of Windows, DFSR auto-recovery was enabled.  I'm sure the reason for this change involves auto-recovery leading to unexpected rollbacks and unauthoritative conflict resolutions between replication partners, especially in wide-spread domains with high end-to-end replication latency and frequent changes... but even though the news was published, I for one didn’t pay enough attention to it and it has a very real effect on the way we manage our Windows systems that utilize DFSR going forward. 

So what if a domain controller or a file server with a DFSR share on it running 2008R2 or 2012 crashes unexpectedly, leaving the DFS database and the NTFS USN journal out of sync?  Then Sysvol no longer receives updates on that DC.  The DFSR file share no longer receives updates on that file server.  It's up to you to manually restart replication, and to resolve any conflicts with replication partners if changes took place during the time that the crashed server wasn't replicating. 

Luckily that is easy to do, and it's also possible to set the behavior back to auto-recovery if that is what you wish. 

How will I know if this effects my server?

While this first example is just a symptom of the problem, here is how it first came to my attention, triggering the investigation:

(Click on images for a better view.)

Errors in my event log

Application of Group Policy was failing, but only on DC02 and servers which were using DC02 as a domain controller.  Not DC01 or any server logged on by DC01.  As it turns out, the GPO referenced by that error event, a new GPO that I had just created on DC01, didn’t exist on DC02, hence the errors.  Sysvol did not seem to be replicating anymore.

Here is the actual event log event to let you know that DFS Replication has stopped on one or more volumes:

DFSR Error

Luckily, starting replication back up again is easy and the command to do it with your actual GUID, is right there in the event:

wmic /namespace:\\root\microsoftdfs path dfsrVolumeConfig where volumeGuid="12345678-ABCD-1234-EFGH-1A2B3C4E5F" call ResumeReplication

 You can also turn auto-recovery back on with wmic or by modifying the registry if you don’t have the time to be bothered by this:

HKLM\System\CurrentControlSet\Services\DFSR\Parameters\StopReplicationOnAutoRecovery = 0

Just be aware that auto-recovery can lead to unwanted rollbacks of DFSR data in some circumstances.

GPO Application Precedence - "Just Because You Can" Edition

by Ryan 14. August 2012 11:38

This one really gets back to my roots as a big fan of everything related to Active Directory and Group Policies. Someone had a question yesterday about GPO application that, I admit, gave me pause. It would have been an excellent question for an MCITP exam or a sysadmin interview.

It's also an example of a GPO strategy that might be too complicated for its own good.

The basic behavior of Group Policy application order is well-known by almost every Windows admin. Let's review:

  • Local policies are applied first.
  • Then policies linked at the site level.
  • Then policies linked at the domain level.
  • Then GPOs linked to OUs in order such that policies linked to "higher" OUs apply first, and the policies linked "closest" to the object go last.
  • If multiple GPOs are linked at the same level, they go from the bottom-up. (AKA by Link Order)
  • Last writer wins, i.e., each subsequent GPO overwrites any conflicting settings defined in earlier GPOs. Settings that do not conflict are merged.
  • Enforce (formerly known as No Override,) Block Inheritance and Loopback Processing can be used at various levels of the aforementioned hierarchy in various combinations to augment the behavior of GPO application.
So that seems like a pretty simple system, but it's just flexible enough that you can get into some confusing situations with it. For instance, take the following OU structure:
 
(OU)All Servers
       |
       +--(OU)Terminal Servers

The Terminal Servers OU is a Sub-OU of the All Servers OU. Now, let's link two different policy objects to each of the OUs:

(OU)All Servers [Servers_GPO]
       |
       +--(OU)Terminal Servers [TS_GPO]

So using what we know, we assume that a computer object in the Terminal Servers OU will get all the settings from Servers_GPO, and then it will receive settings from TS_GPO, which will overwrite any conflicting settings from Servers_GPO.

Now let's put the Enforced flag on Servers_GPO:

(OU)All Servers [Servers_GPO-ENFORCED]
       |
       +--(OU)Terminal Servers [TS_GPO]

Now the settings in Servers_GPO will win, even if they conflict with settings in TS_GPO. But let's go one step further. What happens if you also Enforce TS_GPO?

(OU)All Servers [Servers_GPO-ENFORCED]
       |
       +--(OU)Terminal Servers [TS_GPO-ENFORCED]

Which GPO will win?  Had I been taking a Microsoft exam, I might have had to flip a coin. I have to admit, I had never considered this scenario. If neither policy was enforced, we know TS_GPO would win. If Servers_GPO was enforced and TS_GPO was not enforced, then we know Servers_GPO would win. But what about now?

And furthermore, why would anyone want to do that? I can't explain what goes on in some administrator's heads when they're planning these things out, but luckily I did have Technet at my disposal:

You can specify that the settings in a GPO link should take precedence over the settings of any child object by setting that link to Enforced. GPO-links that are enforced cannot be blocked from the parent container. Without enforcement from above, the settings of the GPO links at the higher level (parent) are overwritten by settings in GPOs linked to child organizational units, if the GPOs contain conflicting settings. With enforcement, the parent GPO link always has precedence. By default, GPO links are not enforced.

So with that, we should be able to surmise that the parent GPO - Servers_GPO - will win. A little testing confirmed it - the higher-level GPO takes precedence over a lower-level GPO even when they're both enforced.

I might call this one of those "just because you can, doesn't mean you should" sort of administrative practices.

SQL Server - Unable to Generate SSPI Context

by Ryan 27. June 2012 19:43

The different sorts of authentication mechanisms in play in a Windows network can be pretty complex.  So when someone asked me, "Why do I get a 'Could not generate SSPI context' error when I try to log in to a SQL server?" I knew that there could be several answers to that question.  Go ahead and Google it yourself -- you won't get a definite *This is absolutely your problem* sort of answer.

First I remembered that there was a situation where RSA SecureID tokens (essentially certificates for our purposes) were used for various authentication tasks in the domain, and if one tried to authenticate to a SQL Server with Windows authentication without having one's RSA token plugged in, the "Could not generate SSPI context" error would be generated. Plug the SecureID device into a USB slot, and you'd log in to the SQL server just fine. But I knew that policy was not an issue in this situation...

Then I thought about how services not having their SPNs registered with Active Directory can cause authentication problems.  Specifically, if a SQL Server doesn't have its SPN registered properly in Active Directory, Kerberos authentication cannot be used.  But that still shouldn't prevent you from authenticating whatsoever... it'll just drop you down to NTLM instead of Kerberos.

Also, I was able to perform a logon with Windows auth to the same SQL Server at the same privilege and security level as the user, so I knew it had to be something at their end.

The only other thing I could think of was that something was just wrong with their security token that was confusing their SSPI?  Maybe it was corrupt somehow?  I'm not sure.  So, I recommended that the user run "klist purge" to purge all their domain controller-issued tickets, knowing that they would be refreshed as soon as they requested access to a domain resource...

Bingo.  Problem solved.

Group Policy Preferences Passwords Continued

by Ryan 29. May 2012 12:04

For the original post, see here.

So in yesterday's post, I mentioned that this guy wrote a neat tutorial and Powershell script called Get-GPPPasswords.ps1 that will decipher the passwords in a valid Groups.xml file.  You can find his scripts here. (The PowerSploit repository on Github.)  I wrote an additional function to go inside of Get-GPPPasswords this morning.  The purpose of the new function is to automatically search your own domain for Groups.xml files, and use Get-GPPPasswords on them.  This can be handy for finding all the Groups.xml files as quickly as possible, especially in a domain with lots of policies.  And especially if you're pressed for time.  It's very simple:

function Find-GPPPasswords 
{

<#
.Synopsis

Scan your own domain in search of valid Groups.xml files in SYSVOL. If found, use Get-GPPPassword on them.
Author: Ryan Ries (www.myotherpcisacloud.com)

.Example

PS C:\> . .\Get-GPPPassword.ps1
PS C:\> Find-GPPPasswords
#>
	Write-Host "Now searching $Env:UserDNSDomain for Group Policy Preferences passwords..."
	$GroupsFiles = Get-ChildItem -Path "\\$Env:UserDNSDomain\SYSVOL" -Recurse -Include Groups.xml
	foreach($_ in $GroupsFiles)
	{		
		Get-GPPPassword -Path $_		
	}
}

About

Name: Ryan Ries
Location: Texas, USA
Occupation: Systems Engineer 

I am a Windows engineer and Microsoft advocate, but I can run with pretty much any system that uses electricity.  I'm all about getting closer to the cutting edge of technology while using the right tool for the job.

This blog is about exploring IT and documenting the journey.


Blog Posts (or Vids) You Must Read (or See):

Pushing the Limits of Windows by Mark Russinovich
Mysteries of Windows Memory Management by Mark Russinovich
Accelerating Your IT Career by Ned Pyle
Post-Graduate AD Studies by Ned Pyle
MCM: Active Directory Series by PFE Platforms Team
Encodings And Character Sets by David C. Zentgraf
Active Directory Maximum Limits by Microsoft
How Active Directory Replication Topology Works by Microsoft


MCITP: Enterprise Administrator

Profile for Ryan Ries at Server Fault, Q&A for system administrators

Twitter

LOPSA

 

I do not discuss my employers on this blog and all opinions expressed are mine and do not reflect the opinions of my employers.