Scheduling Server Restarts

If you manage servers you have likely come to a point where you finished doing work and got a prompt ‘Your server needs to reboot.  Reboot now?’  Well you can’t reboot now… not during business hours.  I guess you’ll have to come back tonight… or this weekend, right?

Wrong.  Scheduling a reboot is actually pretty easy in Windows.  Try this:

  1. Open Task Scheduler (taskschd.msc).
  2. In the Actions pane click Create Basic Task…
  3. Name the task accordingly… Reboot System for example.
  4. On the Task Trigger page click the radio button One Time
  5. On the One Time page enter the date and time when you want the server to reboot.
  6. image
  7. On the Action page select Start a program.
  8. On the Start a Program page enter the name of the program shutdown.exe.  In the Add arguments box enter /f /r /t 0.  This will force the programs to close, restart the server (instead of just turning it off), and set the delay time to 0 seconds.
  9. image
  10. Once you have done this your server will reboot at the precise time you want it to, and will come back up.

**NOTE: Don’t forget to check.  it is not unheard of in this world for servers to go down and not come back up as they are supposed to!

Do it in PowerShell!

Using PowerShell to script this will allow you to not only save the script, but also run it on remote servers.  From Justin Rich’s blog article I found this script:

register-ScheduledJob -Name systemReboot -ScriptBlock {

Restart-Computer -ComputerName $server -Force -wait

Send-MailMessage -From mitch@email.com -To mitch@email.com -Subject "Rebooted" -SmtpServer smtp.mail.com

} -Trigger (New-JobTrigger -At "04/14/2017 8:45pm" -Once) -ScheduledJobOption (New-ScheduledJobOption -RunElevated) -Credential (Get-Credential)

 

Have fun!

Advertisements

Resize Live Virtual Hard Drives

 

I have used Hyper-V for as long as there has been Hyper-V.  Today I use it much less than I once did, but it is still handy for running VMs on my laptop.  I run a particular VM called ‘Sandbox’ in which I do all sorts of things that I would not want to do on my live system… things that I can simply try and then wipe.

When I built the Sandbox VM I was spending a lot of time at home, and portability was not a huge issue.  I ran it on one of my external drives, and it worked fine.  I allocated 100GB and was good to go.

When I realized I was going to be on the road again I could just as easily take my external hard drive with me, but the shortage of USB ports on my Surface Pro meant making a decision… I was going to shrink the VHDX file and put it on my internal hard drive.

76GB free space.  That’s going to be a problem.

Step 1: Shrink your partitions

My 100GB virtual hard drive (.vhdx file) meant that somewhere within the VM I had a 100GB partition (or at least a few partitions that added up to that).  I had to shrink as much as I could.

  1. If you have a Pagefile.sys, Swapfile.sys, and Hiberfil.sys you should eliminate them now.  Remember that even if you turn off Memory Paging the files don’t disappear until you reboot.
  2. Defragment the disk.  We may not talk much about it anymore, but the old faithful defrag.exe C: still works. 
  3. Use the Disk Manager console to shrink your C: as much as you can… but not too much.  When I tried it I had the option to shrink it down to 11.5 GB… I’m pretty sure that would render my VM pretty useless.  Pick a number that works for you.  I chose 60GB.
  4. Using the diskpart tool delete any partitions at the end of your drive.  I had a 450MB Recovery partition on mine.

image

Because it was a Recovery (read: SYSTEM) partition I needed to do the following:

Select Partition 5

Delete Partition OVERRIDE

image

Good… Now we can shrink the VHDX file.

In the older versions of Hyper-V this would have meant shutting down the VM.  You don’t have to do that anymore… but you do have to run PowerShell as an Admin.  Once you do:

Step 2: Shrink your VHDX file

The cmdlet is easy…

  1. Navigate to the directory where you keep your VHD file;
  2. Resize-VHD -Path .\Sandbox-PC.vhdx -SizeBytes 60GB

It will only take a minute and you will be done.  Simple as pie!

Remotely Enable RDP

Like most IT Managers I manage myriad servers, most of which are both remote and virtual.  So when I configure them initially I make sure that I can manage them remotely… including in most cases the ability to connect via RDP (Remote Desktop).

But what happens if you have a server that you need to connect to, but does not have RDP enabled?  Using PowerShell it is rather simple to enable the RDP feature remotely:

Enter-PSSession -ComputerName computername.domain.com –Credential domain\username
Set-ItemProperty -Path ‘HKLM:\System\CurrentControlSet\Control\Terminal Server’-name “fDenyTSConnections” -Value 0
Enable-NetFirewallRule -DisplayGroup “Remote Desktop”
Set-ItemProperty -Path ‘HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp’ -name “UserAuthentication” -Value 1

That should get you going.  Good luck!

Wireless Networks: Know your strengths!

It is not uncommon for me to hear people complain that their wireless network is not stable, is not working properly, disconnects, is slow, and just isn’t good enough.

