diff --git a/CHANGELOG.md b/CHANGELOG.md
index f93bac3..68086ca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -77,6 +77,7 @@ For major (breaking) changes - **version 4, 3 and 2** - see end of page.
| Version | Date | Comment |
| -------------- | -------------- | -------- |
+| 5.7.0 | 2021-05-20 | `diskLayout()` added smartdata for win (if istalled) |
| 5.6.22 | 2021-05-18 | `diskLayout()` fixed to small buffer smartdata (linux) |
| 5.6.21 | 2021-05-14 | `graphics()` fixed dual gpu issue (macOS) |
| 5.6.20 | 2021-05-07 | `system()` fixed vm detection (linux) |
diff --git a/README.md b/README.md
index e22ef15..c3f2d50 100644
--- a/README.md
+++ b/README.md
@@ -103,6 +103,7 @@ si.cpu()
(last 7 major and minor version releases)
+- Version 5.7.0: `diskLayout()` added S.M.A.R.T for Windows (if installed)
- Version 5.6.0: `cpuTemperature()` added added socket and chipset temp (linux)
- Version 5.5.0: `dockerVolumes()` added
- Version 5.4.0: `dockerImages()` added
@@ -424,7 +425,7 @@ Full function reference with examples can be found at [https://systeminformation
| | [0].interfaceType | X | | | X | | SATA, PCIe, ... |
| | [0].smartStatus | X | | X | X | | S.M.A.R.T Status (see Known Issues) |
| | [0].temperature | X | | | | | S.M.A.R.T temperature |
-| | [0].smartData | X | | | | | full S.M.A.R.T data from smartctl requires at least smartmontools 7.0 |
+| | [0].smartData | X | | | X | | full S.M.A.R.T data from smartctl requires at least smartmontools 7.0 |
| si.blockDevices(cb) | [{...}] | X | | X | X | | returns array of disks, partitions, raids and roms |
| | [0].name | X | | X | X | | name |
| | [0].type | X | | X | X | | type |
diff --git a/docs/filesystem.html b/docs/filesystem.html
index 0dea89d..be7ff5f 100644
--- a/docs/filesystem.html
+++ b/docs/filesystem.html
@@ -252,7 +252,7 @@
X
-
+ X
full S.M.A.R.T data from smartctl requires at least smartmontools 7.0 (see Known Issues)
@@ -286,8 +286,8 @@ si.diskLayout().then(data => console.log(data));
smartctl: [Object],
device: [Object],
model_name: 'SAMSUNG xxxxxxxxxxxx-xxxx',
- serial_number: '...serial....',
- ...
+ serial_number: '...serial....', // full structure
+ ... // see index.d.ts
}
},
{
diff --git a/docs/history.html b/docs/history.html
index 9f0562f..eb768fe 100644
--- a/docs/history.html
+++ b/docs/history.html
@@ -56,6 +56,11 @@
+
+ 5.7.0
+ 2021-05-20
+ diskLayout() added smartdata fro Windows (if installed)
+
5.6.22
2021-05-18
diff --git a/docs/index.html b/docs/index.html
index 4603855..b40657e 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -170,7 +170,7 @@
systeminformation
- New Version: 5.6.22
+ New Version: 5.7.0
View on Github
@@ -211,7 +211,7 @@
Downloads last month
diff --git a/lib/filesystem.js b/lib/filesystem.js
index 9f1a029..b10f255 100755
--- a/lib/filesystem.js
+++ b/lib/filesystem.js
@@ -13,11 +13,13 @@
// 8. File System
// ----------------------------------------------------------------------------------
-const exec = require('child_process').exec;
-const execSync = require('child_process').execSync;
const util = require('./util');
const fs = require('fs');
+const exec = require('child_process').exec;
+const execSync = require('child_process').execSync;
+const execPromiseSave = util.promisifySave(require('child_process').exec);
+
let _platform = process.platform;
const _linux = (_platform === 'linux');
@@ -1114,8 +1116,25 @@ function diskLayout(callback) {
}
if (_windows) {
try {
- util.wmic('diskdrive get /value').then((stdout) => {
- let devices = stdout.toString().split(/\n\s*\n/);
+ const workload = [];
+ workload.push(util.wmic('diskdrive get /value'));
+ workload.push(util.powerShell('Get-PhysicalDisk | Format-List'));
+ if (util.smartMonToolsInstalled()) {
+ try {
+ const smartDev = JSON.parse(execSync('smartctl --scan -j'));
+ if (smartDev && smartDev.devices && smartDev.devices.length > 0) {
+ smartDev.devices.forEach((dev) => {
+ workload.push(execPromiseSave(`smartctl -j -a ${dev.name}`, util.execOptsWin));
+ });
+ }
+ } catch (e) {
+ util.noop();
+ }
+ }
+ util.promiseAll(
+ workload
+ ).then(data => {
+ let devices = data.results[0].toString().split(/\n\s*\n/);
devices.forEach(function (device) {
let lines = device.split('\r\n');
const size = util.getValue(lines, 'Size', '=').trim();
@@ -1125,7 +1144,7 @@ function diskLayout(callback) {
device: util.getValue(lines, 'PNPDeviceId', '='),
type: device.indexOf('SSD') > -1 ? 'SSD' : 'HD', // just a starting point ... better: MSFT_PhysicalDisk - Media Type ... see below
name: util.getValue(lines, 'Caption', '='),
- vendor: util.getValue(lines, 'Manufacturer', '='),
+ vendor: getVendorFromModel(util.getValue(lines, 'Caption', '=', true).trim()),
size: parseInt(size),
bytesPerSector: parseInt(util.getValue(lines, 'BytesPerSector', '=')),
totalCylinders: parseInt(util.getValue(lines, 'TotalCylinders', '=')),
@@ -1142,43 +1161,51 @@ function diskLayout(callback) {
});
}
});
- util.powerShell('Get-PhysicalDisk | Format-List')
- .then(data => {
- let devices = data.split(/\n\s*\n/);
- devices.forEach(function (device) {
- let lines = device.split('\r\n');
- const serialNum = util.getValue(lines, 'SerialNumber', ':').trim();
- const name = util.getValue(lines, 'FriendlyName', ':').trim().replace('Msft ', 'Microsoft');
- const size = util.getValue(lines, 'Size', ':').trim();
- const model = util.getValue(lines, 'Model', ':').trim();
- const interfaceType = util.getValue(lines, 'BusType', ':').trim();
- let mediaType = util.getValue(lines, 'MediaType', ':').trim();
- if (mediaType === '3' || mediaType === 'HDD') { mediaType = 'HD'; }
- if (mediaType === '4') { mediaType = 'SSD'; }
- if (mediaType === '5') { mediaType = 'SCM'; }
- if (mediaType === 'Unspecified' && (model.toLowerCase().indexOf('virtual') > -1 || model.toLowerCase().indexOf('vbox') > -1)) { mediaType = 'Virtual'; }
- if (size) {
- let i = util.findObjectByKey(result, 'serialNum', serialNum);
- if (i === -1 || serialNum === '') {
- i = util.findObjectByKey(result, 'name', name);
- }
- if (i != -1) {
- result[i].type = mediaType;
- result[i].interfaceType = interfaceType;
- }
+ devices = data.results[1].split(/\n\s*\n/);
+ devices.forEach(function (device) {
+ let lines = device.split('\r\n');
+ const serialNum = util.getValue(lines, 'SerialNumber', ':').trim();
+ const name = util.getValue(lines, 'FriendlyName', ':').trim().replace('Msft ', 'Microsoft');
+ const size = util.getValue(lines, 'Size', ':').trim();
+ const model = util.getValue(lines, 'Model', ':').trim();
+ const interfaceType = util.getValue(lines, 'BusType', ':').trim();
+ let mediaType = util.getValue(lines, 'MediaType', ':').trim();
+ if (mediaType === '3' || mediaType === 'HDD') { mediaType = 'HD'; }
+ if (mediaType === '4') { mediaType = 'SSD'; }
+ if (mediaType === '5') { mediaType = 'SCM'; }
+ if (mediaType === 'Unspecified' && (model.toLowerCase().indexOf('virtual') > -1 || model.toLowerCase().indexOf('vbox') > -1)) { mediaType = 'Virtual'; }
+ if (size) {
+ let i = util.findObjectByKey(result, 'serialNum', serialNum);
+ if (i === -1 || serialNum === '') {
+ i = util.findObjectByKey(result, 'name', name);
+ }
+ if (i != -1) {
+ result[i].type = mediaType;
+ result[i].interfaceType = interfaceType;
+ }
+ }
+ });
+ // S.M.A.R.T
+ data.results.shift();
+ data.results.shift();
+ data.results.forEach((smartStr) => {
+ const smartData = JSON.parse(smartStr);
+ if (smartData.serial_number) {
+ const serialNum = smartData.serial_number;
+ let i = util.findObjectByKey(result, 'serialNum', serialNum);
+ if (i != -1) {
+ result[i].smartStatus = (smartData.smart_status.passed ? 'Ok' : (smartData.smart_status.passed === false ? 'Predicted Failure' : 'unknown'));
+ if (smartData.temperature && smartData.temperature.current) {
+ result[i].temperature = smartData.temperature.current;
}
- });
- if (callback) {
- callback(result);
+ result[i].smartData = smartData;
}
- resolve(result);
- })
- .catch(() => {
- if (callback) {
- callback(result);
- }
- resolve(result);
- });
+ }
+ });
+ if (callback) {
+ callback(result);
+ }
+ resolve(result);
});
} catch (e) {
if (callback) { callback(result); }
diff --git a/lib/index.d.ts b/lib/index.d.ts
index 30b2530..e72dc39 100644
--- a/lib/index.d.ts
+++ b/lib/index.d.ts
@@ -138,6 +138,7 @@ export namespace Systeminformation {
}
interface SmartData {
+ json_format_version: number[];
smartctl: {
version: number[];
platform_info: string;
@@ -145,17 +146,23 @@ export namespace Systeminformation {
argv: string[];
exit_status: number;
};
- json_format_version: number[];
device: {
name: string;
info_name: string;
type: string;
protocol: string;
}
+ model_family?: string,
+ model_name?: string,
+ serial_number?: string,
+ firmware_version?: string,
smart_status: {
passed: boolean;
}
- ata_smart_attributes: {
+ trim?: {
+ supported: boolean
+ },
+ ata_smart_attributes?: {
revision: number;
table: {
id: number;
@@ -177,20 +184,13 @@ export namespace Systeminformation {
raw: { value: number; string: string }
}[];
};
- power_on_time: {
- hours: number;
- };
- power_cycle_count: number;
- temperature: {
- current: number;
- };
- ata_smart_error_log: {
+ ata_smart_error_log?: {
summary: {
revision: number;
count: number;
};
};
- ata_smart_self_test_log: {
+ ata_smart_self_test_log?: {
standard: {
revision: number;
table: {
@@ -210,6 +210,42 @@ export namespace Systeminformation {
error_count_outdated: number;
};
}
+ nvme_pci_vendor?: {
+ id: number,
+ subsystem_id: number
+ },
+ nvme_smart_health_information_log?: {
+ critical_warning?: number,
+ temperature?: number,
+ available_spare?: number,
+ available_spare_threshold?: number,
+ percentage_used?: number,
+ data_units_read?: number,
+ data_units_written?: number,
+ host_reads?: number,
+ host_writes?: number,
+ controller_busy_time?: number,
+ power_cycles?: number,
+ power_on_hours?: number,
+ unsafe_shutdowns?: number,
+ media_errors?: number,
+ num_err_log_entries?: number,
+ warning_temp_time?: number,
+ critical_comp_time?: number,
+ temperature_sensors?: number[]
+ },
+ user_capacity?: {
+ blocks: number,
+ bytes: number
+ },
+ logical_block_size?: number,
+ temperature: {
+ current: number;
+ };
+ power_cycle_count: number;
+ power_on_time: {
+ hours: number;
+ };
}
interface DiskLayoutData {
diff --git a/lib/util.js b/lib/util.js
index 6b6d5c2..b4c1029 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -33,6 +33,7 @@ const _netbsd = (_platform === 'netbsd');
let _cores = 0;
let wmicPath = '';
let codepage = '';
+let _smartMonToolsInstalled = null;
const WINDIR = process.env.WINDIR || 'C:\\Windows';
@@ -458,6 +459,30 @@ function getCodepage() {
}
}
+function smartMonToolsInstalled() {
+ if (_smartMonToolsInstalled !== null) {
+ return _smartMonToolsInstalled;
+ }
+ _smartMonToolsInstalled = false;
+ if (_windows) {
+ try {
+ const pathArray = execSync('WHERE smartctl 2>nul', execOptsWin).toString().split('\r\n');
+ if (pathArray && pathArray.length) {
+ _smartMonToolsInstalled = pathArray[0].indexOf(':\\') >= 0;
+ } else {
+ _smartMonToolsInstalled = false;
+ }
+ } catch (e) {
+ _smartMonToolsInstalled = false;
+ }
+ }
+ if (_linux || _darwin || _freebsd || _openbsd || _netbsd) {
+ const pathArray = execSync('which smartctl 2>/dev/null', execOptsWin).toString().split('\r\n');
+ _smartMonToolsInstalled = pathArray.length > 0;
+ }
+ return _smartMonToolsInstalled;
+}
+
function isRaspberry() {
const PI_MODEL_NO = [
'BCM2708',
@@ -931,6 +956,18 @@ function promisify(nodeStyleFunction) {
};
}
+function promisifySave(nodeStyleFunction) {
+ return function () {
+ var args = Array.prototype.slice.call(arguments);
+ return new Promise(function (resolve) {
+ args.push(function (err, data) {
+ resolve(data);
+ });
+ nodeStyleFunction.apply(null, args);
+ });
+ };
+}
+
function linuxVersion() {
let result = '';
if (_linux) {
@@ -975,6 +1012,8 @@ exports.isPrototypePolluted = isPrototypePolluted;
exports.decodePiCpuinfo = decodePiCpuinfo;
exports.promiseAll = promiseAll;
exports.promisify = promisify;
+exports.promisifySave = promisifySave;
+exports.smartMonToolsInstalled = smartMonToolsInstalled;
exports.linuxVersion = linuxVersion;
exports.stringReplace = stringReplace;
exports.stringToLower = stringToLower;