1

I seem to have a lot of trouble understanding how to get this working. I am trying to gather all variables up front that way I can call psexec and pass those variables to it in a scriptblock.

The reason I am using psexec is due to the fact I have old 2003 servers without powershell installed. My goal was to have powershell multithread out against a list of servers in a text file and spawn processes in a manner below.

    #Gather info
    $servers = "test1234"
    $userName = Read-host "What is the user name?"
    $userPassword = Read-host "What is the user password?"

    $scriptBlockwork = {c:\scripts\message\psexec.exe "$servers" -u domain\$userName -p $userPassword -c InstallMShotfix.cmd -f InstallMShotfix.cmd}.GetNewClosure()
    & $scriptBlockwork
    echo $scriptBlockwork

Why does the script block not take the variables defined even when using .GetNewClosure()

3 Answers 3

1

It's not entirely clear from your question in which order you want to bind the parameters, but for a proper closure:

$PartialInstaller = {
    param($servers)
    return {
        param($userName,$userPassword)
        c:\scripts\message\psexec.exe "$servers" -u domain\$userName -p $userPassword -c InstallMShotfix.cmd -f InstallMShotfix.cmd
    }.GetNewClosure()
}

$Installer = &$PartialInstaller $servers
$Result = &Installer "username","password"

Alternatively, the call operator (&) supports splatting as well:

$ScriptArguments = @{}
$ScriptArguments.servers = "test1234"
$ScriptArguments.userName = Read-host "What is the user name?"
$ScriptArguments.userPassword = Read-host "What is the user password?"

$Work = {
    param($servers,$userName,$userPassword)
    c:\scripts\message\psexec.exe "$servers" -u domain\$userName -p $userPassword -c InstallMShotfix.cmd -f InstallMShotfix.cmd
}

& $Work @ScriptArguments
Sign up to request clarification or add additional context in comments.

2 Comments

With this if I i want to call $work, it would not & $work and @scriptsarguments . Trying something like $work2= {$work = {{ param($server,$Credential) echo $server $Credential | out-file C:\echoplease.txt -NoClobber}& $work $ScriptArguments}} Invoke-Command -ComputerName localhost -AsJob -ScriptBlock $work2 Didnt seem to work
Oh sorry, neglected to address your requirement for a proper Closure. My example must be very confusing then, I'll update it
0

Not sure why, but I've never been able to get .getnewclosure() to work for that.

Fortunately [scriptblock]::Create() provides an workaround:

#Gather info
    $servers = "test1234"
    $userName = Read-host "What is the user name?"
    $userPassword = Read-host "What is the user password?"

    $scriptBlockwork = 
    [scriptblock]::Create(@"
    c:\scripts\message\psexec.exe "$servers" -u domain\$userName -p $userPassword -c InstallMShotfix.cmd -f InstallMShotfix.cmd
"@)
    & $scriptBlockwork
    echo $scriptBlockwork

Comments

0

invoke-command on TechNet.

Example 2 and Example 5 are each similar to your example.

Example 3 and Example 4 would allow you to do it without psexec, but you'll need WinRM enabled on the remote machine. These are especially useful if you need to execute a number of commands.

Also research Get-Credential for prompting for authentification. Depending on the environment (information security policy in your organization, etc.), you may be able to store the credentials in a file (encrypted format) and reuse them in scripts. Bare minimum, you won't be passing admin credentials over the wire in the clear.

TL;DR Invoke-Command is your friend. Get-Credential is more secure than Read-Host.

$Credential = $get-credential
foreach ($Server in $Serverlist) {
    $scriptBlockwork = { psexec $Server -c InstallMShotfix.cmd -f InstallMShotfix.cmd }
    Invoke-Command -credential $Credential -scriptblock $scriptBlockwork
}

This will run your psexec command with the credentials you enter. They need the right to run psexec locally and to run the cmd file on the remote machine. Populate $Serverlist by reading in a text file or statically defining it above.

4 Comments

Just as an aside, consider installing WMF on your 2003 servers, so you can simplify this to: Invoke-Command -ComputerName server01 -Credential domain01\user01 -ScriptBlock { InstallMShotfix.cmd } In this case Invoke-Command replaces psexec.
This will wait until each session is complete before proceeding, and not thread out. If i had 25 servers in that list it would take a long time to complete. Right?
@james I think that using the -asjob switch parameter in invoke-command can do the trick,
I was worried because -asjob starts a PS job on the target computer. Documentation says "Remote" but it should say "target". The switch -asjob is not allowed without a target. But there's an easy workaround. Invoke-Command -ComputerName localhost -AsJob -ScriptBlock ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.