Script to Report ESXi Path Status to a SAN

Hey everyone - one of my customers was doing some maintenance on the FC switches recently and wanted an easy way to ensure that all of their ESXi hosts had 4 Active links to their datastores before bringing a switch down for maintenance.  Sure, we can click through the GUI and manually examine each host... or we can automat it! So, I wrote a script to report the status of all paths to a given datastore (or datastores via wildcard matching) for all hosts that are connected to it!  The usage on this guy is pretty straight-forward: .\report-datastorePaths.ps1 -datastoreName <name of datastore to examine; multiple datastores may be specified with wildcards> -alertThreshold <if the number of active paths is less than this number, alert the user> That -alertTreshold parameter (which defaults to 4) is used to cause the script to write to the host if it ever finds a host with fewer than that number Active links.  So, if it doesn't spit out any red text, you're probably goo

ESXi Syslog to Multiple Servers

 Hey guys - just a quick note today.  I was configuring a second Syslog server for a customer's ESXi via the advanced setting, but was getting a generic "Internal Error" error whenever I tried to save my configuration.  Some quick googling made it look like this might be related to the scratch directory configuration having a problem or possibly the setting pointing at a folder that didn't exist, but in this case it was much simpler. When setting up multiple logHosts, the example shows "udp://hostName:514, hostName2, ssl://hostName3:1514" but that's not actually the correct syntax to use.  It should be "udp://hostName:514,hostName2,ssl://hostName3:1514" to get it working.  Note that the servers are separated only by commas, instead of by a comma and a space.

vCF External Backups using a Windows SFTP Server and the D:\

I was working with a customer who wanted to configure a Windows SFTP server as the backup target for their VCF SDDC backups, and it was a bit of a pain to get working right, although in the end it wasn't too complicated.  So, I'm writing my notes here! In this environment, the server is not given internet access, so installing the OpenSSH feature took a bit of extra work in Windows.  The key there was to download the FOD ISO from Microsoft and mount that to our VM (not the normal Windows install ISO).  Once that ISO was mounted (as the E:\ drive), I used the following DISM command to install the OpenSSH Server optional feature: dism /add-capability /online /capabilityname:OpenSSH.Server~~~~ /source:E:\LanguagesAndOptionalFeatures That got OpenSSH installed, so I made sure that the service was set to Automatic in Windows and figured that we were good to go!  Not quite... The server needed some configuration.  The config file is "C:\ProgramData\SSH\sshd_config" a

PowerShell Function to Extract Subnet/CIDR for a Pair of IP Addresses

Well, this one is hyper-specific... but in case anyone else needs to do something similar, I figure that I should share!  As a tiny part of a much bigger project, one of my customers gave me a list of VLAN IDs and the IP Ranges that they want to use on each VLAN.  Unfortunately, that list did not include either Subnet Mask or CIDR values, so I had to work backwards from the given ranges to determine what would be an acceptable Subnet Mask.  This process involves some annoying binary math, so you know that I put together a script to do it for me! I wrote the extract-CIDR function to accept two IP Addresses, and then to output the smallest subnet/CIDR that could contain those two IP Addresses (so they don't technically need to be the start and end of the range, but it's safer to use those two).  For example, if I give the script and, I want to get back  If I'm playing around with subnets though, I want to be able to give it 192.168.1.

Using Microsoft.Graph PowerShell Module to Update a Sharepoint List

I've been working on a big VMware automation project for a customer who wants to use their Sharepoint site as the source of authority for configuration files.  They are using Microsoft Graph to give me access to that environment, so my permissions do not extend to the standard PnP.Powershell module and I've been learning the Microsoft.Graph module instead. We came across an issue when using the new-MgSiteListItem cmdlet though, where we were getting error messages like "Field 'title' is not recognized."  In this case, there was a field called Title and the configuration that we'd passed the cmdlet specified Title, but the internal workings of the cmdlet were converting the first character to lowercase and thus the whole thing wasn't working.  But, there's an easy work-around! The Microsoft.Graph PowerShell module has a catch-all cmdlet: Invoke-MgGraphRequest.  With it, you can use the Graph API directly, without having to worry about headers and au

Powershell to Validate IP Configuration (Address, Gateway, Subnet Mask, DNS)

I'm working on a VM deployment script for one of my customers.  As you might expect, input validation is incredibly important, as we want to filter out a malformed configuration before starting the actual deployment.  To that end, I put together a bit of PowerShell that I'm pretty proud of; this script does a basic sanity check on a network configuration . It does a fair amount of work.  Firstly, it checks to ensure that the IP Address, Gateway, Subnet Mask, and all DNS Servers are being supplied as valid IP addresses.  PowerShell makes this trivial to do, as you can cast a string as an [ipaddress] object and PowerShell will parse it for you.  If it's a string that can't be parsed (such as [ipaddress]"JasonIsAwesome!" which is a string that most people would agree is inherently incomprehensible*), it'll throw an Exception and thus end the execution of the script.  So, that most basic input validation is over in a blink... but wait, there's more! Since

PowerCLI and Get-TagAssignment Execution Speed

I've been working on a script for a customer recently, and part of that script checks all of the VMs in their environment to ensure that they comply with the customer's VM Tagging policy.  As you might expect, this script revolves around the get-tagAssignment cmdlet and I've noticed an interesting quirk about how it runs!  I'm not clear on the "why" of it, but run these two commands and compare the results: measure-command {get-vm | get-tagAssignment} vs. measure-command {get-tagAssignment -entity (get-vm)} It's a profound difference!  In this customer's environment, piping the results of get-vm into get-tagAssignment takes over 73 seconds to run... but when I run get-vm as the entity for get-tagAssignment, it completes in a bit over 0.5 seconds! I'm not sure what's going on here, but I do know that once I changed my script to use the -entity property it sure ran faster!