A part of why I write, is to have a place to store things I’m probably going to forget the moment I need them. Notice the search feature to the right. I’d be surprised to find out that someone has used it more than me.
That brings us to today’s topic: getting a locally declared function into a remote session. I wrote a recent post about getting variables into a remote sessions — you can read that here: http://tommymaynard.com/quick-learn-getting-local-variables-into-remote-sessions-2015 — and thought that getting a local function into a remote session, would make for a good followup.
First, let’s start with a function. This is a mildly complex function to use for an example, but by using it, I’ll be ensuring I can find it later, too. This function is a wrapper for the command: Dism /online /Get-Features. It takes the text produced by that command and returns the results as objects. I wrote this as part of an answer to a thread on the Microsoft Technet Forums: https://social.technet.microsoft.com/Forums/scriptcenter/en-US/972d87a9-9930-4f64-8592-5406f5fab8f4/dism-online-getfeatures-with-where-clause?forum=ITCG#01aeebe3-01b5-49cd-a8dd-1b1ce0352c8b.
Function Get-DismFeatures { [CmdletBinding()] Param () Begin { $Results = Dism /online /Get-Features $Results = $Results[8..($Results.Count - 3)] | Where-Object {$_ -ne ''} $Feature = $Results | Select-String 'Feature' $State = $Results | Select-String 'State' $ResultsCounter = $Results.Count/2 } # End Begin. Process { for ($i = 0; $i -lt $ResultsCounter; $i++) { [pscustomobject]@{ Feature = $Feature[$i].ToString().Split(':')[-1].Trim() State = $State[$i].ToString().Split(':')[-1].Trim() } } } # End Process. End { } # End End. } # End Function.
Again, we could’ve use a much simpler function. Once a function is declared, we run the actions inside the function by invoking it — entering its name into the console. To run this locally, we’d just enter Get-DismFeatures, press Enter, and it would produce the results below. I’ve greatly shortened the results to save space.
PS C:\> Get-DismFeatures Feature State ------- ----- Microsoft-Hyper-V-All Enabled Microsoft-Hyper-V-Tools-All Enabled Microsoft-Hyper-V Enabled Microsoft-Hyper-V-Management-Clients Enabled Microsoft-Hyper-V-Management-PowerShell Enabled Printing-Foundation-Features Enabled Printing-Foundation-LPRPortMonitor Disabled Printing-Foundation-LPDPrintService Disabled ...
To run this on a remote computer, or computers, we would need to ensure PS Remoting is available and working. You can test this with your own computer, or with a remote computer. Yes, you can use your local computer to determine if PS Remoting is working from, and into, your computer. Here’s three different examples of using my own computer, and one example of using a remote one.
PS> Invoke-Command -Computer localhost -ScriptBlock {$env:COMPUTERNAME} TOMMYSCPU PS> Invoke-Command -Computer . -ScriptBlock {$env:COMPUTERNAME} TOMMYSCPU PS> Invoke-Command -ScriptBlock {$env:COMPUTERNAME} TOMMYSCPU PS> Invoke-Command -Computer DC05 -ScriptBlock {$env:COMPUTERNAME} DC05
Okay, so on to taking the function to a remote computer. Here’s how we do that (also with shorten results). Notice the placement of the dollar sign ($). This is different that we saw when taking locally declared variables to the remote session.
PS> Invoke-Command -ComputerName DC05 -ScriptBlock ${function:Get-DismFeatures} Feature : NetFx4ServerFeatures State : Enabled PSComputerName : DC05 RunspaceId : 72dc5b41-31b8-22b1-b5b1-29eae648123a Feature : NetFx4 State : Enabled PSComputerName : DC05 RunspaceId : 72dc5b41-31b8-22b1-b5b1-29eae648123a ...
And, that’s it.
If you’re like me, you’re sitting back now and wondering, “Why not include the ability to run the function against remote computers, inside the function?” That’s an option, and often employed to make a function useful on both local and remote systems. Here’s the thing: You may not always write the tools you use, so having a way to use one that was written without a way to run it remotely, might be helpful one day.
I’ve used this technique before. It’s a simple solution for running a single function.
Thanks for sharing.