Wednesday, March 23, 2011

PowerShell - Enable Exchange 2010 Mailbox from Active Directory

I installed Windows Live Writer the other day, so I figured I’d finally give it a shot. Step one was to load up with four cheese sandwiches, a cup of tea and a script! Earlier today when I pondered what to write about, I was deciding between managing NTFS inheritance with PowerShell or using redircmp to better control new domain computers.

Turns out I won’t be writing about either. In this post.

Lets instead turn our focus to Active Directory (AD) and Exchange 2010. Anyone who has worked with AD and Exchange before 2007 will most likely be familiar with the additional tabs in the Active Directory Users and Computers properties sheet for managing Exchange settings. These are gone in Exchange 2010, and as far as I know, won’t be coming back. All the Exchange management is now done in the Exchange Management Console (EMC). While EMC does allow you to create AD objects and mail/mailbox enable them, I find it a but cumbersome if all you want to do is create a mailbox for a user account.

One really nice touch with EMC is that it provides you with the PowerShell (PS) command to do <whatever it is you’re configuring>. Mailbox enabling a user account for example. This means if you’ve done it once in EMC you can easily do it in PowerShell instead. If you don’t mind typing or firing up a PS script to do this, it’s all good. But that’s not why we’re here.

Lets think back to the Exchange 2003 days and how we used to mailbox enable users by right clicking and going to “Exchange Tasks” and then selected what we wanted to do, and went through the wizard.

This is more like it!

Is there something similar in Exchange 2010? No. Not as far as I know (feel free to correct me). But if there’s a will, there’s a way! Since we already have the PowerShell command to mailbox enable the user, we can take advantage of the AD display specifiers and add our own menu item that will appear when you right click a user account. All it will take is a little bit of VBScript magic and an update of a configuration attribute in Active Directory.

We’ll start out by writing a VBScript. The script will perform a couple of checks to make sure that the user account is enabled (it’s a requirement for the PowerShell command), and that it isn’t already mail or mailbox enabled. Then it will proceed by launching PowerShell and finally execute the “Enable-Mailbox” cmdlet.

When a context menu item is selected, the object (ADsPath) itself is passed as an argument to the program.

Enable-Mailbox.vbs

Option Explicit
Dim objShell, objArgs, objUser

Set objShell = WScript.CreateObject("WScript.Shell")
Set objArgs = WScript.Arguments
Set objUser = GetObject(objArgs(0))

If Not IsEmpty(objUser.legacyExchangeDN) Then
    MsgBox "Object " & objUser.CN & " is already mail or mailbox enabled.", vbInformation, "Active Directory Domain Services"
    WScript.Quit
End If

If objUser.AccountDisabled = True Then
    MsgBox "Object " & objUser.CN & " is disabled. Please enable before proceeding.", vbInformation, "Active Directory Domain Services"
    WScript.Quit
End If

objShell.Run("powershell.exe -noexit Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010; Enable-Mailbox -Identity '" & objUser.distinguishedName & "' -Alias '" & objUser.sAMAccountName & "'")

Set objArgs = Nothing
Set objUser = Nothing
Set objShell = Nothing

As always, watch out for unintentional line breaks.

Save this script and place it in a suitable location. I put mine in the \\testlab.local\NETLOGON share for high availability.

The next step is to edit the user account display specifier in the Active Directory configuration partition. I used ADSIEdit.msc to do this. Open it up and connect to the configuration naming context. The attribute is found in this location:
CN=user-Display,CN=409,CN=DisplaySpecifiers,CN=Configuration,DC=testlab,DC=local

At the top you will find an attribute called “adminContextMenu”. We have to edit this attribute to add our entry to the context menu. Leave any entry already there, and add a new one. Mine looks like this:
2,Enable Mailbox,\\testlab.local\NETLOGON\Enable-Mailbox.vbs

The first position is simply where in the menu it should appear. I only had one entry, so I picked number 2. The second position is the name you want to appear in the context menu. Prefixing a letter with the ampersand character (&) adds a shortcut to it. The third entry is the location of the script. In this case, Enable-Mailbox.vbs in the netlogon share.

This MSDN article talks a bit more about the adminContextMenu: http://msdn.microsoft.com/en-us/library/ms677915(v=vs.85).aspx

Once applied, start or restart the Active Directory Users and Computers mmc and look up a user without a mailbox. Right click the user and now “Enable Mailbox” should appear. If you click it, PowerShell will start and load “Microsoft.Exchange.Management.PowerShell.E2010” (this must be present for this to work), and then run the cmdlet to enable a mailbox for the user account!

This should work if the EMC is installed on the system. If you’re trying to do this remote, you may have to use a remote pssession to first connect to a suitable server. I haven’t tried this yet, since right now there are no clients in my lab. –Maybe I’ll revisit this later.

 

As always, try this out in a lab first to ensure it behaves as expected, before you go live.

Thursday, March 17, 2011

Domain Computers - Local Administrators


With the addition of Group Policy Preferences (GPP) adding a domain group to the local Administrators group on client computers has become a real walk in the park. 


