diff --git a/local-app/python-tools/cross-organization/org_runner.py b/local-app/python-tools/cross-organization/org_runner.py index a4aa1001..7974193c 100755 --- a/local-app/python-tools/cross-organization/org_runner.py +++ b/local-app/python-tools/cross-organization/org_runner.py @@ -20,7 +20,7 @@ def tqdm(iterable, **kwargs): return iterable # --- VERSIONING --- -__version__ = "1.5.3" +__version__ = "1.5.4" class OrgTaskRunner: def __init__(self, args): @@ -28,6 +28,7 @@ def __init__(self, args): self.output_log = [] self.full_results = [] self.hierarchy_cache = {} + self.created_files = [] self.start_time = 0 def log_print(self, message=""): @@ -94,6 +95,7 @@ def run(self): sts = session.client('sts') partition = sts.get_caller_identity()['Arn'].split(':')[1] + # Load tasks & build dynamic filename suffix tasks, check_names = [], [] if self.args.enable_checks: sys.path.append(os.getcwd()) @@ -109,8 +111,11 @@ def run(self): for acc in page['Accounts'] if acc['Status'] == 'ACTIVE'] all_accounts.sort(key=lambda x: x['Name' if self.args.sort == 'name' else 'Id'].lower()) + # UPDATED HEADER print("-" * 100) - print(f"AWS ORG TASK RUNNER - v{__version__} | Max Workers: {self.args.max_workers}") + print(f"AWS ORG TASK RUNNER - v{__version__}") + print(f"Runners (Max Workers): {self.args.max_workers}") + print(f"Active Check: {check_suffix}") print("-" * 100) with ThreadPoolExecutor(max_workers=self.args.max_workers) as executor: @@ -121,22 +126,36 @@ def run(self): if data: self.full_results.append(data) pbar.update(1) + # FINAL EXPORTS if self.args.output: ds = datetime.now().strftime("%Y-%m-%dT%H%M%S") base = self.args.output if self.args.output != 'DEFAULT' else f"audit_results.{check_suffix}" - with open(f"{base}.{ds}.csv", 'w', newline='') as f: + # Save CSV + csv_file = f"{base}.{ds}.csv" + with open(csv_file, 'w', newline='') as f: writer = csv.writer(f) writer.writerow(["account_id", "account_name", "account_alias", "ou_path", "ou_id", "region", "field_name", "field_value"]) for acc in self.full_results: for reg, fields in acc["checks"].items(): for k, v in fields.items(): writer.writerow([acc["account_id"], acc["account_name"], acc["alias"], acc["ou_path"], acc["ou_id"], reg, k, v]) + self.created_files.append(csv_file) - with open(f"{base}.{ds}.json", 'w') as f: + # Save JSON + json_file = f"{base}.{ds}.json" + with open(json_file, 'w') as f: json.dump(self.full_results, f, indent=2) + self.created_files.append(json_file) - print(f"\nCompleted in {round(time.perf_counter() - self.start_time, 2)}s.") + # UPDATED TRAILER + print("\n" + "=" * 100) + print(f"Run Complete | Time: {round(time.perf_counter() - self.start_time, 2)}s") + if self.created_files: + print("Files Created:") + for f in self.created_files: + print(f" - {f}") + print("=" * 100) if __name__ == "__main__": p = argparse.ArgumentParser() @@ -146,6 +165,5 @@ def run(self): p.add_argument("--sort", choices=['id', 'name'], default='name') p.add_argument("--output", nargs='?', const='DEFAULT') p.add_argument("--enable-checks", nargs='+') - # Updated default to 8 workers - p.add_argument("--max-workers", type=int, default=8, help="Number of concurrent accounts to process (default: 8)") + p.add_argument("--max-workers", type=int, default=8) OrgTaskRunner(p.parse_args()).run()