Wednesday, December 17, 2014

How to manage the FSMO roles with Powershell

There was a time when I used legacy commands to do my daily duties. Most of you have at least used them once or more: stuff like dcpromo.exe, comp.exe, netdom.exe, xcopy.exe, tasklist.exe and taskkill.exe. It was a time when the Windows system administrators where the laughing stocks of Unix sysadmins, and for a good reason! Our skils were limited by the possibilities of the graphical user interface and we had a limited understanding of the way those old black boxes (read NT4, Windows 2000, 2003) worked under the hood. The console was just a joke, which we barely used to do a few ipconfigs or pings.

Today Microsoft is opening. There are new possibilities: Virtualization was a great (or giant?) step forward. The Cloud brought a new way of thinking to datas and to system administration. Interconnecting systems requires today a greater view of what's behind our operating systems. That's how I came to Windows Powershell. I wanted something better to do my job. I wanted to open and learn a way of managing computers which could give me satisfaction beyond that upsetting mouse clicking. Something that could make me feel prouder.

Powershell was the answer to this. A plyayful tool which in good hands can give great results.

Let me take an example: FSMO roles.

We all have an Active Directory out there indexing users, computers and resources. In these old times when you wanted to check what were the holders for each and every role you had to move down to the console and run something like this:

netdom query fsmo

Schema master               labdc01.contoso.com
Domain naming master        labdc01.contoso.com
PDC                         labdc01.contoso.com
RID pool manager            labdc01.contoso.com
Infrastructure master       labdc01.contoso.com

The command completed successfully.
Very static. I don't even want to show you how long and intricated was the procedure to learn how to move or seize those roles in case you needed to.

Today with Powershell we have a new way to manage those FSMO roles and make those Flexible Single Master Roles more... flexible! I want to show you now a few lines of code that are used to shuffle around your domain controllers the FSMO roles at random.

But a bit of theory first.

There are five roles: two at forest level and three at domain level. The Schema Master is the first Forest role and is in charge of keeping a writable copy of the Schema partition. The Domain Naming Master is the second forest role and keeps a writeable copy of the Configuration partition (that is the place where the logical view of your domains and trusts and the physical view of your Active Directory sites are stored). Then, at Domain level, there is the PDC Emulator, which manages time synchronization between clients and DCs (have ever heard about the 5 minutes kerberos ticket lifetime?), as well as GPO edition. The RID Master, which gives RID scopes to other DCs in the Domain. And the Infrastructure Master, which manages groups coherency between domains.

The two Forest roles can be found with Get-AdForest:

Get-ADForest | Select-Object SchemaMaster,DomainNamingMaster

SchemaMaster                         DomainNamingMaster
------------                         ------------------
labdc01.contoso.com                  labdc01.contoso.com
The three Domain roles can be found with Get-AdDomain:

Get-ADDomain | Select-Object PDCEmulator,RIDMaster,InfrastructureMaster

PDCEmulator             RIDMaster               InfrastructureMaster
-----------             ---------               --------------------
labdc01.contoso.com     labdc01.contoso.com     labdc01.contoso.com
Once you know that a list of all your domain controllers can be generated with:

Get-ADDomainController -filter * | select -ExpandProperty Name
then you can put in place a powerful oneliner that moves each FSMO role to a random DC in less than a second. Like shuffling and serving cards for a game, but with FSMO roles instead:

0..4 | % {Move-ADDirectoryServerOperationMasterRole -Identity (Get-Random (Get-ADDomainController -filter * | select -ExpandProperty Name)) -OperationMasterRole $PSItem -Confirm:$False -Verbose}
Notice the 0..4 | % {}. This is a quick way to index the five FSMO roles without having to manually write them down: Powershell will make the translation for you:
  • PDCEmulator: 0
  • RIDMaster: 1
  • InfrastructureMaster: 2
  • SchemaMaster: 3
  • DomainNamingMaster: 4
Here's the result:


Now I could be willing to play more and shuffle my FSMO roles around every day, then send me an e-mail in case I loose a DC, so that I know what roles were on it in that particular moment. I would store the e-mail in a dedicated folder and have an history of all role moves in my Domain.

Let's prepare the e-mail. The ingredients here are a couple of variables, a bit of splatting, a PSObject and a connection to a valid mail server:

$ForestFSMORoles = Get-ADForest | Select-Object SchemaMaster,DomainNamingMaster

$DomainFSMORoles = Get-ADDomain | Select-Object PDCEmulator,RIDMaster,InfrastructureMaster

