Skip to content

Commit 51e4a47

Browse files
fixup net_localgroup parser
1 parent 883f0c9 commit 51e4a47

File tree

3 files changed

+190
-23
lines changed

3 files changed

+190
-23
lines changed

CHANGELOG

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
jc changelog
22

33
20250904 v1.25.6
4-
- Add `x509-crl` file parser to support Certificate Revocation List PEM and DER files
4+
- Add `net-localgroup` Windows command parser
5+
- Add `net-user` Windows command parser
56
- Add `route-print` Windows command parser
7+
- Add `x509-crl` file parser to support Certificate Revocation List PEM and DER files
68
- Fix `bluetoothctl` command parser to support output with the `cable_pairing` attribute
79
- Fix `nmcli` command parser to support blank `team.config` JSON value and `team-port.config` JSON value
810
- Fix `top` command parsers to correct memory size field parsing. Several new unit

jc/parsers/net_localgroup.py

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
r"""jc - JSON Convert `net localgroup` command output parser
22
3-
43
Usage (cli):
54
6-
$ net localgroup | jc --net-localgroup -p
7-
$ net localgroup /domain | jc --net-localgroup -p
8-
$ net localgroup Administrators | jc --net-localgroup -p
9-
$ net localgroup Administrators /domain | jc --net-localgroup -p
5+
$ net localgroup | jc --net-localgroup
6+
$ net localgroup /domain | jc --net-localgroup
7+
$ net localgroup Administrators | jc --net-localgroup
8+
$ net localgroup Administrators /domain | jc --net-localgroup
109
1110
Usage (module):
1211
@@ -29,15 +28,6 @@
2928
],
3029
}
3130
32-
33-
Notes:
34-
[0] - 'lease_expires' and 'lease_obtained' are parsed to ISO8601 format date strings. if the value was unable
35-
to be parsed by datetime, the fields will be in their raw form
36-
[1] - 'autoconfigured' under 'ipv4_address' is only providing indication if the ipv4 address was labeled as
37-
"Autoconfiguration IPv4 Address" vs "IPv4 Address". It does not infer any information from other fields
38-
[2] - Windows XP uses 'IP Address' instead of 'IPv4 Address'. Both values are parsed to the 'ipv4_address'
39-
object for consistency
40-
4131
Examples:
4232
4333
$ net localgroup | jc --net-localgroup -p
@@ -57,12 +47,7 @@
5747
}
5848
]
5949
}
60-
$ net localgroup Administrators | jc --net-localgroup -p
61-
$ net localgroup /domain | jc --net-localgroup -p
62-
6350
"""
64-
65-
from datetime import datetime
6651
import re
6752
import jc.utils
6853

@@ -73,7 +58,7 @@ class info():
7358
description = '`net localgroup` command parser'
7459
author = 'joehacksalot'
7560
author_email = 'joehacksalot@gmail.com'
76-
compatible = ['windows']
61+
compatible = ['win32']
7762
magic_commands = ['net localgroup']
7863
tags = ['command']
7964

