Home » PowerShell

Category Archives: PowerShell

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!

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.


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

Select Partition 5

Delete Partition OVERRIDE


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:


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.


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.


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


imageSee? I told you!

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


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:


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


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!

%d bloggers like this: