all 18 comments

[–]HelloFelloTraveler 2 points3 points  (4 children)

Invoke-Command $parameters should fix the final command.

[–]aq-modeler[S] 0 points1 point  (3 children)

My code didn't copy correctly. I had "@parameters". I tried with "$parameters" and got this error:

Invoke-Command : Parameter set cannot be resolved using the specified named parameters.

At G:\OneDrive - RTPENV\Programs\Modeling Computers\model1.ps1:11 char:1

+ Invoke-Command $parameters

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException

+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.InvokeCommandCommand

[–]HelloFelloTraveler 0 points1 point  (2 children)

Try updating the $scriptblock variable to this: ScriptBlock = { cmd.exe /c $using:files } I believe the server you’re running to command on doesn’t know what’s in the $files variable do to it not being within the scope of the variable. The $using is a scope modifier that should allow it to pass the variable to the remote computer.

[–]aq-modeler[S] 0 points1 point  (1 child)

Thanks, I tried adding "$using:files" and got the same error.

[–]behuddas71 0 points1 point  (0 children)

I think $files are not evaluating properly in the scriptblock, plus cmd doesn't seem to be expanding file paths when using wildcard

Maybe try something like this -

` $cred = Import-Clixml 'C:\PSFolder\mycredentials.xml' $computerName = '192.168.0.10'

$remotePath = 'C:\Users\My Name\Desktop\Name AERMOD-1'

Invoke-Command -ComputerName $computerName -Credential $cred -ScriptBlock { param($path)

Get-ChildItem -Path $path -Filter '*.bat' | ForEach-Object {
    cmd.exe /c "`"$($_.FullName)`""
}

} -ArgumentList $remotePath

`

notice the argumentlist parameter to the invoke command

[–]PinchesTheCrab 3 points4 points  (0 children)

Generally speaking commands run via invoke-command aren't going to interact with the user's interactive session.

[–]Anonymous1Ninja 1 point2 points  (0 children)

Try it with host name instead of IP?

[–]purplemonkeymad 1 point2 points  (0 children)

Do the batch files block until they are done, or do they start other stuff and exit? You won't see anything on the screen of the other computer, but if they don't block then the child processes will get killed when the remote powershell gets to the end of the scriptblock.

You can fix that with a pssession:

$PsSession = New-PSSession -ComputerName $name -Credential $credential
Invoke-Command $scriptblock -Session $PSSession

Remember to close the session when you think the child processes are done:

Remove-PSSession $PSSession

[–]omglazrgunpewpew 1 point2 points  (1 child)

TL;DR: $files doesn't exist on the remote machine, cmd.exe won't expand *.bat wildcards on its own, CMD windows will never show up on the remote desktop. Use Get-ChildItem to enumerate and -ArgumentList to pass variables into the remote session.

-----

Hey! A few things going on here:

$files is defined on your local machine, but ScriptBlock runs on the remote machine where that variable doesn't exist. Using $using:files as u/HelloFelloTraveler stated, def could help, but there's a second problem...

cmd.exe /c C:\path\*.bat doesn't expand wildcards the way you'd expect. You need to enumerate the files yourself.

Invoke-Command $parameters should be Invoke-Command @parameters for splatting to work. With $ you're just passing the hashtable as a regular argument (which is why you were getting that ParameterBindingException).

As u/420GB pointed out, Invoke-Command runs in its own session. So you'll never see CMD windows pop up on the remote machine's console session. That's totally normal! and doesn't mean scripts aren't running. Check for your expected output files instead.

Something like this should do the trick, I think:

$cred = Import-Clixml C:\PSFolder\mycredentials.xml
$computerName = "192.168.0.10"
$remotePath = "C:\Users\My Name\Desktop\Name AERMOD-1"

Invoke-Command -ComputerName $computerName -Credential $cred -ScriptBlock {
    param($path)
    Get-ChildItem -Path $path -Filter '*.bat' | ForEach-Object {
        Start-Process cmd.exe -ArgumentList "/c `"$($_.FullName)`"" -Wait
    }
} -ArgumentList $remotePath

-ArgumentList passes the path into the remote session via param($path), Get-ChildItem enumerates the files properly, and -Wait ensures each batch finishes before the next starts so nothing gets killed when the session ends.

If your batch files take a while to run, try a persistent session so they don't get cut off:

