Module: Train::Platforms::Detect::Helpers::Windows

Included in:
OSCommon
Defined in:
lib/train/platforms/detect/helpers/os_windows.rb

Instance Method Summary collapse

Instance Method Details

#check_cmdObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 7

def check_cmd
  # try to detect windows, use cmd.exe to also support Microsoft OpenSSH
  res = @backend.run_command("cmd.exe /c ver")

  return false if (res.exit_status != 0) || res.stdout.empty?

  # if the ver contains `Windows`, we know its a Windows system
  version = res.stdout.strip
  return false unless version.downcase =~ /windows/

  @platform[:family] = "windows"

  # try to extract release from eg. `Microsoft Windows [Version 6.3.9600]`
  release = /\[(?<name>.*)\]/.match(version)
  if release[:name]
    # release is 6.3.9600 now
    @platform[:release] = release[:name].downcase.gsub("version", "").strip
    # fallback, if we are not able to extract the name from wmic later
    @platform[:name] = "Windows #{@platform[:release]}"
  end

  read_wmic
  true
end

#check_powershellObject



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 32

def check_powershell
  command = @backend.run_command(
    "Get-WmiObject Win32_OperatingSystem | Select Caption,Version | ConvertTo-Json"
  )
  # some targets (e.g. Cisco) may return 0 and print an error to stdout
  return false if (command.exit_status != 0) || command.stdout.downcase !~ /window/

  begin
    payload = JSON.parse(command.stdout)
    @platform[:family] = "windows"
    @platform[:release] = payload["Version"]
    @platform[:name] = payload["Caption"]

    read_wmic
    true
  rescue
    false
  end
end

#detect_windowsObject



3
4
5
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 3

def detect_windows
  check_cmd || check_powershell
end

#local_windows?Boolean

Returns:

  • (Boolean)


52
53
54
55
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 52

def local_windows?
  @backend.class.to_s == "Train::Transports::Local::Connection" &&
    ruby_host_os(/mswin|mingw|windows/)
end

#read_wmicObject

reads os name and version from wmic Thanks to Matt Wrock (github.com/mwrock) for this hint



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 60

def read_wmic
  res = @backend.run_command("wmic os get * /format:list")
  if res.exit_status == 0
    sys_info = {}
    res.stdout.lines.each do |line|
      m = /^\s*([^=]*?)\s*=\s*(.*?)\s*$/.match(line)
      sys_info[m[1].to_sym] = m[2] unless m.nil? || m[1].nil?
    end

    @platform[:release] = sys_info[:Version]
    # additional info on windows
    @platform[:build] = sys_info[:BuildNumber]
    @platform[:name] = sys_info[:Caption]
    @platform[:name] = @platform[:name].gsub("Microsoft", "").strip unless @platform[:name].empty?
    @platform[:arch] = read_wmic_cpu
  end
end

#read_wmic_cpuObject

‘OSArchitecture` from `read_wmic` does not match a normal standard For example, `x86_64` shows as `64-bit`



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
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 80

def read_wmic_cpu
  res = @backend.run_command("wmic cpu get architecture /format:list")
  if res.exit_status == 0
    sys_info = {}
    res.stdout.lines.each do |line|
      m = /^\s*([^=]*?)\s*=\s*(.*?)\s*$/.match(line)
      sys_info[m[1].to_sym] = m[2] unless m.nil? || m[1].nil?
    end
  end

  # This converts `wmic os get architecture` output to a normal standard
  # https://msdn.microsoft.com/en-us/library/aa394373(VS.85).aspx
  arch_map = {
    0 => "i386",
    1 => "mips",
    2 => "alpha",
    3 => "powerpc",
    5 => "arm",
    6 => "ia64",
    9 => "x86_64",
  }

  # The value of `wmic cpu get architecture` is always a number between 0-9
  arch_number = sys_info[:Architecture].to_i
  arch_map[arch_number]
end

#windows_uuidObject

This method scans the target os for a unique uuid to use



108
109
110
111
112
113
114
115
116
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 108

def windows_uuid
  uuid = windows_uuid_from_chef
  uuid = windows_uuid_from_machine_file if uuid.nil?
  uuid = windows_uuid_from_wmic if uuid.nil?
  uuid = windows_uuid_from_registry if uuid.nil?
  raise Train::TransportError, "Cannot find a UUID for your node." if uuid.nil?

  uuid
end

#windows_uuid_from_chefObject



129
130
131
132
133
134
135
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 129

def windows_uuid_from_chef
  file = @backend.file("#{ENV["SYSTEMDRIVE"]}\\chef\\cache\\data_collector_metadata.json")
  return if !file.exist? || file.size == 0

  json = JSON.parse(file.content)
  json["node_uuid"]
end

#windows_uuid_from_machine_fileObject



118
119
120
121
122
123
124
125
126
127
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 118

def windows_uuid_from_machine_file
  %W{
    #{ENV["SYSTEMDRIVE"]}\\chef\\chef_guid
    #{ENV["HOMEDRIVE"]}#{ENV["HOMEPATH"]}\\.chef\\chef_guid
  }.each do |path|
    file = @backend.file(path)
    return file.content.chomp if file.exist? && file.size != 0
  end
  nil
end

#windows_uuid_from_registryObject



144
145
146
147
148
149
150
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 144

def windows_uuid_from_registry
  cmd = '(Get-ItemProperty "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography" -Name "MachineGuid")."MachineGuid"'
  result = @backend.run_command(cmd)
  return unless result.exit_status == 0

  result.stdout.chomp
end

#windows_uuid_from_wmicObject



137
138
139
140
141
142
# File 'lib/train/platforms/detect/helpers/os_windows.rb', line 137

def windows_uuid_from_wmic
  result = @backend.run_command("wmic csproduct get UUID")
  return unless result.exit_status == 0

  result.stdout.split("\r\n")[-1].strip
end