Fix Windows task and certificate collector reliability

This commit is contained in:
2026-10-30 13:06:14 -07:00
parent 57e716b710
commit 7fed3b9ab9
11 changed files with 283 additions and 19 deletions

View File

@@ -48,12 +48,14 @@ def powershell_executable():
return executable
def run_section(section, executable, cancelled=lambda: False, timeout=45):
def run_section(section, executable, cancelled=lambda: False, timeout=45, diagnostic=False):
if section not in SECTIONS:
raise ValueError('Unknown Windows inventory section.')
if cancelled():
raise CollectionCancelled()
args = [str(executable), '-NoLogo', '-NoProfile', '-NonInteractive', '-File', str(SCRIPT), '-Section', section]
if diagnostic:
args.append('-Diagnostic')
environment = os.environ.copy()
# Only inbox modules are needed. Do not autoload user-supplied modules or profiles.
environment['PSModulePath'] = str(Path(executable).parent / 'Modules')
@@ -77,6 +79,8 @@ def run_section(section, executable, cancelled=lambda: False, timeout=45):
if cancelled():
raise CollectionCancelled()
if process.returncode:
if process.returncode == 3:
raise WindowsCollectionError('serialization_failed', 'PowerShell could not serialize inventory metadata; no successful evidence was substituted.')
raise WindowsCollectionError('powershell_failed', 'The trusted script could not run. Check script signing policy, module availability and read permissions; raw diagnostics are excluded.')
output.seek(0)
raw = output.read(MAX_OUTPUT + 1)
@@ -127,7 +131,7 @@ def failure_check(code, message, section, start, status='failed'):
def collect_local_windows(stage=lambda message: None, cancelled=lambda: False, profile='auto',
section_timeout=45, total_timeout=300, runner=None):
section_timeout=45, total_timeout=300, runner=None, diagnostic=False):
if platform.system() != 'Windows':
raise ValueError('Local Windows collection requires an authorized Windows Server execution host.')
if profile != 'auto' and not profile.startswith('windows:'):
@@ -150,7 +154,10 @@ def collect_local_windows(stage=lambda message: None, cancelled=lambda: False, p
raise ValueError('The Windows identity check could not run within the time limit.')
continue
try:
record = validate_section(runner(section, executable, cancelled=cancelled, timeout=min(section_timeout, remaining)), section)
options = {'cancelled': cancelled, 'timeout': min(section_timeout, remaining)}
if diagnostic:
options['diagnostic'] = True
record = validate_section(runner(section, executable, **options), section)
total_bytes += len(json.dumps(record).encode('utf-8'))
if total_bytes > MAX_OUTPUT:
raise WindowsCollectionError('output_limit', 'Total inventory exceeded the 10 MiB limit; this section was omitted.')
@@ -178,10 +185,11 @@ def collect_local_windows(stage=lambda message: None, cancelled=lambda: False, p
def main():
parser = argparse.ArgumentParser(description='Read-only local Windows Server inventory. No remoting is used.')
parser.add_argument('--output', required=True, help='New local JSON file to create')
parser.add_argument('--diagnostic', action='store_true', help='Include sanitized exception types and categories')
parser.add_argument('--profile', choices=['auto','windows:2016','windows:2019','windows:2022','windows:2025'], default='auto')
args = parser.parse_args()
try:
data = collect_local_windows(profile=args.profile)
data = collect_local_windows(profile=args.profile, diagnostic=args.diagnostic)
with open(args.output, 'x', encoding='utf-8') as output:
json.dump(data, output, indent=2)
print('Windows inventory saved. Review all failed/partial checks and permission limitations before retirement decisions.')