v2.3
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import re, json, sys, io
|
||||
from openpyxl import load_workbook
|
||||
from unidecode import unidecode
|
||||
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
ps = open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\audit_check_script\audit_cis_windows.ps1', 'r', encoding='utf-8').read()
|
||||
|
||||
# Strategy: find ALL lines with Write-CheckResult, regardless of conditional context
|
||||
# Also handle the case where IsDomain branches produce different descriptions
|
||||
|
||||
all_checks = []
|
||||
|
||||
# Find all Write-CheckResult calls - including those inside conditionals
|
||||
for m in re.finditer(r'Write-CheckResult\s+"([^"]+)"\s+"([^"]+)"', ps):
|
||||
check_id = m.group(1)
|
||||
desc = m.group(2)
|
||||
if not check_id.startswith('$'):
|
||||
all_checks.append((check_id, desc))
|
||||
|
||||
print(f'Direct calls (no variables): {len(all_checks)}')
|
||||
|
||||
# Now expand variable-based calls from Test-FirewallProfile and Test-EventLogPolicy
|
||||
fw_calls = re.findall(r'Test-FirewallProfile\s+"(\w+)"\s+"([\d.]+)"\s+"(\w+)"', ps)
|
||||
for profile, prefix, label in fw_calls:
|
||||
all_checks.append((f'{prefix}.1', f"Thiet lap trang thai 'Windows Firewall: {label} : Firewall state'"))
|
||||
all_checks.append((f'{prefix}.2', f"Thiet lap trang thai 'Windows Firewall: {label} : Inbound connections'"))
|
||||
all_checks.append((f'{prefix}.3', f"Thiet lap trang thai 'Windows Firewall: {label} : Outbound connections'"))
|
||||
|
||||
log_calls = re.findall(r'Test-EventLogPolicy\s+"(\w+)"\s+"([\d.]+)"\s+"(\w+)"', ps)
|
||||
for logname, prefix, label in log_calls:
|
||||
all_checks.append((f'{prefix}.1', f"Thiet lap chinh sach '{label} : Control Event Log behavior when the log file reaches its maximum size'"))
|
||||
all_checks.append((f'{prefix}.2', f"Thiet lap chinh sach '{label} : Specify the maximum log file size (KB)'"))
|
||||
|
||||
# Build criteria list, removing duplicates (same CheckId + same Description)
|
||||
seen = set()
|
||||
criteria_unique = []
|
||||
for cid, desc in all_checks:
|
||||
key = (cid, desc)
|
||||
if key not in seen:
|
||||
seen.add(key)
|
||||
criteria_unique.append((cid, desc))
|
||||
|
||||
criteria = criteria_unique
|
||||
print(f'Total unique criteria: {len(criteria)}')
|
||||
|
||||
# Build ps_criteria lookup
|
||||
ps_criteria = {}
|
||||
for cid, desc in criteria:
|
||||
full = f"{cid}. {desc}"
|
||||
key = unidecode(full)
|
||||
ps_criteria[key] = full
|
||||
|
||||
# Load Excel
|
||||
wb = load_workbook(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\Windows_Checklist.xlsx')
|
||||
ws = wb.worksheets[0]
|
||||
|
||||
excel_rows = {}
|
||||
|
||||
# Pass 1: match by full unidecoded text
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
val_b = str(ws.cell(row=row, column=2).value or "").strip()
|
||||
combined = f"{val_a} {val_b}".strip()
|
||||
norm = unidecode(combined)
|
||||
if norm in ps_criteria:
|
||||
excel_rows[row] = ps_criteria[norm]
|
||||
del ps_criteria[norm]
|
||||
|
||||
# Pass 2: match by CheckId prefix
|
||||
still = dict(ps_criteria)
|
||||
for cid_key, full_text in still.items():
|
||||
cid = full_text.split('. ')[0]
|
||||
for row in range(1, ws.max_row + 1):
|
||||
if row in excel_rows:
|
||||
continue
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
if val_a and cid in val_a:
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[cid_key]
|
||||
break
|
||||
|
||||
# Pass 3: match column B alone
|
||||
still2 = dict(ps_criteria)
|
||||
for cid_key, full_text in still2.items():
|
||||
cid = full_text.split('. ')[0]
|
||||
for row in range(1, ws.max_row + 1):
|
||||
if row in excel_rows:
|
||||
continue
|
||||
val_b = str(ws.cell(row=row, column=2).value or "").strip()
|
||||
if val_b:
|
||||
norm_b = unidecode(val_b)
|
||||
parts = norm_b.split()
|
||||
if parts and cid in parts[0]:
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[cid_key]
|
||||
break
|
||||
|
||||
print(f'\nMatched rows: {len(excel_rows)}')
|
||||
print(f'Unmatched: {len(ps_criteria)}')
|
||||
|
||||
if ps_criteria:
|
||||
print('\nUnmatched check IDs:')
|
||||
for k in sorted(ps_criteria.keys()):
|
||||
cid = ps_criteria[k].split('. ')[0]
|
||||
print(f' {cid}: {ps_criteria[k][:80]}')
|
||||
|
||||
# Build new config
|
||||
new_data = []
|
||||
for row in sorted(excel_rows.keys()):
|
||||
new_data.append({str(row): excel_rows[row]})
|
||||
|
||||
new_config = {"data": new_data}
|
||||
|
||||
output_path = r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\windows_config.json'
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(new_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
print(f'\nNew config: {output_path}')
|
||||
print(f'Total entries: {len(new_data)}')
|
||||
|
||||
# Verify against actual output
|
||||
out_file = r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\output\MEVAS-NTL-DATAN_2026_07_29-05_18_36.txt'
|
||||
with open(out_file, 'r', encoding='utf-8', errors='replace') as f:
|
||||
lines = f.read().splitlines()
|
||||
|
||||
audit_results = {}
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line.startswith('{') and line.endswith('}'):
|
||||
try:
|
||||
parsed = json.loads(line)
|
||||
key = unidecode(str(list(parsed.keys())[0]))
|
||||
audit_results[key] = (str(list(parsed.values())[0]), line)
|
||||
except:
|
||||
pass
|
||||
|
||||
cfg_names = {unidecode(str(list(item.values())[0])) for item in new_config['data']}
|
||||
output_names = set(audit_results.keys())
|
||||
|
||||
matched = cfg_names & output_names
|
||||
output_only = output_names - cfg_names
|
||||
|
||||
print(f'Output lines: {len(output_names)}')
|
||||
print(f'Config matches output: {len(matched)}/{len(output_names)}')
|
||||
print(f'Output not in config: {len(output_only)}')
|
||||
if output_only:
|
||||
print('Missing from config:')
|
||||
for n in sorted(list(output_only))[:5]:
|
||||
print(f' {n[:80]}')
|
||||
Reference in New Issue
Block a user