@@ -117,7 +102,7 @@ def _process(proc_data):
117102
118103
Processed Dictionary. Structured data to conform to the schema.
119104
"""
120-
return proc_data # No further processing is needed
105+
return proc_data
121106

122107

123108
class _PushbackIterator:
@@ -176,7 +161,7 @@ def _parse(data):
176161
# Skip empty lines
177162
if not line.strip():
178163
continue
179-
164+
180165
match_domain_processed = re.match(r"^The request will be processed at a domain controller for domain (.+)", line, re.IGNORECASE)
181166
match_localgroup_list = re.match(r"^Aliases for[\s]*([^:]+)", line, re.IGNORECASE) # "Aliases for \\DESKTOP-WIN11:"
182167
match_localgroup_members = re.match(r"^Alias name[\s]*([^:]+)", line, re.IGNORECASE) # "Alias name administrators:"
@@ -205,4 +190,5 @@ def _parse(data):
205190
"name": group_name,
206191
"members": names_list
207192
}]
193+
208194
return result

tests/test_net_localgroup2.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import os
2+
import unittest
3+
import json
4+
from typing import Dict
5+
from jc.parsers.net_localgroup import parse
6+
7+
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
8+
9+
10+
class MyTests(unittest.TestCase):
11+
f_in: Dict = {}
12+
f_json: Dict = {}
13+
14+
@classmethod
15+
def setUpClass(cls):
16+
fixtures = {
17+
'windows_xp_net_localgroup': (
18+
'fixtures/windows/windows-xp/net_localgroup.out',
19+
'fixtures/windows/windows-xp/net_localgroup.json'),
20+
'windows_xp_net_localgroup_administrators': (
21+
'fixtures/windows/windows-xp/net_localgroup.administrators.out',
22+
'fixtures/windows/windows-xp/net_localgroup.administrators.json'),
23+
'windows_7_net_localgroup': (
24+
'fixtures/windows/windows-7/net_localgroup.out',
25+
'fixtures/windows/windows-7/net_localgroup.json'),
26+
'windows_7_net_localgroup_administrators': (
27+
'fixtures/windows/windows-7/net_localgroup.administrators.out',
28+
'fixtures/windows/windows-7/net_localgroup.administrators.json'),
29+
'windows_2008_net_localgroup': (
30+
'fixtures/windows/windows-2008/net_localgroup.out',
31+
'fixtures/windows/windows-2008/net_localgroup.json'),
32+
'windows_2008_net_localgroup_administrators': (
33+
'fixtures/windows/windows-2008/net_localgroup.administrators.out',
34+
'fixtures/windows/windows-2008/net_localgroup.administrators.json'),
35+
'windows_2016_net_localgroup': (
36+
'fixtures/windows/windows-2016/net_localgroup.out',
37+
'fixtures/windows/windows-2016/net_localgroup.json'),
38+
'windows_2016_net_localgroup_administrators': (
39+
'fixtures/windows/windows-2016/net_localgroup.administrators.out',
40+
'fixtures/windows/windows-2016/net_localgroup.administrators.json'),
41+
'windows_10_net_localgroup': (
42+
'fixtures/windows/windows-10/net_localgroup.out',
43+
'fixtures/windows/windows-10/net_localgroup.json'),
44+
'windows_10_net_localgroup_administrators': (
45+
'fixtures/windows/windows-10/net_localgroup.administrators.out',
46+
'fixtures/windows/windows-10/net_localgroup.administrators.json'),
47+
'windows_11_net_localgroup': (
48+
'fixtures/windows/windows-11/net_localgroup.out',
49+
'fixtures/windows/windows-11/net_localgroup.json'),
50+
'windows_11_net_localgroup_administrators': (
51+
'fixtures/windows/windows-11/net_localgroup.administrators.out',
52+
'fixtures/windows/windows-11/net_localgroup.administrators.json'),
53+
}
54+
55+
for file, filepaths in fixtures.items():
56+
with open(os.path.join(THIS_DIR, filepaths[0]), 'r', encoding='utf-8') as a, \
57+
open(os.path.join(THIS_DIR, filepaths[1]), 'r', encoding='utf-8') as b:
58+
cls.f_in[file] = a.read()
59+
cls.f_json[file] = json.loads(b.read())
60+
61+
62+
def test_net_localgroup_nodata(self):
63+
"""
64+
Test 'net_localgroup' with no data
65+
"""
66+
self.assertEqual(parse('', quiet=True), {})
67+
68+
69+
def test_net_localgroup_windows_xp(self):
70+
"""
71+
Test 'net_localgroup' on Windows XP
72+
"""
73+
self.assertEqual(
74+
parse(self.f_in['windows_xp_net_localgroup'], quiet=True),
75+
self.f_json['windows_xp_net_localgroup']
76+
)
77+
78+
def test_net_localgroup_administrators_windows_xp(self):
79+
"""
80+
Test 'net_localgroup' administrators on Windows XP
81+
"""
82+
self.assertEqual(
83+
parse(self.f_in['windows_xp_net_localgroup_administrators'], quiet=True),
84+
self.f_json['windows_xp_net_localgroup_administrators']
85+
)
86+
87+
def test_net_localgroup_windows_7(self):
88+
"""
89+
Test 'net_localgroup' on Windows 7
90+
"""
91+
self.assertEqual(
92+
parse(self.f_in['windows_7_net_localgroup'], quiet=True),
93+
self.f_json['windows_7_net_localgroup']
94+
)
95+
96+
def test_net_localgroup_administrators_windows_7(self):
97+
"""
98+
Test 'net_localgroup' administrators on Windows 7
99+
"""
100+
self.assertEqual(
101+
parse(self.f_in['windows_7_net_localgroup_administrators'], quiet=True),
102+
self.f_json['windows_7_net_localgroup_administrators']
103+
)
104+
105+
def test_net_localgroup_windows_2008(self):
106+
"""
107+
Test 'net_localgroup' on Windows 2008
108+
"""
109+
self.assertEqual(
110+
parse(self.f_in['windows_2008_net_localgroup'], quiet=True),
111+
self.f_json['windows_2008_net_localgroup']
112+
)
113+
114+
def test_net_localgroup_administrators_windows_2008(self):
115+
"""
116+
Test 'net_localgroup' administrators on Windows 2008
117+
"""
118+
self.assertEqual(
119+
parse(self.f_in['windows_2008_net_localgroup_administrators'], quiet=True),
120+
self.f_json['windows_2008_net_localgroup_administrators']
121+
)
122+
123+
def test_net_localgroup_windows_2016(self):
124+
"""
125+
Test 'net_localgroup' on Windows 2016
126+
"""
127+
self.assertEqual(
128+
parse(self.f_in['windows_2016_net_localgroup'], quiet=True),
129+
self.f_json['windows_2016_net_localgroup']
130+
)
131+
132+
def test_net_localgroup_administrators_windows_2016(self):
133+
"""
134+
Test 'net_localgroup' administrators on Windows 2016
135+
"""
136+
self.assertEqual(
137+
parse(self.f_in['windows_2016_net_localgroup_administrators'], quiet=True),
138+
self.f_json['windows_2016_net_localgroup_administrators']
139+
)
140+
141+
def test_net_localgroup_windows_10(self):
142+
"""
143+
Test 'net_localgroup' on Windows 10
144+
"""
145+
self.assertEqual(
146+
parse(self.f_in['windows_10_net_localgroup'], quiet=True),
147+
self.f_json['windows_10_net_localgroup']
148+
)
149+
150+
def test_net_localgroup_administrators_windows_10(self):
151+
"""
152+
Test 'net_localgroup' administrators on Windows 10
153+
"""
154+
self.assertEqual(
155+
parse(self.f_in['windows_10_net_localgroup_administrators'], quiet=True),
156+
self.f_json['windows_10_net_localgroup_administrators']
157+
)
158+
159+
def test_net_localgroup_windows_11(self):
160+
"""
161+
Test 'net_localgroup' on Windows 11
162+
"""
163+
self.assertEqual(
164+
parse(self.f_in['windows_11_net_localgroup'], quiet=True),
165+
self.f_json['windows_11_net_localgroup']
166+
)
167+
168+
def test_net_localgroup_administrators_windows_11(self):
169+
"""
170+
Test 'net_localgroup' administrators on Windows 11
171+
"""
172+
self.assertEqual(
173+
parse(self.f_in['windows_11_net_localgroup_administrators'], quiet=True),
174+
self.f_json['windows_11_net_localgroup_administrators']
175+
)
176+
177+
178+
if __name__ == '__main__':
179+
unittest.main()

0 commit comments

Comments
 (0)