#!/usr/bin/env python3 """ Glaztech ScreenConnect Site Tag Update Maps machines to sites based on subnet, then batch-updates CustomProperty2 (Site) """ import json import os import subprocess import sys # Subnet to Site mapping SUBNET_MAP = { '192.168.0': 'TUC', '192.168.1': 'SAN', '192.168.2': 'PHX', '192.168.4': 'DEN', '192.168.5': 'BOI', '192.168.6': 'SLC', '192.168.7': 'BRL', '192.168.8': 'INV', '192.168.9': 'SHV', '192.168.10': 'ABQ', '192.168.12': 'SLC', } def get_site_for_ip(ip): """Determine site code from IP address""" if not ip: return None # VPN clients (10.x.x.x) if ip.startswith('10.'): return 'REMOTE' # Standard subnets subnet = '.'.join(ip.split('.')[:3]) return SUBNET_MAP.get(subnet) def main(): preview_only = '--preview' in sys.argv # Load sessions with open('/Users/azcomputerguru/ClaudeTools/.glaztech-sessions.json') as f: sessions = json.load(f) updates = [] no_change = [] no_mapping = [] for session in sessions: session_id = session.get('SessionID') name = session.get('Name', 'Unknown') ip = session.get('GuestInfo', {}).get('PrivateNetworkAddress', '') current_site = session.get('CustomProperties', {}).get('CustomProperty2', '') company = session.get('CustomProperties', {}).get('CustomProperty1', '') tag = session.get('CustomProperties', {}).get('CustomProperty3', '') new_site = get_site_for_ip(ip) if not new_site: no_mapping.append({'name': name, 'ip': ip, 'session_id': session_id}) continue if current_site == new_site: no_change.append({'name': name, 'ip': ip, 'site': new_site}) else: updates.append({ 'session_id': session_id, 'name': name, 'ip': ip, 'current_site': current_site, 'new_site': new_site, 'company': company, 'tag': tag }) # Report print(f'=== Glaztech Site Tag Update ===') print(f'Total machines: {len(sessions)}') print(f'Need update: {len(updates)}') print(f'Already correct: {len(no_change)}') print(f'No mapping: {len(no_mapping)}') if no_mapping: print('\n[WARNING] Machines with no subnet mapping:') for m in no_mapping: print(f' {m["name"]:30s} {m["ip"]:15s} SessionID: {m["session_id"]}') if not updates: print('\n[OK] All machines already have correct Site tags.') return 0 print(f'\n=== Changes Preview ===') print(f'{"Name":30s} {"IP":15s} {"Current":10s} -> {"New":10s}') print('-' * 70) for u in updates[:20]: # Show first 20 print(f'{u["name"]:30s} {u["ip"]:15s} {u["current_site"]:10s} -> {u["new_site"]:10s}') if len(updates) > 20: print(f'... and {len(updates) - 20} more') if preview_only: print('\n[PREVIEW MODE] Use --execute to apply changes') return 0 if '--execute' not in sys.argv: print('\n[INFO] Dry run complete. Add --execute to apply changes.') return 0 # Execute updates print(f'\n=== Executing {len(updates)} updates ===') success_count = 0 fail_count = 0 for i, u in enumerate(updates, 1): # Build custom properties array: [Company, Site, Tag, ...] # Keep existing Company/Tag, update Site only props = [ u['company'] or 'Glaz-Tech Industries', u['new_site'], u['tag'] or '', '', '', '', '', '' # CP4-CP8 empty ] props_json = json.dumps(props) cmd = [ 'bash', '/Users/azcomputerguru/ClaudeTools/.claude/scripts/py.sh', '/Users/azcomputerguru/.claude/skills/screenconnect/scripts/sc.py', 'set-properties', '--session', u['session_id'], '--props-json', props_json, '--confirm' ] env = { 'CLAUDETOOLS_ROOT': '/Users/azcomputerguru/ClaudeTools', 'PATH': os.environ.get('PATH', '/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin'), 'HOME': os.environ.get('HOME', '/Users/azcomputerguru'), 'SCREENCONNECT_API_SECRET': os.environ.get('SCREENCONNECT_API_SECRET', '') } try: result = subprocess.run(cmd, env=env, capture_output=True, text=True, timeout=30) if result.returncode == 0: print(f'[{i}/{len(updates)}] OK: {u["name"]} -> {u["new_site"]}') success_count += 1 else: print(f'[{i}/{len(updates)}] FAIL: {u["name"]} - {result.stderr.strip()}') fail_count += 1 except Exception as e: print(f'[{i}/{len(updates)}] ERROR: {u["name"]} - {e}') fail_count += 1 print(f'\n=== Summary ===') print(f'Success: {success_count}') print(f'Failed: {fail_count}') return 0 if fail_count == 0 else 1 if __name__ == '__main__': sys.exit(main())