Posts

Showing posts with the label Powershell

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

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

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

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

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

Accessing the vCloud Director API

I've been working on a vCloud Director environment recently and need to use the API for my current project.  Well, I'm not a big API guy, so this has been a good learning experience for me!  The first hurdle that I had to overcome was authentication, and since I didn't find that to be super well documented, I figure that I should put my notes up here.  So, here's how I get authenticated to vCloud Director's API via PowerShell (because, of course PowerShell!). First things first, you've got to figure out what credentials you want to use.  The most basic way to authenticate is with a local account (rather than an LDAP account), but you need to append a scope to that account name to get logged in.  If the account is part of an Organization, you can use that Organization's name, but if it's a system administrator, you'll need to use "@system" instead. Next, you'll need to Base64/UTF8 encode your credentials in order to pass them success...

Using the vRNI API through PowerShell

I've been plugging away with vRNI and the NSX Distributed firewall a lot, but that hasn't generally leant itself well to writing blog posts... until recently!  We are working on an auditing process to help us decommission NSX firewall rules in favor of policies.  Typically, when retiring a firewall rule, you would just change its priority so that it's below the newer Allow rules but still above the Deny rules, then wait a while and see if it still gets any hits.  In this situation, we're looking to retire some manually created firewall rules in favor of our new set of policy-driven rules, and you can't put manual rules in the middle of your policy rules... so the typical firewall procedure won't work here! So, we've been working on a process to use vRNI to look at all traffic that's hitting a given firewall rule, then check on the policy-based rules and ensure that it will all be allowed by those rules.  The process itself is pretty simple, and looks ...

Summarizing NSX Security Policy Firewall Rules

I've been working with one of my customers to implement the NSX Distribtued Firewall via Security Policies instead of hand-crafted rules.  For auditing and reporting purposes, we needed to be able to display all of the policies that have been created and the DFW rules within each one.  Ideally, we'd need to be able to generate this report on demand, with real-time data... and since the NSX GUI doesn't make that easily visible, I figured that I should put together a script to do it for me! Enter the summarize-NSXSecurityPolicy.ps1 script.  This script uses PowerNSX to get all of the defined Security Policies in the environment, then builds a table with one row per DFW Rule.  Each row contains several columns, including one for the policy that defines the rule, so we can easily filter the table to show what's going on with specific policies or we can easily search it to find a policy that involves specific traffic.  That later use case is almost certainly more im...

Speeding Up Scripts: Sorting and Selecting Unique

I often find myself working with large collections of objects, and one challenge that frequently comes up is to distill that collection to a set of unique items.  For example, I'm working on a project that involves analyzing a lot of network flow data that I receive with parameters for Source, Destination, Protocol, and Port.  For a part of this project, I need to create a bunch of computer objects, with parameters for InboundTCPPorts, InboundUDPPorts, InboundOtherPorts, OutboundTCPPorts, OutboundUDPPorts, and OutboundOtherPorts.  To make these computer objects, I need to start by getting all of the unique computers from my input data's Source and Destination fields.  That's pretty simple.  I start by combining the source and destination fields into a single array: $computers = $data.source + $data.destination That gives me a single list of all computers that are involved in these network flows, but that list is going to have a ton of duplication in it (si...

Changing your Windows Password in Nested RDP Sessions

Due to some strict security requirements, I often find myself working inside of an RDP session that's nested inside of another RDP session (that is occasionally nested inside of a Virtual Desktop).  Generally speaking, this works really well... except for when I need to change my password.  When you're buried that deeply in nested RDP sessions, neither ctrl-alt-del nor ctrl-alt-end are going to do the trick for you.  Fortunately, Serge Pavlov, deep in the comments of a technet article , had the solution!  I'm mostly writing about it here to make it easier for me to find it again when I need to go through this process 30 days from now ;) In a PowerShell window, run this command: (New-Object -COM Shell.Application).WindowsSecurity() That'll open the Windows Security Center (the same thing that pops up when you hit ctrl-alt-del normally).  From there, you can just click "change password" and be on your merry way!  I like this because, since it's ini...

PowerNSX and Security Group Membership Exclusions

