GET AUTOMATED
SERVER ADMINISTRATION IN THE AGE OF AUTOMATION
(The Creation & Analysis of a PowerShell script)
Code will change your life. More accurately, the proper USE of code will. And let’s be clear by what I mean. It can be called “code” or “scripting” or “programming” or whatever. It can be a high level tool accessing pre-assembled routines as objects, methods, or properties in libraries of code, or it can be low level machine commands sending individualized instructions for minute aspects of hardware manipulation on a factory assembly line, in a hard drive or for a missile guidance system.
Either way, there’s some “code” involved. Whether it’s hardware, or software, or the firmware in between, code will change — and has changed — your life.
The particular aspect of code that I’m talking about — one of the best parts — is the automation part. Automation gives us the ability to do something repeatedly (seemingly autonomously) to accomplish human goals, reduce human effort, or solve human needs. And it can scale unbelievably.
With automation, I can outsource my job — not overseas — but to myself (and my own little code minions). That’s just an awesome productivity advancement tool! And in this case, server administration and almost every aspect of a modern Microsoft Windows ecosystem, can be automated, managed, and controlled through Microsoft’s automation and scripting language called PowerShell.
Let me give you a relevant example that I think illustrates this perfectly.
A recent project in our server administration class found my group (named “Accelutions, Inc.”) completing many real world tasks, from creating and installing forests and domains, to setting up domain controllers, DNS servers, DHCP servers, routers and file servers, and setting up group policy and other things as well. For reference, the scope of just two parts of the project can be found below.
Part 1:
1. Install a Forest root domain on a Server Core. Domain name: TailSpinToys.com.
2. Install 2 Domain Controllers on Server Core for a child domain called Corp.TailSpinToys.com. Make both DNS server with AD integrated DNS.
3. Install 1 Server Core w/DHCP. Set reservations for all servers.
4. Install a file server with full GUI. Configure 5 hard disks (VHD’s) into a storage space & share it for users home folders.
5. User GPO’s to redirect documents folder to users home folder on the file server. Make the users roaming profiles. Set password to a length of 10 & change every 30 days. Remember the last 10 passwords & make them complex. Set lockout to 3 attempts & time for 5 minutes.Part 2:
1. Configure all clients (Win7, Win8 & Win10) to connect to the domain.
2. Use a GPO to install Visio to the Windows 8 client.
3. Use a GPO to publish Adobe Reader to all clients.
4. Configure the Win 8 client to use BitLocker on the hard disk.
5. Create a group for Sales users.
6. Create an OU for Sales users & computer accounts.
7. Put the account for the Win8 PC in the OU.
8. Create a shared folder for Sales called Sales Contracts.
9. Sales users can only access this folder from the Win8 client PC’s.
10. Configure this folder to classify the files put in there to be confidential.
11. This folder should have a quota of 1GB and sends all files to an archive folder called Old Contracts if the file is older than 6 months old.
Just these two parts of the group project (of about 16 total steps) actually break down into HUNDREDS of smaller steps upon further examination! And Part 1, step 4 is where I would like to focus. This step is requesting:
4. Install a file server with full GUI. Configure 5 hard disks (VHD’s) into a storage space & share it for users home folders.
The 1st part of the 2nd sentence is to “…configure 5 hard disks (VHD’s)…”. This requires creating 5 virtual hard disks first. Seems simple enough, right?
Not so difficult for that piece. A bunch of clicks in Server 2012 Disk Management and that will get the job done. Well, after making all the correct selections for the first disk it will. But then you have to do that 4 more times (because we need 5 in total). And, as they say, it doesn’t scale.
Let’s take a look at how we might use PowerShell to automate this (and then scale it). The command to create a new virtual hard disk in PowerShell looks something like this:
New-VHD
with a bunch of switches after it (“Switches,” as they are used here, are options that further refine the command and specify what you want it to do). With some of the appropriate switches (but not all), it could look something like this:
New-VHD -Path C:\Users\Administrator\VHD1.vhd -SizeBytes 3MB -Dynamic
This will create a new VHD file:
- that is dynamic (rather than fixed)
- whose maximum size could grow to 3MB
- place it in the specified folder location (C:\Users\Administrator)
- name it VHD1.vhd
One member of our team was discussing with another the possibility of how this (and all of our other tasks) could be automated using PowerShell. He went on to put together a little script that not only creates 1 VHD, but all 5 requested VHD files in PowerShell as follows:
#Make 5 VHD's
for ($i=1; $i -le 5; $i++)
{
New-VHD -Path c:\users\administrator\VHD$i.vhd -SizeBytes 3MB -Dynamic
}
This short script creates 5x3MB dynamic VHDs in the location shown and names them with sequential numbers (VHD1.vhd, VHD2.vhd, VHD3.vhd, etc.).
for ($i=1; $i -le 5; $i++)
Let’s walk through how this code works. The line that starts with “for” sets up to loop 5 (and ONLY 5) times. Each time through the “for” loop, it increases the variable ($i) by 1 ($i++), which it uses to track all the loops (which go from 1 to 5). That same variable is also cleverly reused as part of the file name. As variable $i increments from 1 to 5, the name VHD$i.vhd changes the file name from VHD1.vhd to VHD5.vhd as it iterates through the 5 loops.
In effect, you’ve automated this process and reduced your workload. Maybe not so much savings for creating 5 VHD’s, but what if you had to create hundreds, or even thousands of them? Then you start to see significant time and effort saving results. Not bad for a scant few lines of code, right?
Well, once this was accomplished, another member of our group suggested that our script might be something that we could give to other groups. I agreed that this would be helpful to our fellow classmates as a prime teaching example of integrating PowerShell automation, as well as reducing their efforts and making their work more easily reproducible (since many were repeating some of the steps from this project in order to correct errors and issues they were having).
I had taken a look at PowerShell a year or two ago and found it had a very interesting and compelling “WOW!” factor that appealed to me (I programmed in Visual Basic for Applications years back), so I readily volunteered to take on this responsibility. I thought it would be a good learning experience for myself as well as a chance to help out my teammates.
Toward that effort, I researched commands and started adding some embellishments over the next day or two that might make this PowerShell script something that would be more publicly consumable — more user friendly — by our classmates, if so desired.
As it stood, the parameters, or switches, for the New-VHD command would need to be gathered from user input rather than hard coded (pre-written into the script). For instance, there is another type of VHD that is not “dynamic,” but rather “fixed” in initial size (Sometimes this is preferable to make sure that the drive that the VHD sits on will not run out of disk space. And fixed size VHD’s have less fragmentation.). The number, size, location and name of the VHD’s would also need to be gathered.
First, I used several PowerShell Write-Host commands to display appropriate strings of informational text to the display (explaining the use of the script).
$BGColor = “Red”
Write-Host “”
Write-Host “DISCLAIMER: Use at your own discretion. Accelutions, Inc. will not be held personally liable for any damage” -backgroundcolor $BGColor
Write-Host “caused as a consequence of using this script.”-backgroundcolor $BGColor
Write-Host “No sophisticated error checking has been put in place in this script so, please be careful as it is offered ‘as is.’”-backgroundcolor $BGColor
Write-Host “”
Write-Host “ -Abel, Darius & the whole Accelutions, Inc. Team” -backgroundcolor $BGColor -foregroundcolor “yellow”
Write-Host “”Write-Host “”
Write-Host “This PS script creates multiple VHD files where you specify options, such as:”
Write-Host “Type: (D)ynamic or (F)ixed”
Write-Host “Size: in KB, MB, GB, etc. (3MB minimum)”
Write-Host “Amount: number of VHD’s”
Write-Host “Drive/Path/Filename: specify the drive, file path & the main, root filename”
Write-Host “”
This produces the following screen display:
Then I used several more Write-Host commands along with Read-Host commands to display strings of text on the display, and, more importantly, to gather user input.
$VHD_Amount = Read-Host “Please enter how many VHD’s to create (eg.: 1; 10; 100; 1000)”
Write-Host “”
$VHD_Size = Read-Host “Please enter VHD size in MB, GB, etc. *3MB minimum* (eg.: 10MB; 100MB; 10GB; 100GB)”
Write-Host “”
Write-Host “Please enter the drive\path combination of where you would like the VHD’s created.”
Write-Host “ <ENTER> for current directory, which is:”, (Get-Location).path
$DrivePath = Read-Host “NOTE: Leave a trailing slash at the end (eg.: C:\users\administrators\ is correct)”
Write-Host “”
Write-Host “Please enter the root filename; .vhd extension will be automatically added”
$Filename = Read-Host “(eg.: VHD will result in VHD_0001.vhd, VHD_0002.vhd,VHD_0003.vhd, etc.)”
The above displays as:
and collects all the information needed from the user.
The last line above is produced from the code below. The Read-Host command displays the line, waits for user input and continues to wait in a “Do-While” loop until it receives either a “d” for dynamic or an “f” for fixed.
Do
{
$Dynamic_Fixed = Read-Host “Please enter D for a Dynamic Disk or F for a Fixed Disk”
If ($Dynamic_Fixed.ToUpper() -eq “F”)
{
$Dynamic_Fixed = “-Fixed”
}
Elseif ($Dynamic_Fixed.ToUpper() -eq “D”)
{
$Dynamic_Fixed = “-Dynamic”
}
} while ($Dynamic_Fixed -ne “-Dynamic” -and $Dynamic_Fixed -ne “-Fixed”)
It changes the user response of “d” or “f” to the proper switch that it needs:
“-dynamic” or “-fixed”.
When run, the script’s resulting output display looks something like this as it creates the VHD’s:
Five VHD’s are created with the name the user entered and the type, size and, location that the user entered. There are also a few other bells and whistles thrown in (like displaying the amount of time that it takes to run this script and enumerating the file name number uniformly padded in 4 characters at the end. Eg.: VHD_0001.vhd, VHD_0002.vhd, VHD_0003.vhd, etc.). And by using this script, we’re able to outsource this portion of our work.
To make this a more prime time public release script, I might add even more features such as error checking and perhaps more sophisticated input gathering (maybe even as command line parameters), but it does get the point across showing what can be done with PowerShell in a short period of time in terms of workload automation for a server administrator.
Now remember, all of this is just to replace half of one sentence in a request. And there were 3 sentences in that step…and 16 steps in 2 parts of this project (and the project is not even over yet).
Broken down, this project would be hundreds of steps. If you were scaling it, it could be thousands or tens of thousands of steps. If you have to do things like this often in your job, doesn’t it make sense to start offloading some of these processes to your minion that is PowerShell? Or saving them so that you have a toolbag of PowerShell modules to make your job easier?
If the work savings aren’t appealing enough, think about the time savings as well. How fast can you create a VHD? How fast can you create 10 VHD’s? 100 VHD’s? 1,000 VHD’s? If it takes you longer than 1.3 seconds per VHD, you might want to consider outsourcing that task to your friendly, neighborhood PowerShell script.
To put this script through its paces, I had it create 2,000 dynamic 3MB VHD files - sequentially numbered. Coming in at just under 43 minutes (that’s 1.29 seconds per VHD), that would’ve taken the average SysAdmin more than 5 minutes each - which equates to a whole work week! This way, you can spend your work week solving much more interesting problems and learning more PowerShell! See the stats shown below:
Now imagine making a change to 85 users in Active Directory. Or having to automate spinning up 200 new VM’s and creating and attaching 200 virtual hard disks. Or having to do a project like this every week. Or enumerating through hundreds of servers (or even thousands in the data centers that I’ve worked in) to gather information, settings and make changes to them.
These can be tall orders by hand.
Don’t fret. Don’t regret. Work smarter, not harder. Automate!
PowerShell is your friend. (And it’s not looking for credit.)
If you saved all your PowerShell scripts in a library of scripts, you could have a nice little toolbag of automation to fall back on to assist you with your daily server administration chores and work. This could result in vast improvements to your efficiency while making you far more marketable and valuable to your employer in your area of expertise.
Now the only thing to worry about, as science fiction has taught us, is the possibility of sentience and the rise of the machines…
Below is a copy of the complete script, for your reference. Can you figure out what the rest of the code is doing?
#Make new VHD’s according to user input
Measure-Command{
$Verbose = $True # or $False$StartTime = Get-Date -format “dddd MM/dd/yyyy HH:mm:ss”#Disclaimer
$BGColor = “Red”
Write-Host “”
Write-Host “DISCLAIMER: Use at your own discretion. Accelutions, Inc. will not be held personally liable for any damage” -backgroundcolor $BGColor
Write-Host “caused as a consequence of using this script.”-backgroundcolor $BGColor
Write-Host “No sophisticated error checking has been put in place in this script so, please be careful as it is offered ‘as is.’”-backgroundcolor $BGColor
Write-Host “”
Write-Host “ -Abel, Darius & the whole Accelutions, Inc. Team” -backgroundcolor $BGColor -foregroundcolor “yellow”
Write-Host “”Write-Host “”
Write-Host “This PS script creates multiple VHD files where you specify options, such as:”
Write-Host “Type: (D)ynamic or (F)ixed”
Write-Host “Size: in KB, MB, GB, etc. (3MB minimum)”
Write-Host “Amount: number of VHD’s”
Write-Host “Drive/Path/Filename: specify the drive, file path & the main, root filename”
Write-Host “”$VHD_Amount = Read-Host “Please enter how many VHD’s to create (eg.: 1; 10; 100; 1000)”
Write-Host “”
$VHD_Size = Read-Host “Please enter VHD size in MB, GB, etc. *3MB minimum* (eg.: 10MB; 100MB; 10GB; 100GB)”
Write-Host “”
Write-Host “Please enter the drive\path combination of where you would like the VHD’s created.”
Write-Host “ <ENTER> for current directory, which is:”, (Get-Location).path
$DrivePath = Read-Host “NOTE: Leave a trailing slash at the end (eg.: C:\users\administrators\ is correct)”
Write-Host “”
Write-Host “Please enter the root filename; .vhd extension will be automatically added”
$Filename = Read-Host “(eg.: VHD will result in VHD_0001.vhd, VHD_0002.vhd,VHD_0003.vhd, etc.)”Do
{
$Dynamic_Fixed = Read-Host “Please enter D for a Dynamic Disk or F for a Fixed Disk”
If ($Dynamic_Fixed.ToUpper() -eq “F”)
{
$Dynamic_Fixed = “-Fixed”
}
Elseif ($Dynamic_Fixed.ToUpper() -eq “D”)
{
$Dynamic_Fixed = “-Dynamic”
}
} while ($Dynamic_Fixed -ne “-Dynamic” -and $Dynamic_Fixed -ne “-Fixed”)If ($Verbose -eq $True)
{
Write-Host “”
Write-Host “Dynamic or Fixed: ", $Dynamic_Fixed.ToUpper()
Write-Host “Size of VHD’s: ", $VHD_Size.ToUpper()
Write-Host “Amount of VHD’s: ", $VHD_Amount.ToUpper()
Write-Host “Drive\Path: ", $DrivePath.ToUpper()
Write-Host “Filename: ", $Filename.ToUpper()
Write-Host “”
}$VHD_Size = $VHD_Size.ToUpper()for ($i=1; $i -le $VHD_Amount; $i++)
{
$ParameterString = “New-VHD -Path " + $DrivePath + $Filename + (“{0:0000}” -f $i) + “.vhd -SizeBytes " + $VHD_Size + “ -ComputerName LOCALHOST " + $Dynamic_Fixed
If ($Verbose -eq $True) {Write-Host $ParameterString}
Invoke-Expression -Command $ParameterString
}If ($Verbose -eq $True) {
Write-Host “”
Write-Host “Dynamic or Fixed: ", $Dynamic_Fixed.ToUpper()
Write-Host “Size of VHD’s: ", $VHD_Size.ToUpper()
Write-Host “Amount of VHD’s: ", $VHD_Amount.ToUpper()
Write-Host “Drive\Path: ", $DrivePath.ToUpper()
Write-Host “Filename: ", $Filename.ToUpper()
}
Write-Host “”
Write-Host “ — brought to you by Accelutions, Inc. © 02/25/2016” -foregroundcolor “red”
Write-Host “”$EndTime = Get-Date -format “dddd MM/dd/yyyy HH:mm:ss”
Write-Host “ Start Time: ", $StartTime
Write-Host “ End Time: ", $EndTime
Write-Host “Elapsed Time: (below)”
}
#
# — A collaboration by Abel, Darius & the entire Accelutions, Inc. Team © 02/25/2016
#