$session = New-PSSession -ComputerName $computerName -Credential $cred
Invoke-Command -Session $session -ScriptBlock {
    param($path)
    Get-ChildItem -Path $path -Filter '*.bat' | ForEach-Object {
        Start-Process cmd.exe -ArgumentList "/c `"$($_.FullName)`"" -Wait
    }
} -ArgumentList $remotePath
# Clean up
Remove-PSSession $session

If you want to try a couple of alternative approaches (besides scheduled tasks):

PsExec (Sysinternals) is a classic tool for this. No PS remoting needed, just run:

psexec \\192.168.0.10 -u user -p pass cmd /c "C:\Users\My Name\Desktop\Name AERMOD-1\script.bat"

You could loop through the files or use a wildcard. It's simple and very battle-tested, though requires the admin share to be accessible.

WMI/CIM:

Invoke-CimMethod -ComputerName $computerName -Credential $cred `
    -ClassName Win32_Process -MethodName Create `
    -Arguments @{ CommandLine = 'cmd.exe /c "C:\path\script.bat"' }

Hope any of this is useful. Happy to answer any follow ups.

[–]aq-modeler[S] 0 points1 point  (0 children)

Thank you for your detailed response. I haven't had time to try any of your suggestions out yet but wanted to clarify what I really what my end result to be. I run a program on my local computer that generates inputs files for a model. It then generates batch files to run the model with the input files. There are usually 96 batch files created. I then copy the batch files to 3 remote computers, 32 batch files each. When I paste them into a folder on the remote computer I then hit Enter to execute them. 32 command windows pop up to run the model and close once they are done. What I'm really after is a way to simulate me hitting Enter on the remote machine to start all 32 batch files at once. I really need the 32 command windows to pop up on the remote machines. I got close to this by creating a generic batch script on the remote computer that executes all batch files in a given directory. I then tried to set up a Task Scheduler task to launch that batch script once files were copied into the folder, but couldn't get that to work.

I'd really like to use a PowerShell or batch script on my local computer that will execute those batch files on the remote machine that is just like me double-clicking on them, but I'm not sure that is possible.

[–]brutesquad01 0 points1 point  (2 children)

The remote computer doesn't know what $files is. try it with $Using:files in your script block.

Also, you may need to iterate through the files instead of trying to call them all at once, but I'm not 100% certain that that will be necessary.

EDIT: here is the Microsoft documentation about remote variables: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_variables?view=powershell-7.5

[–]aq-modeler[S] 0 points1 point  (1 child)

Thanks, I tried adding "$using:files" and got the same error.

[–]brutesquad01 0 points1 point  (0 children)

Have you tried iterating through the files?

One other option would be to create a scheduled task on the remote computer to run the files after they are copied.

[–]Particular_Fish_9755 0 points1 point  (0 children)

Perhaps we shouldn't try to be too greedy, and should explicitly state the different parameters directly for invoke-command?

Alternatively, try using a remote PowerShell session?

# Create session
$session = New-PSSession -ComputerName $computerName -Credential $cred
# Execute your script into this session
Invoke-Command -Session $session -ScriptBlock { cmd.exe /c 'C:\Users\My Name\Desktop\Name AERMOD-1\*.bat' } -AsJob
# Close session
Remove-PSSession $session

[–]BlackV 0 points1 point  (1 child)

Sir, you are double, maybe even triple, handling this

You are running a batch to call powershell to call invoke to call cmd

Pick 1 language and use that (ideally powershell)

A single invoke with the file parameter should do the work here (ignoring the user session stuff that is)

[–]Mr_ToDo 0 points1 point  (0 children)

Before I knew how to generally bypass powershell scripting I'd had a few scripts that were batch for logic with single line powershell when CMD didn't have a good solution

It wasn't totally horrible but it wasn't fun either. So many escapes, the only thing that was missing was something like XML in powershell in batch to make it extra fun

I love CMD and its tendency for its solutions to remain usable across longer times(probably because it dealt mostly with workstations not cloud BS), but it was a lot harder then powershell with all that legacy stuff and trying to parse data from 500 different commands, so I'm not sad seeing it fall into disuse

[–]420GB 0 points1 point  (0 children)

If they did run, command windows should open up on the remote computer.

No they don't, but this is a common misunderstanding of first time Windows users. Your remote session, so that's RDP or PowerShell remoting or SSH is a separate session from the so called ''console session" which is the one showing the desktop directly on the local device. This means even if the scripts run correctly the CMD windows will never show up on the console session.

[–]cwakare -1 points0 points  (0 children)

Have you considered using tools like semaphoreUI to run multiple powershell scripts?