Unfortunately, unless you are a networking specialist, wireless connectivity is essentially a binary state: It works… or it doesn’t work. There are three things I ask people to check before I get involved:

  1. Wireless device driver issues (try downloading the latest driver);
  2. Interference (verify that there are no microwaves or wireless phones or devices between the computer and the nearest wireless access point;
  3. Distance to nearest wireless access point (move closer and try)

Of course, when we talk about interference or distance, there are a lot of factors, and while it can be binary insofar as ‘Yes there is a problem or No there isn’t a problem,’ the reality is that signPowerShellal strength is decidedly not binary.  Knowing what the signal strength is can be directly related to your answer.  So how do we check this in Windows?

Of course, many wireless adapters have their own software that will provide this information.  But that is no way to standardize things.

There is a quick PowerShell script that you can run though that will give you exactly what you need:

(netsh wlan show interfaces) -Match ‘^\s+Signal’ -Replace ‘^\s+Signal\s+:\s+’,””

Notice that we are using a netsh command, which you will agree is not PowerShell.  However if you try to run this in a basic Command Prompt it will come back with an error because if the command line switches.

I ran the script from my desk at Rakuten; I am sitting about fifteen feet from the nearest wireless access point (WAP), so my response is 99%.  I know that Rakuten (who just moved into their new offices last month, and spent a considerable amount of time planning for connectivity and productivity) wants all of their employees to have the best possible signal.

For the sake of ensuring I was not always going to get the same number I ran the same script sitting in a busy Starbucks location in Akasaka, where they are more concerned with patrons buying coffee than they are offering fast Internet.  Here are the results:

image

A paltry 79%… which may seem great, but when you take into account the entire room is maybe 15 metres by 20 metres you realize there is probably interference… until you account for the fact that there are another dozen patrons connected to the same single Access Point at the same time, and at least three of them that I can see are watching streaming videos.

Of course, many IT Support people will want to run this command remotely.  No problem:

Invoke-Command {(netsh wlan show interfaces) -Match ‘^\s+Signal’ -Replace ‘^\s+Signal\s+:\s+’,””} -ComputerName RemotePC

(Making sure you get all of the single and double quotes and regular and squiggly parentheses correct Smile).

Of course, if you have a group of users you who are complaining you can run it in a batch by using a Session:

$session=New-PSSession -ComputerName RemotePC1 RemotePC2 RemotePC3
Invoke-Command -session $session {(netsh wlan show interfaces) -Match ‘^\s+Signal’ -Replace ‘^\s+Signal\s+:\s+’,””}

Now that you can measure the wireless signal on your computer, you can

  • Determine if the signal is the problem, or if you have to look elsewhere;
  • See if you need to implement more access points, or distribute existing ones differently; and
  • Figure out where the best place to sit in the lunch room is when your favourite hockey team is playing when you have to work.

No go forth and administer!

How To Cheat With PowerShell

Admit it… you are a crappy coder.  You may be a pretty fair IT Professional, but you cannot script your way out of a paper bag.  There’s a support group for you.

Hi, my name is Mitch, and I’m a lousy scripter. 

Admittedly I have never been to an AA or NA meeting; I have never really done well with support groups, and the only addiction I ever had I kicked without anyone’s help.  However I’ve seen plenty of AA meetings on TV and in movies, and that’s how they usually start.

4214_Powershell%20blore-logo_png-550x0Recently I wrote an article called iSCSI Virtual Disks: If you have to make a bunch… Use PowerShell! Thanks to one of my loyal readers (who despite or because of their loyalty are always quick to point out when I make a mistake) I realized that despite saying that it did, the script did not actually connect the virtual disks to the iSCSI Target… and I had to find a way to do that before looking stupid for too long.

Here’s the problem… I’m not really a PowerShell guru, just a regular IT guy who realizes the amazing power of the tool.  And as was written in an article that went live this week (guest-written by a colleague and friend), while using Google to find samples of scripts is great, there are two spectacular tools to help you on your way. 

The first such tool is called Get-Help.  You can type that in PowerShell to find out about any cmdlet.  Cool!

However what do you do if you know there is probably a cmdlet, but you don’t know what it is?  Well, the second one is the Integrated Scripting Environment (ISE).  PowerShell’s ISE is the easiest way to build your scripts, whether they are simple, single-line cmdlets, or large, vast, flowing scripts that take up pages and pages.

Step 1: Run PowerShell ISE.  This is pretty easy, and if you haven’t figured it out, just click on the Start menu and type ISE.

Step 2: Select your Module.

image

The PowerShell ISE window is generally divided into three parts: A live PowerShell window, a scripting window, and the Commands list.  The Commands section is literally a list of every command and cmdlet in PowerShell… thousands of them.  However let’s say you know the command you are looking for has to do with iSCSI Targeting… select that Module from the drop-down list, and all of a sudden your thousands of commands turn to twenty-six.

What I want to do is to map a previously created iSCSI Virtual Disk to an iSCSI Virtual Target… so the top target (Add-IscsiVirtualDiskTargetMapping) sounds pretty spot-on. I’ll click on it, and if this is the first time clicking on a command for this module, I will get the following message:

To import the “iSCSITarget” module and its cmdlets, including “Add-IscsiVirtualDiskTargetMapping”, click Show Details.

SNAGHTML37e7dde

When I click Show Details, I am presented with several options.  These will differ for every cmdlet, and they will correspond to the optional (and required) command-line switches that I might need.

The Path is going to be the full name and path of the previously created iSCSI Virtual Disk.  In my case I created several, but they all look like q:\iSCSIVirtualDisks\Disk1.vhdxThat is what I am going to enter there.

The TargetName is the name of the target I created… in this case it might look like Target1.

It is important that you pay attention to the ComputerName box because as you saw in my previous article, I might name the iSCSI Virtual Disks (my VHDX files) the same thing on each host.  When I enter the ComputerName TargetServer1 PowerShell knows to look for Target1 on that server.  If you do not enter a ComputerName then it will assume that it should look on the local server… and that could be disastrous, especially if those VHDX files are already otherwise mapped and in use.

The Credential box is exactly what it sounds like… If your user account does not have credentials to execute a command on a remote system, you can use this box to specify alternate credentials.

The Lun box allows you to set the LUN (Logical Unit Number) of the virtual disk.  If you are not concerned by this, the default is for the lowest available LUN number to be assigned automatically.

If you want more help, notice that there is a blue circle with a ? right in the window.  Click on that, and you get a much more detailed Help dialog than you would get by typing Get-Help Add-IscsiVirtualDiskTargetMapping in the PowerShell window will pop up for you.  If you don’t believe me, try them both Smile

image

imageSee? I told you!

So let’s go ahead and populate those fields the way I said:

image

Once you populate them, there are three buttons at the bottom of the Commands console that you can use:

Run does exactly what you would think… it runs the command with the appropriate switches.

Insert puts the command and switches into your PowerShell (blue) window, but does not execute the command.

Copy is also pretty self-explanatory… it copies it to the clipboard for you to put in the scripting (white) window… or anywhere else you might want to insert it with a Ctrl-V.

So I don’t really know how to script, but I know what I want to accomplish… PowerShell ISE takes me from base-camp to the goal like a Sherpa guiding me on Everest.  Yet another way to love PowerShell… and get to know it better!

PowerShell: HELP!

This is a guest article written by my colleague Michael.  Mike and I have been working closely together for the past two years, and I have turned him into a monster!  He is now trying to learn anything he can get his hands on.  So when he wrote me an e-mail with a suggestion for an article on how to get help with PowerShell.  He wrote it out, and I didn’t feel the need to change anything.  Here is what he wrote. –MDG

I was reading some of your blog articles today (not everyday, sorry!) and the one on Distinguished Names (see article) caught my attention, I started writing a comment but then thought it might be better to suggest a follow up article in terms of using PowerShell and how to really get-intoPowerShell | get-TheMost | out-OfIt.

I started using PowerShell when we first met at your suggestion, but only really used it in a superficial way, get-this | set-that (and do it for 20 computers that I list). So about a month ago, I took the time and went through the MVA (Microsoft Virtual Academy) PowerShell courses with Jeffrey Snover (very entertaining and super informative), the regular Jumpstart and the advanced scripting. I would strong recommend these, as not only did it give me great ideas, but they describe how to make cmdlets that don’t normally work together, actually work together on the fly. Later they went on to teach how to make your own scripts, functions, cmdlets, tools and even modules.

What prompted me to write though, was the suggestion as Google and Bing as a first point to look, and I totally agree, its great for ideas and for examples. My suggestion for a follow up would be the PowerShell Help system, and maybe the ISE (Integrated Scripting Environment) built-in functions (like snippets and the intellisense) later.

For example, I don’t know the cmdlet, but what to do something with Active Directory Groups

Get-help *-ad*group*

Oh, I want Add-ADGroupMember,  but how do I use it…

Get-help Add-ADGroupMember –showwindow ( or –full, or if only need examples –examples)

Cool, I now know Smile

Thanks Michael, you have some very interesting and important points here.  And yes, I promise that coming soon I will write a post on the Integrated Scripting Environment! –MDG

iSCSI Virtual Disks: If you have to make a bunch… Use PowerShell!

I don’t mean to sound like a broken record but when you have to do things over and over again, it simply doesn’t make sense to do it manually.  Sure, the GUI (Graphical User Interface) in Windows is great… but if you have to click through the same wizard ten times to create ten of something… well, I guess all I am saying is that PowerShell makes a lot more sense.

Last month I went through a relatively time-consuming exercise to create three LUNs on each of three Software SANs on Windows Server 2012R2.  Ok great… but I then discovered that for my project I couldn’t use three LUNs of 1.5TB each… rather I needed to create nine LUNs of 500GB each.  What a royal pain!  By the way, seeing as I have to do this on three separate servers, my workload just tripled from doing it 9 times to doing it 27 times!  This does not sound like fun.

Fortunately, I can do it all in PowerShell, which means I can save a whole lot of clicking.  We are going to do this all on three different servers, named   Let’s look at how:

Parameters

a) We are going to create three iSCSI Target Servers called TargetServer1, TargetServer2, and TargetServer3.

