Module: Veewee::Provider::Core::BoxCommand

Included in:
Box, Kvm::Box, Parallels::Box, Vmfusion::Box
Defined in:
lib/veewee/provider/core/box/scp.rb,
lib/veewee/provider/core/box/ssh.rb,
lib/veewee/provider/core/box/vnc.rb,
lib/veewee/provider/core/box/copy.rb,
lib/veewee/provider/core/box/exec.rb,
lib/veewee/provider/core/box/halt.rb,
lib/veewee/provider/core/box/issh.rb,
lib/veewee/provider/core/box/sudo.rb,
lib/veewee/provider/core/box/build.rb,
lib/veewee/provider/core/box/wincp.rb,
lib/veewee/provider/core/box/winrm.rb,
lib/veewee/provider/core/box/floppy.rb,
lib/veewee/provider/core/box/poweroff.rb,
lib/veewee/provider/core/box/validate_tags.rb

Defined Under Namespace

Classes: Platform

Instance Method Summary collapse

Instance Method Details

#check_output_run(command, expected_string) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/veewee/provider/core/box/validate_tags.rb', line 76

def check_output_run(command,expected_string)
  result = { :command => command,
             :expected_string => expected_string,
             :output => nil
           }

  begin
    sshresult = self.exec(command, {:exitcode => '*',:mute => true})
    result[:output]   = sshresult.stdout
    result[:match]    = ! sshresult.stdout.match(/#{expected_string}/).nil?
  rescue
    result[:match] = false
  end
  return result
end

#check_output_sudorun(command, expected_string) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/veewee/provider/core/box/validate_tags.rb', line 58

def check_output_sudorun(command,expected_string)
  result = { :command => command,
             :expected_string => expected_string,
             :output => nil
           }

  begin
    self.exec("echo '#{command}' > /tmp/validation.sh && chmod a+x /tmp/validation.sh", :mute => true)
    sshresult = self.exec(self.sudo("/tmp/validation.sh"),:mute => true)

    result[:output]   = sshresult.stdout
    result[:match]    = ! sshresult.stdout.match(/#{expected_string}/).nil?
  rescue
    result[:match] = false
  end
  return result
end

#checks_linuxObject



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/veewee/provider/core/box/validate_tags.rb', line 92

def checks_linux
  return [
    { :description => 'Checking user',
      :tags => [ 'virtualbox','kvm', 'parallels'],
      :command => 'who am i',
      :expected_string => definition.ssh_user,
      :sudo => false
  },
  { :description => 'Checking sudo',
    :tags => [ 'virtualbox','kvm', 'parallels'],
    :command => 'whoami',
    :expected_string => 'root',
    :sudo => true
  },
  { :description => 'Checking ruby',
    :tags => [ 'virtualbox','kvm', 'parallels','ruby'],
    :command => '. /etc/profile ;ruby --version 2> /dev/null 1> /dev/null;  echo $?',
    :expected_string => "0",
    :sudo => false
  },
  { :description => 'Checking gem',
    :tags => [ 'virtualbox','kvm', 'parallels','gem'],
    :command => '. /etc/profile ;gem --version 2> /dev/null 1> /dev/null;  echo $?',
    :expected_string => "0",
    :sudo => false
  },
  { :description => 'Checking chef',
    :tags => [ 'chef'],
    :command => '. /etc/profile ;chef-client --version 2> /dev/null 1>/dev/null; echo $?',
    :expected_string => "0",
    :sudo => false
  },
  { :description => 'Checking puppet',
    :tags => [ 'puppet'],
    :command => '. /etc/profile ;puppet --version 2> /dev/null 1>/dev/null; echo $?',
    :expected_string => "0",
    :sudo => false
  },
  { :description => 'Checking shared folder',
    :tags => [ 'vagrant'],
    :command => 'mount|grep veewee-validation; echo $?',
    :expected_string => "0",
    :sudo => false
  }
  ]
end

#checks_windowsObject



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/veewee/provider/core/box/validate_tags.rb', line 139

def checks_windows
  return [
    { :description => 'Checking user',
      :tags => [ 'virtualbox','kvm','vmfusion'],
      :command => 'whoami',
      :expected_string => definition.ssh_user,
      :sudo => false
  },
  { :description => 'Checking ruby',
    :tags => [ 'virtualbox','kvm','vmfusion'],
    :command => 'ruby --version > %TEMP%\devnull && echo %ERRORLEVEL%',
    :expected_string => "0",
    :sudo => false
  },
  { :description => 'Checking gem',
    :tags => [ 'virtualbox','kvm','vmfusion'],
    :command => 'gem --version > %TEMP%\devnull && echo %ERRORLEVEL%',
    :expected_string => "0",
    :sudo => false
  },
  { :description => 'Checking chef',
    :tags => [ 'chef'],
    :command => 'chef-client --version > %TEMP%\devnull && echo %ERRORLEVEL%',
    :expected_string => "0",
    :sudo => false
  },
  ]
end

#copy_to_box(localfile, remotefile, options = {}) ⇒ Object

Raises:



6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/veewee/provider/core/box/copy.rb', line 6

def copy_to_box(localfile,remotefile,options={})
  raise Veewee::Error,"Box is not running" unless self.running?
  if
    definition.winrm_user && definition.winrm_password # prefer winrm
  then
    self.wincp(localfile,remotefile,options)
  elsif
    definition.os_type_id =~ /^Windows/
  then
    raise "Trying to transfer #{localfile} to windows machine without 'winrm_user' and 'winrm_password' set in definition."
  else
    self.scp(localfile,remotefile,options)
  end
end

#create_floppy(floppy_filename) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/veewee/provider/core/box/floppy.rb', line 5

def create_floppy(floppy_filename)
  # Todo Check for java
  # Todo check output of commands
  # Todo allow for .erb templates

  # Check for floppy
  unless definition.floppy_files.nil?
    require 'tmpdir'
    temp_dir=Dir.mktmpdir
    definition.floppy_files.each do |filename|
      full_filename=full_filename=File.join(definition.path,filename)
      FileUtils.cp("#{full_filename}","#{temp_dir}")
    end
    javacode_dir=File.expand_path(File.join(__FILE__,'..','..','..','..','..','java'))
    floppy_file=File.join(definition.path,floppy_filename)
    if File.exists?(floppy_file)
      env.logger.info "Removing previous floppy file"
      FileUtils.rm(floppy_file)
    end
    command="java -jar \"#{javacode_dir}/dir2floppy.jar\" \"#{temp_dir}\" \"#{floppy_file}\""
    shell_exec("#{command}")
  end
end

#create_wget_vbs_command {|bootstrap_bat.join(" && "), chunk_num += 1| ... } ⇒ Object

Yields:

  • (bootstrap_bat.join(" && "), chunk_num += 1)


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/veewee/provider/core/box/wincp.rb', line 56

def create_wget_vbs_command(&block)
  bootstrap_bat = []
  chunk_num = 0
  wget_vbs.each_line do |line|
    # escape WIN BATCH special chars
    line.gsub!(/[(<|>)^]/).each{|m| "^#{m}"}
    # windows commands are limited to 2047 characters
    if((bootstrap_bat + [line]).join(" && ").size > 2047 )
      yield bootstrap_bat.join(" && "), chunk_num += 1
      bootstrap_bat = []
    end
    bootstrap_bat << ">> #{wget_vbs_file} (echo.#{line.chomp.strip})"
  end
  yield bootstrap_bat.join(" && "), chunk_num += 1
  bootstrap_bat = []
end

#escape_and_echo(file_contents) ⇒ Object

escape WIN BATCH special chars and prefixes each line with an echo



119
120
121
# File 'lib/veewee/provider/core/box/wincp.rb', line 119

def escape_and_echo(file_contents)
  file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1')
end

#exec(command, options = {}) ⇒ Object

Raises:



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/veewee/provider/core/box/exec.rb', line 16

def exec(command,options={})
  raise Veewee::Error,"Box is not running" unless self.running?
  if definition.winrm_user && definition.winrm_password
    begin
      new_options=winrm_options.merge(options)
      self.(self.ip_address,winrm_options.merge(options)) do
        result = self.winrm_execute(self.ip_address,command,new_options)
        return result
      end
    rescue RuntimeError => ex
      env.ui.error "Error executing command #{command} : #{ex}"
      raise Veewee::WinrmError, ex
    end
  else # definition.ssh_user && definition.ssh_password
    begin
      new_options=ssh_options.merge(options)
      self.(self.ip_address,new_options) do
        begin
          env.logger.info "About to execute remote command #{command} on box #{name} - #{self.ip_address} - #{new_options}"
          result=self.ssh_execute(self.ip_address,command,new_options)
          return result
        rescue RuntimeError => ex
          env.ui.error "Error executing command #{command} : #{ex}"
          raise Veewee::SshError, ex
        end
      end
    rescue Net::SSH::AuthenticationFailed => ex # may want to catch winrm auth fails as well
      env.ui.error "Authentication failure"
      raise Veewee::SshError, "Authentication failure\n"+ex.inspect
    end
  end


end

#halt(options = {}) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/veewee/provider/core/box/halt.rb', line 7

def halt(options={})
  if self.running?
    if options["force"]==true
      self.poweroff
    else
      if definition.winrm_user && definition.winrm_password # prefer winrm 
        self.exec("#{definition.shutdown_cmd}")
      else
        self.exec("echo '#{definition.shutdown_cmd}' > /tmp/shutdown.sh")
        self.exec("chmod +x /tmp/shutdown.sh")
        self.exec(sudo("/tmp/shutdown.sh"))
      end
    end
  else
    raise Veewee::Error,"Box is not running"
  end
end

#issh(command = nil, options = {}) ⇒ Object



7
8
9
# File 'lib/veewee/provider/core/box/issh.rb', line 7

def issh(command=nil,options={})
  self.ssh(command,options.merge({:interactive => true}))
end

#poweroff(options = {}) ⇒ Object



6
7
# File 'lib/veewee/provider/core/box/poweroff.rb', line 6

def poweroff(options={})
end

#run_hook(name) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/veewee/provider/core/box/build.rb', line 8

def run_hook(name)
  hooks = definition.instance_variable_get(:@hooks)
  if ! hooks.nil?
    hook = hooks[name]
    if hook.nil?
      ui.info "Hook ##{name} is not defined"
    else
      raise Veewee::Error, "Hook is not callable" if ! hook.respond_to?(:call)
      ui.info "Running ##{name} hook"
      hook.call
    end
  end
end

#scp(localfile, remotefile, options = {}) ⇒ Object

Raises:



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/veewee/provider/core/box/scp.rb', line 7

def scp(localfile,remotefile,options={})
  raise Veewee::Error,"Box is not running" unless self.running?
  begin
    new_options=ssh_options.merge(options)
    self.(self.ip_address,new_options) do
      begin
        env.logger.info "About to transfer #{localfile} to #{remotefile} to the box #{name} - #{self.ip_address} - #{new_options.inspect}"
        self.ssh_transfer_file(self.ip_address,localfile,remotefile,new_options)
      rescue RuntimeError => ex
        ui.error("Error transfering file #{localfile} failed, possible not enough permissions to write? #{ex}",:prefix => false)
        raise Veewee::SshError,ex
      end
    end
  rescue Net::SSH::AuthenticationFailed => ex
    ui.error("Authentication failure",:prefix => false)
    raise Veewee::SshError,ex
  end

end

#send_vnc_keycode(vnc, keycode) ⇒ Object



36
37
38
39
40
41
42
43
44
45
# File 'lib/veewee/provider/core/box/vnc.rb', line 36

def send_vnc_keycode(vnc,keycode)

  if keycode.is_a?(Symbol)
    vnc.key_press keycode
    sleep 1
  else
      vnc.type_string keycode,{:wait => 0.1}
  end

end

#ssh(command = nil, options = {}) ⇒ Object

Raises:



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/veewee/provider/core/box/ssh.rb', line 10

def ssh(command=nil,options={})

  raise Veewee::Error,"Box is not running" unless self.running?

  host_ip=self.ip_address

  if (options[:interactive]==true)
    unless host_ip.nil? || host_ip==""
      ssh_command="ssh #{ssh_commandline_options(options)} #{host_ip} #{Shellwords.escape(command) if command}"

      fg_exec(ssh_command,options)

    else
      ui.error("Can't ssh into '#{@name} as we couldn't figure out it's ip-address",:prefix => false)
    end
  else
    ssh_options={:user => definition.ssh_user,:password => definition.ssh_password, :port => definition.ssh_host_port}
    ssh_options[:keys] = ssh_key_to_a(definition.ssh_key) if definition.ssh_key
    ssh_execute(host_ip, command, ssh_options)
  end

end

#ssh_command_stringObject



7
8
9
# File 'lib/veewee/provider/core/box/exec.rb', line 7

def ssh_command_string
 "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p #{ssh_options[:port]} -l #{definition.ssh_user} #{self.ip_address}"
end

#string_to_vnccode(thestring) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/veewee/provider/core/box/vnc.rb', line 48

def string_to_vnccode(thestring)

  # https://github.com/aquasync/ruby-vnc/blob/master/data/keys.yaml

  special=Hash.new
  # Specific veewee
  special['<Wait>'] = :wait

  # VNC Codes
  special['<Enter>'] = :return
  special['<Return>'] =  :return
  special['<Esc>'] = :escape

  # These still need some work!
  special['<Backspace>'] = :backspace
  special['<Spacebar>'] = ' '
  special['<Tab>'] = :tab
  # Hmm, what would the equivalent be here
  special['<KillX>'] = '1d 38 0e';

  special['<Up>'] = :up
  special['<Down>'] = :down
  special['<PageUp>'] = :page_up
  special['<PageDown>'] = :page_down
  special['<End>'] = :end
  special['<Insert>'] = :insert
  special['<Delete>'] = :delete
  special['<Left>'] = :left
  special['<Right>'] = :right
  special['<Home>'] = :home

  special['<F1>'] = :f1
  special['<F2>'] = :f2
  special['<F3>'] = :f3
  special['<F4>'] = :f4
  special['<F5>'] = :f5
  special['<F6>'] = :f6
  special['<F7>'] = :f7
  special['<F8>'] = :f8
  special['<F9>'] = :f9
  special['<F10>'] = :f10

  keycodes=Array.new
  thestring.gsub!(/ /,"<Spacebar>")

  until thestring.length == 0
    nospecial=true;
    special.keys.each { |key|
      if thestring.start_with?(key)
        #take thestring
        #check if it starts with a special key + pop special string
        keycodes<<special[key];
        thestring=thestring.slice(key.length,thestring.length-key.length)
        nospecial=false;
        break;
      end
    }
    if nospecial
      code = thestring.slice(0,1)
      keycodes << code
      #pop one
      thestring=thestring.slice(1,thestring.length-1)
    end
  end

  return keycodes
end

#sudo(scriptname) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
# File 'lib/veewee/provider/core/box/sudo.rb', line 6

def sudo(scriptname)
  if definition.ssh_user=="root"
    return "#{scriptname}"
  else
    command=definition.sudo_cmd
    newcommand=command.gsub(/%p/,"#{definition.ssh_password}")
    newcommand.gsub!(/%u/,"#{definition.ssh_user}")
    newcommand.gsub!(/%f/,"#{scriptname}")
    return newcommand
  end
end

#validate_tags(tags, options) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/veewee/provider/core/box/validate_tags.rb', line 6

def validate_tags(tags,options)

  unless self.exists?
    ui.error "Error:: You tried to validate box '#{name}' but it does not exist"
    exit -1
  end

  unless self.running?
    ui.error "Error:: You tried to validate box '#{name}' but it is not running"
    exit -1
  end

  if definition.winrm_user && definition.winrm_password # prefer winrm
    checks = checks_windows
  else
    checks = checks_linux
  end

  # Some reject here based on tags
  checks.reject! { |c|
    tagged = false
    c[:tags].each do |t|
      tagged = true if tags.include?(t)
    end
    ! tagged
  }

  # Assume clean exitcode
  exitcode = 0

  # Loop over checks
  checks.each do |check|
    if check[:sudo]
      result = check_output_sudorun(check[:command],check[:expected_string])
    else
      result = check_output_run(check[:command],check[:expected_string])
    end

    if result[:match]
      ui.success("#{check[:description]} - OK")
    else
      ui.error("#{check[:description]} - FAILED")
      ui.error("Command: #{check[:command]}")
      ui.error("Expected string #{check[:expected_string]}")
      ui.error("Output: #{check[:output]}")
      exitcode = -1
    end
  end

  exit -1 if exitcode < 0
end

#vnc_type(sequence, host, display = 20) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/veewee/provider/core/box/vnc.rb', line 12

def vnc_type(sequence,host,display=20)
  counter=0
  env.logger.info "Opening VNC #{host} on display #{display}"
  Net::VNC.open("#{host}:#{display}",{:wait => 0.001}) do |vnc|
    sequence.each { |s|
      counter=counter+1

      ui.info "Typing:[#{counter}]: "+s

      keycodes=string_to_vnccode(s)

        keycodes.each do |keycode|
          if keycode==:wait
            sleep 1
          else
            send_vnc_keycode(vnc,keycode)
          end
        end
    }
    ui.info "Done typing."
    ui.info ""
  end
end

#wget_vbsObject



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/veewee/provider/core/box/wincp.rb', line 73

def wget_vbs
  wget_vbs = <<-WGET
url = WScript.Arguments.Named("url")
path = WScript.Arguments.Named("path")
Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP")
Set wshShell = CreateObject( "WScript.Shell" )
Set objUserVariables = wshShell.Environment("USER")

rem http proxy is optional
rem attempt to read from HTTP_PROXY env var first
On Error Resume Next

If NOT (objUserVariables("HTTP_PROXY") = "") Then
objXMLHTTP.setProxy 2, objUserVariables("HTTP_PROXY")

rem fall back to named arg
ElseIf NOT (WScript.Arguments.Named("proxy") = "") Then
objXMLHTTP.setProxy 2, WScript.Arguments.Named("proxy")
End If

On Error Goto 0

objXMLHTTP.open "GET", url, false
objXMLHTTP.send()
If objXMLHTTP.Status = 200 Then
Set objADOStream = CreateObject("ADODB.Stream")
objADOStream.Open
objADOStream.Type = 1
objADOStream.Write objXMLHTTP.ResponseBody
objADOStream.Position = 0
Set objFSO = Createobject("Scripting.FileSystemObject")
If objFSO.Fileexists(path) Then objFSO.DeleteFile path
Set objFSO = Nothing
objADOStream.SaveToFile path
objADOStream.Close
Set objADOStream = Nothing
End if
Set objXMLHTTP = Nothing
WGET
  #escape_and_echo(win_wget)
  wget_vbs
end

#wget_vbs_fileObject



52
53
54
# File 'lib/veewee/provider/core/box/wincp.rb', line 52

def wget_vbs_file
  "%TEMP%\\\\wget.vbs"
end

#wincp(localfile, remotefile, options = {}) ⇒ Object

Raises:



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/veewee/provider/core/box/wincp.rb', line 9

def wincp(localfile,remotefile,options={})
  raise Veewee::Error,"Box is not running" unless self.running?

  if self.exec("cmd.exe /C dir #{wget_vbs_file} > NUL",{:exitcode=>"*"}).status != 0
    env.ui.warn "Creating wget.vbs"
    create_wget_vbs_command do |command_chunk, chunk_num|
      self.exec(%Q!cmd.exe /C echo "Rendering #{wget_vbs_file} chunk #{chunk_num}" && #{command_chunk}!)
    end
  end

  # Calculate an available kickstart port which we will use for wincp
  definition.kickstart_port = "7000" if definition.kickstart_port.nil?
  guessed_port=guess_free_port(definition.kickstart_port.to_i,7199).to_s
  if guessed_port.to_s!=definition.kickstart_port
    env.ui.warn "Changing wincp port from #{definition.kickstart_port} to #{guessed_port}"
    definition.kickstart_port=guessed_port.to_s
  end

  urlpath = localfile.to_slug
  urlpath = urlpath.start_with?('/') ? urlpath : '/' + urlpath

  begin
    self.(self.ip_address,winrm_options.merge(options)) do
      env.ui.warn "Spinning up an allow_for_http_request on http://#{host_ip_as_seen_by_guest}:#{definition.kickstart_port}#{localfile} at URL #{urlpath}"
      allow_for_http_request(
          localfile,
          urlpath,
          {
            :port => definition.kickstart_port,
            :timeout => 300,
          }
      )

      env.ui.info "Going to try and copy #{localfile} to #{remotefile.inspect}"
      self.exec("cmd.exe /C cscript %TEMP%\\wget.vbs /url:http://#{host_ip_as_seen_by_guest}:#{definition.kickstart_port}#{urlpath} /path:#{remotefile}")
      # while true do
      #   sleep 0.1 # used to debug
      # end
    end
  end
end

#winrm(command = nil, options = {}) ⇒ Object

Raises:



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/veewee/provider/core/box/winrm.rb', line 8

def winrm(command=nil,options={})

  raise Veewee::Error,"Box is not running" unless self.running?
  winrm_options={:user => definition.winrm_user,:password => definition.winrm_password, :port => definition.winrm_host_port, :exitcode => '*'}

  if (command.nil?)
    env.ui.info "This is a simple interactive shell"
    env.ui.info "To exit interactive mode, use 'quit!'"

    while 1
      command = ui.ask("veewee>")
      case command.strip
      when 'quit!'
        env.ui.info 'Bye!'
        break
      else
        winrm_execute(self.ip_address,command,winrm_options.merge(options))
      end
    end
  else
    winrm_execute(self.ip_address,command,winrm_options.merge(options))
  end


end

#winrm_command_stringObject



11
12
13
14
# File 'lib/veewee/provider/core/box/exec.rb', line 11

def winrm_command_string
  "knife winrm -m #{self.ip_address} -P #{winrm_options[:port]} -x #{definition.winrm_user}" +
    " -P #{definition.winrm_password} COMMAND"
end