1

I want create a few shortcuts on my desktop, it works locally. But when I try it on a remote PC I got only one shortcut for the first target (path1), and script ignores path2 variable.

$Servers = Get-Content D:\1.txt

function add-sc {
    param ([string[]]$Targets) 
    BEGIN {}
    PROCESS {
        foreach ($a in $Targets) {
            $WshShell = New-Object -comObject WScript.Shell
            $b = $a.Substring($a.length - 5)
            $Shortcut = $WshShell.CreateShortcut("$Home\Desktop\$b.lnk")
            $Shortcut.TargetPath = $a
            $Shortcut.Save()
        }
    }
    END {}
}

foreach ($server in $Servers) {
    Invoke-Command -ComputerName $server -ScriptBlock ${function:add-sc} -Args "path1", "path2"
}
henrycarteruk
  • 12,708
  • 2
  • 36
  • 40
Pavel Mi
  • 45
  • 2
  • 7
  • Looks like your function expects a string array, that is different from just multiple arguments. You can either supply an array: "-Args @("path1", "path2")" or you can read the $args array instead of $Targets in your loop. – Niels Apr 04 '18 at 07:50
  • 1
    Your syntax and code look fine to me, are you sure the target for `path2` exists on the remote computer? You can't create a shortcut if the target isn't valid. – henrycarteruk Apr 04 '18 at 08:03
  • Hello. Thank you for quick response. Second adviсe works! – Pavel Mi Apr 04 '18 at 08:07

3 Answers3

3

For one thing, you should define your function inside the scriptblock. I'm not sure about PowerShell v5+, but in PowerShell v4 and earlier a command

Invoke-Command -Computer bar -Scriptblock {function:foo}

would throw an error because the function isn't recognized inside the scriptblock.

Also, you need to actually pass your parameters to the function you're invoking. There are basically 2 ways how you could handle that:

  • Pass the arguments to the function via the automatic variable $args:

    Invoke-Command -Computer $server -ScriptBlock {
        function add-sc {
            Param([string[]]$Targets)
            Process {
                ...
            }
        }
        add-sc $args
    } -ArgumentList 'path1', 'path2'
    
  • Pass the arguments to the scriptblock as a single array and splat them on the function:

    Invoke-Command -Computer $server -ScriptBlock {
        function add-sc {
            Param([string[]]$Targets)
            Process {
                ...
            }
        }
        add-sc @args
    } -ArgumentList @('path1', 'path2')
    

The difference between the 2 approaches is that the former takes all arguments and passes them as a single array to the function whereas the latter takes all arguments to the scriptblock and passes them as individual arguments to the function. Hence the need to pass the arguments to the scriptblock as a single array in the latter case.

In your scenario both approaches are equivalent, but if your function expected a second parameter besides the array you'd need the second approach and pass the arguments to the scriptblock as -ArgumentList @('a','b'), 'c'.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
0

You can also use -ArgumentList parameter, or shortly -args, to send multiple parameters to your scriptblock. You just need to handle them inside of the scriptblock.

See this short example on how it's done

Invoke-Command -ArgumentList "Application",10 -ScriptBlock {
    param([string]$log,[int]$lines)
    Get-EventLog $log -Newest $lines
}

Here -ArgumentList contains two parameters

  • String "Application" and
  • Integer 10

They are sent to the scriptblock as parameters and as such, defined at the beginning of it.

You can now access them inside the scriptblock like normal parameters:

  • $log and
  • $lines
kim
  • 3,385
  • 2
  • 15
  • 21
0

Your syntax and code look fine to me, are you sure the target for path2 exists on the remote computer? You can't create a shortcut if the target isn't valid.

henrycarteruk
  • 12,708
  • 2
  • 36
  • 40