b) We are going to present the targets to five servers called InitServer1, InitServer2, InitServer3, InitServer4, and InitServer5.

c) We are going to create 9 500GB drives on each server, plus three 1GB drive on each server.  In case you can’t tell, these drives will be used for nine different Failover Clusters, and the 1GB drive will be the witnesses.

d) We are going to attach all of the iSCSI Virtual Disks to the appropriate Targets.

Let’s Go!

1) Before we do anything, we want to create a session that will repeat the same tasks on each computer.

PS C:\> $session=New-PSSession –ComputerName Server1,Server2,Server3

That will save us having do do a few things over again, even though we could have done it with a simple ‘'<Up-Arrow> <Backspace>” or two.

2) We have to install the iSCSI Target Role Feature on all of these server. So:

PS C:\> Invoke-Command –Session $session {Install-WindowsFeature –Name iSCSI-TargetServer

2) The next thing we are going to do is actually create the iSCSI Targets on the three servers.  By doing this with the $session that we created we will end up with three targets with the same name.  I trust you will go back and fix that by hand later on.  If you prefer to avoid that step though, we could bypass the $session and use the manual-PowerShell way Smile

PS C:\> Invoke-Command –session $session {New-IscsiServerTarget –TargetName Target1 –Credential InitServer1,InitServer2,InitServer3,InitServer4,InitServer5

or…

PS C:\> New-IscsiServerTarget –ComputerName TargetServer1 –TargetName Target1 –Credential InitServer1,InitServer2,InitServer3,InitServer4,InitServer5

PS C:\> New-IscsiServerTarget –ComputerName TargetServer2 –TargetName Target2 –Credential InitServer1,InitServer2,InitServer3,InitServer4,InitServer5

PS C:\> New-IscsiServerTarget –ComputerName TargetServer3 –TargetName Target3 –Credential InitServer1,InitServer2,InitServer3,InitServer4,InitServer5

PS C:\> New-IscsiServerTarget –ComputerName TargetServer4 –TargetName Target4 –Credential InitServer1,InitServer2,InitServer3,InitServer4,InitServer5

PS C:\> New-IscsiServerTarget –ComputerName TargetServer5 –TargetName Target5 –Credential InitServer1,InitServer2,InitServer3,InitServer4,InitServer5

3) Now that we have created the Targets, we have to create the disks.  Unlike the Targets (whose names will be used outside of their own servers), I don’t mind if the names of the actual disks on each server.

