PowerShell Script launching a batch file on remote systems locally - powershell

I have a simple batch file I need to run via PowerShell as a POC. I need the batch file to run concurrently with the other batch files.
Batch file on each server at c:\pathtofile\file.bat:
cd /d c:\
ping 127.0.0.1 -n 5 > null
ECHO test > c:\temp\echo.txt
time /t >> c:\temp\echo.txt
PowerShell script:
$servers = #(
"Server02",
"Server03",
"Server04",
"Server05",
"Server06")
$creds = Get-Credential
foreach ($server in $servers){
Invoke-Command -ComputerName "$Server" -Verbose -ScriptBlock {'cmd.exe c:\pathtofile\file.bat'} -Credential $creds
}
I've tried a million different things and I can't get the dang script to run. Help would be greatly appreciated.

Related

Power shell Invoke remote script is not working

I am trying to invoke a remote bat file from my local machine that should start and run the bat in a remote machine terminal. My script is able to connect and show me the output. However, it is invoking the remote bat file but waiting on my screen with bat file output. and my idea is the bat file should invoke and running in the remote machine rather than showing the output on my terminal local terminal. What should be the way here?
loop{
Invoke-Command -ComputerName $computer -credential $cred -ErrorAction Stop -ScriptBlock { Invoke-Expression -Command:"cmd.exe /c 'C:\apacheserver.bat'" }
}
From what I understand you want the .bat file to not show you the result. If so, you should do it with the Out-Null or by redirecting STDOUT and STDERR to NULL.
IE: Invoke-Expression -Command:"cmd.exe /c 'C:\apacheserver.bat'" | Out-Null
If I'm understanding correctly, you want to suppress the output from the .bat file inside your local console? If so, redirecting to some form of $null is the way to go. You also shouldn't need Invoke-Expression as Invoke-Command can run the file directly:
Invoke-Command -ComputerName $computer -Credential $cred -ErrorAction Stop -Scriptblock {
cmd.exe /c 'C:\apacheserver.bat' | Out-Null
}
You could also use > $null instead of Out-Null if you prefer.
If you want to redirect the output of the Invoke-Command call to the remote console instead, that kind of defeats the purpose of the cmdlet. You could try redirecting the console output to a file on the remote computer if you want a local record:
$remoteFile = '\\server\C$\Path\To\Output.txt'
Invoke-Command -ComputerName $computer -Credential $cred -ErrorAction Stop -Scriptblock {
cmd.exe /c 'C:\apacheserver.bat' > $remoteFile
}
If I understand you, you want to run the script in the background and not wait for it:
Invoke-Command $computer -Credential $cred { start-process C:\apacheserver.bat }

How to run a .bat file in a VM from Powershell

