Closed djberg96 closed 5 years ago
I'd think you would open a shell and then run the start-job
command and capture the job ID. That should return immediately. You just want to make sure to call wait-job
in a separate run
call in the same shell.
@mwrock Hm, upon further review, it doesn't seem to return right away. But, it always returns a job ID of "1", which can't be right, and trying to Get-Job
on Id 1 causes an error, as it's not found. I also tried using a custom name, but I see the same thing - always a job ID of 1. I'm basically just doing this:
connection.shell(:powershell) do |shell|
command = "Start-Job -Name dberger -ScriptBlock { sleep 30; Get-Process -Name system }"
output = shell.run(command)
if output.stderr && output.stderr.size > 0
puts "Failed: #{output.stderr}"
else
puts output.stdout
end
end
What am I doing wrong here?
Ah, I think the issue is that the Job ID is for the current shell, and since a new shell is always created and closed, I'll never be able to get at the job with a separate session. Is there a way to persist the shell?
yes! Just assign the shell to a variable instead of running in a do
block:
shell = connection.shell(:powershell)
output = shell.run(command)
# do a whole bunch of super great stuff
shell.close
Aha, thanks! For anyone following, this was what I did (includes some extra debug prints):
require 'winrm'
require 'json'
host = "1.2.3.4"
port = "5985"
options = {
:endpoint => "http://#{host}:#{port}/wsman",
:user => "dberger",
:password => "xxx",
:disable_sspi => true
}
connection = WinRM::Connection.new(options)
begin
shell = connection.shell(:powershell)
command = "Start-Job -ScriptBlock { sleep 30; Get-Process -Name system } | Select -ExpandProperty Id"
puts "FIRST COMMAND: #{command}"
output = shell.run(command)
job_id = if output.stderr && output.stderr.size > 0
raise "Failed: #{output.stderr}"
else
output.stdout.strip
end
puts "Job ID: #{job_id}"
state = "Running"
interval = [shell.connection_opts[:operation_timeout], 10].min
command = "Get-Job -Id #{job_id} | Select -ExpandProperty State"
while !state.casecmp('completed').zero?
puts "COMMAND: #{command}"
state = shell.run(command).stdout.strip.downcase
puts "STATE: #{state}"
raise "OOPS!" if state == 'failed'
sleep(interval)
end
command = "Receive-Job -Id #{job_id} | ConvertTo-Json -Depth 1"
output = shell.run(command).stdout
p JSON.parse(output)
ensure
shell.close if shell
end
I'm trying to figure out how to do some async + poll using winrm. My idea was to create a wrapper that would wrap everything in a
Start-Job -ScriptBlock { ... }
, and then immediately return control. I would then periodically poll the job viaWait-Job
in a separate call, and finallyReceive-Job
when the job has finished (presumably successfully).However, I'm having trouble getting that approach to work, as the API seems to wait for the job to complete before returning. Am I doing something wrong? Has this workflow already been simplified in some way? Is there a better way?