Here's how you do it, step by step. 


If you don't have a default computer policy already, I recommend you create one. Mine is called "Default Computer Policy". This policy contains the settings that all domain computers will have in common. And while you're at it, also create the security group you want to add, if you haven't already. Something short and simple like "Computer Administrators" will do just fine, and the name is self explanatory. 


Edit the GPO and expand the Computer Configuration, Preferences, Control Panel Settings and finally right click "Local Users and Groups" and select New -> Local Group. Select Update as action, then click the group name drop down arrow. Scroll down and select "Administrators (built-in)". Skip "Rename to" and "Description" and the checkboxes for deleting users and groups (unless you really want to restrict the membership to what you specify). In the "Members" box, click "Add..." and enter the name of the domain group you want to add to the local Administrators group. I'd suggest clicking the button with the three dots to search AD for the group. Make sure the action "Add to this group" is selected and click OK. Believe it or not, but click "Apply" and you're done. 


Now it's time to confirm the setting. You can either fire up a test machine in scope for this policy, or if it's already running, reboot it (it's a computer setting after all). If you're feeling lazy, you can even do this remotely. 


You can use psexec to connect to the computer (psexec \\computername cmd) and force a gpupdate (gpupdate /force). You can reboot the computer using shutdown /m "computername" /f /r /t 0. The switches are force, reboot and time in seconds. Once it's back up, you can once again connect to it using psexec, and the run the command "net localgroup administrators". This lists the members of the local Administrators group. 


For me, it worked like a charm! 




And here's how you did it back in the day with the "Restricted Groups" GPO setting. 


Create or edit your Default Computer Policy. Expand the Computer Configuration, Policies, Windows Settings, Security Settings and right click "Restricted Groups". Select "Add Group" and browse AD for the domain group you want to add to the local Administrators group. Click OK. 
In the bottom section, "This group is a member of", click "Add..." and browse for "Administrators". Click OK and then apply the setting. The setting should now say that group name "Domain\Group" (your domain\your group name) is a member of "Administrators". If it says anything else it has been configured wrong, and this may cause damage if rolled out. 


Enter: Copy and paste: 


Now it's time to confirm the setting. You can either fire up a test machine in scope for this policy, or if it's already running, reboot it (it's a computer setting after all). If you're feeling lazy, you can even do this remotely. 


You can use psexec to connect to the computer (psexec \\computername cmd) and force a gpupdate (gpupdate /force). You can reboot the computer using shutdown /m "computername" /f /r /t 0. The switches are force, reboot and time in seconds. Once it's back up, you can once again connect to it using psexec, and the run the command "net localgroup administrators". This lists the members of the local Administrators group. 


For me, it worked like a charm! 


Monday, March 14, 2011

VBScript - Desktop Shortcut

A quick one today, if you ever have the need to create a desktop shortcut using VBScript. This can be deployed in a user logon script (GPO or AD) for example.


Set objShell = CreateObject("WScript.Shell")
strDesktop = objShell.SpecialFolders("Desktop")
Set objLink = objShell.CreateShortcut(strDesktop & "\Andreas - Talk nerdy to me.lnk")
objLink.TargetPath = "C:\Program Files\Internet Explorer\iexplore.exe"
objLink.Arguments = "http://ahultgren.blogspot.com/"
objLink.WorkingDirectory = "%HOMEDRIVE%%HOMEPATH%"
objLink.IconLocation = "C:\Program Files\Internet Explorer\iexplore.exe, 2"
objLink.Description = "Andreas - Talk nerdy to me!"
objLink.Save

This link fires up Internet Explorer and goes straight to my blog. It should be fairly obvious 
what the different methods do and how you change them. 


Sunday, March 13, 2011

Domain Computers - Scheduled Reboot



Ever been assigned the task to set up nightly reboots of all your domain computers? I haven't. 
I have however been asked how to do this. Now, I'm pretty sure you can deploy this using for example SCCM, if it's available to you, but lets assume it isn't. So we'll go about this another way.


What about a GPO setting? Well, as far as I know (feel free to correct me) there isn't a GPO setting to configure a scheduled reboot (recurring or not).


You can use shutdown.exe /m to reboot a remote computer, but that's really for a one time thing, on one or a couple of computers. Running shutdown /m on all domain computers every night is not something I'd look forward to at least!


But what if we could make each computer run shutdown.exe on its own? I think we may be on to something!


So, lets write a batch file, shall we? How about we want all computers rebooted at 4 in the morning?


This is what the batch file would look like:
at 04:00 shutdown.exe /f /r /t 60


When this runs it will schedule the command "shutdown.exe /f /r /t 60" to be run at 04:00. It will also force (/f) any open programs to close, then reboot (/r) the computer after 60 seconds (/t 60). If anyone is using their computer at 4 AM, they'll have 60 seconds to save their work before it reboots itself. Once the task has been run, it's automatically removed. 


The next step is to create a new GPO and assign this batch file as a startup script. The reason I say create a new GPO is because you don't want to include something like a mandatory reboot in your default computer policy. 
Why, you ask? 
Well, image that you do configure this in your standard policy and everything is working just fine, until you receive that e-mail from the boss saying x, y and z computers have a business need to not be included in the nightly reboot. Now what? They're supposed to have the same settings as all other computers, except for the mandatory reboot. You've effectively painted yourself into a corner. 


This is why you create a new GPO and a security group. Name the GPO something along the lines of "Computer Nightly Reboot", and the group "Excluded from Nightly Reboots". Assign the batch file as a computer startup script, and deny the security group the right to apply the policy settings. This way, if any computer is going to be excluded from the reboots, just add them to the security group. Problem solved! 


A one time option to prevent a computer from rebooting is to log on to the computer (or use psexec) and run "at <task id> /delete", which will remove the task from the list. If the reboot has already been triggered, you can use the command "shutdown -a" to abort it. 






This post only explains how to do this using a batch file and a GPO computer startup script, but if Group Policy Preferences (GPP) are available to you, it's also possible to use them to configure a scheduled task for the computer. If you want to schedule a weekly reboot instead of a nightly, GPP is probably the best way to go. Although you can also use startup scripts, and perhaps a more advanced VBScript solution to either create a scheduled task, or to first check what day of week it is and if it's, say friday, schedule the reboot. 







Wednesday, March 9, 2011

DFS - What's that namespace?

I have on several occasions made an (albeit half-hearted) attempt to figure out how to check what DFS mode (2000 or 2008) a domain namespace (DFSN) is using. Last week I finally decided to get to the bottom of it.

If your domain functional level (DFL) is lower than 2008, then this should not be an issue. Windows Server 2000 mode is the only option.

However, if your DFL is Windows Server 2008, then you have an option to create a namespace using either Windows Server 2000 or 2008 mode. You can see which mode a namespace is using if you open the DFS Management console. Right click a namespace, click properties, and the mode is listed on the "General" tab. It can also be seen in the description bar if a namespace is selected.

But this is not what I wanted. I wanted a way to retreive this information using the command line.

The command line tools available for DFS management are dfscmd, dfsutil and dfsdiag. I checked the documentation and help/syntax for a way to display the DFSN mode. I found nothing.

I searched the Internet and posted in a forum on technet, but it bore no fruit.


I fired up ldp.exe and adsiedit to look for any clues, in case the information was stored there (the mmc console obviously knew which mode a namespace was in!).

The DFS configuration can be found here: 
CN=Dfs-Configuration,CN=System,DC=testlab,DC=local

Here I found the namespace attribute msDFS-SchemaMajorVersion. I found it on my 2008 namespaces but not on my 2000. I looked it up.

The article explains that this attribute was "Implemented on Windows Server® 2008 operating system and Windows Server® 2008 R2 operating system." Which means it's not present on Windows Server 2000 namespaces!

So, what can I do with this information? Can I check if the attribute is present on the namespace and make an assumption that it is either 2000 or 2008, depending on if it's there or not? Yep!

Now to the fun part. 

This VBScript will bind to the DFS-Configuration and loops through all the namespaces it contains. It will attempt to get and check for the msDFS-SchemaMajorVersion for each namespace to see if its empty or not. If it cannot retreive it, it will make the assumption that it's dealing with a namespace in WS 2000 mode. On the other hand, if it can retreive it, we're dealing with a 2008 namespace. Right? Well, I and my script will assume so. At least until the next Windows Server operating system is released. (Then perhaps we can check for the version number instead?).

If InStr(1, WScript.FullName, "wscript.exe", vbTextCompare) Then
  Set objShell = WScript.CreateObject("WScript.Shell")
 
objShell.Run "cmd /k cscript.exe """ & WScript.ScriptFullName & ""
  WScript.Quit
End If

Set objRootDSE = GetObject("LDAP://RootDSE")
Set objSysInfo = CreateObject("ADSystemInfo")

Const MODE_DFS2000 = "(Windows Server 2000 mode)"
Const MODE_DFS2008 = "(Windows Server 2008 mode)"
Const MODE_ERROR  = "(Could not determine mode)"

strDomainComponents = objRootDSE.Get("DefaultNamingContext")
strDomainFQDN = objSysInfo.DomainDNSName

Set objDFS = GetObject("LDAP://CN=Dfs-Configuration,CN=System," & strDomainComponents & "")
For Each dfsNameSpace In objDFS
  On Error Resume Next
    If IsEmpty(dfsNameSpace.Get("msDFS-SchemaMajorVersion")) Then
      WScript.Echo "\\" & strDomainFQDN & "\" & dfsNameSpace.CN & vbTab & MODE_DFS2000
    ElseIf Not IsEmpty(dfsNameSpace.Get("msDFS-SchemaMajorVersion")) Then
      WScript.Echo "\\" & strDomainFQDN & "\" & dfsNameSpace.CN & vbTab & MODE_DFS2008
    Else
      WScript.Echo "\\" & strDomainFQDN & "\" & dfsNameSpace.CN & vbTab & MODE_ERROR
    End If
  On Error Goto 0
Next