I grew up playing with legos. They were fun, and they spurn the imagination. You might start with a block or a premade prop. You put things together, maybe follow the instructions, and eventually let your imagination run wild building whatever comes to mind. Perhaps a car.
I use the lego anecdote when talking about PowerShell with newcomers. You might start with single cmdlets and premade functions. You can pipe them together, follow some examples and blog posts, and eventually get the hang of building advanced functions and modules to meet your needs and imagination.
Modular code is one of the many benefits to scripting and programming in general. Let’s take a look at a practical example, with a function that can speed up testing connectivity to systems.
One of the first commands you learn in PowerShell is Test-Connection. It does the trick, but it’s not exactly speedy. Let’s pretend I want to run against all the servers in my organization, but want to skip over systems that don’t respond:
Thirty minutes tests my patience, and wouldn’t it be nice to have a single command rather than writing logic for looping and output?
A few years back, Boe Prox wrote a great article on using runspaces to speed up network information queries. I mashed together some of Boe’s code with some crude duct tape, and rolled out the first iteration of Invoke-Parallel. Sergei Vorobev contributed a number of helpful ideas, including adding Pester tests and automated testing through AppVeyor.
Invoke-Parallel is like a mashup of Foreach-Object and Invoke-Command. You can use it to run a script block against a collection of objects (like foreach), and it does it incredibly quickly, but you need to be wary that runspaces are fairly independent. You need to consciously pass in variables and load modules as needed, similar to Invoke-Command.
Pretty good! I can live with 45 seconds, but it’s pretty bare bones, and it’s not abstract enough. What if I want to test remote registry, remote RPC, SMB, or other connectivity?
Justin Rich has a handy tool we can use for these connectivity tests - Test-Server.
A few tweaks to Test-Server, and we have the ingredients for a convenient and fast solution that works in PowerShell 2:
All we need to do now is bundle these ingredients into a simple to use package, Invoke-Ping. Hit the link, download and unblock the .ps1, and load it up!
# dot source the function . "\\Path\To\Invoke-Ping.ps1" # Get help for Invoke-Ping Get-Help Invoke-Ping -Full # Check for WSMan, Remote Registry, Remote RPC, RDP, and SMB (via C$) connectivity against 3 machines Invoke-Ping Server1, Server2, Server3 -Detail *
There are a few ways to run it:
This simply runs Test-Connection and returns a selection of properties.
This executes the same code as the plain example, but we only return responding computer names.
This is a great way to filter out systems that don’t respond to ping. Remember our original thirty minute query? We can get it down to less than 45 seconds:
Finally, what if we want more details? Here are a few examples; note that you can specify which tests to perform:
Snippets of code are great, and they have their place. If you really want to save time, consider building re-usable tools that you can use across solutions and within other tools. If you follow best practices and conventions, your functions and modules will integrate with the wider PowerShell ecosystem.
Once you get the hang of it, adding the scaffolding around a function becomes second nature, and you may find yourself preferring to start with the assumption that you will be writing a function.