$FSMORoles = New-Object PSObject -Property @{

                    InfrastructureMaster = $DomainFSMORoles.InfrastructureMaster

                    PDCEmulator = $DomainFSMORoles.PDCEmulator

                    RIDMaster = $DomainFSMORoles.RIDMaster

                    DomainNamingMaster = $ForestFSMORoles.DomainNamingMaster

                    SchemaMaster = $ForestFSMORoles.SchemaMaster

  }

$EmailSplatting = @{
 
            To = 'administrator@contoso.com'

            From = 'administrator@contoso.com'

            Subject = "FSMO Roles owners of the day for $((Get-AdForest).Name)"

            Body = $FSMORoles | ConvertTo-Html | Out-String

            SMTPServer = 'smtp.contoso.com'

            BodyAsHtml = $True

            }
        
Send-MailMessage  @EmailSplatting
Just put the code in a .ps1, put the ps1 in a scheduled task and you're done.
 
What do you think? Funny, isn't it? Of course I am not reponsible of what you do with your FSMO roles. I am just showing the power of Powershell and the fun it is to make the most out of it. Limited only by our imagination.

Wednesday, December 3, 2014

Powershell oneliner to get disk usage by file extension

These days storing multimedia files (like family videos, travel pictues, etc) requires a lot of storage and since I am a big fan of SSDs (and those kind of disks are still quite expensive), I wanted to show the simple Powershell one-liner I wrote in the weekend that checks what kind of file extensions are (over)consuming space on all my local drives.

The first step is to retrieve a list of all my local drives, which resumes to a query to Win32_LogicalDisk:

(Get-CIMInstance -class Win32_LogicalDisk -Filter 'drivetype=3').DeviceID
C:
D:
E:
L:
N:
Z:
A lot of drives, so a lot of work that Powershell will silently do for me.

Let's start to run Get-ChildItem against this list of local drives and hunt for every file in every subfolder:

Get-ChildItem $((Get-CIMInstance -class Win32_LogicalDisk -Filter 'drivetype=3').DeviceID) `
-File -Recurse
Once you know (thanks Get-Member!) that Get-ChildItem returns the file extension as a full grown property, you can ask Powershell to make the grouping for you:

Get-ChildItem $((Get-CIMInstance -class Win32_LogicalDisk -Filter 'drivetype=3').DeviceID) `
-File -Recurse |

 Group-Object Extension
The next step is to send this result down the pipeline to Select-Object, which is very good at defining what I call 'calculated properties'.

The properties I need for my report are:
- the extension itself
- the total size of all the files for the given extension
- the Count of those files

Since Group-Object returns four properties:

Count       Property   int Count {get;}                                                
Group       Property   System.Collections.ObjectModel.Collection[psobject] Group {get;}
Name        Property   string Name {get;}                                              
Values      Property   System.Collections.ArrayList Values {get;} 
we have to build on top of this to get what we want.

Let's start by letting Select-Object chew the Group properties (which is a PSObject, as you can see above) to get the total file size for each extension:

... | Select-Object ..., @{n='Size';e={$($_.Group | Measure-Object Length -Sum).Sum}}, ...

Name        Size Count
----        ---- -----
.JPG  2507712043  2704
.jpeg     319979     1
.mp4  1605261912   119
.tif    22024960     1

Very well, now we have to beautify this to make it readable. I'll perform rounding on the size of the files after having converted it to megabytes:

... | Select-Object Name, @{n='Size (MB)';e={[math]::Round((($_.Group | Measure-Object Length -Sum).Sum / 1MB), 2)}}, Count
Then I'll change the name property to Extension, suppress the dot at the beginning of the string (through some very complex regex!), and make the resulting string uppercase:

... | Select-Object @{n='Extension';e={($_.Name -replace '^\.').ToUpper()}}, ...
Here's the final result, sorted by total file size by extension:

gci $((gcim Win32_LogicalDisk -Filter 'drivetype=3').DeviceID) -File -Rec |
  
  Group Extension |

  Select @{
   n='Extension';
   e={($_.Name -replace '^\.').ToUpper()}
   },

   @{
   n="Size (MB)";
   e={[math]::Round((($_.Group | Measure Length -Sum).Sum/1MB),2)}
   },

   Count |

  Sort 'Size (MB)' -Desc

Extension Size (MB) Count
--------- --------- -----
JPG         2391,54  2704
MP4          1530,9   119
TIF              21     1
JPEG           0,31     1
Of course the one-liner can be modified to taste.

You could for instance pass to Get-ChildItem a manual list of drives or folders in the form or an array:

Get-ChildItem @('c:\','d:\','n:\pictures','n:\videos') -File -Recurse
Or you could use a different measure unit from MB. In Powershell V5 there are for instances five measure units: KB, MB, GB, TB and PB. The one you choose depends on the amount of files you have.

Powershell, anything is possible.
Related Posts Plugin for WordPress, Blogger...