Zoho Banner September 2011

I had a requirement recently to try and find out where and when a whole lot of mailboxes were hidden from the GAL.  Yes, fingering some poor sucker for the blame is an immensely satisfying task, isn’t it?  I’ve found that an effective way to do this is to query the AD replication metadata for the attribute concerned (in this case ‘msexchhidefromaddresslists’).  The replication metadata will provide you with the date/time for when the attribute value was last changed as well as the name of the DC where the last change was made.  From there you can search the Security Event Log on the DC in question for the audit events corresponding to the change.  This of course assumes that you have Audit Directory Service Changes switched on.

Typically, I would use the excellent Repadmin.exe command line tool to query the replication metadata, e.g. -

Repadmin /showobjmeta MyDC1 “CN=MyUser,OU=User Accounts,DC=contoso,DC=com”

However, in this case someone had already reversed most of the changes (i.e. unhidden the mailboxes) and I needed to query a large number of objects to find some others that were still hidden, hoping that some of them would have a common data/time stamp.  For this the Repadmin.exe would work but would be hopelessly inefficient.  And what (I said to myself) is the best method for performing bulk operations such as this?  Yes, that’s right:  Powershell to the rescue!

After some Googling, I found an excellent code snippet from Powershell MVP Brandon shell that hooks into the underlying .Net class to expose the replication metadata.  His is the clever bit (that’s why he’s paid the big bucks) – I’ve basically just done the wrapper to perform a bulk query and output the results to a CSV file.  Here’s the script for your enjoyment.

 

#########################################################
#
# Name: BulkReportReplicationMetadata.ps1
# Author: Tony Murray
# Version: 2.0
# Date: 27/03/2014
# Comment: PowerShell 2.0 script to find change times
# for an individual AD attribute using replication metadata
# 
# Some bits borrowed from: Get-ADObjectREplicationMetadata.ps1
# Brandon Shell (www.bsonposh.com)
#
#########################################################

# import the AD module
ipmo ActiveDirectory

# Define variables
$domain = (get-addomain).dnsroot # Use the current AD domain
$property = "msexchhidefromaddresslists" # This is the AD attribute we are interested in
$outfile = "c:\csv\outfile.csv" # CSV output file

# Blow away the existing file if it exists
if (test-path $outfile) {remove-item $outfile}

# We will build our own CSV rather than work with export-csv
$header = "samaccountname,modified,dc"
Add-Content -Value $header -Path $outfile

$sb = "OU=Standard User Accounts,DC=contoso,DC=com" # Search base for where our mailbox users live
$fl = "(&(homemdb=*)(msexchhidefromaddresslists=TRUE))" # LDAP filter to find our users
$users = Get-ADUser -LDAPFilter $fl -searchbase $sb

# Loop through our list of users
foreach ($user in $users) {

    $objectDN = $user.distinguishedname # used for finding the replication metadata
    $name = $user.samaccountname # Just for info
    # Sets Context to Domain for System.DirectoryServices.ActiveDirectory.DomainController
    $context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$domain)
    # .NET Class that returns a Domain Controller for Specified Context
    $dc = [System.DirectoryServices.ActiveDirectory.DomainController]::findOne($context)
    # GetReplicationMetadata returns metadata from the DC for the DN specified.
    $meta = $dc.GetReplicationMetadata($objectDN)
    # Get the last time the attribute value was changed
    $ctime = $meta | %{$_.$Property.LastOriginatingChangeTime}
    # Get the DC that the change was made on
    $dcon = $meta | %{$_.$Property.OriginatingServer}
    # Build the values to write to the output file
    $line =  "`"$name`",`"$ctime`",`"$dcon`""
    # Write the line to the output file
    Add-Content -Value $line -Path $outfile

} # end foreach

The shrewd amongst you would ask why I didn’t query the Exchange (2010 in this case) audit log for this information. The answer is that I did, but couldn’t find the relevant audit entries. The Exchange audit events are only captured if the Exchange tools (EMC/EMS/ECP) were used to perform the change. In my case the changes had been made in bulk, probably using the AD cmdlets.

Reading the post title you maybe wondering whether I’ve taken leave of my senses.  Why call Robocopy from Powershell to count files when Powershell has a perfectly good method of doing this natively? For example,

(Get-ChildItem e:\powershell -Recurse -force | ?{! $_.PSIsContainer} | Measure-Object).count

Well, the problem comes in when an individual file length exceeds 260 characters.  At this point Powershell throws an error similar to the one below.

Get-ChildItem : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

At E:\Powershell\CountFiles.ps1:243 char:32

