diff --git a/report.py b/report.py index b04c9cb..958648b 100644 --- a/report.py +++ b/report.py @@ -608,14 +608,60 @@ class NinjaOneReporter: print("Check NinjaOne dashboard for progress.") + def scan_devices(self, device_ids=None): + """Trigger patch scan on devices""" + self.authenticate() + self.load_organizations() + self.load_devices() + + if device_ids is None: + # Get devices with critical patches + print("\nLoading software patches...") + result = self.api_get('/queries/software-patches') + patches = result.get('results', []) if isinstance(result, dict) else result + critical = [p for p in patches if p.get('impact', '').lower() == 'critical'] + device_ids = list(set(p.get('deviceId') for p in critical)) + + print(f"\nTriggering scan on {len(device_ids)} devices...") + print("=" * 60) + + success = 0 + failed = 0 + + for device_id in device_ids: + info = self.devices.get(device_id, {}) + name = info.get('name', f"Device-{device_id}") + + try: + headers = {'Authorization': f'Bearer {self.access_token}', 'Content-Type': 'application/json'} + url = f"{self.config['base_url']}/api/v2/device/{device_id}/patch/software/scan" + response = requests.post(url, headers=headers) + + if response.status_code in [200, 201, 204]: + print(f" Scan triggered: {name}") + success += 1 + else: + print(f" Failed: {name} - {response.status_code}: {response.text[:80]}") + failed += 1 + except Exception as e: + print(f" Error: {name} - {str(e)}") + failed += 1 + + print("=" * 60) + print(f"COMPLETE: {success} scans triggered, {failed} failed") + + if __name__ == '__main__': import sys reporter = NinjaOneReporter() if '--apply' in sys.argv: - # Actually trigger patch apply on devices + # Trigger patch apply on devices reporter.apply_patches(dry_run=False) + elif '--scan' in sys.argv: + # Trigger patch scan on devices + reporter.scan_devices() elif '--remediate' in sys.argv: # Dry run - show what would be patched reporter.apply_patches(dry_run=True)