boris 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/LICENSE.md +9 -0
  2. data/README.md +94 -0
  3. data/boris.gemspec +28 -0
  4. data/doc/Array.html +437 -0
  5. data/doc/Boris.html +230 -0
  6. data/doc/Boris/ConnectionAlreadyActive.html +123 -0
  7. data/doc/Boris/ConnectionFailed.html +127 -0
  8. data/doc/Boris/Connector.html +794 -0
  9. data/doc/Boris/InvalidCredentials.html +131 -0
  10. data/doc/Boris/InvalidOption.html +123 -0
  11. data/doc/Boris/InvalidTargetName.html +123 -0
  12. data/doc/Boris/Lumberjack.html +466 -0
  13. data/doc/Boris/MissingCredentials.html +123 -0
  14. data/doc/Boris/NoActiveConnection.html +123 -0
  15. data/doc/Boris/NoProfileDetected.html +123 -0
  16. data/doc/Boris/Options.html +783 -0
  17. data/doc/Boris/Profiles.html +117 -0
  18. data/doc/Boris/Profiles/Linux.html +1151 -0
  19. data/doc/Boris/Profiles/RedHat.html +875 -0
  20. data/doc/Boris/Profiles/Solaris.html +1230 -0
  21. data/doc/Boris/Profiles/Structure.html +2050 -0
  22. data/doc/Boris/Profiles/UNIX.html +893 -0
  23. data/doc/Boris/Profiles/Windows.html +1846 -0
  24. data/doc/Boris/Profiles/Windows/Windows2003.html +304 -0
  25. data/doc/Boris/Profiles/Windows/Windows2008.html +379 -0
  26. data/doc/Boris/Profiles/Windows/Windows2012.html +304 -0
  27. data/doc/Boris/SNMPConnector.html +512 -0
  28. data/doc/Boris/SSHConnector.html +633 -0
  29. data/doc/Boris/Target.html +2002 -0
  30. data/doc/Boris/WMIConnector.html +1134 -0
  31. data/doc/BorisLogger.html +217 -0
  32. data/doc/Hash.html +195 -0
  33. data/doc/String.html +1246 -0
  34. data/doc/_index.html +420 -0
  35. data/doc/class_list.html +53 -0
  36. data/doc/css/common.css +1 -0
  37. data/doc/css/full_list.css +57 -0
  38. data/doc/css/style.css +328 -0
  39. data/doc/file.README.html +183 -0
  40. data/doc/file_list.html +55 -0
  41. data/doc/frames.html +28 -0
  42. data/doc/index.html +183 -0
  43. data/doc/js/app.js +214 -0
  44. data/doc/js/full_list.js +173 -0
  45. data/doc/js/jquery.js +4 -0
  46. data/doc/method_list.html +1468 -0
  47. data/doc/top-level-namespace.html +126 -0
  48. data/lib/boris.rb +30 -0
  49. data/lib/boris/connectors.rb +47 -0
  50. data/lib/boris/connectors/snmp.rb +56 -0
  51. data/lib/boris/connectors/ssh.rb +110 -0
  52. data/lib/boris/connectors/wmi.rb +186 -0
  53. data/lib/boris/errors.rb +17 -0
  54. data/lib/boris/helpers/array.rb +63 -0
  55. data/lib/boris/helpers/constants.rb +20 -0
  56. data/lib/boris/helpers/hash.rb +8 -0
  57. data/lib/boris/helpers/scrubber.rb +51 -0
  58. data/lib/boris/helpers/string.rb +130 -0
  59. data/lib/boris/lumberjack.rb +47 -0
  60. data/lib/boris/options.rb +86 -0
  61. data/lib/boris/profiles/linux/redhat.rb +77 -0
  62. data/lib/boris/profiles/linux_core.rb +216 -0
  63. data/lib/boris/profiles/unix/solaris.rb +307 -0
  64. data/lib/boris/profiles/unix_core.rb +85 -0
  65. data/lib/boris/profiles/windows/windows2003.rb +15 -0
  66. data/lib/boris/profiles/windows/windows2008.rb +23 -0
  67. data/lib/boris/profiles/windows/windows2012.rb +15 -0
  68. data/lib/boris/profiles/windows_core.rb +530 -0
  69. data/lib/boris/structure.rb +167 -0
  70. data/lib/boris/target.rb +340 -0
  71. data/test/connector_tests/test_snmp.rb +35 -0
  72. data/test/connector_tests/test_ssh.rb +51 -0
  73. data/test/connector_tests/test_wmi.rb +129 -0
  74. data/test/helper_tests/test_array.rb +25 -0
  75. data/test/helper_tests/test_hash.rb +10 -0
  76. data/test/helper_tests/test_string.rb +136 -0
  77. data/test/profile_tests/test_core_skeleton +107 -0
  78. data/test/profile_tests/test_linux_core.rb +331 -0
  79. data/test/profile_tests/test_redhat.rb +134 -0
  80. data/test/profile_tests/test_solaris.rb +523 -0
  81. data/test/profile_tests/test_unix_core.rb +117 -0
  82. data/test/profile_tests/test_windows.rb +536 -0
  83. data/test/setup_tests.rb +14 -0
  84. data/test/test_all.rb +8 -0
  85. data/test/test_options.rb +44 -0
  86. data/test/test_structure.rb +136 -0
  87. data/test/test_target.rb +146 -0
  88. metadata +241 -0
@@ -0,0 +1,85 @@
1
+ require 'boris/structure'
2
+
3
+ module Boris; module Profiles
4
+ module UNIX
5
+ include Structure
6
+
7
+ def self.connection_type
8
+ Boris::SSHConnector
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ return true if connector.value_at('uname -a') !~ /linux/i
13
+ end
14
+
15
+ def get_file_systems
16
+ super
17
+
18
+ file_system_command = %q{df -kl 2>/dev/null | grep ^/ | nawk '{print $1 "|" $2 / 1024 "|" $3 / 1024 "|" $6}'}
19
+ @connector.values_at(file_system_command).each do |file_system|
20
+ h = file_system_template
21
+ file_system = file_system.split('|')
22
+
23
+ h[:capacity_mb] = file_system[1].to_i
24
+ h[:file_system] = file_system[0]
25
+ h[:mount_point] = file_system[3]
26
+ h[:used_space_mb] = file_system[2].to_i
27
+
28
+ @file_systems << h
29
+ end
30
+ end
31
+
32
+ def get_hardware; super; end
33
+ def get_hosted_shares; super; end
34
+ def get_installed_applications; super; end
35
+ def get_installed_patches; super; end
36
+ def get_installed_services; super; end
37
+
38
+ def get_local_user_groups
39
+ super
40
+
41
+ user_data = @connector.values_at('cat /etc/passwd | grep -v "^#"')
42
+ group_data = @connector.values_at('cat /etc/group | grep -v "^#"')
43
+
44
+ users = []
45
+ groups = []
46
+
47
+ user_data.each do |x|
48
+ h = {}
49
+ x = x.split(':')
50
+ h[:status] = nil
51
+ h[:primary_group_id] = x[3]
52
+ h[:username] = x[0]
53
+ users << h
54
+ end
55
+
56
+ group_data.each do |group|
57
+ group = group.split(':')
58
+ h = {:members=>[], :name=>group[0]}
59
+
60
+ h[:members] = users.select{|user| (user[:primary_group_id] == group[2])}.collect{|user| user[:username]}
61
+
62
+ @local_user_groups << h
63
+ end
64
+ end
65
+
66
+ def get_network_id
67
+ super
68
+
69
+ hostname = @connector.value_at('hostname')
70
+ domain = @connector.value_at('domainname')
71
+ domain = nil if domain =~ /\(none\)/i
72
+
73
+ if hostname =~ /\./
74
+ hostname = hostname.split('.').shift
75
+ domain = hostname.join('.') if hostname =~ /\./
76
+ end
77
+
78
+ @network_id[:hostname] = hostname
79
+ @network_id[:domain] = domain
80
+ end
81
+
82
+ def get_network_interfaces; super; end
83
+ def get_operating_system; super; end
84
+ end
85
+ end; end
@@ -0,0 +1,15 @@
1
+ require 'boris/profiles/windows_core'
2
+
3
+ module Boris; module Profiles; module Windows
4
+ module Windows2003
5
+ include Windows
6
+
7
+ def self.connection_type
8
+ Windows.connection_type
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ return true if connector.value_at('SELECT Name FROM Win32_OperatingSystem')[:name] =~ /2003/
13
+ end
14
+ end
15
+ end; end; end
@@ -0,0 +1,23 @@
1
+ require 'boris/profiles/windows_core'
2
+
3
+ module Boris; module Profiles; module Windows
4
+ module Windows2008
5
+ include Windows
6
+
7
+ def self.connection_type
8
+ Windows.connection_type
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ return true if connector.value_at('SELECT Name FROM Win32_OperatingSystem')[:name] =~ /2008/
13
+ end
14
+
15
+ def get_operating_system
16
+ super
17
+
18
+ # grab the 'features' from win2008 servers, as it's only available on this version
19
+ # and already deprecated as of win2012
20
+ @operating_system[:features] = @connector.values_at('SELECT Name FROM Win32_ServerFeature').map {|f| f[:name]}
21
+ end
22
+ end
23
+ end; end; end
@@ -0,0 +1,15 @@
1
+ require 'boris/profiles/windows_core'
2
+
3
+ module Boris; module Profiles; module Windows
4
+ module Windows2012
5
+ include Windows
6
+
7
+ def self.connection_type
8
+ Windows.connection_type
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ return true if connector.value_at('SELECT Name FROM Win32_OperatingSystem')[:name] =~ /2012/
13
+ end
14
+ end
15
+ end; end; end
@@ -0,0 +1,530 @@
1
+ require 'boris/structure'
2
+
3
+ module Boris; module Profiles
4
+ module Windows
5
+ include Structure
6
+
7
+ APP32_KEYPATH = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'
8
+ APP64_KEYPATH = 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
9
+
10
+ NIC_CFG_KEYPATH = 'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}'
11
+ TCPIP_CFG_KEYPATH = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces'
12
+
13
+ ORACLE_KEYPATH = 'SOFTWARE\ORACLE'
14
+ IIS_KEYPATH = 'SOFTWARE\Microsoft\INetStp'
15
+
16
+ DUPLEX_REG_VALS = [
17
+ :autonegadvertised,
18
+ :duplexmode,
19
+ :forcedspeedduplex,
20
+ :media_type,
21
+ :mediaselect,
22
+ :req_medium,
23
+ :requestedmediatype,
24
+ :speedduplex
25
+ ]
26
+
27
+ def self.connection_type
28
+ Boris::WMIConnector
29
+ end
30
+
31
+ def self.matches_target?(connector)
32
+ return true if connector.value_at('SELECT Name FROM Win32_OperatingSystem')[:name] =~ /windows/i
33
+ end
34
+
35
+ def get_file_systems
36
+ super
37
+
38
+ logical_disks = @connector.values_at('SELECT Antecedent, Dependent FROM Win32_LogicalDiskToPartition')
39
+ disk_partitions = @connector.values_at('SELECT Antecedent, Dependent FROM Win32_DiskDriveToDiskPartition')
40
+ physical_drives = @connector.values_at('SELECT DeviceID, Model FROM Win32_DiskDrive')
41
+ disk_space = @connector.values_at('SELECT FreeSpace, Name, Size FROM Win32_LogicalDisk WHERE DriveType=3')
42
+
43
+ disk_space.each do |ds|
44
+ h = file_system_template
45
+ h[:mount_point] = ds[:name]
46
+ h[:capacity_mb] = ds[:size].to_i / 1024
47
+ h[:used_space_mb] = h[:capacity_mb] - (ds[:freespace].to_i / 1024)
48
+
49
+ ld = logical_disks.select{|ld| ld[:dependent].include?(h[:mount_point])}[0]
50
+ h[:file_system] = ld[:antecedent].split(/\"/)[1]
51
+
52
+ dp = disk_partitions.select{|dp| dp[:dependent].include?(h[:file_system])}[0]
53
+ drive_id = dp[:antecedent].split('\\').last.delete('\"')
54
+
55
+ physical_drive = physical_drives.select{|pd| pd[:deviceid].include?(drive_id)}[0]
56
+ h[:san_storage] = true if physical_drive[:model] =~ /open-v/i
57
+
58
+ @file_systems << h unless h[:file_system].nil?
59
+ end
60
+ end
61
+
62
+ def get_hardware
63
+ super
64
+
65
+ serial_data = @connector.value_at('SELECT SerialNumber, SMBIOSBIOSVersion FROM Win32_BIOS')
66
+ @hardware[:serial] = serial_data[:serialnumber]
67
+ @hardware[:firmware_version] = serial_data[:smbiosbiosversion]
68
+
69
+ system_data = @connector.value_at('SELECT Manufacturer, Model, TotalPhysicalMemory FROM Win32_ComputerSystem')
70
+ @hardware[:vendor] = system_data[:manufacturer]
71
+ @hardware[:model] = system_data[:model]
72
+ @hardware[:memory_installed_mb] = system_data[:totalphysicalmemory].to_i / 1024 / 1024
73
+
74
+ cpu_data = @connector.values_at('SELECT * FROM Win32_Processor')
75
+
76
+ @hardware[:cpu_physical_count] = cpu_data.size
77
+
78
+ cpu = cpu_data.first
79
+
80
+ @hardware[:cpu_architecture] = cpu[:datawidth]
81
+ @hardware[:cpu_core_count] = cpu[:numberofcores]
82
+
83
+ @hardware[:cpu_model] = cpu[:name]
84
+ @hardware[:cpu_speed_mhz] = cpu[:maxclockspeed]
85
+ @hardware[:cpu_vendor] = cpu[:manufacturer]
86
+ end
87
+
88
+ def get_hosted_shares
89
+ super
90
+
91
+ share_data = @connector.values_at('SELECT Name, Path FROM Win32_Share WHERE Type = 0')
92
+ share_data.each do |share|
93
+ h = hosted_share_template
94
+ h[:name] = share[:name]
95
+ h[:path] = share[:path]
96
+ @hosted_shares << h
97
+ end
98
+ end
99
+
100
+ def get_installed_applications
101
+ super
102
+
103
+ @patches_from_registry = []
104
+
105
+ [APP32_KEYPATH, APP64_KEYPATH].each do |app_path|
106
+ @connector.registry_subkeys_at(app_path).each do |app_key|
107
+ h = installed_application_template
108
+
109
+ app_values = @connector.registry_values_at(app_key)
110
+
111
+ h[:date_installed] = DateTime.parse(app_values[:installdate]) if app_values[:installdate].kind_of?(String)
112
+
113
+ if app_values.has_key?(:displayname) && !(app_values[:displayname] =~ /^kb|\(kb\d+/i)
114
+ h[:install_location] = app_values[:installlocation] if app_values[:installlocation].nil?
115
+ h[:license_key] = get_product_key(app_values[:displayname], app_key)
116
+ h[:name] = concat_app_edition(app_values[:displayname])
117
+ h[:vendor] = app_values[:publisher]
118
+ h[:version] = app_values[:displayversion]
119
+
120
+ @installed_applications << h
121
+ elsif app_values[:displayname] =~ /^kb|\(kb\d+/i
122
+ # likely a ms patch, so we'll save this data to parse later in #get_installed_patches
123
+ @patches_from_registry << {:key_path=>app_key, :values=>app_values}
124
+ end
125
+ end
126
+ end
127
+
128
+ # look for some other popular applications not found in the usual spots
129
+
130
+ # Oracle (RDMS, AppServer (AS), Client)
131
+ oracle_keys = @connector.registry_subkeys_at(ORACLE_KEYPATH)
132
+ oracle_keys.each do |app_key|
133
+ if app_key =~ /^key_ora(db|home)/i
134
+ app_values = registry_values_at(app_key)
135
+ if app_values.has_key?(:oracle_group_name)
136
+ h = installed_application_template
137
+ h[:install_location] = app_values[:oracle_home]
138
+ h[:name] = app_values[:oracle_group_name].split('_')[0] + " #{app_values[:oracle_bundle_name]}"
139
+ h[:vendor] = VENDOR_ORACLE
140
+
141
+ @installed_applications << h
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ def get_installed_patches
148
+ super
149
+
150
+ # get patches via wmi
151
+ patch_data = @connector.values_at('SELECT Description, HotFixID, InstalledBy, InstalledOn, ServicePackInEffect
152
+ FROM Win32_QuickFixEngineering')
153
+
154
+ patch_data.each do |patch|
155
+ if !(patch[:hotfixid] =~ /\{/)
156
+
157
+ h = installed_patch_template
158
+
159
+ h[:patch_code] = patch[:hotfixid] == 'File 1' ? patch[:servicepackineffect] : patch[:hotfixid]
160
+
161
+ h[:installed_by] = patch[:installedby] unless patch[:installedby].empty?
162
+ h[:installed_by] = get_username(patch[:installedby]) if patch[:installedby][0, 4] == 'S-1-'
163
+
164
+ h[:date_installed] = DateTime.strptime(patch[:installedon], '%m/%d/%Y') unless patch[:installedon].empty?
165
+
166
+ @installed_patches << h
167
+ end
168
+ end
169
+
170
+ # get patches from the registry (under the application keys) if necessary
171
+ if @patches_from_registry.nil?
172
+ @patches_from_registry = []
173
+
174
+ [APP32_KEYPATH, APP64_KEYPATH].each do |app_path|
175
+ @connector.registry_subkeys_at(app_path).each do |app_key|
176
+ app_values = @connector.registry_values_at(app_key)
177
+ if app_values[:displayname] =~ /^kb|\(kb\d+/i
178
+ @patches_from_registry << {:key_path=>app_key, :values=>app_values}
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ @patches_from_registry.each do |patch_hash|
185
+ h = installed_patch_template
186
+
187
+ key_path = patch_hash[:key_path].after_slash
188
+ patch = patch_hash[:values]
189
+
190
+ h[:date_installed] = DateTime.strptime(patch[:installdate], '%Y%m%d') if patch[:installdate].kind_of?(String)
191
+
192
+ if key_path =~ /^kb/i
193
+ h[:patch_code] = key_path
194
+ elsif key_path.after_period =~ /^kb/i
195
+ h[:patch_code] = key_path.after_period
196
+ elsif patch[:displayname] =~ /\(kb\d+/i
197
+ h[:patch_code] = patch[:displayname].between_parenthesis
198
+ end
199
+
200
+ @installed_patches << h if @installed_patches.select{|p| p[:patch_code] == h[:patch_code]}.empty?
201
+ end
202
+ end
203
+
204
+ def get_installed_services
205
+ super
206
+
207
+ service_data = @connector.values_at('SELECT Name, PathName, StartMode FROM Win32_Service')
208
+ service_data.each do |service|
209
+ h = installed_service_template
210
+ h[:name] = service[:name]
211
+ h[:install_location] = service[:pathname]
212
+ h[:start_mode] = service[:startmode]
213
+ @installed_services << h
214
+ end
215
+ end
216
+
217
+ def get_local_user_groups
218
+ super
219
+
220
+ # first, retrieve the network id if necessary (will be used in later wmi queries)
221
+ get_network_id if !@network_id || !@network_id[:hostname]
222
+
223
+ # next, let's check if this system is a domain controller, otherwise, our query results
224
+ # may return all user accounts associated with the domain
225
+ if @operating_system.nil?
226
+ system_roles = @connector.value_at('SELECT Roles FROM Win32_ComputerSystem')[:roles]
227
+ else
228
+ system_roles = @operating_system[:roles]
229
+ end
230
+
231
+ if system_roles.select{|role| role =~ /domaincontroller/i}.empty?
232
+ # not a domain controller, so move on with retrieving users
233
+ groups = []
234
+
235
+ group_data = @connector.values_at("SELECT Name FROM Win32_Group WHERE Domain = '#{@network_id[:hostname]}'")
236
+ group_data.each {|group| @local_user_groups << {:name=>group[:name], :members=>[]}}
237
+
238
+ @local_user_groups.each do |group|
239
+
240
+ members = @connector.values_at("SELECT * FROM Win32_GroupUser WHERE GroupComponent = \"Win32_Group.Domain='#{@network_id[:hostname]}',Name='#{group[:name]}'\"")
241
+
242
+ members.each do |member|
243
+ hostname, username = member[:partcomponent].within_quotes
244
+ group[:members] << "#{hostname}\\#{username}"
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ def get_network_id
251
+ super
252
+
253
+ network_data = @connector.value_at('SELECT Domain, Name FROM Win32_ComputerSystem')
254
+ @network_id[:domain] = network_data[:domain]
255
+ @network_id[:hostname] = network_data[:name]
256
+ end
257
+
258
+ def get_network_interfaces
259
+ super
260
+
261
+ # retrieve ethernet interfaces
262
+ ethernet_interfaces = @connector.values_at('SELECT Index, MACAddress, Manufacturer, NetConnectionID, NetConnectionStatus, ProductName FROM Win32_NetworkAdapter WHERE NetConnectionID IS NOT NULL')
263
+
264
+ ethernet_interfaces.each do |interface_profile|
265
+ h = network_interface_template
266
+
267
+ index = interface_profile[:index]
268
+ padded_index = '%04d' % index
269
+ h[:is_uplink] = false
270
+ h[:mac_address] = interface_profile[:macaddress]
271
+ h[:model] = interface_profile[:productname]
272
+ h[:name] = interface_profile[:netconnectionid]
273
+ h[:status] = case interface_profile[:netconnectionstatus]
274
+ when 1, 2; 'up'
275
+ else; 'down'
276
+ end
277
+ h[:type] = 'ethernet'
278
+ h[:vendor] = interface_profile[:manufacturer]
279
+
280
+ # retrieve config for this interface
281
+ interface_config = @connector.value_at("SELECT DNSServerSearchOrder, IPAddress, IPSubnet, SettingID FROM Win32_NetworkAdapterConfiguration WHERE Index = #{index}")
282
+ guid = interface_config[:settingid]
283
+ h[:dns_servers] = interface_config[:dnsserversearchorder]
284
+
285
+ subnet = interface_config[:ipsubnet]
286
+ interface_config[:ipaddress].each do |ip_address|
287
+ h[:ip_addresses] << {:ip_address=>ip_address, :subnet=>subnet}
288
+ end
289
+
290
+ cfg_keypath = NIC_CFG_KEYPATH + "\\#{padded_index}"
291
+
292
+ # retrieve auto negotiate/duplex setting. tricky to get because this is very driver-specific.
293
+ # basically we have some known duplex values in DUPLEX_REG_VALS, then we search in the registry
294
+ # for each value and see if it exists. if it exists, then we dig deeper into the subkeys
295
+ # of this NIC's driver registry key and get the translated value from the list of options
296
+ # (found in the \Enum subkey)
297
+ interface_driver_config = @connector.registry_values_at(cfg_keypath)
298
+ h[:auto_negotiate] = false
299
+ duplex_reg_value = interface_driver_config.select {|key, val| DUPLEX_REG_VALS.include?(key)}
300
+
301
+ if duplex_reg_value.empty?
302
+ h[:auto_negotiate] = true
303
+ h[:duplex] = 'auto'
304
+ else
305
+ duplex_value = @connector.registry_values_at(cfg_keypath + "\\Ndi\\params\\#{duplex_reg_value.keys[0]}\\Enum")
306
+ duplex_value = duplex_value.select{|key, val| key.to_s == duplex_reg_value.values[0].to_s}.values[0]
307
+
308
+ if duplex_value =~ /auto|default/i
309
+ h[:auto_negotiate] = true
310
+ h[:duplex] = 'auto'
311
+ elsif duplex_value =~ /1000|full/i
312
+ h[:duplex] = 'full'
313
+ elsif duplex_value =~ /half/i
314
+ h[:duplex] = 'half'
315
+ end
316
+ end
317
+
318
+ # get model/vendor ids
319
+ hardware_ids = interface_driver_config[:matchingdeviceid].scan(/[ven|dev]_(\d{4})/i)
320
+
321
+ h[:vendor_id] = '0x' + hardware_ids[0].join unless hardware_ids[0].nil?
322
+ h[:model_id] = '0x' + hardware_ids[1].join unless hardware_ids[1].nil?
323
+
324
+ # retrieve mtu
325
+ mtu_data = @connector.registry_values_at(TCPIP_CFG_KEYPATH + "\\#{guid}")
326
+ h[:mtu] = mtu_data[:mtu] if mtu_data.has_key?(:mtu)
327
+
328
+ # translate the adapter guid to it's internal device name (usually prefixed with \\DEVICE)
329
+ device_guid = @connector.registry_values_at(cfg_keypath + '\\Linkage')[:export][0].gsub(/\\/, '\\\\\\')
330
+
331
+ adapter_name_data = @connector.value_at("SELECT InstanceName FROM MSNdis_EnumerateAdapter WHERE DeviceName = '#{device_guid}'", :root_wmi)
332
+ internal_adapter_name = adapter_name_data[:instancename]
333
+
334
+ # now with the internal adapter name, we can grab the connection speed.
335
+ speed_data = @connector.value_at("SELECT NdisLinkSpeed FROM MSNdis_LinkSpeed WHERE InstanceName = '#{internal_adapter_name}'", :root_wmi)
336
+ h[:current_speed_mbps] = speed_data[:ndislinkspeed] / 10000
337
+
338
+ @network_interfaces << h
339
+ end
340
+
341
+ # retrieve fibre channel interfaces. for windows 2003, this only works if the hbaapi is
342
+ # available, which can be installed by the fibre controller software provided by the
343
+ # vendor, or is installed as a separate package (fcinfo from microsoft). newer versions
344
+ # should have it built-in by default.
345
+ fibre_interface_profiles = @connector.values_at('SELECT Attributes, InstanceName FROM MSFC_FibrePortHBAAttributes', :root_wmi)
346
+
347
+ fibre_interfaces = @connector.values_at('SELECT InstanceName, Manufacturer, ModelDescription FROM MSFC_FCAdapterHBAAttributes', :root_wmi)
348
+
349
+ fibre_interfaces.each do |fibre_interface|
350
+ h = network_interface_template
351
+
352
+ index = fibre_interface_profiles.index{|profile| profile[:instancename] == fibre_interface[:instancename]}
353
+ profile = fibre_interface_profiles[index]
354
+
355
+ h[:fabric_name] = profile[:fabricname].to_wwn
356
+
357
+ if h[:fabric_name] == '0000000000000000'
358
+ h[:fabric_name] = nil
359
+ h[:status] = 'down'
360
+ else
361
+ h[:current_speed_mbps] = case profile[:portspeed]
362
+ when 1; 1000
363
+ when 2; 2000
364
+ when 4; 10000
365
+ when 8; 4000
366
+ when 16; 8000
367
+ when 32; 16000
368
+ end
369
+ h[:status] = 'up'
370
+ end
371
+
372
+ hardware_ids = fibre_interface[:instancename].scan(/[ven|dev]_(\d{4})/i)
373
+
374
+ h[:vendor_id] = '0x' + hardware_ids[0].join
375
+ h[:model_id] = '0x' + hardware_ids[1].join
376
+
377
+ h[:is_uplink] = false
378
+ h[:model] = fibre_interface[:modeldescription]
379
+ h[:name] = "fc#{index}"
380
+ h[:node_wwn] = profile[:nodewwn].to_wwn
381
+ h[:port_wwn] = profile[:portwwn].to_wwn
382
+ h[:type] = 'fibre'
383
+ h[:vendor] = fibre_interface[:manufacturer]
384
+
385
+ @network_interfaces << h
386
+ end
387
+ end
388
+
389
+ def get_operating_system
390
+ super
391
+
392
+ os_data = @connector.value_at('SELECT Caption, CSDVersion, InstallDate, OtherTypeDescription, Version FROM Win32_OperatingSystem')
393
+ @operating_system[:date_installed] = DateTime.parse(os_data[:installdate])
394
+ @operating_system[:kernel] = os_data[:version]
395
+ @operating_system[:license_key] = get_product_key('microsoft windows')
396
+ @operating_system[:name] = 'Microsoft Windows'
397
+ @operating_system[:service_pack] = os_data[:csdversion]
398
+
399
+ role_data = @connector.value_at('SELECT Roles FROM Win32_ComputerSystem')
400
+ @operating_system[:roles] = role_data[:roles]
401
+
402
+ os_data[:caption].gsub!(/microsoftr*|windows|(?<=server)r|\(r\)|edition|,/i, '').strip!
403
+ edition = os_data[:othertypedescription]
404
+ os_data[:caption].sub!(/20[0-9]*/) {|y| "#{y} #{edition}"} if edition
405
+
406
+ @operating_system[:version] = os_data[:caption]
407
+ end
408
+
409
+ def get_product_key(app_name, guid=nil)
410
+
411
+ product_key = nil
412
+
413
+ if app_name =~ /microsoft/i
414
+
415
+ app_name.remove_arch
416
+
417
+ case
418
+ when app_name =~ /microsoft exchange/i
419
+
420
+ debug 'attempting to retrieve ms exchange product key'
421
+
422
+ key_path = 'SOFTWARE\Microsoft\Exchange\Setup'
423
+ product_key = @connector.registry_values_at(key_path)[:digitalproductid]
424
+ product_key = product_key.to_ms_product_key unless product_key.nil?
425
+
426
+ when app_name =~ /office/i
427
+
428
+ debug 'attempting to retrieve ms office product key'
429
+
430
+ version_code = case
431
+ when app_name =~ /2003/; 11
432
+ when app_name =~ /2007|server 12/; 12
433
+ when app_name =~ /2010/; 14
434
+ when app_name =~ /2013/; 15
435
+ end
436
+
437
+ key_path = "SOFTWARE\\Microsoft\\Office\\#{version_code}.0\\Registration\\#{guid}"
438
+ product_key = @connector.registry_values_at(key_path)[:digitalproductid]
439
+ product_key = product_key.to_ms_product_key unless product_key.nil?
440
+
441
+ when app_name =~ /sql server/i
442
+
443
+ debug 'attempting to retrieve ms sqlserver product key'
444
+
445
+ app_edition = nil
446
+
447
+ key_path = 'SOFTWARE\Microsoft\Microsoft SQL Server'
448
+
449
+ @connector.registry_subkeys_at(key_path).each do |key|
450
+
451
+ if key =~ /mssql(\.|10|11)/i
452
+
453
+ version_code = case
454
+ when key =~ /_50/i; nil # express edition (use nil to avoid detection of product key)
455
+ when key =~ /mssql\./i; 90 # 2005
456
+ when key =~ /mssql10/i; 100 # 2008
457
+ when key =~ /mssql11/i; 110 # 2012
458
+ end
459
+
460
+ if version_code
461
+ key_path = "#{key_path}\\#{version_code}\\ProductID"
462
+ product_key = @connector.registry_values_at(key_path)[:digitalproductid]
463
+ product_key = product_key.to_ms_product_key unless product_key.nil?
464
+ end
465
+ end
466
+ end
467
+
468
+ when app_name =~ /visual studio/i
469
+
470
+ debug 'attempting to retrieve ms visual studio product key'
471
+
472
+ version_code = case
473
+ when app_name =~ /2005/; 8
474
+ when app_name =~ /2008/; 9
475
+ when app_name =~ /2010/; 10
476
+ when app_name =~ /2012/; 11
477
+ end
478
+
479
+ key_path = "SOFTWARE\\Microsoft\\VisualStudio\\#{version_code}.0\\Registration"
480
+ product_key = @connector.registry_values_at(key_path)[:pidkey]
481
+ product_key = product_key.scan(/.{5}/).join('-') unless product_key.nil?
482
+
483
+ when app_name =~ /^microsoft windows$/i
484
+
485
+ debug 'attempting to retrieve ms windows product key'
486
+
487
+ key_path = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
488
+ product_key = @connector.registry_values_at(key_path)[:digitalproductid]
489
+ product_key = product_key.to_ms_product_key unless product_key.nil?
490
+ end
491
+
492
+ if product_key
493
+ debug 'product key retrieved'
494
+ return product_key
495
+ else
496
+ debug 'product key could not be retrieved'
497
+ end
498
+
499
+ end
500
+ end
501
+
502
+ def get_username(guid)
503
+ username = guid
504
+
505
+ user = @connector.value_at("SELECT Caption, SID FROM Win32_UserAccount WHERE SID = '#{guid}'")
506
+ username = user[:caption] if user[:sid] == guid
507
+
508
+ return username
509
+ end
510
+
511
+ private
512
+
513
+ def concat_app_edition(app_name)
514
+
515
+ case
516
+ when app_name =~ /sql server/i
517
+ # grab the edition (standard, enterprise, etc)
518
+ app_edition = connector.registry_values_at('SOFTWARE\Microsoft\Microsoft SQL Server\Setup')[:edition]
519
+
520
+ app_name = if app_name =~ /\(64\-bit\)/i
521
+ app_name.sub('(64-bit)', "#{app_edition} (64-bit)")
522
+ else
523
+ app_name + " #{app_edition}"
524
+ end unless !app_edition
525
+ end
526
+
527
+ return app_name
528
+ end
529
+ end
530
+ end; end