CTVMUG – Ditch the UI

2018-03-01 21_33_09-ClipboardFirst off, if you attended my session at the CT Usercon, thank you for attending and engaging. If you weren’t there, I have to ask WHY WEREN’T YOU!?!

I honestly tried to jam a bit much content into the presentation, so as promised here is all of the code I presented today, complete with more detailed comments (after I get some rest). The code is way too much for one post, so I’m going put the code out now and expand on the posts more in the coming days.

Create a new vDS and add a server   (updated March 3, 2018)

Update from .msi based PowerCLI to module-based PowerCLI from the PowerShell Gallery (updated March 13, 2018)

Building Blocks: increasingly larger samples of VM deployment

Building Blocks: modify disks via PowerCLI #1

Building Blocks: PowerCLI HardDisk #2, introducing parameters and functions

Cleanup snapshots

Tag based SPBM policy

Checking SPBM compliance

Install programs via Invoke-VMScript (updated March 3, 2018)

Performance Reports via vCenter statistics

Get-EsxCli oh my! (updated March 2, 2018)

vRops & Remove-VM


Exchange Forward Rules via PowerShell

I’m really quite enamored with the Exchange PowerShell modules lately. Well to be honest, I’m just enamored with PowerShell in general… For someone who is a part time Exchange admin, the option to script out changes is really nice. I’d like to share a couple of examples of how simple managing forwarding rules is with PowerShell.

Recently we had someone go out on maternity leave and their manager wanted to keep up with their email. Reasonable request. Super easy to implement with PowerShell.


Set-Mailbox $ForwardingUser -ForwardingAddress $ForwardedToUser -DeliverToMailboxAndForward $true

It’s a pretty simple one-liner using Set-Mailbox. I was a little lazy on this one and used the positional parameter for -Identity to set the Originating user. Bad Scott, but I’ll fix it in a moment. Since in this case I’m forwarding within the organization, I use the -ForwardingAddress parameter with another SamAccountName, however if I needed to forward this externally I could just as easily use the -ForwardingSmtpAddress parameter. Lastly, I want both users to get copies of all messages so we set -DeliverToMailboxAndForward to $true.

Easy peasy, right?

In another recent example my employer recently merged with another entity. During our integration we wanted everyone to stay in communication. What we ended up doing in our domain was:

  • We created a contact entity in Exchange, pointed to their original domain’s SMTP address.
  • We then created their new Exchange accounts, and set the ForwardingAddress to be the aforementioned contact entity.

This solution worked great, but after the merger I didn’t really feel like going through and manually undoing all of that forwarding. Here’s the code I came up with to finish the job.


