boris 1.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.md +9 -0
- data/README.md +94 -0
- data/boris.gemspec +28 -0
- data/doc/Array.html +437 -0
- data/doc/Boris.html +230 -0
- data/doc/Boris/ConnectionAlreadyActive.html +123 -0
- data/doc/Boris/ConnectionFailed.html +127 -0
- data/doc/Boris/Connector.html +794 -0
- data/doc/Boris/InvalidCredentials.html +131 -0
- data/doc/Boris/InvalidOption.html +123 -0
- data/doc/Boris/InvalidTargetName.html +123 -0
- data/doc/Boris/Lumberjack.html +466 -0
- data/doc/Boris/MissingCredentials.html +123 -0
- data/doc/Boris/NoActiveConnection.html +123 -0
- data/doc/Boris/NoProfileDetected.html +123 -0
- data/doc/Boris/Options.html +783 -0
- data/doc/Boris/Profiles.html +117 -0
- data/doc/Boris/Profiles/Linux.html +1151 -0
- data/doc/Boris/Profiles/RedHat.html +875 -0
- data/doc/Boris/Profiles/Solaris.html +1230 -0
- data/doc/Boris/Profiles/Structure.html +2050 -0
- data/doc/Boris/Profiles/UNIX.html +893 -0
- data/doc/Boris/Profiles/Windows.html +1846 -0
- data/doc/Boris/Profiles/Windows/Windows2003.html +304 -0
- data/doc/Boris/Profiles/Windows/Windows2008.html +379 -0
- data/doc/Boris/Profiles/Windows/Windows2012.html +304 -0
- data/doc/Boris/SNMPConnector.html +512 -0
- data/doc/Boris/SSHConnector.html +633 -0
- data/doc/Boris/Target.html +2002 -0
- data/doc/Boris/WMIConnector.html +1134 -0
- data/doc/BorisLogger.html +217 -0
- data/doc/Hash.html +195 -0
- data/doc/String.html +1246 -0
- data/doc/_index.html +420 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +328 -0
- data/doc/file.README.html +183 -0
- data/doc/file_list.html +55 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +183 -0
- data/doc/js/app.js +214 -0
- data/doc/js/full_list.js +173 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +1468 -0
- data/doc/top-level-namespace.html +126 -0
- data/lib/boris.rb +30 -0
- data/lib/boris/connectors.rb +47 -0
- data/lib/boris/connectors/snmp.rb +56 -0
- data/lib/boris/connectors/ssh.rb +110 -0
- data/lib/boris/connectors/wmi.rb +186 -0
- data/lib/boris/errors.rb +17 -0
- data/lib/boris/helpers/array.rb +63 -0
- data/lib/boris/helpers/constants.rb +20 -0
- data/lib/boris/helpers/hash.rb +8 -0
- data/lib/boris/helpers/scrubber.rb +51 -0
- data/lib/boris/helpers/string.rb +130 -0
- data/lib/boris/lumberjack.rb +47 -0
- data/lib/boris/options.rb +86 -0
- data/lib/boris/profiles/linux/redhat.rb +77 -0
- data/lib/boris/profiles/linux_core.rb +216 -0
- data/lib/boris/profiles/unix/solaris.rb +307 -0
- data/lib/boris/profiles/unix_core.rb +85 -0
- data/lib/boris/profiles/windows/windows2003.rb +15 -0
- data/lib/boris/profiles/windows/windows2008.rb +23 -0
- data/lib/boris/profiles/windows/windows2012.rb +15 -0
- data/lib/boris/profiles/windows_core.rb +530 -0
- data/lib/boris/structure.rb +167 -0
- data/lib/boris/target.rb +340 -0
- data/test/connector_tests/test_snmp.rb +35 -0
- data/test/connector_tests/test_ssh.rb +51 -0
- data/test/connector_tests/test_wmi.rb +129 -0
- data/test/helper_tests/test_array.rb +25 -0
- data/test/helper_tests/test_hash.rb +10 -0
- data/test/helper_tests/test_string.rb +136 -0
- data/test/profile_tests/test_core_skeleton +107 -0
- data/test/profile_tests/test_linux_core.rb +331 -0
- data/test/profile_tests/test_redhat.rb +134 -0
- data/test/profile_tests/test_solaris.rb +523 -0
- data/test/profile_tests/test_unix_core.rb +117 -0
- data/test/profile_tests/test_windows.rb +536 -0
- data/test/setup_tests.rb +14 -0
- data/test/test_all.rb +8 -0
- data/test/test_options.rb +44 -0
- data/test/test_structure.rb +136 -0
- data/test/test_target.rb +146 -0
- 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
|