"""tools/find_dynamic_sql_procs.py Simple CLI wrapper that runs the T-SQL scanner against a SQL Server database using pyodbc. Usage: python tools/find_dynamic_sql_procs.py --server demo.azonix.in --database hs-prod3 --uid user --pwd pass It prints a CSV to stdout with basic columns and confidence score. Notes: - Requires pyodbc installed in your environment. - Use Windows authentication by omitting uid/pwd and passing --trusted. """ import argparse import csv import sys import pyodbc import os SQL_PATH = os.path.join(os.path.dirname(__file__), 'find_dynamic_sql_procs.sql') SQL_TEMPLATE = open(SQL_PATH, 'r', encoding='utf-8').read() def run_scan(conn_str, top=1000): sql = SQL_TEMPLATE.replace('TOP(@Top)', f'TOP({top})') if 'TOP(@Top)' in SQL_TEMPLATE else SQL_TEMPLATE with pyodbc.connect(conn_str, autocommit=True) as cn: cur = cn.cursor() cur.execute(sql) cols = [c[0] for c in cur.description] writer = csv.writer(sys.stdout) writer.writerow(cols) for row in cur: writer.writerow(row) if __name__ == '__main__': ap = argparse.ArgumentParser(description='Find procs using dynamic SQL patterns') ap.add_argument('--server', required=True) ap.add_argument('--database', required=True) ap.add_argument('--uid') ap.add_argument('--pwd') ap.add_argument('--trusted', action='store_true') ap.add_argument('--top', type=int, default=1000) args = ap.parse_args() if args.trusted: conn = f'DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={args.server};DATABASE={args.database};Trusted_Connection=yes;' else: if not args.uid or not args.pwd: ap.error('Either --trusted or both --uid and --pwd are required') conn = f'DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={args.server};DATABASE={args.database};UID={args.uid};PWD={args.pwd};' run_scan(conn, top=args.top)