+ $hcountpost = (Get-ChildItem e:\powershell -Recurse -force | Measure-Obj …

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : ReadError: (\\myserver\homed… – blah blah:String) [Get-ChildItem], PathTooLongException

+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand

The problem is not so much to do with Powershell as the underlying .NET APIs, as the following article succinctly explains.

http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx

This is where Robocopy comes in handy as it doesn’t suffer from the same limitations.  On the other hand Robocopy has its own output formatting that doesn’t play nicely with Powershell.  I came across a very handy code snippet from MVP Boe Prox that can help with this.  The only change I have made is to roll it up into a function (shown below for your pleasure).

Function Count-Files ($path) {
    $params = New-Object System.Collections.Arraylist
    $params.AddRange(@("/L","/S","/NJH","/BYTES","/FP","/NC","/NDL","/TS","/XJ","/R:0","/W:0"))
    $countPattern = "^\s{3}Files\s:\s+(?\d+).*"
    $sizePattern = "^\s{3}Bytes\s:\s+(?\d+(?:\.?\d+)).*"
    $return = robocopy $path NULL $params
    If ($return[-5] -match $countPattern) {
        $Count = $matches.Count
    } # end if
    else {
    $Count = 0
    } # end else
    Return $count
} # end Count-Files function

 

Enjoy.

 

Another short blog posting (brevity is obviously my thing for 2014).

I occasionally come across environments in which Strict Replication Consistency is not enabled.  This is invariably because these environment have forests that were created with Windows 2000 server, but which have subsequently been upgraded.  If you need to know more about Strict Replication Consitency and why it is important for your AD environment, I don’t plan to bore you with the details here as this topic is well covered elsewhere.  The best article I have found on the topic is this one.

http://blogs.technet.com/b/askds/archive/2010/02/15/strict-replication-consistency-myth-versus-reality.aspx

The article makes the essential point that if the environment does not have SRC enabled then you need to do two things:

  1. Ensure the required registry key is configured on each DC.  The quickest method to achieve this is using Repadmin as follows: repadmin /regkey * +strict
  2. Ensure any new DCs promoted within the forest automatically have SRC enabled by creating an operational GUID (actually a Container object in the Configuration Partition).  There are several ways to create the object, but as you know, I’m a fan of Powershell, so here’s the code to do it:

 

# Strict Consistency - add operational GUID
$cnc = (get-adrootdse).configurationnamingcontext
$path = "CN=Operations,CN=ForestUpdates," + $cnc
$obj = "94fdebc6-8eeb-4640-80de-ec52b9ca17fa"
New-ADObject -Name $obj -Type container -Path $path -OtherAttributes @{showInAdvancedViewOnly="TRUE"}

Enjoy!

Today’s post is another short one.  It’s a Powershell one-liner to find all the Primary SMTP address suffixes in use by the mailboxes in your Exchange Org.

In this example I know that my default suffix is “contoso.com”, but I want to find out what others are being used as primary:

get-mailbox -ResultSize unlimited | ? {$_.primarySMTPaddress -notmatch "@contoso.com" } `
| select @{l="SMTPSuffix";expression={$_.primarysmtpaddress.tostring().Split("@")[1]}} –unique

The output (which will take a while as there is a lot of post-processing in the pipeline) looks like this:

SMTPSuffix
_______
fabrikam.com
northwindtraders.com
fouthcoffee.com

Enjoy!

 

Short answer:  No, AppLocker is not supported on Windows Server 2012 Server Core.

Slightly more long-winded answer:

My Google/Bing mojo failed to find a definitive answer to this question on-line.  In fact, I found two apparently conflicting sources of information.

This was the first one:

Windows PowerShell can used to manage AppLocker on Server Core installations using the AppLocker cmdlets and, if administered within a GPO, the Group Policy cmdlets. For more information, see the AppLocker PowerShell Command Reference.

http://technet.microsoft.com/en-us/library/hh831440.aspx

I tried to test this, but switching from “Server with a GUI” to Server Core removes the Application Identity service, which is required for enforcement of AppLocker rules.   The AppLocker event log is also removed.

This was the second one I found:

In Windows Server 2012 and Windows 8

AppLocker is supported on all Windows beta evaluation versions except the Server Core installation option.

http://technet.microsoft.com/en-us/library/ee619725(v=ws.10).aspx

Mmm, it only mentions the “beta evaluation” version, so a strong hint, but no definitive statement.

In the end I received a response from someone within Micrsoft to a Technet Forum post.  You can read the full thread here:

http://social.technet.microsoft.com/Forums/en-US/4d78ac57-df3d-444f-b6a4-9df892db8df8/applocker-on-server-core?forum=winservercore

 

Today’s blog entry is short and sweet.  You want to quickly find out whether the AD Recycle Bin feature is enabled or not.   There are a few ways to do this, but this is a quick Powershell method.

 

# Is the AD Recycle Bin enabled in my forest?
Import-Module ActiveDirectory
If ((Get-ADOptionalFeature -Identity "Recycle Bin Feature").EnabledScopes) {
    write-host "AD Recycle Bin is enabled"
    } # end if
Else {
    write-host "AD Recyle Bin is not yet enabled"
} # end else

I quite regularly come across Active Directory environments where users have been mistakenly added to groups protected by the AdminSDHolder and subsequently removed when the mistake has been realised.  This process creates “orphans” because the AdminSDHolder process doesn’t tidy up after itself.  Here’s what happens:

  1. User added to group protected by the AdminSDHolder (e.g. Account Operators)
  2. The AdminSDHolder process (actually a thread within LSASS.EXE on the PDC Emulator) sets the adminCount attribute value to 1 on the user object and replaces the user’s security descriptor with that of the AdminSDHolder container object.
  3. User is then removed from Account Operators.
  4. The adminCount value of 1 is not cleared and the security descriptor is not changed (i.e. remains the same as that of the AdminSDHolder).

It doesn’t make sense to leave these orphans as they are.  For one, it plays havoc with any delegation model that is in place.  It also makes it difficult to determine what objects are actually protected.  For example, searching for objects that have an adminCount of 1 will potentially give you misleading results.

So what can you do about it?  One option is to manually look at each object to determine whether it is genuinely a protected object and then clear the adminCount value and re-set the inheritance flag for any objects no longer protected.  This is likely to be incredibly time consuming as you will need to factor in nested group membership into your investigation.  Another option is to run a script that clears the adminCount value and resets the inheritance flag for *all* protected objects.  Any objects that should genuinely be protected will be re-protected (I just made that word up) when the AdminSDHolder next cycles (within 1 hour by default).

The second option sounds like the clear winner.  There are some small risks that you should be aware of with this approach.  Firstly, there might be some malware “lurking” in your environment that will take the opportunity to compromise privileged accounts when they are in an unprotected state (even for a short period).  Secondly, re-setting the inheritance flag on objects might cause unforeseen problems.  For example, a user object might have had the inheritance flag unchecked prior to being protected by the AdminSDHolder.

Basically, there is no silver bullet here.  Personally, I think the small risk associated with the scripted option generally outweighs the negative impact of AdminSDHolder orphans.  Here’s the script that I use:

#########################################################
#
# Name: Cleanup-AdminSDHolder.ps1
# Author: Tony Murray
# Version: 1.0
# Date: 28/08/2013
# Comment: PowerShell 2.0 script to re-set inheritance
# flag for objects no longer protected by the 
# AdminSDHolder
#
########################################################### 

# Import the AD module
Import-Module ActiveDirectory

# Find objects that appear to be protected in AD
$probjs = Get-ADObject -LDAPFilter "(admincount=1)"
$bcount = $probjs.count
if ($bcount) {
    write-host "Protected object count before change is $bcount"
} # end if
else {
    write-host "No objects are currently protected - nothing to do"
    exit
} # end else

# Change to the AD drive
cd AD:

# Loop through protected objets to set inheritance flag
# and clear the adminCount value
foreach ($probj in $probjs) {
    $dn = $probj.distinguishedname
    $acl = get-acl $dn
    if ($acl.AreAccessRulesProtected) {
        write-host "$dn has inheritance blocked - we will remove the block"
        $acl.SetAccessRuleProtection($false, $false);
        set-acl -aclobject $acl $dn
        # We need to clear the adminCount attribute too
        Set-ADObject -Identity $dn -Clear adminCount
    } # end if
} # end foreach    

# Count the number of protected objects
$acount = (Get-ADObject -LDAPFilter "(admincount=1)").count
if ($acount) {
    write-host "Protected object count after change is $acount"
} # end if
else {
    write-host "No objects are currently protected"
} # end else

Please leave a comment if you have any thoughts on how to improve the script, or if you are aware of a better method of handling AdminSDHolder orphans.

You can download a copy of the script here: Cleanup-AdminSDHolder

 

Back in March 2010 when Powershell and I were on somewhat less friendly terms, I wrote an OU shadow script to populate group membership based on the contents of an OU. Since then, Powershell and I now at least acknowledge eachother when we pass in the corridor and I have updated the script with some improvements.

One common use for the script is populating group memberships for use with Fine-Grained Password Policy (FGPP).

Please leave a comment if you see any scope for improvement.  You can download a copy of the script here: OUBasedGroupMembership ps1

#########################################################
#
# Name: OUBasedGroupMembership.ps1
# Author: Tony Murray
# Version: 1.0
# Date: 03/09/2013
# Comment: PowerShell 2.0 script to
# manage group membership based on OU contents
#
#########################################################

# Import the AD module
ipmo ActiveDirectory

# Define arrays to be used for matching
$arrou = @()
$arrgp = @()

# Domain controller to be used
$dc = (Get-ADRootDSE).dnshostname
write-host "Using DC $dc for all AD reads/writes"

# Specify the OU where the accounts are located
$OUdn = "OU=Admin Accounts,OU=AD Administration,DC=contoso,DC=com"
$OuUsrs = Get-ADUser -Filter * -SearchBase $oudn -Server $dc

# Specify the group to use
$grp = "de42112f-81d2-4849-900c-d6907c77d3f5" # "Service Accounts"
$grpusers = Get-ADGroupMember -Identity $grp -Server $dc

# Build arrays using the DN attribute value
$OuUsrs | % {$arrou += $_.distinguishedname}
$grpusers | % {$arrgp += $_.distinguishedname}

# Add to group membership (new user in OU)
foreach ($usr in $arrou) {
    if ($arrgp -contains $usr) {
        write-host "User $usr is a member of the group"
    }
    else {
        write-host "User $usr is not a member of the group - adding..."
        #Add-ADGroupMember -Identity $grp -Members $usr -Server $dc
    } # end else
    Remove-Variable -ErrorAction SilentlyContinue -Name usr    
} # end foreach

write-host "`n"

# Remove from group membership (no longer in OU or has been manually added to group)
# The assumption here is that the OU is authoritative for the group's membership
foreach ($mem in $arrgp) {
    if ($arrou -contains $mem) {
        write-host "User $mem is located in the OU.  Nothing to do"
    } # end if
    else {
        write-host "User $mem is not present in the OU.  Removing from membership..."
        #Remove-ADGroupMember -Identity $grp -Members $mem -Server $dc -Confirm:$false
    } # end else
    Remove-Variable -ErrorAction SilentlyContinue -Name mem
} # end foreach

I’ve recently been looking at Microsoft’s Security Compliance Manager 3.0.  SCM allows provides a rich set of server-role-based security baselines for deployment using either GPO or SCCM.  This latest version includes baselines for Windows Server 2012. 

After deploying the “WS2012 Domain Controller Security Compliance 1.0″ baseline settings via GPO into my lab environment I found RDP sessions to my Windows Server 2012 DCs to be horrendously slow – almost to the point of not being able to do anything.

My on-line searches for the cause revealed nothing official from Microsoft, but I did find some references to one specific setting being the probable cause.  The setting is “Use FIPS compliant algorithms for encryption, hashing, and signing” set to Enabled.

Computer Config->Policies->Windows Settings->Security Settings->Local Policies->Security Options->System Cryptography->Use FIPS compliant algorithms for encryption, hashing, and signing

After setting the value to Disabled and updating Group Policy on the DCs my RDP sessions returned immediately to normal speed.

I hope this information helps others who might come across the same behaviour.

 

Have you ever considered running BitLocker to encrypt the drives within a Virtual Machine running on, e.g. Hyper-V or VMWare? On the face of it, it seems a sensible thing to do, especially considering how portable VHDX and VMDK files are. Despite the process of enabling BitLocker for VMs being described online, you should be aware that it is not actually supported.

The Microsoft support statement is here:

Can I use BitLocker within a virtual machine operating environment?

BitLocker is not supported for use within a virtual machine. Do not run BitLocker Drive Encryption within a virtual machine. You can use BitLocker in the virtual machine management operating system to protect volumes that contain configuration files, virtual hard disks, and snapshots.

Source: http://technet.microsoft.com/en-us/library/hh831507.aspx

The VMWare support statement follows logically from Microsoft’s:

As the operating system vendor does not support this configuration, it is unsupported by VMware in a Player, Workstation, Fusion or ESX/ESXi virtual machine.

Source: http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2036142

In the context of Active Directory Domain Controllers, Microsoft makes the following recommendations for securing virtual domain controllers:

If you implement virtual domain controllers, you should ensure that domain controllers run on separate physical hosts than other virtual machines in the environment. Even if you use a third-party virtualization platform, consider deploying virtual domain controllers on Hyper-V Server in Windows Server 2012 or Windows Server 2008 R2, which provides a minimal attack surface and can be managed with the domain controllers it hosts rather than being managed with the rest of the virtualization hosts. If you implement System Center Virtual Machine Manager (SCVMM) for management of your virtualization infrastructure, you can delegate administration for the physical hosts on which domain controller virtual machines reside and the domain controllers themselves to authorized administrators. You should also consider separating the storage of virtual domain controllers to prevent storage administrators from accessing the virtual machine files.

Source: Best Practices for Securing Active Directory

It will be interesting to see whether Microsoft change their support statement in future versions of Windows.  I’ve not seen anything in Windows Server 2012 R2 to indicate a change, so it might be a while yet.