Running a script with parameters on remote computers

Hi,

I’m trying to run a PowerShell script along with parameters on remote computers using the below:

$Computers = "Computer1","Computer2"

Invoke-Command -ComputerName $Computers -Filepath '"C:\Scripts\Windows_Path_Enumerate.ps1" -FixUninstall -WhatIf'

This returns the error

Invoke-Command : The value of the FilePath parameter must be a Windows PowerShell script file
I've tried the following alternatively but my understanding is that this is used to pass local variables rather than the script parameters
Invoke-Command -ComputerName $Computers -Filepath C:\Scripts\Windows_Path_Enumerate.ps1 -ArgumentList "-FixUninstall", "-WhatIf"
Is what I'm trying to do even possible?

Unfortunately the -ArgumentList parameter of Invoke-Command takes an object collection so passing arguments using named parameters in that parameter is not possible. You would have to pass them positionally in the order they appear in the script. If FixUninstall is the first parameter you would just pass “$true” like this:

Invoke-Command -ComputerName $Computers -Filepath C:\Scripts\Windows_Path_Enumerate.ps1 -ArgumentList $true

Including -Whatif may be a challenge since it is a common parameter. There are some ways to do this but it is a little tricky. One way to do it is to modify your script to take a parameter to set the WhatIf switch.

This is a 3rd Party script I’ve found that addresses a vulnerability so wasn’t created by myself, however, does do what’s intended when run locally.

The WhatIf parameter is actually a builtin switch as it goes so can be called.

Many of the parameters are simply switches that don’t expect a value:

Param (
    [parameter(Mandatory=$false,
        ParameterSetName = "Fixing")]
    [parameter(Mandatory = $False,
        ParameterSetName = "Restoring")]
    [Alias("s")]
        [Bool]$FixServices=$true,
[parameter(Mandatory = $false,
    ParameterSetName = "Fixing")]
[parameter(Mandatory=$False,
    ParameterSetName = "Restoring")]
[Alias("u")]
    [Switch]$FixUninstall,


[parameter(Mandatory = $false,
    ParameterSetName = "Fixing")]
[Alias("e")]
    [Switch]$FixEnv,


[parameter(Mandatory = $False,
    ParameterSetName = "Fixing")]
[Alias("cb","backup")]
    [switch]$CreateBackup,


[parameter(Mandatory=$False,
    ParameterSetName = "Restoring")]
[Alias("rb","restore")]
    [switch]$RestoreBackup,


[parameter(Mandatory=$False,
    ParameterSetName = "Fixing")]
[parameter(Mandatory = $False,
    ParameterSetName = "Restoring")]
    [string]$BackupFolderPath = "C:\Temp\PathEnumerationBackup",


[parameter(Mandatory = $False,
    ParameterSetName = "Fixing")]
[parameter(Mandatory = $False,
    ParameterSetName = "Restoring")]
    [string]$LogName = "C:\Temp\ServicesFix-3.4.Log",


[parameter(Mandatory = $False,
    ParameterSetName = "Fixing")]
[parameter(Mandatory = $False,
    ParameterSetName = "Restoring")]
[Alias("ShowOnly")]
    [Switch]$WhatIf,


[parameter(Mandatory = $true,
    ParameterSetName = "Help")]
[Alias("h")]
    [switch]$Help

)


I’ve tried the following but this gives me the error: “A positional parameter cannot be found that accepts argument ‘True’”

Invoke-Command -ComputerName $Computers -Filepath C:\Scripts\Windows_Path_Enumerate.ps1 -ArgumentList $true,$true,$false,$false,$false,$false,$false,$true,$false
What am I missing?

Rather than using ArgumentList, try named parameters:

C:\Scripts\Windows_Path_Enumerate.ps1 -FixServices $true -FixUninstall -FixEnv

[quote quote=274098]Rather than using ArgumentList, try named parameters:

PowerShell
<textarea class="urvanov-syntax-highlighter-plain print-no" style="tab-size: 4; font-size: 14px !important; line-height: 18px !important; z-index: 0; opacity: 0;" readonly="readonly" data-settings="dblclick">C:\Scripts\Windows_Path_Enumerate.ps1 -FixServices $true -FixUninstall -FixEnv</textarea>
1
C:\Scripts\Windows_Path_Enumerate.ps1 -FixServices $true -FixUninstall -FixEnv
[/quote]

Rob, I’m not aware of how to use named parameters with Invoke-Command. -FilePath will only take a path to a script (no arguments after) and -ArgumentList will only take a collection of objects (no named parameters).

I’m still working on a decent solution but this really shouldn’t be that hard one would think…

 

Here is a solution. Not very pretty and could probably be cleaned up some, but should work. Leave your script (windows_path_enumerate.ps1) as is, but call it with this script. Modify $params for whatever arguments you want to pass.

$params = @{
    FixUninstall=$true
    WhatIf=$true
} #params

#build scriptblock
$scriptContents = '$params = $using:params; .{'
$scriptContents += Get-Content -Path "C:\Scripts\Windows_Path_Enumerate.ps1" -Raw
$scriptContents += '} @params'
$sb = [scriptblock]::Create("$scriptContents")

#invoke scriptblock on $computers
Invoke-Command -ComputerName $Computers -ScriptBlock {$sb}

 

 

Great stuff thanks Mike. Really appreciate your persistence. I’ll give this a test and let you know how I get on. I was going to run this via SCCM but my preference is to run it from a server and see the results in real time rather than having to check SCCM client logs etc.

I tested this on a single server and although it didn’t error, nothing came back as output. I’m interested to know why you’ve split the construction of the $ScriptContents variable into three separate lines? What benefit does this provide over simply "$scriptContents = ‘$params = $using:params; .{Get-Content -Path “C:\Scripts\Windows_Path_Enumerate.ps1” -Raw } @params ?

I wouldn’t bust your balls trying to assist with this one as can at least push this out via SCCM but would have been nice to be able to run this and see the results via the local console as and when.

Just easier to read in my opinion.

Ok, thanks for the update. Just wondering if I was missing something and it was required etc. Thanks again.