Fix Windows task and certificate collector reliability
This commit is contained in:
@@ -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.')
|
||||
|
||||
Reference in New Issue
Block a user