Invoke-Command –session $session {

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk1.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk2.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk3.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk4.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk5.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk6.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk7.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk8.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk9.vhdx –SizeBytes (500GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk1W.vhdx –SizeBytes (1GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk2W.vhdx –SizeBytes (1GB) –UseFixed

New-IscsiVirtualDisk –Path q:\iSCSIVirtualDisks\Disk3W.vhdx –SizeBytes (1GB) –UseFixed}

Warning: This script is going to take a ridiculously long time.  That is because when creating the virtual disks, PowerShell is zeroing out all of the bits.  This is the safer way to do things if you are re-using your disks.  If they are brand new clean disks, then you can add the switch DoNotClearData to your statements.  However unless you are in a real hurry, I would take the extra time.

4) Our disks have been created, but we have to attach them to the Targets.  So:

Invoke-Command –session $session {

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk1.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk2.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk3.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk4.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk5.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk6.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk7.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk8.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk9.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk1W.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk2W.vhdx –TargetName Target1

Add-IscsiVirtualDiskTargetMapping –Path q:\ISCSIVirtualDisks\Disk3W.vhdx –TargetName Target1}

So if we did it properly, we should now have three software SANs (Targets) with nine virtual disks each, that are each connected to three iSCSI targets, which are in turn each presented to five iSCSI initiators.  Additionally, we have three ‘Quorum Disks’ on each Target. 

In my next article, I will show you what needs to be done on the initiator side to get these all going for your Failover Clusters.  Until then… Happy scripting!

Distinguished Names: How do I…

powershell1Yeah yeah, I know… A little while ago I talked about how to determine the Distinguished Name (DN) of an Active Directory Object, and I got a flurry of requests for doing it with PowerShell.

Now, normally I do like to show you how to do things via the GUI, and then what the PowerShell cmdlet would be for the same task.  However since I didn’t actually show a GUI way of doing it, I didn’t think to show you the PowerShell way of doing it.  My bad… Here you go!

1) Let’s say you want to get the DN of all objects with the name Mitch in it.  We can use the Get-ADObect cmdlet.  Like so:

Get-ADObject –Filter { CN –like “Mitch*” }

image

Okay, that’s not bad… but what am I going to do with a DN that includes an ellipses? Of course that is useless, so instead let’s use a full list,… or |fl:

Get-ADObject –Filter { CN –like “Mitch*” } |fl

image

So here we see the full DN (with the domain name hidden to protect the customer’s identity). 

Of course, if you don’t want a whole list, and you know the exact name of the Active Directory Object, you can change the parameters, so:

Get-ADObject –Filter { CN –eq “Mitchell Garvis” } |fl

image

We have eliminated the need for wildcards by changing the switch from –like to –eq, but we now need the exact name (no typos now!) for it to work.

2) The problem is, that doesn’t seem to work with Organization Units, which is what I was talking about in the first place.  So try this:

Get-ADObject –LDAPFilter “(objectClass=organizationalUnit)” |fl

image

Here we have changed the switch from –Filter to –LDAPFilter, and are able to see the entire list of our Object Class… in this case OUs, but you can change that for sites or domains or users.

Windows PowerShell may look complicated to those who grew in the GUI, but here’s the best part… you don’t have to memorize anything to become a PowerShell PowerUser!  All you have to do is know how to use Google (or Bing, if you are still drinking the KoolAid).  Type into the Search Bar PowerShell AD Distinguished and you will come up with a good starting point.

Now go forth and script!

Where am I? HELP!

My colleague created a virtual machine for me in our datacentre a few weeks ago.  (Thanks Michael!)  Earlier this week I needed to create a second virtual machine to cluster with it, and I felt that the best way to maximize my resources completely would be to create another virtual machine identical to the first.  Okay, all I had to do was pop open the Settings window for the virtual machine and copy it.

We have 25 physical host servers in the lab environment in question, and no Virtual Machine Manager.  Crap.

I could, if I had to, connect to each host one by one looking for the virtual machine in question, but that would be a waste of time… not to mention that as a one-off solution it could work, but it is a bad habit to get into.  I needed a better solution.

If you ever find yourself in the position, here’s a tip: As long as you have the Integration Services installed, there is a registry key in the virtual machine that gives me my answer.  So open Regedit and navigate to:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters

See? There it is, right there in black and white.  In fact, it’s there three times – under HostName, PhysicalHostName, and PhysicalHostNameFullyQualified.   I no longer need a map, I no longer need to go looking by hand.

But Mitch, isn’t there a way to do this in PowerShell?

I’m glad you asked.  Sure, here it is:

(Get-ItemProperty –path “HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters”).PhysicalHostName

Of course, if you are a stickler about it, you can change the last bit to PhysicalHostNameFullyQualified, but that’s up to you.

Now that you know where you are… keep going!

Insanity Is…

