Blog - Title

September, 2008

  • Fun with WMI Filters in Group Policy

    Hi, Ned here again. You may remember Mike Stephens writing about importing and exporting WMI filters back in May. A common follow up question we got from that blog post was: “Hey cool. So, uh, what are WMI filters again?”

    Group Policy WMI filters were introduced with Windows XP, and are supported in Windows Server 2003, Windows Vista, and Windows Server 2008. They are not supported in Windows 2000, so if you have an all-2000 environment you’re out of luck (10 years is a long time to go without upgrading :-P).

    For those still with us…

    You can use WMI filters to add a decision on when to apply a given group policy. This can be very useful when users or computers are located in a relatively flat structure instead of specific OU’s, for example. Filters can also help when you need to apply certain policies based on server roles, operating system version, network configuration, or other criteria. Windows evaluates these filters in the following order of overall Group Policy Processing:

    1. Policies in hierarchy are located.
    2. WMI Filters are checked.
    3. Security settings are checked.
    4. Finally, once everything has ‘passed’, a policy is applied.

    So we find all the policies that exist in the user/computer’s Local, Site, Domain, and OU hierarchy. Then we determine if the WMI filter evaluates as TRUE. Then we verify that the user/computer has Read and Apply Group permissions for the GPO. This means that WMI filters are still less efficient than hierarchical linking, but can definitely use filters to make decisions in a non-hierarchical Active Directory design.

    You configure WMI filters using the WMI Filters node in GPMC.MSC.


    Figure 1 – GPMC WMI Filters Node

    Then you can create, delete or edit a filter.


    Figure 2 – WMI Filter Editor

    Then you can link the WMI filter to any GPO you like (or more than one GPO), like below:


    Figure 3 – GPMC Filter Dropdown

    So in this case, I created a filter (you will see more on this below) that allows a GPO to apply to operating systems earlier than Windows Vista. I linked the WMI filter to a GPO that is applied to Windows Server 2008 computers – so the GPO shouldn’t apply. If I force Group Policy processing using GPUPDATE /FORCE then run GPRESULT /R, I see:


    Figure 4 – GPRESULT output


    WMI filters use a language called WQL, which will be very familiar to anyone that has ever written a SQL query. The nice thing about learning WMI queries is that it forces you to learn more about the extremely powerful WMI system as a whole and its massive repository of data within it. WMI works within a construct of Namespaces and Classes. 99% of every WQL query will operate in the CIMV2 namespace, like all of the examples below.

    So let’s look at some syntax examples:

    Only for certain operating systems

    It is common to want Group Policy objects to apply to a computer using a specific operating system or service pack installed. Here are some examples that cover a few bases:

    SELECT Version FROM Win32_OperatingSystem WHERE Version < "6"

    The above WQL query returns true for any operating systems older than Vista (so Windows XP and Windows Server 2003).

    SELECT Version FROM Win32_OperatingSystem WHERE Version LIKE "6.0%"

    The above WQL query returns true for only Windows Vista or Windows Server 2008 operating systems.

    SELECT Version FROM Win32_OperatingSystem WHERE Version = "5.1.2600"

    The above WQL query returns true only if the operating system is Windows XP Service Pack 2.

    SELECT * FROM Win32_OperatingSystem WHERE Version LIKE “6.0.%” AND ProductType <> “1”

    The above WQL query returns true only if the computer is running Windows Server 2008 regardless of service pack. Why so complex, you ask? Remember that Windows Server2008 and Vista SP1 share the same codebase, so they actually have the same exact version. Choosing a product type not equal to 1 (which is Workstation) returns only servers or domain controllers running Windows Server 2008.

    Only on Windows Server 2008 Core servers

    What if you have a GPO that you want to apply only to servers running Windows Server 2008 Core installations? Here is a sample query (wrapped for readability, this should be done as a single line in the filter dialog):

    SELECT OperatingSystemSKU FROM Win32_OperatingSystem WHERE OperatingSystemSKU = 12 OR OperatingSystemSKU = 39 OR OperatingSystemSKU= 14 OR OperatingSystemSKU = 41 OR OperatingSystemSKU = 13 OR OperatingSystemSKU = 40 OR OperatingSystemSKU = 29

    These values map back to HEX values, which map back to:

    Value Meaning



    Server Datacenter Edition (core installation)




    Server Datacenter Edition without Hyper-V (core installation)




    Server Enterprise Edition (core installation)




    Server Enterprise Edition without Hyper-V (core installation)




    Server Standard Edition (core installation)




    Server Standard Edition without Hyper-V (core installation)




    Web Server Edition (core installation)


    If you want GPOs to apply only to computers NOT running Windows Server 2008 Core (and you can probably think of some reasons to do that), then you would change all the equal signs (=) in the above query to signs above to angled brackets (<>).
    (See for details and the
    non-CORE values.)

    Only on a certain day of the week

    Yes this is possible! Yes, customers have asked how to do this! No, I have no idea why! Ok, kidding about that last one, but it sure seems like an odd request at first. It turns out that some companies like to do things like set a specific message of the day for their legal notice. Or have a separate screensaver running every day of the week for their users. Different strokes for different folks, I suppose.

    To do this, your WQL queries (one filter per GPO that you wanted to set, remember) would be:

    Select DayOfWeek from Win32_LocalTime where DayOfWeek = 1

    Select DayOfWeek from Win32_LocalTime where DayOfWeek = 2

    Select DayOfWeek from Win32_LocalTime where DayOfWeek = 3

    You get the idea. One is Monday, two is Tuesday, etc.

    Wrapping it up

    Hopefully you’ve found some new things to think about regarding WMI filters and Group Policy. A closing note: not all WMI filters are created equal. Not everything in WMI is as optimized as we’d like it to be, and some WMI queries are not as performant as we’d like. Avoid loose wildcard queries when possible as they will run slower (for example, Select * from Win32_LocalTime where DayOfWeek = 5 will run slightly slower than the samples provided above). And above all, always test before deploying to production, using the slowest hardware you can find so that you get a good idea about baseline performance.

    Got a filter question or a good sample to share? Hit the comments section below.

    - Ned Pyle

  • Vista’s MoveUser.exe replacement

    Hi Rob here again. I recently had a customer that needed the functionality of MoveUser.exe from the Windows 2000 Resource Kit available in Windows Vista. The customer had quite a few Windows Vista machines that were not joined to the domain but were now migrating to Active Directory. For their own business reasons they were previously unable to join the machines to the domain, instead all the users logged on with local user accounts. Since they had this new fancy Active Directory they created user accounts in AD for the users and joined the machines to the domain. They then found that they needed a way to attach the users’ existing local profile to their Active Directory user accounts so that the users would have their normal setup and desktop when they logged in-a seamless experience. Now if you have been around forever like most of us here in support in Windows 2000 and up we used a utility named MoveUser.exe to accomplish this.

    Well, in Windows Vista moveuser.exe is no longer supported. However, now we expose this functionality with a new WMI provider called Win32_UserProfile, which is discussed in KB930955. This is awesome because we expose things about user profiles in WMI now… and we can also move the profile to another user as well as delete user profiles. However, once I started looking at MSDN to understand what methods were available I quickly found that MSDN has not been updated as of yet for this new class. So we did some digging into the source code to find out how this works and what is supported.

    I wrote a sample script that illustrates how you can leverage this provider to move an existing user profile to another user’s profile. I know that I could have made the script smaller by not listing out all the different properties available in the provider, but the different things exposed are just way too many and if you are planning on using this provider they are just way too cool.


    Please keep in mind that this is a sample script-you will need to alter it and test it in your environment and for your needs. To use:

    1. Copy the below script into Notepad then save as moveuser.vbs

    2. You will need to modify the following variables within the script.

    • strComputer: The computer name that this script needs to run against
    • strSourceAcct: The user account that has the source profile on the system
    • strSourceAcctDomain: The domain of the source user account that the profile belongs to. If the source account that you want to move the profile from is a local computer user you put in the computers name for the domain. If this is another domain then you type in the domain name.
    • strTargetAcct: The user account that the source profile should be moved to.
    • strTargetDomain: The domain of the target user account that the profile should be moved to. If the target account that you want to move the profile to is a local computer user you put in the computers name. If this is another domain then you type in the domain name.
    • strDomainDN: The Target Account Domains Distinguished Name. This is done for the LDAP query to be built to find the target accounts SID. for example dc=contoso,dc=com

    3. Run the script by typing cscript moveuser.vbs

    Sample Script

    '     This script is provided "AS IS" with no warranties, and confers no rights.
    '     For more information please visit
    ' to find terms of use.
    Option Explicit
    DIM strComputer, strSourceAcct, strSourceAcctDomain, strTargetAcct
    DIM strTargetAcctDomain, strTargetAcctSID
    DIM objProfile, objCommand, objRecordSet, objConnection, objWMIService, objSID
    DIM dtStart, colProfiles, oSID, oUsr
    DIM Revision, IssueAuthorities(11), strSDDL, subAuthorities
    DIM strDomainDN


    '  This script has hard coded variables in it that must be filled out.
    '  strComputer = The computer name that this script needs to run against.
    '                                   With WMI the "." means this computer.
    '  strSourceAcct = user account that has the source profile on the system.
    '  strSourceAcctDomain = The domain of the source user account that the profile belongs to.
    '                                   If the source account that you want to move the profile from
    '                                   is a local computer user you put in the computers name for the domain. 
    '                                   If this is another domain then you type in the domain name.
    ' strTargetAcct = The user account that the source profile should be moved to.
    ' strTargetDomain = The domain of the target user account that the profile should be moved to
    '                                   If the target account that you want to move the profile to.
    '                                   is a local computer user you put in the computers name. 
    '                                   If this is another domain then you type in the domain name.
    ' strDomainDN = The Target Account Domains Distinguished Name. 
    '                                  This is done for the LDAP query to be built to find the target accounts SID

    strComputer ="."
    dtStart = TimeValue(Now())
    Set objConnection = CreateObject("ADODB.Connection")
    objConnection.Open "Provider=ADsDSOObject;"
    Set objCommand = CreateObject("ADODB.Command")
    objCommand.ActiveConnection = objConnection

    ' We need the proper Active Directory domain name where the user exists in a DN format.  You can
    ' modify the strDomainDN variable to you Active Directory domain name is in DN format.

    objCommand.CommandText = _
        "SELECT AdsPath, cn FROM 'LDAP:// "+strDomainDN+"' WHERE objectCategory = 'user'" & _
             "And sAMAccountName= '"+strTargetAcct+"'"
    objcommand.Properties("searchscope") = ADS_SCOPE_SUBTREE 
    Set objRecordSet = objCommand.Execute
    If objRecordset.RecordCount = 0 Then
        WScript.Echo "sAMAccountName: " & strTargetAcct & " does not exist."
    ElseIf objRecordset.RecordCount > 1 Then
        WScript.Echo "There is more than one account with the same sAMAccountName"
        WScript.Echo "Found account:  "+strTargetAcctDomain+"\"+strTargetAcct + " in the domain."
        Do Until objRecordSet.EOF
            Set Ousr = GetObject(objRecordSet.Fields("AdsPath").Value)
            strTargetAcctSID = SDDL_SID(oUsr.Get("objectSID"))
            WScript.echo "SID for  "+ strTargetAcctDomain+"\"+strTargetAcct + _
    " is:  "+strTargetAcctSID
            WScript.Echo VBNewLine
            WScript.Echo VBNewLine



    Set objWMIService = GetObject("winmgmts:\\" & strComputer &"\root\cimv2")
    Set colProfiles = objWMIService.ExecQuery("Select * from Win32_UserProfile")
    For Each objProfile in colProfiles
        Set objSID = objWMIService.Get("Win32_SID.SID='" & objProfile.SID &"'")
        Wscript.Echo"======================================================"& VBNewLine _
            &"Sid:" & objProfile.Sid & VBNewLine _
            &"User Name:" & objSID.AccountName & VBNewLine _
            &"User Domain:" & objSID.ReferencedDomainName & VBNewLine _
            &"LocalPath:" & objProfile.LocalPath & VBNewLine _
            &"Loaded:" & objProfile.Loaded & VBNewLine _
            &"RefCount:" & objProfile.RefCount & VBNewLine _
            &"RoamingConfigured:" & objProfile.RoamingConfigured & VBNewLine _
            &"RoamingPath:" & objProfile.RoamingPath & VBNewLine  _
            &"RoamingPreference:" & objProfile.RoamingPreference & VBNewLine _
            &"Status:" & objProfile.Status & VBNewLine _
            &"LastUseTime:" & objProfile.LastUseTime & VBNewLine  _
            &"LastDownloadTime:" & objProfile.LastDownloadTime & VBNewLine  _
            &"LastUploadTime:" & objProfile.LastUploadTime & VBNewLine 

    '    Testing to verify that the current profile handle is for the Source Account that we want to
    '    Move to the domain user.
    if UCase(objsid.referencedDomainName+"\"+objsid.AccountName)= _ 
    UCase(strSourceAcctDomain+"\"+strSourceAcct) Then
        ' Making sure that the source profile is currently not in use.  If it is we will bail out.
            If objProfile.RefCount < 1 Then
    WScript.echo "Change Profile for:  "+ strSourceAcctDomain+"\"+ _
    strSourceAcct+" to: "+ strTargetAcctDomain+"\"+strTargetAcct
            ' ChangeOwner method requires to String SID of Target Account and a Flag setting

            ' Flag 1 = Change ownership of the source profile to target account
    ' even if the target account  already has a profile on the system.

            ' Flag 2 = Delete the target account Profile and change ownership
    '  of the source user account profile to the target account.

            '  To use the ChangeOwner method, both the source and
    '  target account profiles (If it exists) must not be loaded.

                ObjProfile.ChangeOwner strTargetAcctSID,1
                Wscript.echo "Could not move the users profile, because " + _
                strSourceAcctDomain+"\"+strSourceAcct+" profile is currently loaded"
            End If   
         End If
    End If
    Sub Init_IssueAuthorities( )
        'DIM IssueAuthorities(11)
        IssueAuthorities(0) = "-0-0"
        IssueAuthorities(1) = "-1-0"
        IssueAuthorities(2) = "-2-0"
        IssueAuthorities(3) = "-3-0"
        IssueAuthorities(4) = "-4"
        IssueAuthorities(5) = "-5"
        IssueAuthorities(6) = "-?"
        IssueAuthorities(7) = "-?"
        IssueAuthorities(8) = "-?"
        IssueAuthorities(9) = "-?"

    end sub

    function SDDL_SID ( oSID )
        DIM Revision, SubAuthorities, strSDDL, IssueIndex, index, i, k, p2, subtotal
        DIM j, dblSubAuth
    ' First byte is the revision value
        Revision = "1-5"
    ' Second byte is the number of sub authorities in the
    ' SID
        SubAuthorities = CInt(ascb(midb(oSID,2,1)))
        strSDDL = "S-" & Revision
        IssueIndex = CInt(ascb(midb(oSID,8,1)))
    ' BYtes 2 - 8 are the issuing authority structure
    ' Currently these values are in the form:
    ' { 0, 0, 0, 0, 0, X}
    ' We use this fact to retrieve byte number 8 as the index
    ' then look up the authorities for an array of values
        strSDDL = strSDDL & IssueAuthorities(IssueIndex)
    ' The sub authorities start at byte number 9. The are 4 bytes long and
    ' the number of them is stored in the Sub Authorities variable.
        index = 9
        i = index
        for k = 1 to SubAuthorities
            ' Very simple formula, the sub authorities are stored in the
            ' following order:
            ' Byte Index Starting Bit
            ' Byte 0 - Index 0
            ' Byte 1 - Index + 1 7
            ' Byte 2 - Index + 2 15
            ' Byte 3 - Index + 3 23
            ' Bytes0 - 4 make a DWORD value in whole. We need to shift the bits
            ' bits in each byte and sum them all together by multiplying by powers of 2
            ' So the sub authority would be built by the following formula:
            ' SUbAuthority = byte0*2^0 + Byte1*2^8 + byte2*2^16 + byte3*2^24
            ' this be done using a simple short loop, initializing the power of two
            ' variable ( p2 ) to 0 before the start an incrementing by 8 on each byte
            ' and summing them all together.
            p2 = 0
            subtotal = 0
            for j = 1 to 4
            dblSubAuth = CDbl(ascb(midb(osid,i,1))) * (2^p2)
            subTotal = subTotal + dblSubAuth
            p2 = p2 + 8
            i = i + 1
    ' Convert the value to a string, add it to the SDDL Sid and continue
        strSDDL = strSDDL & "-" & cstr(subTotal)
        SDDL_SID = strSDDL
    end function

    Please keep in mind if you have not installed Service Pack 1 for Vista, you will need to download the MSI installer to get the new WMI Profile provider since it was released after Vista shipped.

    Well, I hope that you find this functionality helpful. Happy scripting.

    - Rob Greene

  • Domain Locator Across a Forest Trust

    Rob and Mike here. We're asked, many times, why a user does not authenticate against a local domain controller in the same site when logging on across a forest. We've setup the most common scenario to help explain how domain locator works for user logons across a forest.


    Let's explain the typical scenario in which we see this problem: The scenario starts with two separate Active Directory forests: and Each forest has a forest (i.e. kerberos) trust to the other. The forest has one Active Directory site name CHARLOTTE. The forest contains two sites: REDMOND and CONTOSO. Administrators in the forest created the CONTOSO site and subnet to support logons for users from terminal servers in the forest.

    Figure 1 Forest trust configuration


    Users from logon to a terminal server existing in the forest. However, Users experience a slower-than-usual logon, and the LOGONSERVER environment variable shows the name of a remote domain controller in the REDMOND site rather than the domain controller from the CONTOSO site.

    However, administrators from the domain expect users from their domain (logging on terminal servers) to authenticate using the domain controller located in the CONTOSO site. The CONTOSO site is the same physical locations as the terminal server. Authentication should occur in the local site and should be fast, right?

    DC Locator

    It is important to know how a Windows computer selects a domain controller. The computer, during startup, determines the Active Directory site in which it belongs. Windows accomplishes this by examining the subnet of its current network configuration. Then, the computer queries a domain controller that hosts the computer object(using the Windows API DsGetSiteName). The domain controller answers this query with the name of the site associated with the computer's currently configured subnet. This is all done by the NetLogon service, which runs the DC Locator code at boot and periodically rechecks the domain controllers’ location.

    The computer determines the site name using a domain of which the computer is a member—not the user's domain. This determination occurs during computer startup—not during user logon. Microsoft Support article 939252 (;EN-US;939252) describes how you can change this behavior

    Windows writes the site name to the registry during each computer startup. You can view the registry to determine the site to which the computer believes it belongs. You should NOT modify this registry value. The path to this registry value is:

    Domain Controller discovery during user logon

    Windows will attempt to use the closest domain controller (on the same subnet) to the local computer for authentication. Windows finds the closest domain controller by using DNS and SRV resource records.

    Here’s how it works: Windows first performs a DNS query to find a _ldap SRV record for the computer's current site, but using the domain name selected from the CTRL+ALT+DEL sequence – the domain name of the user. An example looks like:

    _ldap._tcp.<Computer Site Name>._sites.dc._msdcs.<User Domain>.com: type SRV, class IN

    The DNS server responds indicating a record by that name is not found. Windows then attempts to find any domain controller within the user's domain. Windows accomplishes this by removing the site name from the DNS query. The example similar to the one above:

    _ldap._tcp.dc._msdcs.<User Domain>.com: type SRV, class IN

    The DNS server's response to the above request includes a resource record for every domain controller in the user's domain. Since the client receives the list of domain controllers in no particular order this result is usually the cause as to why the domain controller locator does not use the closest domain controller for authentication.

    The Netlogon service of a domain controller is responsible for dynamically registers the _ldap service resource records with its configured DNS server. This registration includes the site specific and domain specific _ldap records.

    Our scenario involves a terminal server, which allows multiple users sessions. This is a great way to take network captures of user logon related issues by sing one of the logon sessions to take the network capture. It is always best to clear the DNS and NetBIOS name caches before starting a network capture. This ensures the network capture includes name resolution. You can clear these caches by using IPConfig /FlushDNS and NbtStat –R from a command window (under an elevated command prompt for Server 2008 and Vista).

    Here is a snippet of the output of the network capture.


    Figure 2 network capture of user logon

    The results of the network capture show the domain controller locator attempts to locate a domain controller in the site with the same name as the site of the computer; but in the user's domain (frame 3). The DNS server responds with no such name. This is correct. The forest has only two sites: REDMOND and CONTOSO. Frame 4 queries for an SRV record a second time; however, this time the query does not include the site name of the computer (_ The DNS response provides a positive answer to the second query. The answer includes a _ldap record for each domain controller in the domain (the user's domain).

    We've covered the background information and the problem. Now, let's talk about how to fix it. We can accomplish this by using Active Directory Sites and Services to rename the CONTOSO site in the domain to CHARLOTTE (the name of the site hosting the computer in the domain). Active Directory site configuration is stored in the configuration partition of Active Directory. Renaming the site creates a change and you'll want ensure this replication converges-- especially to the domain controller that is now located in the CHARLOTTE site of the domain. After Active Directory replication completes, then restart the Netlogon service on the domain controller in CHARLOTTE site (in the domain). This registers the service resource records in DNS for the domain controller, including the new site in which it belongs.


    Figure 3 Forest trust configuration after site rename

    Let's take another network trace of a domain user logon from the terminal server in the domain.


    Figure 4 Network capture after site rename in

    The same DNS query from figure 1 appears in figure 2. Frame 3 shows the domain controller locator attempting to find a domain controller service resource record in the CHARLOTTE site of the user's domain, However, the difference between figure 1 and figure 2 is the DNS response. Figure 1 returned a negative DNS response because a resource record for the domain controller did not exist in the CHARLOTTE site in the domain. But, figure 2 shows a positive DNS response (frame 5) for a service resource record for a domain controller in the CHARLOTTE site of the domain.


    After renaming the sites so that they match in both forests, the terminal server in the domain successfully located a domain controller covering the CHARLOTTE site for domain. Ideally, in this scenario you would also want the domain controller covering for the CHARLOTTE site to be on the same subnet as the terminal server. This helps expedite logon requests originating from the terminal servers. Regardless, the configuration provides a way to distinguish a specific domain controller for use with logons that span across forests.

    - Rob Greene and Mike Stephens

  • Service Connection Points (SCPs) and ADAM/AD LDS


    Hello, it’s LaNae again. A major issue I see when customers call in regarding ADAM/AD LDS is around the creation of Service Connection Points and why they are needed. Let’s take a further look into this topic and uncover the mystery of this object.

    What are Service Connection Points?

    Service Connection Points (SCPs) are objects in Active Directory that hold information about services. Services can publish information about their existence by creating serviceConnectionPoint objects in Active Directory. Client applications use this information to find and connect to instances of the service. ADAM/AD LDS is no exception to this. The serviceConnectionPoint object class is derived from the connectionPoint class. ServiceConnectionPoints in ADAM/AD LDS will contain some key attribute information that is needed for client application discovery. The table below lists the contents of the serviceConnectionPoint object attributes. You can also find this information by using ADSIEDIT.MSC and viewing the properties of the child object of the computer that the ADAM/AD LDS instance is installed.

    For example, Exchange 2007 uses SCPs to advertise autodiscover service information. The serviceBindingInformation attribute of this object is updated during setup with the autodiscover service URL. For more information on how Exchange 2007 uses Service Connection Points see Doug Gowans blog :


    This image was taken from the Understanding ADAM service publication TechNet article.

    Discovering ADAM/AD LDS with Service Connection Points

    If ADAM/AD LDS is installed in a domain and the ADAM/AD LDS service account has the Create Child right on the computer object where the serviceConnectionPoint object will be created it will attempt to create a serviceConnectionPoint object in Active Directory. By default global catalogs in Active Directory contain the same information that can be found in the Keywords attribute of a SCP object. Client applications will search the SCP attributes located in the global catalog to find an ADAM/AD LDS instance. Client applications can search for:

    • The ADAM/AD LDS object identifier
    • Configuration partition GUID
    • ADAM/AD LDS instance GUID
    • ADAM/AD LDS instance name, or any directory partition.
    • Client applications may perform load balancing by choosing an ADAM/AD LDS instance randomly when a search returns more than one applicable instance.

    Discovering ADAM/AD LDS without Service Connection Points

    Understand that ADAM/AD LDS do not need SCPs to be published in order to function properly. ADAM/AD LDS can run with or without SCPs. If ADAM/AD LDS is installed in a workgroup environment or if the service account that ADAM/AD LDS is running under does not have the proper permissions to create SCPs then it will not create an SCP. Under these circumstances client applications will use DNS to resolve the host name of a computer that has ADAM/AD LDS installed.

    Creating Service Connection Point Objects

    Service Connection Point objects can be created automatically or manually. When ADAM/AD LDS is installed on a machine that is part of a domain it will attempt to create a service connection point object. This object will appear as a child object of the computer object where the ADAM/AD LDS instance is installed. If the service account that is used to run ADAM/AD LDS does not have the “Create Child Right on the computer object where the ADAM/AD LDS instance is installed it will fail to create the service connection point object. ADAM/AD LDS will then log an Event ID 2537 in the ADAM/AD LDS event log stating that it could not create the SCP due to insufficient rights.

    How are SCP Objects updated?

    ADAM/AD LDS checks the SCP object for changes when the instance is started and then it will review the SCP object every hour after that to make sure it is still valid. When the instance starts it will search the Global Catalog for its GUID and then use that to find the distinguished name of the SCP object. The ADAM/AD LDS instance will bind to the distinguished name of the SCP object and updates it if needed. The interval that the ADAM/AD LDS instance reviews the SCP object can be modified by adding the Server information update interval (mins) dword value to the following registry key: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\instancename\parameters. The value data will be set to the time interval in minutes that is desired.

    Managing SCP Objects

    You can manage the ADAM/AD LDS by creating an OU that contains the computer objects that host ADAM/AD LDS instances. Doing this will place all SCP objects in the same location and allow for ease of administration.

    Modifying the SCP Object Creation Location

    Earlier in this blog I stated that the SCP object is created as a child object of the computer object that holds the ADAM/AD LDS instance. This location can be changed by modifying the SCPContainer attribute located on the SCP Publication Service object. This can be done to make administration of SCP objects easier. The following steps are identical for ADAM and AD LDS with a few exceptions: in the AD LDS schema you do not have to make any modification to the msDs-SCPContainer attribute. Also, there is no separate ADSIEDIT snapin for AD LDS.

    You will connect to the AD LDS instance using the ADSIEDIT.msc that is used to manage AD DS and connect to the instance on its respective port.

    1. You must first open the ADAM Schema (ADAM-adsiedit.msc) and navigate to the msDS-SCPContainer attribute.


    2. Right click on the attribute and select properties. Check the box next to “Allow this attribute to be shown in advanced view” and “Index this attribute in the Active Directory” and click “OK”.



    4. Connect to the configuration container of the ADAM/AD LDS instance and navigate to “CN=Directory Service,CN=Windows NT, CN=Services,CN=Configuration, CN=GUID of Instance”.


    5. In the right pane double click on the CN=SC Publication Service object.

    6. Locate the msDS-SPContainer attribute and click edit.


    7. Enter the DN of the location where you would like the SCP object to be created.

    Note: you will need to give the ADAM/AD LDS service account the create child object right on the object you put in the Value. This can be done by right-clicking on the DN of the SCP object and going to properties. Click on the security tab and add the ADAM/AD LDS service account to the “Create Child Object” right.

    Once you have completed these steps all ADAM/AD LDS instances will create the SCP in the specified location.


    I hope this blog post has given you a better understanding of what Service Connection Point objects are. You should hopefully now know why we use service connection point objects and how to administer them.

    - LaNae Wade

  • Third Party Application Fails Using LDAP over SSL

    Hi, Michael here. The following issue is one that I have seen come up from time to time and can be a challenge for IT administrators who are trying to use the built in Version 2 Domain Controller Authentication template in their environment. The concern may be seen when folks used a version 1 certificate in the past but the newer one (version 2) seems to give some unexpected results.

    So what’s the problem? Well, if you have a third party application which uses LDAP over SSL to connect to the domain controller it may not work initially using the new version 2 Domain controller Authentication certificate.

    So let’s go over the issue in detail. A 3rd party application was making LDAP over SSL connections to the Domain Controllers as part of what it does intentionally.  This was working when the domain controller had a certificate based on the “old style” version 1 Domain Controller template. An Enterprise Certification Authority had issued the certificate. However, the “Domain Controller” certificates have been superseded by certificates based on the “Domain Controller Authentication” certificates which can happen for several reasons that we won’t go into great detail on in this blog post today.  The end result which is seen is that the 3rd party application now fails. 

    What is the apparent problem? By default, the “Domain Controller Authentication” certificate has a blank subject field and the Subject Alternate Name (SAN) field is marked critical on the “Domain Controller Authentication” certificate. Simply put, some applications cannot use a certificate if the SAN field being marked critical.

    Why is this field important? Some applications may have difficulty using the certificate if the SAN field is marked critical and the subject field is blank because of how these fields are checked when deciding whether to use a certificate.

    So, how do you resolve this little quandary?

    a.) You could change you application to be in compliance with RFC 3280 (see excerpts from RFC 3280 below)

    b.) You could configure the domain controller to use a certificate based on the version 1 Domain Controller template.

    c.) In the Domain Controller authentication certificate template, you can change the subject field from “none” to “common”.  You can then issue a new Domain Controller Authentication certificate to the Domain Controller.  In this certificate, the subject field contains the DNS name of the machine and the SAN field is not marked critical on the domain controller authentication certificate. Then delete the old “Domain Controller Authentication” certificate. Finally, reboot the machine.

    Why reboot? As a general rule, if a Domain Controller already has a certificate for LDAP over SSL, it will not pick up the new one until the next reboot.

    End result: The 3rd party application can successfully connect to this Domain Controller.

    So why did this whole problem occur?

    This change to have a “blank Subject field and a Critical SAN field” was made to conform to RFC 3280 (Internet X.509 Public Key Infrastructure   April 2002).  Here’s an excerpt from that RFC on why the change was made:

    • Subject Common name use is ambiguous.
    • Sometimes a DNS name is stored in this RDN, and sometimes other types of names are stored there.
    • The Subject Common Name is also limited to 64 characters in CCITT conforming implementations, so it can easily be too short for a full DNS name.
    • The Subject Alt Name extension encoding tags fields to identify their use.
    • This RFC was published in April 2002, and the V2 DC template change was implemented in Windows 2003.

    The bottom line here is that client applications using LDAP over SSL need to be updated to conform to current standards (mentioned in the afore mentioned RFC)

    Our development team tells us this: Currently, we do not expect any immediate negative impact to reverting back to the old name representation – as long as all of the full DNS names are shorter than 64 characters, and as long as all of the characters in the full DNS names conform to the IA5 string character set.

    There is certainly a potential danger of some applications no longer accepting DNS names in the Subject Common Name, but we have not yet seen that issue. For more detail you can read the RFC for yourself here (insert link on here

    RFC 3280        Internet X.509 Public Key Infrastructure  Subject Alternative Name

    The subject alternative names extension allows additional identities to be bound to the subject of the certificate. Defined options include an Internet electronic mail address, a DNS name, an IP address, and a uniform resource identifier (URI). Other options exist, including completely local definitions.  Multiple name forms, and multiple instances of each name form, MAY be included. Whenever such identities are to be bound into a certificate, the subject alternative name (or issuer alternative name) extension MUST be used; however, a DNS name MAY be represented in the subject field using the domainComponent attribute as described in section

    Because the subject alternative name is considered to be definitively    bound to the public key, all parts of the subject alternative name MUST be verified by the CA.

    Further, if the only subject identity included in the certificate is an alternative name form (e.g., an electronic mail address), then the subject distinguished name MUST be empty (an empty sequence), and the subjectAltName extension MUST be present.  If the subject field contains an empty sequence, the subjectAltName extension MUST be marked critical.

    When the subjectAltName extension contains a domain name system label, the domain name MUST be stored in the dNSName (an IA5String). The name MUST be in the "preferred name syntax," as specified by RFC 1034 [RFC 1034].  Note that while upper and lower case letters are allowed in domain names, no signifigance is attached to the case.  In addition, while the string " " is a legal domain name, subjectAltName extensions with a dNSName of " " MUST NOT be used.  Finally, the use of the DNS representation for Internet mail addresses ( instead of MUST NOT be used; such identities are to be encoded as rfc822Name.

    Note: work is currently underway to specify domain names in international character sets.  Such names will likely not be accommodated by IA5String.  Once this work is complete, this profile will be revisited and the appropriate functionality will be added.

    Finally, here are a few additional links which can be helpful in planning and understanding this issue.

    How to troubleshoot LDAP over SSL connection problems

    You may be unable to connect to a Windows Server 2003-based domain controller by using LDAP over an SSL connection

    Until next time folks, take care out there!

    - Michael Hunter

  • Command-Line Compression in Core

    Hi, Ned here again. Today I’m going to talk about handling compressed files in Windows Server 2008 running as a Core server. You know, that thing with no pretty graphical interface and just a big command prompt that stares at you, daring you to try some successful administration.

    Core mode is pretty slick – super-small footprint on the disk, great memory utilization, and plenty of useful roles that can be installed. But sheesh – it can be a real pain in the tail if your command-line skills are rusty or if you just haven’t ever had to deal with certain operations sans GUI.

    So, quick question: have you tried to zip a file on a Core server yet? It’s sorta hard… because there is no zip.

    With Core, there is no Explorer, so there is no file compression functionality. What if you need to compress a file on your Core server in order to copy it over some awfully slow connection and you want to do it all locally? You have two options:

    1. Make sure you have one of the 400 billion trillion zillion command-line zipping tools installed on your Core servers. Many of which are free even for commercial use, if you are that ‘frugal’.
    2. Cheat like a pro, and use MAKECAB.EXE and EXPAND.EXE.

    Let’s talk about pro-style cheating.

    Compressing a single file with MAKECAB

    MAKECAB is a tool present in all later SKU’s of Windows. While it cannot create ZIP files, it can create cabinet (CAB) files. It’s an odd little utility as it was designed for developers to package files for installs, but it works well with decent compression.

    So let’s take the scenario where you are remoted into your Core server through Terminal Services, WINRM, or (yuck) Telnet. You have a single file you need to compress and copy elsewhere. In your CMD prompt session, type:

    MAKECAB <source> <destination> /l <some folder path>

    So for example:

    MAKECAB c:\somefolder\somebig.fil /l c:\

    This will cab up the ‘somebig.fil’ into ‘’ and put that file at the root of the C: drive for easier access.

    Compressing a bunch of files with MAKECAB

    Things get trickier with multiple files. Remember that MAKECAB was designed for developers, so naturally it’s as complex as possible :-). Using MAKECAB for a bunch of files requires that you use a directives file. Let’s say we have a folder full of files, and we want to zip them all up into one cab:

    1.  CD into the folder containing your files.

    2.  Run:

    DIR /B > mycab.ddf

    3.  Run:

    MAKECAB /d /d maxdisksize=CDROM /f mycab.ddf

    4.  You will now have a folder called ‘Disk1’ that contains ‘’

    So a bit tricky, but not too terrible. If you want to get fancy you can add paths in a DDF file, and can even add more directives. If you want a definite cure for insomnia, you can read everything you ever wanted to know about cab files and the Cabinet SDK by going here. This includes further tools like CABARC that add advanced cabinet features. The "maxdisksize" switch there tells makecab.exe to write to the cab file up to 660MB. If there is still data to go, it will then create a "disk2" folder, write to that cab file, and so on.

    Decompressing a cab file with EXPAND

    Naturally, you’re going to want a way to decompress these files. If you had just copied to a Full Windows 2008 computer, Explorer is perfectly ok at reading CAB files. But let’s say you’ve been copying these CAB files between Core servers and now need to expand the data out. Simple:

    EXPAND -R <cab file> -F:* <destination folder that must exist>

    So using our from above:

    EXPAND –R –F:* c:\

    And now our file(s) in the CAB file are decompressed and ready to roll. All without any fancy Explorer shell.


    Final Raymond Chen-style preemptive strike: you’re probably firing up the Comment section below to lambast the developers about leaving zip tools out of Win2008 and how this is a conspiracy to… make people not like us? The real reason there is no command-line zip in Core is because there has never been a command-line zip in Windows. IT Pros just haven’t asked for it; they had their favorite zipping tools of choice, and there was always a GUI method for the home users. In fact, there was no MAKECAB in Core mode for most of its development history, because no MS beta customer had asked for it or for zip functionality after a year of testing! Yours truly raised a (polite, professional) stink and it was added in RC1. Don’t say I never did anything for you, folks.

    - Ned Pyle

  • Fail to log Security Settings from Default Domain Policy

    Hello everyone, Scott Goad here, and today I want to take a few minutes and talk about a recent case where we fail to log security settings from the Default Domain Policy. In this case, we had a small environment with 2 domain controllers, one holding all of the FSMO roles, the other a replica domain controller.

    The issue was noticed during an internal audit, and the customer noticed that certain security settings were not logged when you run GPRESULT /v, which normally details the resultant set of policies for the particular user and computer. To troubleshoot the issue we began gathering data, and sure enough, some items that were specified in the Default Domain Policy were skipped, and no errors were logged.

    We could even demote the Domain Controller down to a member server, and policy would apply and report correctly.

    Here’s a piece from each domain controller:

    ….snippet from GPRESULT on DC1 (non FSMO holder)….

            Account Policies
            ----------------             GPO: Default Domain Policy
                    Policy:            MaxServiceAge
                    Computer Setting:  600             GPO: Default Domain Policy
                    Policy:            MaxTicketAge
                    Computer Setting:  10             GPO: Default Domain Policy
                    Policy:            MaxClockSkew
                    Computer Setting:  5             GPO: Default Domain Policy
                    Policy:            MaxRenewAge
                    Computer Setting:  7 ….snippet from GPRESULT on DC2 (holds FSMO roles)….






       Account Policies

                GPO: Default Domain Policy
                    Policy:            MaxServiceAge
                    Computer Setting:  600

                GPO: Default Domain Policy
                    Policy:            MaxTicketAge
                    Computer Setting:  10

                GPO: Default Domain Policy
                    Policy:            MinimumPasswordAge

                    Computer Setting:  1

                GPO: Default Domain Policy
                    Policy:            PasswordHistorySize

                    Computer Setting:  6

                GPO: Default Domain Policy
                    Policy:            LockoutDuration

                    Computer Setting:  4294967295

                GPO: Default Domain Policy
                    Policy:            ResetLockoutCount

                    Computer Setting:  30

                GPO: Default Domain Policy
                    Policy:            MaxClockSkew
                    Computer Setting:  5

                GPO: Default Domain Policy
                    Policy:            MinimumPasswordLength

                    Computer Setting:  8

                GPO: Default Domain Policy
                    Policy:            LockoutBadCount

                    Computer Setting:  3

                GPO: Default Domain Policy
                    Policy:            MaximumPasswordAge

                    Computer Setting:  90

                GPO: Default Domain Policy
                    Policy:            MaxRenewAge
                    Computer Setting:  7

    Also, on both Domain Controllers, we logged Event ID 1704:

    image image

    At this point, we looked at the Default Domain Policy, and the settings were there:


    After investigating the issue further, we decided to look at the local security policy, and see what was actually getting applied. Below is a piece that was failing, according to GPRESULT:



    These screenshots were taken from different servers, after we made the changes in the policy. At this point, we know that we applied the settings, but we are not logging this anywhere. We asked our friends at the Global Escalation Services (GES) Team to take a look. They asked us to move the PDC emulator role to the other DC, and see if the behavior changed. It did! The policy settings in GPRESULT followed the PDC emulator role.

    GES reviewed the code and this is a by design behavior. The PDC emulator, member servers and domain-joined workstations apply these settings through group policy. Replica domain controllers for a domain apply these settings by monitoring what is present on the domain naming context head. These settings are replicated via Active Directory replication between the domain controllers of each domain in a forest. These settings are looked at by the domain controllers to help govern some aspects of how they behave. If these settings are changed somehow, the change is replicated and then immediately noticed by the receiving DC and the new behavior takes effect. Here is the full list of attributes:

    • minPwdAge
    • pwdHistoryLength
    • lockoutDuration
    • lockOutObservationWindow
    • minPwdLength
    • lockoutThreshold
    • maxPwdAge
    • pwdProperties (this is complexity on/off)

    These settings can be viewed in LDP, as seen in the snippet below:

    Expanding base 'DC=adatum,DC=com'...
    Result <0>: (null)
    Matched DNs:
    Getting 1 entries:
    >> Dn: DC=adatum,DC=com
              3> objectClass: top; domain; domainDNS; 
              1> distinguishedName: DC=adatum,DC=com; 
              1> instanceType: 0x5 = ( DS_INSTANCETYPE_IS_NC_HEAD | IT_WRITE ); 
              1> lockoutDuration: 1800; 
              1> lockOutObservationWindow: 1800; 
              1> lockoutThreshold: 0; 
              1> maxPwdAge: 3710851; 
              1> minPwdAge: 86400; 
              1> minPwdLength: 7; 
              1> modifiedCountAtLastProm: 0; 
              1> nextRid: 1006; 
              1> pwdProperties: 1; 
              1> pwdHistoryLength: 24; Until next time,


    - Scott “Scooter” Goad

  • Changes to Professional Level (Non-Premier) Support Model

    Ned here. On October 1, 2008 the Professional level “Enterprise Platforms Support” business at Microsoft will transition to a call-back model for all Professional support incidents in the United States and Canada.  Below is a description of how to contact Microsoft customer service, as well as other relevant information regarding this change:

    Why are we moving to a call-back model?

    1. To minimize the amount of time that customers spend on hold
    2. To enable the support incident to be routed to the correct resource, thus minimizing the incorrect routing of support incidents.

    Contacting Microsoft Product Support by Phone

    You can submit a support request via phone by calling 800-936-4900.  Once your support incident is created, the case will be routed to the appropriate support team and you will receive a call from a support engineer.  The response time is based on the severity of the incident.  During business hours (Monday – Friday, 6:00 am – 6:00 PM US Pacific Time), the cost is $259.  If you need to work with a support engineer outside of these hours, the cost is $515.  Please note that you can open a support incident via phone at any time.  The after-hours rate only applies if you need to work with a support engineer during non-business hours.  This information is also outlined on the Microsoft Help and Support site.

    Contacting Microsoft Product Support using Online Support Submissions

    As an alternative to opening a support incident via phone, you can use our Online Support Submissions process.  As with our Phone support offering, this is a call-back model also, and the response time is based on the incident severity.  At this time, Online Support Submissions call-backs are only available during business hours (Monday – Friday, 6:00 am – 6:00 PM US Pacific Time), and the cost of a support incident is $259.

    For more information on this change, please refer to the following web page on the Microsoft Support site: Professional Support Options and Phone Numbers

    For more information on contacting Microsoft Product Support, please refer to the following resources:

    You can also direct questions to us through the EMAIL link at the top of the page.

    - Ned Pyle