Run Local Function Remotely with Arguments Unordered

Is it possible to execute a local function remotely and specify the argument order? See example

function myfunction ($param1,$param2){
     get-dscresource -module $param2 -name $param1
}

invoke-command server -scriptblock ${function:myfunction} -argumentslist $param1,$param2 #<-- does not work
invoke-command server -scriptblock ${function:myfunction} -argumentslist $param2,$param1 #<-- works

The reason I’m asking is because several functions that I’d like to execute remotely do not have sequential parameters and it appears to only feed in mandatory parameters.

Yes, try splatting. Define named parameters inside the function.

Here are two options.

$splat = @{

fore = 'red'
back = 'white'

}

icm -scriptblock {write-host "this is splatting" @splat} -argumentlist $splat 



function myfunction{
  

param(

[parameter(mandatory=$true)]
[string]$fore,

[parameter(mandatory=$true)]
[string]$back

)

 icm -scriptblock {write-host "this is text" -fore $fore -back $back } -argumentlist $fore,$back

}


That works when running a normal script block, but for some reason when you use the local function method it runs the arguments in sequences and provides the variables to the mandatory parameters in that order. As a work around I’m just entering the session running the script from ISE into the remote server session and executing the function I need.

Below works

function MyFunction ($ModuleName,$Name)
{
    Get-DscResource -Module $ModuleName -Name $Name
}

$Module = 'xAdcsDeployment'
$Name = 'xAdcsWebEnrollment'

icm -ComputerName cert -ScriptBlock ${Function:MyFunction} -ArgumentList $Module,$Name

Below does not work because it attempts to use $Name for the -Module parameter

function MyFunction ($ModuleName,$Name)
{
    Get-DscResource -Module $ModuleName -Name $Name
}

$Module = 'xAdcsDeployment'
$Name = 'xAdcsWebEnrollment'

icm -ComputerName cert -ScriptBlock ${Function:MyFunction} -ArgumentList $Name,$Module

I attempted to use splatting, but it doesn’t seem to allow you to use the -parameter name to specify which parameter to use with which variable…

function MyFunction ($ModuleName,$Name)
{
    Get-DscResource -Module $ModuleName -Name $Name
}

$splat = @{
Module = 'xadcsdeployment'
Name = 'xAdcsWebEnrollment'
}

icm -ComputerName cert -ScriptBlock ${Function:MyFunction} -ArgumentList $splat

It hurts when I do this doc:-)

Perhaps something like this:

function MyFunction
{
    [CmdletBinding()]
    param
    (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [PSTypeName('DSCResource')]$DSCResource
    )


    Get-DscResource -Module $DSCResource.ModuleName -Name $DSCResource.Name
}


$resource = [pscustomobject]@{
    PSTypeName = 'DSCResource'
    ModuleName = 'xPSDesiredStateConfiguration'
    Name = 'MSFT_xArchive'
}

icm -ComputerName servername -ScriptBlock ${Function:MyFunction} -ArgumentList $resource

It’s a start, but here is an example of interchangeable parms.

function MyFunction
{
    [CmdletBinding()]
    param
    (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        $ModuleName,
        
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        $Name
    )

    if(Get-Module -ListAvailable | Where-Object { $_.name -eq $ModuleName }) 
    {
        Write-Verbose "Module-Name Order"
        Get-DscResource -Module $ModuleName -Name $Name
    }
    elseif(Get-Module -ListAvailable | Where-Object { $_.name -eq $Name }) 
    {
        Write-Verbose "Name-Module Order"
        Get-DscResource -Module $Name -Name $ModuleName
    }
    else
    {
        Write-Verbose "Module Doesn't Exist"
    }
}


$server = 'servername'

# Proper Order
icm -ComputerName $server -ScriptBlock ${Function:MyFunction} -ArgumentList 'xPSDesiredStateConfiguration', 'MSFT_xArchive'

# Flipped Order
icm -ComputerName $server -ScriptBlock ${Function:MyFunction} -ArgumentList 'MSFT_xArchive', 'xPSDesiredStateConfiguration'

# Bogus
icm -ComputerName $server -ScriptBlock ${Function:MyFunction} -ArgumentList 'xxx','yyy'

How do you mean Dan? Never hurts to reply, I always appreciate all and any replies on my posts :slight_smile:

Michael,

I’ll give that a try and update the function I’m working on to include that logic, I’m also thinking I can modify it to specify the param order in the function. I’ll post once I’ve got it working :slight_smile:

Thanks!

Got it working! By using the Position option for parameters I was able to move them around, so if you just use that to move around the position you can pass them in ordered and get it to work.

function MyFunction
{
    [CmdletBinding()]
    Param
    (
        # Param1 help description
        [Parameter(Position=0)]
        $Name,

        # Param2 help description
        [Parameter(Position=1)]
        $Module
    )

    Get-DscResource -Module $Module -Name $Name

}

$Module = 'xAdcsDeployment'
$Name = 'xAdcsWebEnrollment'

icm -ComputerName cert -ScriptBlock ${Function:MyFunction} -ArgumentList $Name,$Module

A man goes to the Doc and says ‘Doc, it hurts when I do this’ and the doctor says ‘Then don’t do that’:slight_smile:

It’d still be beneficial to put the command within the function. Use another argument to accept array of computers.