Insanity

We have all heard this quote before… and it is exactly true.  However in your server environment, when you want things identical, then we would turn this phrase around:

Insanity: Doing things manually over and over and expecting identical results.

I have not spent a great deal of time learning PowerShell… but whenever I have a task to do, such as installing a role or a feature, I try to do it with PowerShell.  I actually leverage another of Einstein’s great axioms:

Memorize

The Internet is a great tool for this… I can look up nearly anything I need, especially with regard to PowerShell. 

So previously, when I wanted to install a role on multiple servers I would run a series of cmdlets:

PS C:\>Install-WindowsFeature Failover-Clustering –IncludeManagementTools –ComputerName Server1

PS C:\>Install-WindowsFeature Failover-Clustering –IncludeManagementTools –ComputerName Server2

PS C:\>Install-WindowsFeature Failover-Clustering –IncludeManagementTools –ComputerName Server3

Of course, this would work perfectly.  However recently I was looking up one of the cmdlets I needed on the Internet and stumbled across an easier way to do it… and especially when I want to run a series of identical cmdlets across the multiple servers.  I can simply create a multi-server session.  Watch:

PS C:\>$session=New-PSSession –ComputerName Server1,Server2,Server3

PS C:\>Invoke-Command –session $session {Add-WindowsFeature Failover-Clustering –IncludeManagementTools}

Two lines instead of three doesn’t really make my life a lot easier… but let’s say I was doing more than simply adding a role… this could save me a lot of time and, more importantly, ensure uniformity across my servers.

Creating a PSSession is great for things like initial configuration of servers… think of all of the tasks you perform on every server in your organization… or even just every web server, or file server.  This will work for Firewall rules, and any number of other settings you can think of.

Try it out… It will save you time going forward!

Do IT Remotely

A few days ago I was in with my boss and he asked me to perform a particular bit of maintenance during off-hours.  ‘Just come into the office tonight after Taekwondo and do it… it shouldn’t take you very long.’  He was right, and I almost did… and then I remembered that in 2014 there is seldom a reason to have to do anything on-site.  So after Taekwondo I went home, showered, then sat down at my computer in my pajamas for a couple of hours and did what I had to do.  No sweat.

Then one morning this week he asked me to make a particular change to all of the servers in a particular group, and report back that it was done.  No problem, I thought… I can do that from my desk using PowerShell.

The change was simple… set the Regional Settings to Canada (the default is, of course, United States). No problem, the PowerShell cmdlet is Set-Culture… so against the local computer I ran:

Set-Culture en-CA.

Success.  I then started to run it against other servers using:

Set-Culture en-CA –ComputerName <ServerName>

image

Uhh… who woulda thunk it?  The Set-Culture cmdlet does not support the –ComputerName parameter.  Crap.  Does that mean I have to actually log on to every one of my servers manually to do it?

No.  Fortunately the guys who wrote PowerShell knew that some of us would want to run legacy commands across systems, and gave us a way to do it anyways. 

Invoke-Command –ComputerName Oak-FS-03 –ScriptBlock {Set-Culture en-ca}

While I suspect the original intent was to use it to run old DOS commands, but it works for PowerShell cmdlets too.

So here you go… Invoke-Command allows you to run the –ScriptBlock against a remote server, whether that is PowerShell or not.

It should be noted, by the way, that Windows Server does not by default allow scripts to be run against it remotely… you have to go into Server Manager and enable Remote management. 

image

Of course, you could also do it in PowerShell… simply run the cmdlet:

Enable-PSRemoting –Force

Of course, you cannot run that one remotely… that would defeat the point of the security Winking smile

So go forth and be lazier than you were… no more logging onto every machine individually for you!

Meet Dr. Scripto

ScriptoWhile I am sure most of you are not familiar with this crazy character, I suspect a lot of you use the tools that he represents.  You see, this is Dr. Scripto.  I am not sure which delusional drunk came up with the idea and design of the character, but I think it is a fair bet that Stan Lee was not in the room.  You see, Dr. Scripto is the mascot… the hero if you will, for PowerShell.  Yes, I am serious, and no, I had nothing to do with the cockamamie idea that a scripting environment needed a mascot or hero.  I would mention that if it is not enough that someone came up with the idea and sketched it out, this is indeed a three-dimensional bobble-head-like statuette.  Yes folks, somebody spent money having these made.

Before I continue with my mockery, I want to mention that I am a huge fan of PowerShell.  While I am not an expert, I think it is an excellent scripting environment that either does or will make the lives of IT Professionals the world over easier.  In a day and age where servers are moving into the cloud (either private or public) it is a relief that we can now execute the same scripts against all of our servers… wherever they may be.  It simplifies our lives in ways that many do not even understand – the back-end management tools, such as System Center and Microsoft Deployment Toolkit, along with dozens of others, are based on PowerShell.  Add-ons like PowerCLI allow us to extend the functionality of PowerShell beyond our Windows servers and manage vSphere and vCenter Server.  I think PowerShell is incredible, and have written several articles about using it to manage Hyper-V, Active Directory, and more.

I also have a great respect for the PowerShell community.  While I may mock them (and they do make it easy, with such fodder as Dr. Scripto and songs like Highway to PowerShell), but they are a passionate group of interesting individuals, some of whom it would even be considered safe to be alone in a room with… although be careful, I am reasonably certain Ed Wilson tried to write a script to reorganize my living room once.  There is no question that if you need to figure out how to do anything in PowerShell one of them has either already written about it, or will be more than willing to do so once you post your question on-line.