foreach($user in $(get-mailbox|where{$_.forwardingaddress})){
  if(Get-Contact $user.ForwardingAddress.DistinguishedName -ea Ignore){
    if( $($(get-contact $user.forwardingaddress.distinguishedname).windowsemailaddress).domain -eq $MatchingDomain ){
      Set-Mailbox $user -ForwardingAddress $null

I know that all of the entities have a ForwardingAddress attribute defined, so I use my ForEach loop to narrow down my list of users. Since I also know that all of the entities I’m looking for are configured as contacts, I leverage the get-contact cmdlet in the first IF statement to narrow down the field further. In the final if statement, I wrap the results in a number of expressions $() in order to do a comparison against $MatchingDomain. Finally we use the Set-Mailbox cmdlet again to set the -ForwardingAddress parameter to $null. As I expressed it to my team, the psuedo-code looks something like this:

If mailbox has ForwardingAddress -> If ForwardingAddress is a contact -> if domain of ForwardingAddress matches -> set-mailbox

Hope this helps someone. I’ll have more Exchange PowerShell posts soon.

Delete Windows Protected Files

If you’ve been following along in my continuing effort to prove that I’m in the wrong field, you may have noticed that my computer/lab blew up weeks before VMworld. Literally started smoking. Just this past week while attempting to upgrade my laptop before the requisite amount of coffee had been consumed, I blew up the raid array and ensured myself a fun Friday. Needless to say, I’ve been spending time with external disk enclosures recovering partitions.

Since I’m having so much fun I figured I’d upgrade my OTHER laptop’s hard drive. I’ve learned something of a lesson though and am least backing up my data first, which brings up the point of today’s post. The SSD I’m about to slap into this laptop was formerly a system drive, so I’d like to clean up all that garbage before I copy it off to other media.

2017-10-11 13_38_51-ClipboardNow the good folks at Microsoft know that 99 times out of 100 you shouldn’t be manually messing with the majority of the system, so removing the C:\Windows directory can be a bit of a challenge, even if that drive no longer is running your OS. It makes for an interesting conundrum though if you’re just trying to clean up a hard drive for reuse. There’s probably a more elegant way to solve this issue, but here’s how I went about it.

Now you know what happens if I try to just go in and change ownership or permissions: Windows tells me what it thinks of my storage skills. My quick way around around this is to use PsExec. Hopefully everyone knows Sysinternals by now. If you don’t, stop reading, go get Sysinternals and polish up your toolkit. So PsExec, although designed to run processes remotely can help you out locally as well. In my case I wanted to run my command as the system account to get this problem out of the way asap. We start off this fun by launching PowerShell via PSExec

psexec -i -s powershell.exe

The -i switch says you want to run in interactive mode, and the -s says to run as the LocalSystem account, which we can see here:

2017-10-11 17_04_28-Administrator_ C__Windows_System32_WindowsPowerShell_v1.0_powershell.exe

You may ask, why did you use PowerShell? Couldn’t you just use a cmd prompt? Well, sure, but cmd prompt is old, and PowerShell is awesome, so there you go. Now we are sitting in a PowerShell session running as the System account. We can use takeown.exe to set the local Administrator (/A) owner of all the files recursively (/R) without having to answer any prompts (/D Y)

takeown /F F:\Windows /A /R /D Y

I had to run this a couple of times.  It appears that there may be some funkiness with the recursion switch. I would also suggest that you output the results to a text file in case you have any issues.

Anyways… At this point we’ve got ownership taken care of, but we still need to grant ourselves access to the files using icacls, before we delete them. Since these are going away we don’t need to worry about security so we /grant the everyone group full permission and use the /T switch to tell it apply the permissions to all downstream files/directories

icacls.exe F:\Windows /grant everyone:F /T /C

And since we’re already in PowerShell let’s just take care of these badboys

remove-item F:\Windows -recurse -force

Blamo. No more Windows directory.

Next time I should really think of a less painful way to come up with a blog post

Take Your Next Step With PowerShell

Note: to hear me talk about this post, I’d like to invite you to visit the VMware Communities Roundtable podcast, episode #420. or here.

I just got back from Boston where I had a great time at the fall VMUG UserCon, presenting on PowerShell and PowerCLI. Regardless of what the title was, the message  behind the presentation was that everyone can become effective with PowerShell and hopefully some of these building blocks help you along the way.

One thing I hadn’t fully thought through before is that not everyone out there has development background. Talking about code with a room full of Systems Engineers finally helped me to realize this.  A couple of techniques came up in conversation that I know helped me take steps with my coding, and obviously hold interest for others who are getting started, so that’s what I’d like to talk about today. I’ve got a little bit of squirrel syndrome today and I see a shiny thing, so let’s go!

Expressions and sub-expressions

I’ve been using these for years, but I honestly had to go back and look up the name for this technique. Expressions harken back to mathematical expressions. Essentially by wrapping statements or an object in parentheses, you are telling the PowerShell engine to process the commands as a group. It’s essentially telling PowerShell about order of operations. Nothing too fancy about that.

What I find really fun with expressions is that they allow you to access properties of the group inline within your script. Take this code for example

$InputFile = "C:\Temp\linux_servers.json"

$Servers = $(Get-Content $InputFile -Raw | ConvertFrom-Json).Servers
 After reading in the contents of the json file, we directly reference the Servers array from the file, rather than individually parsing the elements of the file. Remember that PowerShell is all about objects, by wrapping Get-Content $InputFile -Raw | ConvertFrom-Json in a $( ) we can directly access the Servers attributes of the object represented within $( ).
Here’s another little example that takes it a bit farther. It’s long so I could use backticks (I’ll get to that in a few) to make it a little more readable, but I want you to see this code in all it’s glory!
 if($($agents.data[$i].hostname.tolower()).substring($agents.data[$i].hostname.tolower().indexof("\") + 1,2) -eq $serverData.Hostname.ToLower().substring(0,2))]
Super fun right? Not all that readable, so let’s break it down:
We use the $i variable (getting updated in a loop we don’t have here) to index through an array of $agents.data[$i]. We are accessing the hostname element and use the tolower() method to cast it for comparison. Finally we use our handy dandy $() expression to take this output and then we can use that property to parse the substring. The point of this giant example is that you can take multiple different elements, do operations inline and use the output directly via expressions.
If I didn’t do this justice for you, please check out the PowerShell blog, SS64, or Mr. Jeff Hicks author of PowerShell Scripting and Toolmaking for more information.


I’ve been known to write dirty code. What I mean is that, I don’t always need the prettiest code, or the most denormalized or code that conforms to style guides. My whole reason for writing, is to make things more efficient and that sometimes results in “dirty code”. That being said, I have a growing love affair with functions. This isn’t a coding primer, so I’ll let the SS64 & Scripting guys teach you about the nuance of a function, but essentially it’s a named piece of code that you can call from some other piece of code. Why would you want to do this? It makes your code more modular. If your code is more modular, you can reuse it more places. If you can reuse it more places you can do more faster. If you can do more faster: PROFIT!

Anyways here’s an example I did for VMworld (with a touch of here-string help from my friends).  Here-strings… sounds like another post…

$Guest = Get-VM -Name "Sql01"
$DiskSize = 40
$Disk = "Hard Disk 2"
$Volume = "D"

Invoke-VMScript -vm $Guest -ScriptText "Get-PSDrive -Name $volume" -ScriptType PowerShell -GuestCredential $cred

$objDisk = Get-HardDisk -VM $Guest -Name $disk
$objDisk | Set-HardDisk -CapacityGB $DiskSize -Confirm:$false
$scriptBlock = @"
echo rescan > c:\Temp\diskpart.txt
echo select vol $Volume >> c:\Temp\diskpart.txt
echo extend >> c:\Temp\diskpart.txt
diskpart.exe /s c:\Temp\diskpart.txt
Invoke-VMScript-vm $Guest-ScriptText $scriptBlock-ScriptType BAT -GuestCredential $cred

Invoke-VMScript -vm $Guest -ScriptText "Get-PSDrive -Name $volume" -ScriptType PowerShell -GuestCredential $cred
This very simple code example will use invoke-vmscript to extend the drive on a windows machine. Now consider the following code:

if($Guest.Staaatus -ne "GuestToolsRunning" ){

Write-Host"Too bad so sad, you'll have to manually extend the OS partition. Maybe you should fix VMtools..."-BackgroundColor White -ForegroundColor DarkRed
else {

### Function to Extend OS Volume
function Set-OSvolume{
echo rescan > c:\Temp\diskpart.txt
echo select vol $Volume >> c:\Temp\diskpart.txt
echo extend >> c:\Temp\diskpart.txt
diskpart.exe /s c:\Temp\diskpart.txt

Invoke-VMScript-vm $Guest-ScriptText $scriptBlock-ScriptType BAT -GuestCredential $cred>$null
$(Invoke-VMScript-vm $Guest-ScriptText "Get-PSDrive -Name $volume"-ScriptType PowerShell -GuestCredential $cred).ScriptOutput

Now that we’ve taken that same code snippet and turned into a function, our code got cleaner, more modular and something something profit. OHH did someone say cleaner code?


Formatting scripts for presentation, or blogs, or community posts and actually making them readable can be a challenge especially when you start getting long one-liners. While prepping for PowerCLI 201 (cough, top 10 session, cough) Mr Luc and I had a bit of a debate around readability. I’ve historically been a fan of of the back-tick ` method to have a command extend beyond a single line.  Here’s what that looks like:

2017-10-18 12_50_39-VMworld 2017 SER2614BU - PowerCLI 201_ Getting More Out of VMware vSphere PowerC
“kyle, what was I thinking using back-ticks?”   “I dunno man, but I see Luc shaking his head over there”

I’m OK admitting when I’m wrong, and while back-ticks may be good in some situations, in others they just look like crap. So enters the splat, or as my wife likes to call it “splatting the gui”. I’m not going to try and give a deep dive on that concept, as there are already a number of great articles out there: Don Jones, author of the Month of Lunches, Rambling Cookie Monster, the googs. Just as a real quick reminder, splatting is a way in which you can specify both the parameter and it’s assigned value within a hashtable. By using this splat hashtable, you can dramatically simplify the code and it’s readability… as with all things, in the appropriate situation.

With that reminder out of the way, what I wanted to talk about is the when/where of splatting, but first I think this picture shows you what I’m talking about in terms of simplified code..

2017-10-18 13_00_27-VMworld 2017 SER2614BU - PowerCLI 201_ Getting More Out of VMware vSphere PowerC
“See how pretty this looks now Scott.”   “whoa”

Here’s what I’m finding with splats: while they make code more readable in a presentation or a blog post, you probably don’t want to try and use them while working out a problem or a new cmdlet. If you’re going to use them in your code, you’ll probably want to figure out your use case and parameters first, then back into using a splat. Likewise I would suggest knowing your audience and their experience level. While talking about this subject in Boston the other day, I got a few blank stares. Even if it’s pretty, the code still has to be usable and that means readable as well.

Hopefully these quick tips help!

It’s a bird, it’s a plane, it’s… Invoke-VMScript

I was at work today and a need came across my desk for a solution that requires SNMP. For some reason which I can’t fathom, SNMP is not installed as a service on the majority of the servers. Who do we turn to in tumultuous times like these? PowerShell and his mighty sidekick PowerCLI!

michael-corleone-pull-me-back-in-just-when-i-thought-i-was-out-they-pull-me-back-inFirst things first I wanted to know the scope of what I was dealing with. When I dove into this problem I had every intention of trying to broaden my horizons and move away from PowerCLI, but it’s so easy to get sucked back into what you know. Besides, I knew I was only targeting a couple of clusters, so it only made sense to go back to PowerCLI, right? Right???

If you ignore the ugly formatting, what I did below was load all of the VM’s I needed to target into an object and then iterate through each of them to make sure they were windows machines and that they were powered on. In hindsight I knew that I was probably going to use invoke-vmscript to get the job done, so I probably should have checked for vmTools status (ExtensionData.Guest.ToolsRunningStatus) while I was at it.  snmp1

So now we’ve got a nice neat little hashtable full of servers that need a little TLC. You’d think that we could immediately get rocking, but without going into details things unexpectedly got a little dodgy at this point. I mentioned earlier that I originally intended to try and break away from PowerCLI just to broaden my horizons. Unfortunately as an Infrastructure person you don’t always have the opportunity to do things the way you’d like, and you have to sacrifice elegance for just getting things done. Luckily as VMware admins when we need to get $hit done, we have a very handy and very powerful tool available to us and that is invoke-vmscript.

b436ea981cd43a8a244370d95fa3f343_super-troopers-better-fix-meow-super-troopers-meme_250-131If you’ve heard me talk, reviewed my scripts or spent any time around me you’d know that I think invoke-vmscript is the cat’s meow. It is without a doubt my favorite cmdlet as it lets you get away with some pretty awesome stuff. At it’s root, invoke-vmscript allows you to run a script via VMtools within the context of the local VM. Now this is different from PSexec or PowerShell remoting; you are actually running the a script within the local OS where VMtools and PowerCLI are just the mechanisms to enable this super hero activity.

Quick sidebar: With great power comes great responsibility. I said above that invoke-vmscript “lets you get away with some pretty awesome stuff.” Many people in this world just deploy VMtools and vCenter with default permissions and credentials. If you are a security person, you need to ensure that your roles and privileges are setup appropriately, of you could have exposure due to what you can accomplish with VMtools.

But I digress. We are here to get things done and at the center of it this whole exercise boils down to a one liner:

<strong>Invoke-VMScript -VM $client.Name -ScriptText "DISM /online /enable-feature /norestart /featurename:SNMP" -ScriptType Powershell

If you refer back to the original snip, we stored all of the servers into an array, which is being iterated through. We invoke the script targeting $client.name. The parameter for ScriptText is where we pass in the script that we would like to run on the remote system. In this case we are using the Microsoft DISM tool to add the SNMP feature to our Windows installation. Lastly is the parameter for ScriptType. You have three ScriptType options available to you as of today: Bat for you old school Windows Cats, Bash for the nix kittens and PowerShell for the up and coming cubs.

When you put it all together, here’s the code to get it done:

$serverset=$(get-cluster cluster1|Get-VM) + $(get-cluster cluster2|Get-VM)


foreach ($client in $serverset){

if($client.powerstate -eq "PoweredOn" -and $client.guestid.contains("windows")){

if(!$(get-service -ComputerName $client -Name SNMP -ea silentlycontinue)){
Invoke-VMScript -VM $client.Name -ScriptText "DISM /online /enable-feature /norestart /featurename:SNMP" -ScriptType Powershell
get-service -ComputerName $client.Name -Name SNMP|Select-Object -Property name, status, starttype |ft





I hope for today you’ll excuse the formatting and less than efficient code, as the mission was to get things done. We achieved our mission and escaped certain doom due to our friendly neighborhood hero Invoke-VMScript. I hope to have a deeper expose into our masked super hero soon, but until then if you have any thoughts or would like to contribute to the conversation, please reach out.