Hey everyone - I've been helping a customer implement their NSX Distributed Firewall recently.  I'm not a big fan of the GUI, but I can do just about everything that I need to do through PowerNSX, which I've found much faster and easier to manage... until I started working with Security Group membership exclusions. NSX follows a fairly sophisticated process for determining what objects are members of a given Security Group.  First, it checks the rules in that Security Group's Dynamic Membership section and adds all of the specified objects to the list (this can be a computationally expensive process, so you probably don't want to use a lot of dynamic membership rules).  Next, it checks the list in that Security Group's Static Include section and adds all of the specified objects to the list (this is a cheaper operation and should be the go-to group membership method).  Finally, it checks the list in the Exclude section and removes those objects from the list. ...

Using PowerVRNI to Register Applications

One of my customers wants to use VRNI to better understand their environment.  They've been fairly disciplined about putting VMs into folders based on the application that the VM serves.  Unfortunately, they've been a little too good about putting the VMs in folders, as each application is broken up into several subfolders.  This causes a bit of a problem when we want to use VRNI to analyze an application's traffic, as the query flows where folder like *application*  certainly works based on the VM folder... but it only looks at the immediate folder for the VM, rather than the whole path.  Since we had everything broken up into subfolders, that query doesn't do us much good here. So, I put together a quick script that can scrape a vCenter inventory to register VRNI applications for each folder that it finds.  Those applications are named based on the absolute path of the VM folder, so that you can run queries like flows where application like *application...

Removing the First Item from an Array in PowerShell

This is a quickie, but I often find myself working with arrays of objects when I'm working on a PowerShell script.  Occasionally, I need to remove the first item from that array, which I've always done by using the array index:  $array = $array[1..($array.count - 1)] .  That certainly works, but it's also kindof ugly. Today, I learned a better way!  PowerShell does a neat trick with commas, the equals sign, and arrays.  If you're assigning an array to a comma delimited list of variables, the array automatically gets split between those variables.  I've used that in the past in situations like this: $IPAddress = "192.168.0.1" $First,$Second,$Third,$Fourth=$IPAddress.split(".") And, as you'd expect, that will split the IP Address into octets, with each one going into its named variable.  That's great, but what happens if you've got this situation? $IPAddress = "192.168.0.1" $First,$Second=$IPAddress.split("....

Syntax Highlighting in Notepad++

I do a lot of work with PowerCLI and my favorite text editor is Notepad++ .  Recently, I've been adding more modules to my repertoire ( PowerNSX and PowerVRNI , I'm looking at you!) and I've finally decided that I need to add all of these modules' cmdlets to my syntax highlighting in NPP.  The proper way to do this is to define a custom language and add everything to it.  This can be done through the GUI (yuk) or by editing a custom language xml file. Unfortunately, there's no way to clone an existing language as a start for a custom language (or at least, I couldn't find a way to do it).  Even more unfortunately, the custom language definitions file syntax is pretty different from the inbuilt ones, so you can't just copy and then edit the XML from the already existing PowerShell language. Not if you want to do it the proper way.  It looks to me like I can trivially edit my default langs.xml file (where PowerShell is defined) and add an arbitrary set o...

Using PowerNSX to Build NSX Distributed Firewall Rules

I've been helping one of my customers set up a proof of concept NSX implementation, which has involved configuring and then destroying several firewall designs.  In order to speed up this process, we've had to get pretty good at using PowerNSX to script out the creation of those NSX firewall rules (and other security objects). First, how do you get PowerNSX?  Just like PowerCLI!  Open up your PowerShell window, then use this command: Install-Module PowerNSX Now that you've got PowerNSX installed, take a moment to look at what it does for you.  Look at all of the available cmdlets by using: get-command -module PowerNSX There's a lot going on there!  In general, the PowerNSX cmdlets use the normal PowerShell verbs: get, set, add, remove, and new, and the nouns are prefixed with NSX.  So, if you're using tab completion to figure out what command you're doing, <verb>-nsx... is usually a pretty safe place to start.  For example, if I want to get...

Getting a list of All ESXi Hosts and their WWNs

One of my customers was doing some work on their storage network and so wanted a list of all ESXi hosts and their WWNs.  This struck me as another excellent scripting opportunity, so I pulled out my old Brocade 1:1 Zoning script and went to work.  I really only needed a one-liner for this situation, so I extracted my needed syntax from that script and quickly put it together.  Here's the (admittedly, ugly) command that I came up with: get-vmhost | select name,@{N="WWNs";E={($_.ExtensionData.config.storagedevice.hostbusadapter.PortWorldWideName | % {("{0:X}"-f$_ -split '(..)' | ? {$_}) -join ':'}) -join ", "}} That'll spit out a list with two columns, ESXi host names in one, and a comma separated list of WWNs in the other.  So, what's that ugly expression in that select statement doing?  Well, it's collecting all of the port WWNs on that ESXi host, then converting each one from decimal into hexadecimal (the "{0:X}...