If you are more interested in face-to-face interactions then they can be found at user group meetings all over the world.  Now fellas, I am not saying that any of these gatherings are good places to meet women, but if you want to learn about scripting these are the place to be.  (Ladies, to be fair: if you want my advice I would not go there trying to pick up the man of your dreams either…)  Experts like Ed Wilson (a long time Microsoft employee), and his wife Teresa (a long-time wife of Ed) not only attend meetings, they (okay, mostly Ed) speak at them all the time.  Teresa has even helped to create these groups, and does a wonderful job of connecting like-minded individuals.  In fact she is so good at it that she was recently recognized with the prestigious Microsoft MVP Award (in the discipline of PowerShell).  Congratulations Teresa!

In fact, it is Teresa who several years ago gave me Dr. Scripto.  While not a PowerShell MVP, she said I did a lot to help the community both in the Greater Toronto Area and around the world.  I was so honoured that it held a place of honour on my desk for several years, until recently when I emptied my home office and moved into the condo.  Dr. Scripto stayed behind temporarily, until such time as he was once again needed.

Recently Teresa and I had the opportunity to get together at the Microsoft MVP Summit in Redmond, Washington.  She told me that it was indeed a shame that a couple of very well known PowerShell MVPs told her that they had never received a Dr. Scripto Bobble-Head.  She was disappointed that there was nothing that she could do for them, but alas, they were a limited edition one-time deal, and even if there was budget to make a new batch (there isn’t) it would diminish the cachet of the existing ones to make more.  She told me the name of the MVP who did not have one, and I immediately recognized it.  It is a shame that he did not have one of these prized (??) collectibles.

‘Teresa, you know your friendship has meant the world to me for many years, and I cherish the gifts you gave to me.  However I know that this MVP is very deserving.  As such, I am willing to part with my limited edition, extremely rare, priceless collectible Dr. Scripto Bobble-Head in order to right what you perceive to be an injustice.  If you give me the shipping address of the MVP, along with a cheque for $2,500.00 made out to cash, I will ship it to him.’

…Okay, the part about the cheque was made up… and I embellished a bit, but the long and the short of it was that when I returned to Canada I was going to look (carefully) through the boxes that my office was packed into to find Dr. Scripto, and if I was able to find it I would give it to the MVP in question.

As you can see from the picture, Dr. Scripto has been located.  He is alive and well, with nary a scratch on him.  He has spent several years – good years – sitting on my desk, but alas, he is needed elsewhere.  When I prepare for my next trip to the USA I will wrap him carefully so that he will not be damaged in transit to his new home… wherever that may be.

If you do not have your own limited edition Dr. Scripto Bobble-Head, don’t worry… you can still learn to script like a champ using the knowledge he brought forth.  He has his own page on Technet.Microsoft.com (Doctor Scripto’s Script Shop), his own Twitter account, and a number of YouTube videos (which were obviously not made by anyone with a firm grasp on reality or sanity).  Don’t worry, he will be with you in spirit… and hopefully in good sanity!

Standardize your Hosts: Simplify your Life

For several years I have been speaking and writing about desktop deployment to standardize your client system environment.  What about your servers? What about your hypervisors? 

A couple of years ago VMware introduced Host Profiles into vCenter Server which allow you to take all of the settings from one host and then apply them to all of your other hosts.  Nice… but unfortunately it is a feature only of the Enterprise Plus SKU of the product. 

Microsoft has similar functionality with System Center 2012 R2, which is a real godsend for larger organizations.  But what about the smaller companies?  What about companies that have not completely implemented the whole System Center suite of tools?  Are they doomed to having multiple hypervisor configurations?  No… that’s what PowerShell is for!

Super-Shell!Okay, PowerShell is for a lot of things; in fact it is for just about everything, depending on how well you want to use it.  However with the help of my friend and fellow Microsoft MVP Sean Kearney I have put together a list of cmdlets that will do the job for you.

Firstly we should recognize that there are infinitely more settings to configure in VMware vSphere than there are in Microsoft’s Hyper-V; hundreds of settings, any of which can prevent critical functionality from performing properly.  There are certainly issues that need to be properly configured in Hyper-V, but not nearly as many.  With that being said, it is still important to standardize your Hyper-V hosts, if for no other reason than to simplify management, but also to ensure failover readiness and more.

For the purpose of this article I am going to assume a directory on all hosts called c:\Profile.  You can really name the directory anything you like.  In fact none of the file names have to be what I call them, as long as you remember what you use.

Hyper-VOh, and before you ask, this article applies to the full GUI version of Windows… and MinShell… and Server Core… and yes, even Hyper-V Server!

In PowerShell there is a simple cmdlet: Get-VMHost |fl.  This will show you all of the host settings.  The fl gets the full list, instead of the basic information.

If you are simply trying to collect the host settings for the purpose of documentation, you can export this information to a .csv (comma separated value) file that can be read in a text editor or, more importantly, in Microsoft Office Excel.  That cmdlet would be Get-VMHost |Export-CSV c:\Profile\HostSettings.csv.

PowerShellWhile this is helpful for documentation purposes, in order to actually work with the information we are going to export it to a .xml (Extended Markup Language) file.  It will be harder for us to read, but easier for the computer to work with.  The cmdlet to do that is Get-VMHost |Export-CLIXML c:\Profile\HostSettings.xml.

Now that we have collected the information, we can start applying the information to other hosts.  The corollary to any Get- cmdlet in PowerShell is a Set- cmdlet.  However the .xml file has some information in it that we would not want to apply to each host – hostname, for example.  So although we could theoretically apply each setting by hand (set-VMHost <parameter>) I have taken the liberty to write a script that would apply all of the information for you, based on the file we collected earlier:

$info=Import-CLIXML C:\Profile\HostSettings.xml

Set-VMHost -VirtualHardDiskPath $info.VirtualHardDiskPath
Set-VMHost –VirtualMachinePath $info.VirtualMachinePath
Set-VMHost –MacAddressMinimum $info.MacAddressMinimum
Set-VMHost –MacAddressMaximum $info.MacAddressMaximum
Set-VMHost –MaximumStorageMigrations $info.MaximumStorageMigrations
Set-VMHost -UseAnyNetworkForMigration $info.UseAnyNetworkForMigration
Set-VMHost -FibreChannelWwnn $info.FibreChannelWwnn
Set-VMHost -FibreChannelWwpnMaximum $info.FibreChannelWwpnMaximum
Set-VMHost -FibreChannelWwpnMinimum $info.FibreChannelWwpnMinimum
Set-VMHost -ResourceMeteringSaveInterval $info.ResourceMeteringSaveInterval
Set-VMHost -NumaSpanningEnabled $info.NumaSpanningEnabled
Set-VMHost -EnableEnhancedSessionMode $info.EnableEnhancedSessionMode

Let’s look at the format of this script.

1)  $info=Import-CLIXML C:\Profile\HostSettings.xml
What we are doing here is importing the .xml file that we created into a variable called $info.  Each piece of information in the XML file will be called using that variable.

Next let’s look at one of the Set-VMHost lines:

2) Set-VMHost -VirtualHardDiskPath $info.VirtualHardDiskPath
What we are doing here is taking one of the parameters – the default directory for new virtual hard disks – and setting it with the VirtualHardDiskPath parameter from the .xml file… because we imported that file into $info, that sub-variable is expressed as $info.VirtualHardDiskPath.  We will repeat that for each parameter.

So essentially for this script we are running the same cmdlet twelve times with different switches.  Can we put them together into a single line? Sure… it would look like this:

Set-VMHost -VirtualHardDiskPath $info.VirtualHardDiskPath –VirtualMachinePath $info.VirtualMachinePath –MacAddressMinimum $info.MacAddressMinimum –MacAddressMaximum $info.MacAddressMaximum –MaximumStorageMigrations $info.MaximumStorageMigrations -UseAnyNetworkForMigration $info.UseAnyNetworkForMigration -FibreChannelWwnn $info.FibreChannelWwnn -FibreChannelWwpnMaximum $info.FibreChannelWwpnMaximum -FibreChannelWwpnMinimum $info.FibreChannelWwpnMinimum -ResourceMeteringSaveInterval $info.ResourceMeteringSaveInterval -NumaSpanningEnabled $info.NumaSpanningEnabled -EnableEnhancedSessionMode $info.EnableEnhancedSessionMode

It may look long and ugly, but the good news is you don’t have to type it out again… all you have to do is copy and paste it from this article!

Of course, you can clean it up a little… if you are not using virtual fibre channel, for example, you could remove all of the parameters that pertain to that.  A lot of companies don’t care about the MAC addresses of their VMs and resource metering, so remove those.  All of a sudden that line gets a lot smaller:

Set-VMHost -VirtualHardDiskPath $info.VirtualHardDiskPath –VirtualMachinePath $info.VirtualMachinePath –MaximumStorageMigrations $info.MaximumStorageMigrations -UseAnyNetworkForMigration $info.UseAnyNetworkForMigration -NumaSpanningEnabled $info.NumaSpanningEnabled -EnableEnhancedSessionMode $info.EnableEnhancedSessionMode

Because PowerShell is plain English, you can easily go through these scripts and customize it the way you like.  No worries, have fun!

Of course, you may have noticed by now that we have not even touched on virtual networks here, and that is certainly an important component.  What do we need for that?  You need to read my next article!

Step by Step: Adding the GUI to Windows Server Core

HELP! Mitch, you told me that I should learn Server Core and I am trying, but you also told me that it wasn’t a problem to add the GUI back into a Server Core machine if I really needed it.  How do I do that?

This is a question I have gotten a few times from readers and students.over the past year.  There are a few of ways to do it, and depending on your situation you may need to try both of them.

Method 1: No problem!

You installed Windows Server with the full GUI previously, and then you removed the GUI.  This is the simplest scenario for our problem.  Here goes:

  1. Open PowerShell (powershell.exe)
  2. Run the cmdlet: Install-WindowsFeature Server-Gui-Mgmt-Infra,Server-Gui-Shell /reboot
      Now, if you are really deathly afraid of the command line, you can connect to a server with

Server Manager

      and use the

Add Roles and Features

    wizard.  Either way will work just fine.  However here’s the catch… both of them depend on the bits for the GUI being on the server’s hard drive.  If you never installed the GUI then they won’t be.  At this point you have to move on to…

Method 2: Still no problem 🙂

powershell_2 You dove in head first, decided to get right into Server Core.  That’s just how you role.  Unfortunately you discovered something that made you backpedal.  No problem, many fine IT Pros have made worse false- starts than this.  It won’t be difficult, all you have to do is add the GUI features.  However since the bits are not on the drive, you have to add a source.  Follow these steps and you’ll be on your way!

      1. Create a folder on the C Drive: MD c:\mount
      2. Check the index number for Server Datacenter (must be performed in a Command Prompt with Elevated privileges): Dism /get-wiminfo /wimfile:<drive>:sources\install.wim
      3. Mount the WIM file to the previously created directory using this command at the same elevated command prompt: Dism /mount-wim /WimFile:<drive>:\sources\install.wim /Index:<#> /MountDir:c:\mount /readonly
      4. Start PowerShell and run this cmdlet: Install-WindowsFeature Server-Gui-Mgmt-Infra,Server-Gui-Shell –Restart –Source c:\mountdir\windows\winsxs

