Tuesday, May 18, 2010

Violate Best Practices at your own risk

Learned something new in one of those crazy, all night "the sky is falling" scenarios that turn out to be a stubborn admin shooting himself in the foot. He chose to ignore best practices that state: put users into global groups, and then global groups into...well...whatever is necessary.

He decided to put users into universal groups in another domain, even though all the users were from one domain and should have simply been put into a global group in their own domain.  The reason? Politics and stubbornness.

You see, we were forced to create some additional domains against our best advice. And then, again, despite our advice to just put centralized computer resources in those domains (a la the old NT resource domain model) they decided to put security groups in that domain, as well. Because they wanted to.

That made the groups Universal.

On the surface, that seems fine...except for the following:
Scenario Setup
1)  All the users were in domain X
2) The computers were in domain Y
3) The security groups were in domain Y (for no reason except political)
4) The OUs containing the users in domain X are being renamed and reorganized
5) All the DCs in domain X and domain Y are GCs, except two per domain: 1 for backups (DIT is smaller); and 1 for the Inf Master.
6) All the DCs that are GCs got the message about the OU changes.
7) But...there are phantom records in the Universal groups that only get updated about every two days...so...the groups broke because for some inexplicable reason, the servers consuming the groups fell in love with the Inf Master role holder.


Phantom Records
Most of us tend to forget about those lovely little phantom records. See Microsoft KB 248047 for details. Basically, non-GC DCs have no direct knolwedge of objects in other trusted domains, because they don't have a GC. So groups like universal groups containing accounts from trusted domains in Active Directory insert a phantom object for these cross-domain group-to-user references.

Phantom records only contain:
  • The distinguished name of the object
  • The GUID of the object
  • The SID of the object
When a user is added to a universal group, for example, in another domain, any non-GC DCs add one of these phantom objects representing the remote user. That way, they can "intellegently" display and identify the user when someon peaks into the group, without requiring access to a GC.

So when these folks renamed the OUs containing the users, the distinguished name for the user object changed. And access to the systems using those security groups containing the bad user DNs stopped.

And we had an all night call. People tried to force replication. They tried creating a new group and adding the users--but low and behold--the users added to the new group showed the same bad DNs on the non-GC DCs!

It had nothing to do with replication. Replication was working fine. Those phantom records were to blame.  Well, no. Not true. The real cause was the decision to put groups, which would normally be global groups in domain X (per best practice), in domain Y. This made them universal and yada, yada, yada.

You see, non-GCs only rescan their phantom objects and refind/correct DNs about every two days. Because it is a "labor" intensive operation. If it did it more frequently, it might not even finish before it had to start the process again. And then there's all that nasty WAN traffic and DC non-responsiveness while it chugs through this process.

Now you can kick off a phantom scan manually (which we did) but you don't want to do so lightly. And an hour after I kicked off the phantom scan, someone actually renamed the OUs again, anyway, thereby causing the problem all over again. Nice. Thanks.

The interesting thing to me is that the folks managing this do not want to correct it by simply making global groups in the appropriate domain. Instead, they wanted directions on kicking off phantom scans, themselves, whenever they felt it necessary. Like every five minutes or so.

Let's just say that's why they are not Enterprise Admins.

So, sorry. If you shoot yourself in the foot, you have to expect to bleed. And don't expect me to load your gun for you.

Wednesday, March 10, 2010

VBA Macro for Outlook to Save E-mails to File

This is hardly stupendous, and I found various versions of this on the Internet, but sadly, most of the versions simply did not work. The following was my final "massaged" version that actually worked pretty well. Not perfect, but it worked.

The task was to write a macro for Outlook that would save the e-mail as a straight TXT file, using the subject as the filename.

For example, if I got an email with the subject: This is my agenda
It would save that e-mail in a file as: This is my agenda.txt

There are some characters, however, that people insert into subject lines that prevent the file from being saved. For example: \, /, *, |

So I had to strip those out before saving the file.

Here is the final macro:

Sub save_email(myItem As Outlook.MailItem)
   Dim tempstr As String
   Dim strname As String
   Dim Badchar As String
   Badchar = "\/:*?<>()"  
   Dim intIndex As Integer
'pick up the e-mail subject

   tempstr = myItem.Subject
'Remove special chars

   For i = 1 To Len(tempstr)
     If InStr(1, Badchar, Mid(tempstr, i, 1), vbTextCompare) Then
        strname = strname & ""
        strname = strname & Mid(tempstr, i, 1)
     End If
'Save to a file

myItem.SaveAs "c:\Users\tuser\My Documents\" & strname & ".txt", olTXT
End Sub

That's it. The piece that was missing from most of the things I've seen posted on the Internet was the strname = strname & "" line where it actually removes the bad char and keeps on building strname with the characters from the e-mail's subject. I have no idea why other people's programs worked when you only specified strname = strname  but the script failed to remove the special characters when I did that, so I had to add the & "" part which essentially adds nothing to the string.

Go figure.
At least it seems to work.

Friday, February 26, 2010

DNS, DNSCMD and Junk like that

I like to use DNSCMD to slam in a lot of DNS records (in bulk) when we're tearing down or moving zones around. I generally use a batch file wrapper around it, to parse a text file with my DNS record information, like host names and IPs.

Today, I had the challenge of taking a little over a hundred host, MX, and CName records and shoving them into a new setup. And I had the devil of a time getting the syntax right.

Looked all over the web and really didn't find that much info that was helpful to me, particularly with the CName and MX records. Loads out there about Host "A" records, though.
Here is Microsoft's idea of help with DNSCMD:

dnscmd [ServerName] /recordadd ZoneName NodeName RRType RRData

Adding MX Records with DNSCMD
This was much trickier than I expected. I ended up with two forms of the command.
Form 1 (Same as Parent)
You use this when the the name for the mail handler is the same as the zone name.  If you look in your DNS console, you'd see this represented as:
DNS Zone = test.org
(same as parent)          Mail Exchanger (MX)     [10] mymailserver.test.org

So you want an MX record for test.org that sends traffic to mymailserver.test.org

The DNSCMD to do this would be:
DNSCMD mydnsserver.test.org /RecordAdd test.org @ MX 10 mymailserver.test.org

The command is color coded so you can see how it all lines up with the information in DNS.

Form 2
You use this form when the name for the mail handler is different from the zone name. If you look in your DNS console, you'd see this represented as:
DNS Zone = test.org
hq                              Mail Exchanger (MX)    [10] myhqmailserver.test.org

You want mail sent to hq.test.org to be handled by myhqmailserver.test.org

The DNSCMD to do this would be:
DNSCMD mydnsserver.test.org /RecordAdd test.org hq MX 10 mymailserver.test.org

Again, it's color coded so you can see how the elements align. Assuming you can see the colors. :-)

Adding a CName record
In some ways, this is easier to understand than the MX. You have an alias for another server that you want to poke into DNS.
Again, you have your three elements, those being: the zone where your server lives, the name of the server, and the alias/cname you want to assign it.

Let's say you have sql1.test.org and want to give it a cname of bigserver.test.org, here is the DNSCMD to do that:
dnscmd mydnsserver.test.org /RecordAdd test.org sql1 CNAME bigserver.test.org

It's color coded, too.
Hope this made some sort of sense.
That's it for now. Have a great evening.