Easily Use PowerShell to Discover the Holders of Active Directory FSMO Roles

Easily Use PowerShell to Discover the Holders of Active Directory FSMO Roles

  • Comments 6
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to discover the Active Directory FSMO role holders

Microsoft Scripting Guy, Ed Wilson, is here. The day has arrived—it is PowerShell Saturday in Columbus, Ohio! Wes Stahler, the Scripting Wife, Ashley McGlone, Brian Jackett, and I have looked forward to this day for over four months. I am really looking forward to meeting everyone who signed up for this historic event. The way cool thing is that by the time the Scripting Wife and I are back in Charlotte, North Carolina, it will be time for my five-day series of live meetings: Windows PowerShell Essentials for the Busy Admin. If you have not signed up for those, you should, because they will cool, fun, and educational.

You know, I continue to be amazed at how powerful Windows PowerShell really is. I know I should not be amazed—after all I have been using Windows PowerShell since way before Windows PowerShell 1.0 was even in beta. You would think that after all these years I would begin to get callous, but that is not the case.

The VBScript way of doing things

One reason, I believe, is that I spent years working with VBScript prior to coming to Windows PowerShell. (In fact, I wrote three books about VBScript.) I spent nearly five years teaching VBScript to Microsoft Premier Customers. As a result, I am very familiar with the amount of effort that is required to accomplish certain tasks.

This morning, the Scripting Wife and I were sitting in the Microsoft Office in Columbus Ohio, early—real early—way before anyone would even dream of showing up. I was showing her how to use the Active Directory module to document FSO roles. She looked up at me, and said, “Didn’t you write a script to do that a long time ago?”

“As a matter of a fact I did,” I replied, “It was in VBScript.”

“Do you still have it?” she asked, “You might want to show it today while you are talking about learning Windows PowerShell.”

I was so proud. I am convinced, at times, that she is a genius. But of course, I would never actually tell her that because I would never hear the end of it. Anyway, here is a script that is very similar to the one I wrote, (I copied this one from the Scripting Guys Script Repository.)

List_FSMO_Role_Holders.vbs

Set objRootDSE = GetObject("LDAP://rootDSE")

 

Set objSchema = GetObject _

    ("LDAP://" & objRootDSE.Get("schemaNamingContext"))

strSchemaMaster = objSchema.Get("fSMORoleOwner")

Set objNtds = GetObject("LDAP://" & strSchemaMaster)

Set objComputer = GetObject(objNtds.Parent)

WScript.Echo "Forest-wide Schema Master FSMO: " & objComputer.Name

 

Set objNtds = Nothing

Set objComputer = Nothing

 

Set objPartitions = GetObject("LDAP://CN=Partitions," & _

    objRootDSE.Get("configurationNamingContext"))

strDomainNamingMaster = objPartitions.Get("fSMORoleOwner")

Set objNtds = GetObject("LDAP://" & strDomainNamingMaster)

Set objComputer = GetObject(objNtds.Parent)

WScript.Echo "Forest-wide Domain Naming Master FSMO: " & objComputer.Name

 

Set objDomain = GetObject _

    ("LDAP://" & objRootDSE.Get("defaultNamingContext"))

strPdcEmulator = objDomain.Get("fSMORoleOwner")

Set objNtds = GetObject("LDAP://" & strPdcEmulator)

Set objComputer = GetObject(objNtds.Parent)

WScript.Echo "Domain's PDC Emulator FSMO: " & objComputer.Name

 

Set objRidManager = GetObject("LDAP://CN=RID Manager$,CN=System," & _

    objRootDSE.Get("defaultNamingContext"))

strRidMaster = objRidManager.Get("fSMORoleOwner")

Set objNtds = GetObject("LDAP://" & strRidMaster)

Set objComputer = GetObject(objNtds.Parent)

WScript.Echo "Domain's RID Master FSMO: " & objComputer.Name

 

Set objInfrastructure = GetObject("LDAP://CN=Infrastructure," & _

    objRootDSE.Get("defaultNamingContext"))

strInfrastructureMaster = objInfrastructure.Get("fSMORoleOwner")

Set objNtds = GetObject("LDAP://" & strInfrastructureMaster)

Set objComputer = GetObject(objNtds.Parent)

WScript.Echo "Domain's Infrastructure Master FSMO: " & objComputer.Name

Does the script work? Well, let’s try it out and see. I save the file as ListFSMORoleHolders.vbs. I then decide to run the script by using CSCRIPT, which I call from within Windows PowerShell. It is a strange sort of irony to run a VBScript script from within Windows PowerShell. The results are shown here.

Image of command output

