invoke-command with a variable path extracted from a service

Hey all,

 

I’m usually lurking in the background learning from other folks issues, but for once I have to come out of the shadows and ask for some assistance. I’m working on a script that needs to run a particular executable on remote servers with a lot of switches. The executable isn’t always in the same location due to various factors outside of my control, but I’m finding it’s location through WMI based on where a running service points to, then splitting the string and removing the exe and replacing it with the other one in the same location I’m interested in. So far so good, but then comes the point I need to run that exe using invoke-command and I’m having some issues when I tried to pass the path through a variable instead of hard-coding it. I haven’t had a lot of need for invoke-command before, so I did what most people (should) do and I went digging through older posts in various powershell forums looking for answers, and looking for examples and tutorials. I learned a little that helped, but what they seem to indicate should work doesn’t seem to for me.

Since I was having issues with what I was doing, I decided to dumb this down to a local exe and play around to figure things out. So to start simple I pointed to c:\scripts\showmbrs.exe on my local machine.

Icm -computername mymachinename -scriptsblock { & “c:\scripts\showmbrs.exe”}

 

This seems to work getting a response from the exe, but remember the real exe I’ll be working with has a variable location so next I tried to pass it via a variable like I would in the actual script.

$test = “c:\scripts\showmbrs.exe”
icm -computername mymachinename -scriptsblock { & $test}

This gives me an error that after & the pipeline element produced an object that was not valid. Since $test should be a replacement string, this doesn’t make sense to me. I’ve hunted for a couple of days, finding various posts that seem to work the same way I’m doing it. If anyone can show me what I’m missing here, I’d appreciate the help.

For reference if you have additional input, where I will go from here is with an argument list holding multiple arguments to include other variables (hoping that will work but not there yet). My intended code looks something like:

 

$myargs = “-rAatuvqe -N $targethost -m $regManager -u $regID -p $regPass”
icm -computername mymachinename -scriptsblock { & $test} -argumentlist $myargs

Any insights will be appreciated.

Thanks for letting us know what all you did, that was a very good explanation.

coming to the problem,

variable $myargs is being passed to the scriptblock properly using -ArgumentList, but there should be someone to receive it inside the script block.

Think about a function/script, whenever we pass an input there will be somebody to receive the input inside the function/script. Those are achieved using Param() blocks. Hence you have to define parmeters for the scriptblock.

Invoke-Command -ComputerName $ComputerName -ScriptBlock {
    Param($Path,$targethost,$regManager,$regID,$regPass)
    & $Path -rAatuvqe  -N $targethost -m $regManager -u $regID -p $regPass
} -ArgumentList $ExePath,$targethost,$regManager,$regID,$regPass

variables wont be available inside the scriptblock as they are defined outside and is in a different scope.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-5.1

You are absolutely spot on, and I thank you for straightening out my thought process. Once you point out that I haven’t defined it for icm, it starts to click into place. It now works perfectly.

So for anyone who comes across this researching in the future, I’ll rephrase the answer in laymen s terms to make it easier. My mistake was I was looking at invoke-command as a command, not as another function call. A command works very different than a function call and we have to code a bit different for that. Treating it as a function we have to define both from the caller end and from the called end and this is where param comes into play.

Sometimes we overthink things and miss the obvious.

Thank you @kvprasoon

Invoke command is a cmdlet in PowerShell, but it executes a scriptblock or a script targetting a remote/local system. When we use a script/scriptblock, we use Param() block to accept parameters and values.

Thanks @kvprasoon, this makes sense, but something new to me. So far I have been achieving these scenarios using $using scope modifier to identify the local variable as a remote variable.