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 the par

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

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 a server plat

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 commands, defining the sou

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 of a wrinkle