@syshcndr/attendance 1.0.0
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.
- package/bin/attendance.js +151 -0
- package/package.json +24 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("node:child_process");
|
|
4
|
+
|
|
5
|
+
function printHelp() {
|
|
6
|
+
console.log(`attendance - WLAN SSID attendance checker\n
|
|
7
|
+
Usage:
|
|
8
|
+
attendance [--ssid <SSID_NAME>] [--start YYYY-MM-DD]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--ssid SSID name to match in WLAN AutoConfig logs. Default: Sapiens-Corporate
|
|
12
|
+
--start Start date in YYYY-MM-DD format. Default: 2026-01-01
|
|
13
|
+
--help Show this help.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
attendance --ssid "Sapiens-Corporate" --start 2026-01-01`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parseArgs(argv) {
|
|
20
|
+
const args = {
|
|
21
|
+
ssid: "Sapiens-Corporate",
|
|
22
|
+
start: "2026-01-01",
|
|
23
|
+
help: false,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
27
|
+
const token = argv[i];
|
|
28
|
+
|
|
29
|
+
if (token === "--help" || token === "-h") {
|
|
30
|
+
args.help = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (token === "--ssid") {
|
|
35
|
+
args.ssid = argv[i + 1];
|
|
36
|
+
i += 1;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (token === "--start") {
|
|
41
|
+
args.start = argv[i + 1];
|
|
42
|
+
i += 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return args;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function validateDate(dateText) {
|
|
51
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(dateText);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function escapeForSingleQuotedPsString(value) {
|
|
55
|
+
return String(value).replace(/'/g, "''");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getAttendanceDates({ ssid, start }) {
|
|
59
|
+
const safeSsid = escapeForSingleQuotedPsString(ssid);
|
|
60
|
+
const safeStart = escapeForSingleQuotedPsString(start);
|
|
61
|
+
|
|
62
|
+
const psScript = `
|
|
63
|
+
$ErrorActionPreference = 'Stop'
|
|
64
|
+
$ssid='${safeSsid}'
|
|
65
|
+
$start=[datetime]'${safeStart}'
|
|
66
|
+
|
|
67
|
+
$rows = Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-WLAN-AutoConfig/Operational'; StartTime=$start; Id=8001} |
|
|
68
|
+
Where-Object { $_.Message -like ('*' + $ssid + '*') } |
|
|
69
|
+
Sort-Object TimeCreated |
|
|
70
|
+
Select-Object @{n='Date';e={$_.TimeCreated.ToString('yyyy-MM-dd')}} -Unique
|
|
71
|
+
|
|
72
|
+
$rows | ConvertTo-Json -Compress
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
const result = spawnSync(
|
|
76
|
+
"powershell",
|
|
77
|
+
["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", psScript],
|
|
78
|
+
{
|
|
79
|
+
encoding: "utf8",
|
|
80
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (result.error) {
|
|
85
|
+
throw result.error;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (result.status !== 0) {
|
|
89
|
+
const stderr = (result.stderr || "").trim();
|
|
90
|
+
throw new Error(stderr || "PowerShell command failed.");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const stdout = (result.stdout || "").trim();
|
|
94
|
+
if (!stdout) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let parsed;
|
|
99
|
+
try {
|
|
100
|
+
parsed = JSON.parse(stdout);
|
|
101
|
+
} catch {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const rows = Array.isArray(parsed) ? parsed : [parsed];
|
|
106
|
+
return rows.map((r) => r.Date).filter(Boolean);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function printResult(ssid, start, dates) {
|
|
110
|
+
console.log(`SSID : ${ssid}`);
|
|
111
|
+
console.log(`Start Date : ${start}`);
|
|
112
|
+
console.log("");
|
|
113
|
+
|
|
114
|
+
if (dates.length === 0) {
|
|
115
|
+
console.log("No attendance days found.");
|
|
116
|
+
console.log("Total Days: 0");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (const date of dates) {
|
|
121
|
+
console.log(date);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log("");
|
|
125
|
+
console.log(`Total Days: ${dates.length}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function main() {
|
|
129
|
+
const args = parseArgs(process.argv.slice(2));
|
|
130
|
+
|
|
131
|
+
if (args.help) {
|
|
132
|
+
printHelp();
|
|
133
|
+
process.exit(0);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!validateDate(args.start)) {
|
|
137
|
+
console.error("Error: --start must be in YYYY-MM-DD format.");
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const dates = getAttendanceDates({ ssid: args.ssid, start: args.start });
|
|
143
|
+
printResult(args.ssid, args.start, dates);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error("Failed to fetch attendance from Windows event logs.");
|
|
146
|
+
console.error(error.message || String(error));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@syshcndr/attendance",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI to list attendance days from Windows WLAN AutoConfig logs for a specific SSID",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"attendance": "./bin/attendance.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"start": "node ./bin/attendance.js"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"attendance",
|
|
18
|
+
"wlan",
|
|
19
|
+
"windows",
|
|
20
|
+
"cli"
|
|
21
|
+
],
|
|
22
|
+
"author": "",
|
|
23
|
+
"license": "MIT"
|
|
24
|
+
}
|