The Windows PowerShell way of doing things

How hard it to find the FSMO role holders by using Windows PowerShell? It comes down to only two commands. Three commands if you want include importing the Active Directory module. Four commands if you want to include making a remote connection to a domain controller to run the commands.

One cool thing about using Windows PowerShell remoting is that I specify the credentials I need to run the command. My normal account is a standard user, and I only use an elevated account when I am required to perform tasks with elevated rights. The first two commands create a remote session on a remote domain controller and load the Active Directory module.

Enter-PSSession dc3 -Credential iammred\administrator

Import-Module activedirectory

When it is loaded, I type a one-line command to get the forest FSMO roles and another one-line command to get the domain FSMO roles. These two commands are shown here.

Get-ADForest iammred.net | Format-Table SchemaMaster,DomainNamingMaster

Get-ADDomain iammred.net | format-table PDCEmulator,RIDMaster,InfrastructureMaster

That is it, two or three or four one-line commands, depending on how you want to count. Even at a worst case, four one-line commands are much easier to type than 33 lines of code. In addition, the Windows PowerShell code is much easier to read and to understand. The commands and the associated output from the Windows PowerShell commands are shown in the image that follows.

Image of command output

Well, that is it. People are starting to arrive for the first ever PowerShell Saturday. I will write more tomorrow.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Ed,

    the battle between VBS and PS is still not over and I'll always like to remind everybody, that there is no need to turn working VB scripts into Powershell scripts. And I don't ask a VB scripter to change his favorite scripting language to Powershell and leave VBS behind ( though I do often talk about the alternative new PS way of doing things :-)

    VBS has been introduced in 1996 and has been over 15 years admin's best friend ... ( or sometimes not *sss* )

    Nobody would have ever even only mentioned VBS if it hadn't had the one and only feature to connect to COM or ActiveX objects. The Get-  or CreateObject feature of VBS made it! This was the door opener to access other existing software modules ( which implemented the IDispatch Interface ). Especially MS office, SQL Server, IE and the ASP technology could be controlled by VBS.

    So even the interaction with ADSI, WMI and other parts of the operating system is not a feature of VBS but something the ADSI or WMI ActiveX objects supplied by Microsoft or other companies brought to VBS via GetObject or CreateObject calls and the methods and properties that they offered. Technology before the year 2000 and the currently available technology isn't the same!

    If it takes a lot of code and calls to GetObject and in this case the Get method of the ADSI objects, this is more or less a problem of the underlying ActiveX component. Nowaday Powershell is build on a modern fundament: the .Net framework 2.0 ( the next v3 and above versions will even build on the new framework 4.0 ) that is even capable to interact with ADS without the imported AD module.

    But if you do import the ActiveDirectory module which does make handling AD objects very easy, you still have to remember that there are thousands of lines of code behind in this module that do the hard work for us.

    So 4 lines against 33 lines looks charming but behind the scenes we have a giant block of frameowrk and module code that is making this possible.

    VBS is great, and Powershell is better ... not only if it comes to counting lines of code necessary to solve a problem, but especially if you look at the new possibilities like remoting, error handling and debugging, advanced functions, integration with .net programming languages like C#, modules, extending PS by your own CmdLets, a real pipeline, working with objects and so on .... and so on ...

    Last words:

    Don't ( and I won't say that you did, Mr. Ed because I know you other :-) blame VBS for anything it can't do for you that easily as PS can and don't throw your working VB scripts away!

    Go for Powershell if you are developing new scripts ... if you can!

    Klaus (Schulte)

  • With V3's ability to import modules on the fly you have one less step to worry about.

  • Ed, as always, great article!

    Not that I would do this, but "netdom /query fsmo" will return the roles also.  For grins, I cast it in to a variable, via PowerShell, and the text actually comes back as an array, so you can view them one at a time, for example:

    $FSMO = netdom /query fsmo

    $FSM0[0] will return the first item in the array, for me that was the "Schema master".  Just more cool stuff about you can do with PowerShell!

  • @Brian Wilhite

    For more fun, you can turn the output of netdom /query fsmo into a full fledged object like this:

    netdom /query fsmo | ForEach {

       If ($_ -match "(?<FSMORole>.*)\s{2,}(?<DC>.*)") {

           $object = New-Object PSObject -Property @{

               DomainController = $matches.DC

               FSMORole = $matches.fsmorole

           }

           $object.pstypenames.insert(0,'Fsmorole.Object')

           $object

       }

    }

  • Would this not be easier?

    get-addomain |format-list -Property RIDMaster,PDCEmulator,InfrastructureMaster

  • thank you