(For the fun of it, PowerShell will accept your Command Prompt commands, so you can do all of the above in a PowerShell window.)

    Again, if you have been soooo spooked by Server Core that you cannot bear to do this in the command prompt, do the following:
      1. Connect to a GUI-based server (or Windows 8.1 system with RSAT Tools) and open the

Server Manager

    .
      2. Right-click

All Servers

      and click

Add Servers

    3. Find and add your Server, ensuring that it reports as On-line.
      4. Click on

Manage

      and from the drop-down menu select

Add Roles and Features

    .
      5. In the

Before you begin

      page click

Next

    .
      6. In the

Select installation type

      page click

Next

    .
      7. In the

Select destination server

      page select your Server Core machine from the list and click

Next

    .
      8. In the

Select server roles

      page click

Next

    .

9. In the Select features page scroll down to User Interfaces and Infrastructure.  Expand the selection, then select Graphical Management Tools and Infrastructure and Server Graphical Shell.  Click Next.

Capture-1 10. In the Confirm installation selections page click on Specify an alternate source path .

11. In the Specify Alternate Source Path page enter the path to the installation media, then click OK.

12. In the Confirm installation selections page select the checkbox marked Restart the destination server automatically if required.

13. Click Install.

That’s it… your server will reboot with the full GUI.  honestly I don’t expect you will be doing this very often – I truly feel that Server Core is the way to go with the vast majority of servers going forward.  However isn’t it nice to know that you have the option should you really need it?

…Oh, and please, for G-d’s sake, if you are re-installing the GUI at least try the PowerShell method!

Server Core: Save money.

I remember an internal joke floating around Microsoft in 2007, about a new way to deploy Windows Server.  There was an ad campaign around Windows Vista at the time that said ‘The Wow Starts Now!’  When they spoke about Server Core they joked ‘The Wow Stops Now!’

Server Core was a new way to deploy Windows Server.  It was not a different license or a different SKU, or even different media.  You simply had the option during the installation of clicking ‘Server Core’ which would install the Server OS without the GUI.  It was simply a command prompt with, at the time, a few roles that could be installed in Core.

While Server Core would certainly save some resources, it was not really practical in Windows Server 2008, or at least not for a lot of applications.  There was no .NET, no IIS, and a bunch of other really important services could not be installed on Server Core.  In short, Server Core was not entirely practical.

Fast Forward to Windows Server 2012 (and R2) and it is a completely different story.  Server Core a fully capable Server OS, and with regard to resources the savings are huge.  So when chatting with the owner of a cloud services provider recently (with hundreds of physical and thousands of virtual servers) I asked what percentage of his servers were running Server Core, and he answered ‘Zero’.  I could not believe my ears.

The cloud provider is a major Microsoft partner in his country, and is on the leading edge (if not the bleeding edge) on every Microsoft technology.  They recently acquired another datacentre that was a VMware vCloud installation, and have embarked on a major project to convert all of those hosts to Hyper-V through System Center 2012.  So why not Server Core?

The answer is simple… When Microsoft introduced Server Core in 2008 they tried it out, and recognizing its limitations decided that it would not be a viable solution for them.  It had nothing to do with the command line… the company scripts and automates everything in ways that make them one of the most efficient datacentres I have ever seen.  They simply had not had the cycles to re-test Server Core in Server 2012 R2 yet.

We sat down and did the math.  The Graphical User Environment (GUI) in Windows Server 2012 takes about 300MB of RAM – a piddling amount when you consider the power of today’s servers.  However in a cloud datacentre such as this one, in which every host contained 200-300 virtual machines running Windows Server, that 300MB of RAM added up quickly – a host with two hundred virtual machines required 60GB of RAM just for GUIs.  If we assume that the company was not going to go out and buy more RAM for its servers simply for the GUI, it meant that, on average, a host comfortably running 200 virtual machines with the GUI would easily run 230 virtual machines on Server Core.

In layman’s terms, the math in the previous paragraph means that the datacentre capacity could increase by fifteen percent by converting all of his VMs to Server Core.  If the provider has 300 hosts running 200 VMs each (60,000 VMs), then an increased workload of 15% translates to 9,000 more VMs.  With the full GUI that translates to forty-five more hosts (let’s conservatively say $10,000 each), or an investment of nearly half a million dollars.  Of course that is before you consider all of the ancillary costs – real estate, electricity, cooling, licensing, etc…  Server Core can save all of that.

Now here’s the real kicker: Had we seen this improvement in Windows Server 2008, it still would have been a very significant cost to converting servers from GUI to Server Core… a re-install was required.  With Windows Server 2012 Server Core is a feature, or rather the GUI itself is a feature that can be added or removed from the OS, and only a single reboot is required.  While the reboot may be disruptive, if managed properly the disruption will be minimal, with immense cost savings.

If you have a few servers to uninstall the GUI from then the Server Manager is the easy way to do it.  However if you have thousands or tens of thousands of VMs to remove it from, then you want to script it.  As usual PowerShell provides the easiest way to do this… the cmdlet would be:

Uninstall-WindowsFeature Server-Gui-Shell –restart

There is also a happy medium between the GUI and Server Core called MinShell… you can read about it here.  However remember that in your virtualized environment you will be doing a lot more remote management of your servers, and there is a reason I call MinShell ‘the training wheels for Server Core.’

There’s a lot of money to be saved, and the effort is not significant.  Go ahead and try it… you won’t be disappointed!