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
Related
I'm trying to run a command on a VM using Invoke-Command. The command should stop a program that processes jobs after it finishes its current job. It works if I run it in the terminal using RDC.
& 'C:\Program Files\Autodesk\Vault Client 2021\Explorer\JobProcessor.exe' /stop
But if I run it from a different machine using Invoke-Command nothing seems to happen.
$session = New-PSSession -ComputerName 'hostname' -Credential (Get-Credential)
Invoke-Command -Session $session -ScriptBlock {
& 'C:\Program Files\Autodesk\Vault Client 2021\Explorer\JobProcessor.exe' /stop
}
However Process Monitor shows the command come in for both cases, but the program is still running.
I have also tried using Start-Process with the same result, i.e. it works in the terminal on the VM but not using Invoke-Command.
Start-Process -FilePath 'C:\Program Files\Autodesk\Vault Client 2021\Explorer\JobProcessor.exe' -ArgumentList '/stop'
I've been stuck for many days and I've exhausted my googlable knowledge for this problem.
Are you sure that file exists on the remote computer?
For simplicity, I rewrote your command to a known executable that is always there in Windows and returns unique info for any given computer.
C:\> & 'C:\Windows\system32\HOSTNAME.EXE'
server1
C:\> icm {& 'C:\Windows\system32\HOSTNAME.EXE'}
server1
C:\> icm {& 'C:\Windows\system32\HOSTNAME.EXE'} -ComputerName server2
server2
Here's your script with some error handling.
$session = New-PSSession -ComputerName 'hostname' -Credential (Get-Credential)
Invoke-Command -Session $session -ScriptBlock {
$exe = 'C:\Program Files\Autodesk\Vault Client 2021\Explorer\JobProcessor.exe'
$ok = Test-Path $exe
if ($ok) {& $exe /stop} else {
Write-Warning "EXE not present on $($env:COMPUTERNAME)!"
}
}
Learn how to add error handling and you'll be well on your way to solving your problems faster and getting more stuff done.
I am trying to write a Powershell script which will deploy software on a collection of WS2016 servers. I am a local administrator on all these servers. Here's what I have so far:
$Cred = Get-Credential
$Computer = 'myserver.contoso.com'
$SplunkMSI = '\\mylocalbox\C$\Splunk.msi'
$InstallDir = 'C:\Apps\Splunk\'
$sb = {
param($installer, $dir)
Start-Process -FilePath 'c:\windows\system32\msiexec.exe' -ArgumentList "$installer INSTALLDIR=$dir AGREETOLICENSE=Yes /qn /norestart /L*v C:\temp\splunkInstall.log" -Wait -NoNewWindow
}
Write-Host "Deploying Splunk to host $Computer"
Invoke-Command -Computer $Computer -Credential $Cred -ScriptBlock $sb -ArgumentList $SplunkMSI, $InstallDir -ErrorAction Stop
When I run this script, I get prompted for credentials, and then I see the output of the Write-Host, but then... nothing. I have to manually terminate the script.
I logged onto the remote host, but see no evidence that the MSI was executed or failed to execute.
Anyone see a smoking gun?
ya, it looks like it's looking for $installer and $dir in the script block but they're not specified
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 }
I'm creating a powershell script to import Dynamics NAV Application Objects to my Dynamics NAV 2018 database.
Microsoft is providing a PS cmdlet - Import-NAVApplicationObjects - to do so, but I have trouble to wait for the command to finish.
I have a calling script which does the following
$PSSession = New-PSSession -ComputerName $TargetMachine -Credential $MyCredential
Invoke-Command -Session $PSSession -ArgumentList $Database_Name_user, $MyCredential -ScriptBlock {
$process = Start-Process powershell.exe -Verb RunAs -Wait -PassThru -ArgumentList "-File `"C:\Users\User\Desktop\Database\Import1.ps1`" $args[0]"
$process.WaitForExit()
if ($process.ExitCode -ne 0) {
throw $process.StandardError.ReadToEnd()
}
}
The script Import1.ps1 on my $TargetMachine looks like this
param(
[String]$Database_Name_user
)
try {
$AllFiles = "C:\Users\User\Documents\AllFiles.txt"
$Modules = "C:\GIT\Loading Components\NAVModuleImport.ps1"
$OutputBuffer = import-module $Modules
Import-NAVApplicationObject -Path $AllFiles -DatabaseServer "SQLSRV001" -DatabaseName $Database_Name_user -SynchronizeSchemaChanges "No" -ImportAction "Overwrite" -Confirm:$false | Out-Null
}
catch{
$_ | Out-File "C:\Users\User\Documents\Import1.txt"
}
The file AllFiles.txt has a size of 220 MB and contains more than 7700 Dynamics NAV Application Objects (tables, pages, codeunits and so on).
When I launch the script which executes Import-NAVApplicationObject directly from the remote computer stored in $TargetMachine everything works smootly and the process takes up to 10 to 15 minutes, as expected.
When calling the script as shown in the first code example the output stops for a minute and then says everything is done.
Any help is appreciated, thank you in advance.
Edit: Solution
I noticed that my scripts as shown are working, the Import-NAVApplicationObjects cmdlet just failed.
When I elevate the powershell process on the remote computer and run the import, the cmdlet tried to authenticate as NT-Authority\Anonymous to the database.
Then I passed the credentials of the user that opens the remote PSSession to Import1.ps1 and used the parameters -UserName and -Password of the import cmdlet.
Sadly this process failed again.
Now I tried some things with the user I want to use for authenticating, changing passwords etc and it worked! The password contained a semicolon ; and apparently the import cmdlet was not happy with that.
So my simple solution is: Removing the semicolon from the password.
For some reason Start-Process msiexec won't work when run through invoke command on a remote machine. I looked it up and while some people recommend using psiexec i have seen a lot of people using the plain old invoke-command to start msi installers on remote machines.
This is the code i am currently using:
$session = New-PSSession -computername $computerName -ea stop
$command = {
Param(
[Parameter()]
[string]$computerName,
[Parameter()]
[string]$domain,
[Parameter()]
[string]$user,
[Parameter()]
[string]$password,
[Parameter()]
[string]$installDir
)
$msiArgumentList = "/i C:\Installer.msi /l c:\log.txt /quiet /qr /norestart IAGREE=Yes DOMAIN=$domain ACCOUNT=$user PASSWORD=$password PASSWORDCONFIRM=$password INSTALLDIR=$installDir"
Start-Process msiexec -ArgumentList $msiArgumentList -Wait
}
Invoke-Command -session $session -ScriptBlock $command -ArgumentList $computerName, $domain, $user, $password, $installDir
Remove-PSsession -session $session
I used the same method to install services remotely using intallutil and it worked. Scripting is enabled on target machine as well as remoting so by all accounts it should work. Both computers have the same credentials but i still tried adding credentials to both invoke-command and the pssession. I tested the code locally and the installation worked. Remotely it doesn't and no errors what so ever. i can see on the target machine in taskmanager that msiexec is started but nothing happens. I even tried disabling the firewall and still nothing. i tried the & operator to start msiexec and still nothing.
Not sure what else i could try.
Maybe you try another way, if you don't come forward?
Use Task scheduler, to start the command line e.g by creating and executing a task on the remote machine:
SchTasks /CREATE /XML mycommand.xml /TN "thiscommand"
SchTasks /RUN /TN "thiscommand"
This is for starting a task (like) on the local computer.
With parameter /S you can create tasks on remote computers as in:
SchTasks /S thatPC /CREATE /XML mycommand.xml /TN "thiscommand"
SchTasks /S thatPC /RUN /TN "thiscommand"
For details of parameters and for syntax of the .xml file defining the task you can look into the help.
You could try executing Start-Process with Passthru to see if an error is being returned:
(Start-Process -FilePath msiexec.exe -ArgumentList $msiArgumentList -Wait -Passthru).ExitCode
The other thing that may help is increasing your logging to /l*v
Update 1
Can you try the following, just to check remote commands for msi are working, it should result in 1619.
(Start-Process -FilePath msiexec.exe -ArgumentList "/i no.msi /quiet /qb!" -Wait -Passthru).ExitCode
It seems the problem was a combination of how the msi installer was build and the restrictions windows server has towards interactive processes. I ended up using psexec to bypass this problem.
The only solution that worked for me was to poll the process status. This can be run inside a scriptblock in a remote powershell session.
$res = Start-Process -FilePath $process -ArgumentList $arguments -Wait -PassThru
while ($res.HasExited -eq $false) {
Write-Host "Waiting for $process..."
Start-Sleep -s 1
}
$exitCode = $res.ExitCode
Using the answers above I ended up with
$session = New-PSSession -ComputerName $serverName -Credential $mycred
invoke-command -Session $session -ScriptBlock { param ($argxs) write-host $argxs; start-process msiexec.exe -ArgumentList $argxs } -ArgumentList "/i `"$pathToMsi`" /qn /L*V `"E:\package.log`""
The write-host is just there to verify the augments are correctly escaped but proved invaluable in debugging.