Posts

Session Authentication in NSX and the Bad XSRF Token

Well, it's been a while since I posted here, but this one was a real head scratcher with ultimately a simple solution, so I figure that I should put it out there!  I've been working with the NSX API lately and wanted to do session based authentication rather than throwing credentials at the system for every operation.  I followed the official guide (as best I could, given that I'm working in PowerShell), so then I followed some really helpful blog posts , and it looked like I had everything right... but I was getting this Bad XSRF Token error that I didn't understand. I did a bunch of fruitless research before I noticed something.  My $headers variable had the XSRF token enclosed in curly brackets, as it came from the value of a hashtable (as seen in Lorenzo's script here): $xsrftoken = $response.headers["X-XSRF-TOKEN"] ... $script:headers.Add("X-XSRF-TOKEN", $xsrftoken) That didn't look right to me.  I was grasping at straws, so I tried pop...

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 p...

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 Syslog.global.logHost 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 Syslog.global.logDir 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~~~~0.0.1.0 /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_con...

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 192.168.0.1 and 192.168.0.254, I want to get back 192.168.0.0/24.  If I'm playing around with subnets though, I want to be able to give i...

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!

Script to Move a VM to a New Portgroup and Update its Network Identity

Hey everyone - I recently put together a script to make it easier to move a VM around between various networks.  It moves the VM onto the specified Port Group and then uses VMTools to run a PowerShell script in the guest (this is for Windows VMs only, sorry!) to update its IP/DNS/Gateway/etc.  Since my old Gist'ing technique isn't working any more, so it's below as simple text (and it's on my GitHub if you want to grab it that way). But first, let's break it down a little bit!  The bulk of this script is really straight-forward.  The most interesting bit is using the PowerCLI Invoke-VMScript cmdlet to do the work inside the target VM's OS (since this operation will break network connectivity).  Invoke-VMScript is, on the surface, similar to the core PowerShell cmdlet Invoke-Command... but they way that they operate is completely different under the covers!  The practical difference that made the most impact for me is that Invoke-Command allows access to th...

Technique for Parsing String Output into PowerShell Objects

I just read a cool article about parsing netstat output (aka unformatted string output) into PowerShell objects.  The solution was great (and their approach taught me that select-object has a -skip # parameter that can be used to chop off the first # of objects from an array, which is super useful), but since I would approach it in a totally different manner, I figured that I'd write out my technique!  I want to be clear: I'm not saying that one approach is better than the other.  There are often many perfectly valid solutions to a scripting problem.  In some situations, one might be preferable to another though, and so here's another option to add to the old toolbelt. (netstat -an | ? {$_ -match '^  '}).trim() -replace '  +',';' | ConvertFrom-Csv -Delimiter ';' That's a pretty dense line (and it's worth noting that there are two adjacent space characters before the plus in the replace string and in the match string), so let's b...

Planning VMware Upgrades

Image
System upgrades are a fact of life in the world of IT.  As systems grow more complex and interrelated, upgrades become more and more difficult to plan, as each of those interacting systems creates a dependency that may or may not support the new version!  In the VMware world, there's a couple of great tools that I use every time one of my customers asks for help with an upgrade project... so I figured that I'd write about them here! If the customer wants to upgrade their ESXi servers (which they almost always do), the first thing that I check is the VMware Compatibility guide .  When I'm using this tool, I typically select the new ESXi version under Product Release Version  and then just use the search bar to find the hardware platform that the customer is using.  After selecting the right server, the page will show us what firmware versions on that server platform are supported (or other interesting notes to be aware of).  These days, it's pretty rare for ...

Secure Credentials in PowerShell Scripts

The scripts that I write occasionally need access to specific user account credentials in order to do their work, so I wanted to write a quick note about how to securely store those credentials for scripts (especially if they're going to be run as a scheduled task)!  It all revolves around the get-credential cmdlet. The get-credential cmdlet is made for this; by default, the object that it creates is encrypted to the account that executed it as a secure powershell object.  This means that you can easily save those credentials to a secure file with these two commands: $creds = get-credential -message "Enter credentials" $creds | export-clixml $credsFile Many PowerShell cmdlets can take credentials in the form of a credentials object (frequently with the "-credential $creds" syntax), but even when you need to supply a username and password, they're really easy to get out of that $creds object: $creds.UserName $creds.GetNetworkCredential().password If some othe...

Powershell Script to start a lot of Robocopy Jobs

 We were recently helping a customer with a domain consolidation where we had to copy a bunch of files from several different domains over to a new file server.  We decided to break the task up into a few steps, the first of which was to simply get the data onto the destination!  To do that, we decided to use Robocopy, but we were going to need to copy data from several different domains without trust relationships, meaning that we'd have to get a bit creative with gaining access to the source data. In the end, I put together a script!  This guy takes several important input parameters: foldersList, drivesList, and logFolder. FoldersList is the path to a CSV that lists all of the folders that are being migrated.  This script ultimately depends on two columns in that CSV: SourceDrive and DestinationDrive, although we put SourceUNC and DesintationUNC fields in that file to help with later steps.  At its core, the FoldersList CSV is used to make the robocopy c...

Authenticating to the NSX-T API via PowerShell

I've had the chance to work on some NSX-T scripting lately, as we work to integrate some other solutions with the tool.  I don't have a ton of experience with API access, but I have been slowly learning... and one of the big hurdles that I had to overcome was just figuring out how to authenticate with the system!  So, that's where I'm going to start here. First, let's talk about the basics of how authentication works when accessing the API.  To use Basic authentication, you need to put together your credentials in the format of "username:password" and pass them to NSX-T.  Since this is being passed through a web request and special characters could mess everything up, so you need to Base64 encode that authentication string.  Once you've got it encoded, you need to put that into the Headers of your requests so that NSX-T will know who you are.  So, let's look at how to actually do that process! First, I'm going to prepare two variables.  One wil...

Using Powershell to Edit Substrings

On my 3D Printing blog , I recently realized that Blogger made a change to the way that images are displayed.  It used to show the full size image when you clicked it, but it has changed to only show a slightly larger version of the image.  That has almost no impact on this blog since I rarely post images, but I frequently write tutorials that have screenshots from Blender or PrusaSlicer... and it's pretty important that the settings in those images be legible!  Well, some google-fu revealed an easy work-around; just change the href links to point to a different subfolder, so that the full resolution image will be displayed.  That's great, except that manually editing the HTML from my blog posts and changing the file path is a highly repetitive and boring task... well, you see where this is going.  PowerShell to the rescue! I've done a fair amount of string manipulation with PowerShell, so I thought this was going to be a trivial task... but this one had a bit o...

Using the NSX-T API

I've been writing some PowerShell scripts to automate NSX-T configuration lately, so I figured that I should put together a primer with notes about how to get started!  Firstly, if you're working with the API, you're going to want to be able to reference the official documentation .  There's a lot that can be done via the API, and that guide will tell you what calls to make to do most of it!  If you're like me and haven't spent a lot of time working with APIs before, that document will present a pretty steep learning curve... so I'm writing out my notes here, to make it easier for people to get started! At its most basic, using the API is just sending a web request to the NSX-T manager and then reading the response.  Since this is potentially sensitive information, you're going to have to authenticate with the server though, so you'll need to include a Header with that login information.  If you want to change anything, you're also going to need ...

Reporting Systems that use KMS

 I was helping a customer resolve an issue with their KMS server recently and we decided that we'd like to get a look at which systems were actually using it, instead of just looking at the total number of systems as displayed by slmgr /dlv.  I couldn't find any slmgr switches that looked like they'd generate a report with this data, but my customer pointed out that we could find it in the event logs (under the Key Management Service grouping), but that it'd be a pain to go through all of the events and pull out the client names.  Well, you can probably guess where this is going - I put together a quick script to do exactly that! This is a really quick and dirty script; I built it to run on the KMS server and generate a table with the client ID in one column and a list of client computer names in the other.  Why is it a list of client computer names?  Well, this particular customer is running a VDI environment and there can be a bit of a problem with KMS and Ins...

Problem while Connecting Horizon 7.12 to vCenter

I was setting up a quick Horizon 7.12 PoC environment and ran into a bit of trouble getting Horizon to talk to vCenter.  Every time I tried to add the vCenter server to the Horizon environment, I got an error: "Certificate validation failed" and gave me no option to accept the certificate.  This was more than a little confusing because the vCenter server had a proper certificate signed by the enterprise CA and we verified that our Connection Server, as a domain member, trusted that CA and could even browse to vCenter via the web browser with no certificate issues. So, I did what we all do in this sort of situation; I started digging through the the logs.  Eventually, I found the line that I needed in the C:\programdata\vmware\vdm\logs\debug-<date>.txt log file on the Connection Server (after searching for my vCenter server's name to help narrow down the contents of the log): "Permission to perform this operation was denied." Well, that struck me as int...

Error during Pre-Checks for vCSA Upgrade from 6.0 to 6.7

Hi everyone - I was helping a customer upgrade their vCenter Server Appliance from 6.0 to 6.7 and we came across a bit of trouble.  During the pre-upgrade checks phase, our logs revealed these errors: No file found matching /etc/vmware/install-defaults/cm.url No file found matching /etc/vmware-vpx/vcdb.properties No file found matching /etc/vmware-vpx/vc-extn-cisreg.prop Googling around revealed some possible DNS related issues, but we doublechecked that all of our DNS records were good so figured that was unlikely to be the issue.  So, after some more unfruitful research, we decided to check on the current version of the vCenter server.  It was a very early version of 6.0.  Lacking further direction, we went ahead and used the management interface (via port 5480) to download the latest 6.0 updates.  After those were applied, we tried the 6.7 upgrade once again and everything went great! So, if you come across those error messages, you may just need to upgr...

Deploying the vCloud Director OVAs from the Command Line

I've recently had the opportunity to do some work with a vCloud Director deployment, which has been a lot of fun! We've been working on a lab environment at the moment, and we want the ability to quickly redeploy the lab now and we want to be able to reliably deploy a similar configuration into production later. So, to that end, I spent a bit of time figuring out how to deploy the VCD Appliance via the CLI, and I'm ready to share my results! I started by spending some quality time with the Deploying vCloud Director with the OVF Tool Guide  to get an idea about what options I was going to need. There's a lot of options in there, and there's a moderate amount of variety to their syntax! After looking over the various options, it looks like we can basically break down the option syntax into 3 parts: a Paramter, a Name, and a Value. Various options use these parts in different combinations. Let's look at these lines from their example: --allowAllExtraConfig --d...