I am trying to parallelize an operation by running .bat files in several remote VMs simultaneously using a Powershell script from a local VM. I can successfully run the .bat file in the local VM by using the following:
Start-Process cmd.exe -ArgumentList $batOptimization_path, $vmNumberParam, $rInstanceParam, $optDataParam, $dataSetParam
The first param in -ArgumentList is the path where the .bat file is located, the rest are command line parameters for the .bat file. To try to run the .bat file on a VM, I am using the following:
$psSession = New-PSSession -ComputerName $script:FsvRConfig.VmList[$i].IpAddress
Invoke-Command -ArgumentList $batOptimization_path, $vmNumberParam, $rInstanceParam, $optDataParam, $dataSetParam `
-Session $psSession `
-ScriptBlock {Start-Job -ScriptBlock { Start-Process cmd.exe -ArgumentList $args[0], $args[1], $args[2], $args[3] -AsJob}} `
-ErrorAction SilentlyContinue
This does not run the .bat files properly. The jobs start and then fail, so obviously this is not the way to launch the jobs. Any advice on getting the .bat files to launch in the remote VMs the way it does in the local VM would be greatly appreciated!

Using PowerShell to execute a remote script that calls a batch file

I am having an issue with running a batch file that is located on a remote server.
I have a batch file located on a remote server that i want to run that kicks off an automated Selenium test. For simplicity, let's say the name of my batch file is mybatch.bat
I have the following code in a Powershell script located on the server:
$BatchFile = "mybatch.bat"
Start-Process -FilePath $BatchFile -Wait -Verb RunAs
If I run this PowerShell script locally on the server in ISE then it runs fine and it kicks off the selenium test which takes a couple minutes to run.
Now I want to try to execute this test from another machine by using PowerShell remoting. Let's assume that remoting is already configured on the servers.
I have a PowerShell script located on another server which has the following code segment. Assume that all of the session variables have the correct information set:
$CMD = "D:\mybatch.bat"
$TargetSession = New-PSSession -ComputerName $FullComputerName -Credential $myCreds -ConfigurationName RemoteExecution
$command = "powershell.exe -File $CMD -Wait"
Invoke-Command -Session $TargetSession -ScriptBlock { $command }
When this script runs, it does connect to the remote machine and create a remote session. It does look like it kicks off the batch file because PowerShell does not give me an error. But it does not wait for the full 3 or 4 minutes for the Selenium test to finish. It seems like it just times out. Also if I am logged onto the other machine, I don't see any Selenium web test running. No Selenium log files or results files are created on remote server as should be expected.
I was wondering what I could be doing wrong with my code.
Also, it seems that the server always returns the echo outputs of the batch file to my local machine. I see these random blinking white screen on ISE which looks like output from the batch file
$command = "powershell.exe -File $CMD -Wait"
Invoke-Command -Session $TargetSession -ScriptBlock { $command }
There are 2 issues with the above code:
$command inside the scriptblock and $command outside the scriptblock are different variables due to different scopes. The variable inside the scriptblock is thus undefined and the scriptblock will simply echo an emtpy value.
Even if $command weren't undefined, the scriptblock would still just echo its value, since it's defined as a string. PowerShell does not execute strings unless you're using something like Invoke-Expression (which you shouldn't).
This should do what you want:
$CMD = "D:\mybatch.bat"
$TargetSession = New-PSSession -ComputerName $FullComputerName -Credential $myCreds -ConfigurationName RemoteExecution
Invoke-Command -Session $TargetSession -ScriptBlock { & $using:CMD }
If you would like execute a bat file from another machine by using PowerShell Remote Session, simply enter dot and then follow by a whitespace, then enter the exact path of bat file located on that remote machine.
Example
Invoke-Command -ComputerName RemoteComputerName -Credential $credential -ScriptBlock {. "D:\Temp\Install_Something.bat"}

Powershell process 'hanging' when running remote batch file

I'm trying to run a batch file on a remote server via a drive mapping as follows, but the process hangs...
Enable-WSManCredSSP -Role Client -DelegateComputer someserver -Force
$credential = Get-Credential -Credential domain\user (then I supply the password in the popup)
$RemoteSession = New-PSSession -ComputerName someserver -Credential $credential -Authentication Credssp
Invoke-Command -Session $RemoteSession -ScriptBlock { Enable-WSManCredSSP -Role Server -Force }
Invoke-Command -Session $RemoteSession -ScriptBlock { New-PSDrive -Name I -PSProvider FileSystem -Root \\server\share$ }
Everything seems fine up to this point and I can 'dir' the I drive and see the expected content.
When I execute the following, the process hangs -
Invoke-Command -Session $RemoteSession -ScriptBlock { Start-Process I:\temp.bat }
The temp.bat file executes the following command and I've verified manually that it works
echo Scott was here > C:\temp.txt
However, the command runs for over 5 minutes without any response.
Can anyone help? What have I done wrong?
Although this is not a direct solution to your question, my suggestion from many weeks of banging my head against my keyboard is to just take a different path.
$taskName = whocares
$command = I:\Temp.bat
$serverName = theServer
$userName = domain\user
$pass = pl4inT3xtPassword
$date = (Get-Date).addMinutes(1)
$formats = $date.getDateTimeFormats()
$startTime = $formats[113]
schtasks.exe /create /sc ONCE /tn $taskName /tr $command /s $serverName /u $userName /p $pass /ru $userName /rp $pass /st $startTime
This will create a task, start the process in the next minute, and then remove itself from the scheduler. There is also a /z flag in there to remove after it runs, but if your like me and on XP then this probably won't be available to you. If you notice your task isnt being removed after it runs you can always wait a minute and then kill it... or you can get a little bit more fancy with it:
while(($timer -lt 60) -and (!$running)) {
schtasks.exe /query /S $serverName /FO CSV /v /u $userName /p $pass | ConvertFrom-CSV | `
% {if($_.Status -eq "Running") {
Write-Host "IT WORKED!"
Write-host $_
$running = $true
}
}
if(!$running) {
$timer++
}
sleep 1
}
schtasks.exe /delete /s $serverName /u $userName /p $pass /tn $taskName /f
This bit just queries the task every second to check if its running... once it is it will delete the old scheduled task and your process will continue to run (until its finished).
The task scheduler is the only clean way I have found to start processes remotely with PowerShell. Instead of being a child process of your PSremote.exe, it will be under System. Also, unlike remote-session, if you X out of your powershell session, the process will persist on the remote computer.
I know it is a lot more than just your one liner, but I hope it is useful, and if you parameterize it or even build a windows forms application on top it will save you a lot of time and headache.
more on schtasks Here
Thanks for your suggestions.
Due to other issues (with the process that we're ultimately trying to run), we've put this down for the minute, without finding a solution
Thanks for your help and suggestions. Will hopefully pick this back up in a few weeks
Scott
Try putting an -AsJob at the end of your Invoke-Command lines?
As an FYI if Invoke-Command always hangs it may be the service or firewall:
Try a simple command to system :
Invoke-Command -ComputerName XXXXX -ScriptBlock { Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion }
Start the Windows Remote Management Service (on that system)
Check for the listening port:
netstat -aon | findstr "5985"
TCP 0.0.0.0:5985 0.0.0.0:0 LISTENING 4
TCP [::]:5985 [::]:0 LISTENING 4

Powershell remote application(.cmd) deployment

I am beginner with PowerShell and struggling to get this around with the help from different sites, My requirement and scenario is
I have a windows server 2008(rktdepy) with PowerShell installed and I have packaged application with a .cmd file. When I click this .cmd file the application will be deployed.
The server name is rktdepy and I want to create a PowerShell script which will connect to other servers in the network (the server names should be picked up from a txt files) and install the application accessing the file remotely from rktdepy server. The files are not supposed to be copied to any server and should not use psxec for security reason.
So far I have used invoke and mapping the network drive but still I have issues
$Comsession = Get-content c:\adminfiles\scripts\deploy.txt | new-pssession -throttlelimit 50
Invoke-command -computername RKTDEPLY54 -scriptblock { (new-object -comobject wscript.network).mapnetworkdrive("R:", "\\rktdepy\deploy", $true) }
Invoke-command -session $comsession -scriptblock {"CMD /C r:\QR_DEPLOY.CMD"}
The above script throws error,
I dont want to use any password in the script and it should fetch the current logged in user password from rktdepy server. I is ok if the scripts prompts for a user name and password which will have admin access to all servers.
It looks like you are dealing with a couple problems. One is that the session where you map the drive is gone when you run the next Invoke-Command that uses the mapped drive. You could move that into the same script block to fix a problem like that. The second one is a "second hop" issue. See a resource like Don Jones' Secrets of PowerShell Remoting free ebook on http://powershell.org/wp/books.
Steve
I have testing the following on my machine and it is working so far. There is also another method you can try out listed below.
Method1:
1. I have txt file with a list of computers named allcomputers.txt. It contains name of machines on each line.
Machine10
Machine20
Machine30
Machine40
The deployment script (mydeploytest.ps1) which accepts Computername, Username and Password as input and creates a new PSSession and then invokes command.
param(
[string]$ComputerName,
[string]$User,
[string]$pass
)
Get-PSSEssion | Remove-PSSession
$session = New-PSSession -ComputerName $ComputerName
Invoke-Command -Session $session -ScriptBlock {
param(
[string]$ComputerName,
[string]$Username,
[string]$Password
)
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("U:", "\\RKTDEPY\deploy", $false, $Username, $Password)
Invoke-Expression "CMD /C U:\deploy.cmd"
$net.RemoveNetworkDrive("U:")
} -args $ComputerName,$User,$pass
Get-PSSEssion | Remove-PSSession
Powershell commandline oneline to accomplish deployment task.
PS C:> Get-Content C:\scripts\allcomputers.txt | Foreach { C:\scripts\mydeploytest.ps1 $_ "yourserviceaccount" "password"}
Method2:
The help method for Invoke-Command has an example on how to solve the doublehop issue stevals is mentioning in the answer.
PS C:\> Enable-WSManCredSSP -Delegate Server02
PS C:\>Connect-WSMan Server02
PS C:\>Set-Item WSMan:\Server02*\Service\Auth\CredSSP -Value $true
PS C:\>$s = New-PSSession Server02
PS C:\>Invoke-Command -Session $s -ScriptBlock {Get-Item \\Net03\Scripts\LogFiles.ps1} -Authentication CredSSP
-Credential Domain01\Admin01
I think with little modification to method 2 you can achieve what you want.