Generate-M365LicenseAssignmentReport.ps1


<#PSScriptInfo
 
.VERSION 2.4
 
.GUID d23c77c4-d7c2-4b50-8518-9c9ee7718d43
 
.AUTHOR Roy Klooster
 
.COMPANYNAME RK Solutions
 
.COPYRIGHT
 
.TAGS
    "RK Solutions"
    Microsoft365
    "Microsoft Entra ID"
    "Microsoft Graph"
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
    Initial release - Comprehensive Microsoft 365 license assignment report with HTML output
    2.1 - Added function Test-MgGraphConnection to check for existing connections with the proper permissions
 
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
 This script generates an advanced M365 license assignment report
 
#>
 
Param()

function New-HTMLReport {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Organization,
        
        [Parameter(Mandatory = $true)]
        [array]$Report,
        
        [Parameter(Mandatory = $true)]
        [array]$SubscriptionOverview,
        
        [Parameter(Mandatory = $false)]
        [string]$ExportPath = "$env:PUBLIC\Documents\$Organization-M365LicensingReport.html"
    )

    # Calculate license counts for dashboard statistics
    $directLicenses = ($Report | Where-Object { $_.AssignmentType -eq "Direct" }).Count
    $inheritedLicenses = ($Report | Where-Object { $_.AssignmentType -eq "Inherited" }).Count
    $bothLicenses = ($Report | Where-Object { $_.AssignmentType -eq "Both" }).Count
    $inactiveUsersWithLicenses = ($Report | Where-Object { $_.AccountEnabled -eq "No" }).Count
    
    # Create HTML Template with DataTables
    $htmlTemplate = @'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>$Organization M365 Licensing Report</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
    <link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.4.1/css/buttons.bootstrap5.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <script src="https://code.jquery.com/jquery-3.7.0.js"></script>
    <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
    <script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
    <script src="https://cdn.datatables.net/buttons/2.4.1/js/dataTables.buttons.min.js"></script>
    <script src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.bootstrap5.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
    <script src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.html5.min.js"></script>
    <script src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.print.min.js"></script>
    <script src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.colVis.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <style>
        :root {
            /* Light mode variables (default) */
            --primary-color: #0078d4;
            --secondary-color: #2b88d8;
            --direct-color: #0078d4;
            --inherited-color: #107c10;
            --both-color: #5c2d91;
            --inactive-color: #d83b01;
            --bg-color: #f8f9fa;
            --card-bg: #ffffff;
            --text-color: #333333;
            --table-header-bg: #f5f5f5;
            --table-header-color: #333333;
            --table-stripe-bg: rgba(0,0,0,0.02);
            --table-hover-bg: rgba(0,0,0,0.04);
            --table-border-color: #dee2e6;
            --filter-tag-bg: #e9ecef;
            --filter-tag-color: #495057;
            --filter-bg: white;
            --btn-outline-color: #6c757d;
            --border-color: #dee2e6;
            --toggle-bg: #ccc;
            --button-bg: #f8f9fa;
            --button-color: #333;
            --button-border: #ddd;
            --button-hover-bg: #e9ecef;
            --footer-text: white;
            --input-bg: #fff;
            --input-color: #333;
            --input-border: #ced4da;
            --input-focus-border: #86b7fe;
            --input-focus-shadow: rgba(13, 110, 253, 0.25);
            --datatable-even-row-bg: #fff;
            --datatable-odd-row-bg: rgba(0,0,0,0.02);
        }
         
        [data-theme="dark"] {
            /* Dark mode variables */
            --primary-color: #0078d4;
            --secondary-color: #2b88d8;
            --direct-color: #0078d4;
            --inherited-color: #107c10;
            --both-color: #5c2d91;
            --inactive-color: #d83b01;
            --bg-color: #121212;
            --card-bg: #1e1e1e;
            --text-color: #e0e0e0;
            --table-header-bg: #333333;
            --table-header-color: #e0e0e0;
            --table-stripe-bg: rgba(255,255,255,0.03);
            --table-hover-bg: rgba(255,255,255,0.05);
            --table-border-color: #444444;
            --filter-tag-bg: #2d2d2d;
            --filter-tag-color: #d0d0d0;
            --filter-bg: #252525;
            --btn-outline-color: #adb5bd;
            --border-color: #444444;
            --toggle-bg: #555555;
            --button-bg: #2a2a2a;
            --button-color: #e0e0e0;
            --button-border: #444;
            --button-hover-bg: #3a3a3a;
            --footer-text: white;
            --input-bg: #2a2a2a;
            --input-color: #e0e0e0;
            --input-border: #444444;
            --input-focus-border: #0078d4;
            --input-focus-shadow: rgba(0, 120, 212, 0.25);
            --datatable-even-row-bg: #1e1e1e;
            --datatable-odd-row-bg: #252525;
        }
         
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 0;
            background-color: var(--bg-color);
            color: var(--text-color);
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            transition: background-color 0.3s ease, color 0.3s ease;
        }
         
        .container-fluid {
            max-width: 1600px;
            padding: 20px;
            flex: 1;
        }
         
        .dashboard-header {
            padding: 20px 0;
            margin-bottom: 30px;
            border-bottom: 1px solid rgba(128,128,128,0.2);
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
         
        .dashboard-title {
            display: flex;
            align-items: center;
            gap: 15px;
        }
         
        .dashboard-title h1 {
            margin: 0;
            font-size: 1.8rem;
            font-weight: 600;
            color: var(--primary-color);
        }
         
        .logo {
            height: 45px;
            width: 45px;
        }
         
        .report-date {
            font-size: 0.9rem;
            color: var(--text-color);
            opacity: 0.8;
        }
         
        .card {
            border: none;
            border-radius: 10px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.05);
            margin-bottom: 25px;
            transition: transform 0.2s, box-shadow 0.2s, background-color 0.3s ease;
            overflow: hidden;
            background-color: var(--card-bg);
        }
         
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 16px rgba(0,0,0,0.1);
        }
         
        .card-header {
            background-color: var(--primary-color);
            color: white;
            font-weight: 600;
            padding: 15px 20px;
            border-bottom: none;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 10px;
        }
         
        .card-header i {
            font-size: 1.2rem;
        }
         
        .card-body {
            padding: 20px;
        }
         
        .stats-card {
            height: 100%;
            text-align: center;
            padding: 25px 15px;
            border-radius: 10px;
            color: white;
            position: relative;
            overflow: hidden;
            min-height: 160px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            cursor: pointer;
            transition: all 0.3s;
        }
         
        .stats-card.active {
            box-shadow: 0 0 0 4px rgba(255,255,255,0.6), 0 8px 16px rgba(0,0,0,0.2);
            transform: scale(1.05);
        }
         
        .stats-card::before {
            content: '';
            position: absolute;
            top: -20px;
            right: -20px;
            width: 100px;
            height: 100px;
            border-radius: 50%;
            background-color: rgba(255,255,255,0.1);
            z-index: 0;
        }
         
        .stats-card i {
            font-size: 2.5rem;
            margin-bottom: 15px;
            position: relative;
            z-index: 1;
        }
         
        .stats-card h3 {
            font-size: 1rem;
            font-weight: 500;
            margin-bottom: 10px;
            position: relative;
            z-index: 1;
        }
         
        .stats-card .number {
            font-size: 2.2rem;
            font-weight: 700;
            position: relative;
            z-index: 1;
        }
         
        .direct-bg {
            background: linear-gradient(135deg, var(--direct-color), #2b88d8);
        }
         
        .inherited-bg {
            background: linear-gradient(135deg, var(--inherited-color), #2a9d2a);
        }
         
        .both-bg {
            background: linear-gradient(135deg, var(--both-color), #7b4db2);
        }
         
        .inactive-bg {
            background: linear-gradient(135deg, var(--inactive-color), #f25c05);
        }
         
        /* DataTables Dark Mode Overrides */
        table.dataTable {
            border-collapse: collapse !important;
            width: 100% !important;
            color: var(--text-color) !important;
            border-color: var(--table-border-color) !important;
        }
         
        .table {
            color: var(--text-color) !important;
            border-color: var(--table-border-color) !important;
        }
         
        .table-striped>tbody>tr:nth-of-type(odd) {
            background-color: var(--datatable-odd-row-bg) !important;
        }
         
        .table-striped>tbody>tr:nth-of-type(even) {
            background-color: var(--datatable-even-row-bg) !important;
        }
         
        .table thead th {
            background-color: var(--table-header-bg) !important;
            color: var(--table-header-color) !important;
            font-weight: 600;
            border-top: none;
            padding: 12px;
            border-color: var(--table-border-color) !important;
        }
         
        .table tbody td {
            padding: 12px;
            vertical-align: middle;
            border-color: var(--table-border-color) !important;
            color: var(--text-color) !important;
        }
         
        .table.table-bordered {
            border-color: var(--table-border-color) !important;
        }
         
        .table-bordered td, .table-bordered th {
            border-color: var(--table-border-color) !important;
        }
         
        .table-hover tbody tr:hover {
            background-color: var(--table-hover-bg) !important;
        }
         
        .badge {
            padding: 6px 10px;
            font-weight: 500;
            border-radius: 6px;
        }
         
        .badge-direct {
            background-color: var(--direct-color);
            color: white;
        }
         
        .badge-inherited {
            background-color: var(--inherited-color);
            color: white;
        }
         
        .badge-both {
            background-color: var(--both-color);
            color: white;
        }
         
        .badge-inactive {
            background-color: var(--inactive-color);
            color: white;
        }
         
        .dataTables_wrapper .dataTables_length,
        .dataTables_wrapper .dataTables_filter,
        .dataTables_wrapper .dataTables_info,
        .dataTables_wrapper .dataTables_processing,
        .dataTables_wrapper .dataTables_paginate {
            color: var(--text-color) !important;
        }
         
        .dataTables_wrapper .dataTables_paginate .paginate_button {
            padding: 0.3em 0.8em;
            border-radius: 4px;
            margin: 0 3px;
            color: var(--text-color) !important;
            border: 1px solid var(--border-color) !important;
            background-color: var(--button-bg) !important;
        }
         
        .dataTables_wrapper .dataTables_paginate .paginate_button.current {
            background: var(--primary-color) !important;
            border-color: var(--primary-color) !important;
            color: white !important;
        }
         
        .dataTables_wrapper .dataTables_paginate .paginate_button:hover {
            background: var(--button-hover-bg) !important;
            border-color: var(--border-color) !important;
            color: var(--text-color) !important;
        }
         
        .dataTables_wrapper .dataTables_length select,
        .dataTables_wrapper .dataTables_filter input {
            border: 1px solid var(--input-border);
            background-color: var(--input-bg);
            color: var(--input-color);
            border-radius: 4px;
            padding: 5px 10px;
        }
         
        .dataTables_wrapper .dataTables_filter input:focus {
            border-color: var(--input-focus-border);
            box-shadow: 0 0 0 0.25rem var(--input-focus-shadow);
        }
         
        .dataTables_info {
            padding-top: 10px;
            color: var(--text-color);
        }
         
        footer {
            background-color: var(--primary-color);
            color: var(--footer-text);
            text-align: center;
            padding: 15px 0;
            margin-top: auto;
        }
         
        footer p {
            margin: 0;
            font-weight: 500;
        }
         
        .filter-buttons {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-bottom: 20px;
        }
         
        .filter-button {
            padding: 8px 16px;
            border-radius: 20px;
            border: none;
            cursor: pointer;
            font-weight: 500;
            transition: all 0.2s;
            display: flex;
            align-items: center;
            gap: 8px;
        }
         
        .filter-button:hover {
            opacity: 0.9;
        }
         
        .filter-button.active {
            box-shadow: 0 0 0 2px rgba(128,128,128,0.2);
        }
         
        .filter-button-direct {
            background-color: var(--direct-color);
            color: white;
        }
         
        .filter-button-inherited {
            background-color: var(--inherited-color);
            color: white;
        }
         
        .filter-button-both {
            background-color: var(--both-color);
            color: white;
        }
         
        .filter-button-inactive {
            background-color: var(--inactive-color);
            color: white;
        }
         
        .filter-button-all {
            background-color: var(--btn-outline-color);
            color: white;
        }
         
        .toggle-container {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 15px;
        }
         
        .toggle-switch {
            position: relative;
            display: inline-block;
            width: 60px;
            height: 30px;
        }
         
        .toggle-switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }
         
        .toggle-slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: var(--toggle-bg);
            transition: .4s;
            border-radius: 34px;
        }
         
        .toggle-slider:before {
            position: absolute;
            content: "";
            height: 22px;
            width: 22px;
            left: 4px;
            bottom: 4px;
            background-color: white;
            transition: .4s;
            border-radius: 50%;
        }
         
        input:checked + .toggle-slider {
            background-color: var(--primary-color);
        }
         
        input:checked + .toggle-slider:before {
            transform: translateX(30px);
        }
         
        .license-filter-container {
            margin: 15px 0;
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }
         
        .license-badge {
            padding: 6px 12px;
            border-radius: 20px;
            background-color: var(--filter-tag-bg);
            color: var(--filter-tag-color);
            cursor: pointer;
            transition: all 0.2s;
            font-size: 0.85rem;
        }
         
        .license-badge.active {
            background-color: var(--primary-color);
            color: white;
        }
         
        @media (max-width: 768px) {
            .dashboard-header {
                flex-direction: column;
                align-items: flex-start;
                gap: 10px;
            }
             
            .stats-card {
                min-height: 140px;
            }
             
            .filter-buttons {
                flex-direction: column;
            }
        }
         
        /* Export buttons styling */
        div.dt-buttons {
            margin-bottom: 1rem;
        }
         
        button.dt-button {
            background-color: var(--button-bg) !important;
            border-color: var(--button-border) !important;
            color: var(--button-color) !important;
            font-weight: 500 !important;
            padding: 8px 16px !important;
            border-radius: 4px !important;
            margin-right: 8px !important;
        }
         
        button.dt-button:hover {
            background-color: var(--button-hover-bg) !important;
            border-color: var(--border-color) !important;
        }
         
        button.dt-button.active {
            background-color: var(--primary-color) !important;
            border-color: var(--primary-color) !important;
            color: white !important;
        }
         
        .filter-section {
            background-color: var(--filter-bg);
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.05);
            margin-bottom: 20px;
            transition: background-color 0.3s ease;
        }
         
        .filter-section h5 {
            color: var(--primary-color);
            margin-bottom: 12px;
            font-weight: 600;
        }
         
        .filter-tags {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            margin-top: 8px;
        }
         
        .filter-tag {
            background-color: var(--filter-tag-bg);
            padding: 4px 12px;
            border-radius: 16px;
            font-size: 0.85rem;
            color: var(--filter-tag-color);
            display: flex;
            align-items: center;
            gap: 6px;
            transition: background-color 0.3s ease, color 0.3s ease;
        }
         
        .filter-tag i {
            cursor: pointer;
            color: var(--filter-tag-color);
        }
         
        .filter-tag i:hover {
            color: var(--inactive-color);
        }
         
        .custom-search {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
        }
         
        .custom-search input {
            flex: 1;
            padding: 8px 12px;
            border: 1px solid var(--border-color);
            background-color: var(--bg-color);
            color: var(--text-color);
            border-radius: 4px;
        }
         
        .custom-search button {
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 4px;
            padding: 8px 16px;
            cursor: pointer;
        }
         
        .active-filters-container {
            margin-bottom: 15px;
        }
         
        /* Show all entries toggle */
        .show-all-container {
            display: flex;
            align-items: center;
            gap: 12px;
            background-color: transparent;
            padding: 0;
            border: none;
            margin-left: 15px;
        }
         
        .show-all-text {
            font-weight: 500;
            margin: 0;
            color: white;
            font-size: 0.85rem;
        }
         
        /* Custom DataTable controls wrapper */
        .datatable-header {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            margin-bottom: 1rem;
        }
         
        .datatable-controls {
            display: flex;
            align-items: center;
            gap: 15px;
            flex-wrap: wrap;
        }
         
        /* Theme toggle styles */
        .theme-toggle {
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 1000;
            display: flex;
            align-items: center;
            gap: 10px;
            background-color: var(--card-bg);
            padding: 8px 12px;
            border-radius: 30px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            transition: background-color 0.3s ease;
        }
         
        .theme-toggle-switch {
            position: relative;
            display: inline-block;
            width: 50px;
            height: 26px;
        }
         
        .theme-toggle-switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }
         
        .theme-toggle-slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: var(--toggle-bg);
            transition: .4s;
            border-radius: 34px;
        }
         
        .theme-toggle-slider:before {
            position: absolute;
            content: "";
            height: 18px;
            width: 18px;
            left: 4px;
            bottom: 4px;
            background-color: white;
            transition: .4s;
            border-radius: 50%;
        }
         
        input:checked + .theme-toggle-slider {
            background-color: var(--primary-color);
        }
         
        input:checked + .theme-toggle-slider:before {
            transform: translateX(24px);
        }
         
        .theme-icon {
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            color: var(--text-color);
        }
         
        /* Form elements for dark mode */
        .form-select, .form-control {
            background-color: var(--input-bg) !important;
            color: var(--input-color) !important;
            border-color: var(--input-border) !important;
        }
         
        .form-select:focus, .form-control:focus {
            border-color: var(--input-focus-border) !important;
            box-shadow: 0 0 0 0.25rem var(--input-focus-shadow) !important;
        }
         
        .form-label {
            color: var(--text-color);
        }
         
        .btn-outline-secondary {
            color: var(--text-color);
            border-color: var(--border-color);
            background-color: transparent;
        }
         
        .btn-outline-secondary:hover {
            background-color: var(--filter-tag-bg);
            color: var(--text-color);
        }
         
        /* Override for dropdown menus and selects */
        .form-select option {
            background-color: var(--input-bg);
            color: var(--input-color);
        }
         
        /* Fix DataTables odd/even row striping */
        table.dataTable.stripe tbody tr.odd,
        table.dataTable.display tbody tr.odd {
            background-color: var(--datatable-odd-row-bg) !important;
        }
         
        table.dataTable.stripe tbody tr.even,
        table.dataTable.display tbody tr.even {
            background-color: var(--datatable-even-row-bg) !important;
        }
         
        /* Fix DataTables background color for hovered rows */
        table.dataTable.hover tbody tr:hover,
        table.dataTable.display tbody tr:hover {
            background-color: var(--table-hover-bg) !important;
        }
         
        /* Fix DataTables border colors */
        table.dataTable.border-bottom,
        table.dataTable.border-top,
        table.dataTable thead th,
        table.dataTable tfoot th,
        table.dataTable thead td,
        table.dataTable tfoot td {
            border-color: var(--table-border-color) !important;
        }
         
        /* Bootstrap 5 DataTables specific overrides */
        .table-striped>tbody>tr:nth-of-type(odd)>* {
            --bs-table-accent-bg: var(--datatable-odd-row-bg) !important;
            color: var(--text-color) !important;
        }
         
        .table>:not(caption)>*>* {
            background-color: var(--card-bg) !important;
            color: var(--text-color) !important;
        }
         
        .table-striped>tbody>tr {
            background-color: var(--datatable-even-row-bg) !important;
        }
         
        /* Direct cell background colors */
        .table tbody tr td {
            background-color: transparent !important;
        }
         
        /* Force Bootstrap Tables to use the correct colors */
        .table-striped>tbody>tr:nth-of-type(odd) {
            --bs-table-accent-bg: var(--datatable-odd-row-bg) !important;
        }
    </style>
</head>
<body>
    <!-- Dark Mode Toggle -->
    <div class="theme-toggle">
        <div class="theme-icon">
            <i class="fas fa-sun"></i>
        </div>
        <label class="theme-toggle-switch">
            <input type="checkbox" id="themeToggle">
            <span class="theme-toggle-slider"></span>
        </label>
        <div class="theme-icon">
            <i class="fas fa-moon"></i>
        </div>
    </div>
     
    <div class="container-fluid">
        <div class="dashboard-header">
            <div class="dashboard-title">
                <svg class="logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
                    <path fill="#ff5722" d="M6 6H22V22H6z" transform="rotate(-180 14 14)"/>
                    <path fill="#4caf50" d="M26 6H42V22H26z" transform="rotate(-180 34 14)"/>
                    <path fill="#ffc107" d="M6 26H22V42H6z" transform="rotate(-180 14 34)"/>
                    <path fill="#03a9f4" d="M26 26H42V42H26z" transform="rotate(-180 34 34)"/>
                </svg>
                <h1>$Organization M365 Licensing Report</h1>
            </div>
            <div class="report-date">
                <i class="fas fa-calendar-alt me-2"></i> Report generated on: $ReportDate
            </div>
        </div>
         
        <div class="row mb-4">
            <div class="col-md-3 mb-3">
                <div class="stats-card direct-bg" id="directFilter">
                    <i class="fas fa-user-tag"></i>
                    <h3>Direct Licenses</h3>
                    <div class="number">$directLicenses</div>
                </div>
            </div>
            <div class="col-md-3 mb-3">
                <div class="stats-card inherited-bg" id="inheritedFilter">
                    <i class="fas fa-users-cog"></i>
                    <h3>Inherited Licenses</h3>
                    <div class="number">$inheritedLicenses</div>
                </div>
            </div>
            <div class="col-md-3 mb-3">
                <div class="stats-card both-bg" id="bothFilter">
                    <i class="fas fa-user-shield"></i>
                    <h3>Both (Direct + Inherited)</h3>
                    <div class="number">$bothLicenses</div>
                </div>
            </div>
            <div class="col-md-3 mb-3">
                <div class="stats-card inactive-bg" id="inactiveFilter">
                    <i class="fas fa-user-slash"></i>
                    <h3>Inactive Users with Licenses</h3>
                    <div class="number">$inactiveUsersWithLicenses</div>
                </div>
            </div>
        </div>
         
        <div class="filter-section">
            <h5><i class="fas fa-filter me-2"></i>Filter Options</h5>
             
            <div class="row">
                <div class="col-md-6">
                    <div class="mb-3">
                        <label for="accountStatusFilter" class="form-label">Account Status</label>
                        <select id="accountStatusFilter" class="form-select">
                            <option value="">All Accounts</option>
                            <option value="Active">Active Accounts</option>
                            <option value="Inactive">Inactive Accounts</option>
                        </select>
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="mb-3">
                        <label for="assignmentTypeFilter" class="form-label">Assignment Type</label>
                        <select id="assignmentTypeFilter" class="form-select">
                            <option value="">All Types</option>
                            <option value="Direct">Direct</option>
                            <option value="Inherited">Inherited</option>
                            <option value="Both">Both</option>
                        </select>
                    </div>
                </div>
            </div>
             
            <div class="mb-3">
                <label for="licenseNameFilter" class="form-label">License Name</label>
                <input type="text" id="licenseNameFilter" class="form-control" placeholder="Search for license names...">
            </div>
             
            <div class="mb-3">
                <label class="form-label">Quick Filters</label>
                <div class="filter-buttons">
                    <button class="filter-button filter-button-all" data-filter="all"><i class="fas fa-globe"></i> Show All</button>
                    <button class="filter-button filter-button-direct" data-filter="direct"><i class="fas fa-user-tag"></i> Direct Only</button>
                    <button class="filter-button filter-button-inherited" data-filter="inherited"><i class="fas fa-users-cog"></i> Inherited Only</button>
                    <button class="filter-button filter-button-both" data-filter="both"><i class="fas fa-user-shield"></i> Both</button>
                    <button class="filter-button filter-button-inactive" data-filter="inactive"><i class="fas fa-user-slash"></i> Inactive Users</button>
                </div>
            </div>
             
            <div class="active-filters-container">
                <div class="d-flex justify-content-between align-items-center">
                    <label class="form-label mb-0">Active Filters:</label>
                    <button id="clearAllFilters" class="btn btn-sm btn-outline-secondary">Clear All</button>
                </div>
                <div class="filter-tags" id="activeFilters">
                    <!-- Active filters will be displayed here -->
                </div>
            </div>
        </div>
         
        <div class="card">
            <div class="card-header">
                <div>
                    <i class="fas fa-id-card"></i> License Assignment
                </div>
                <div class="show-all-container">
                    <label class="toggle-switch">
                        <input type="checkbox" id="licensesShowAllToggle">
                        <span class="toggle-slider"></span>
                    </label>
                    <p class="show-all-text">Show all entries</p>
                </div>
            </div>
            <div class="card-body">
                <div class="table-responsive">
                    <table id="licensesTable" class="table table-striped table-bordered" style="width:100%">
                        <thead>
                            <tr>
                                <th>Display Name</th>
                                <th>User Principal Name</th>
                                <th>Account Status</th>
                                <th>License</th>
                                <th>Assignment Type</th>
                                <th>Inheritance Details</th>
                            </tr>
                        </thead>
                        <tbody>
                            {{TABLE_DATA}}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
         
        <div class="card">
            <div class="card-header">
                <div>
                    <i class="fas fa-project-diagram"></i> Subscription Overview
                </div>
                <div class="show-all-container">
                    <label class="toggle-switch">
                        <input type="checkbox" id="subscriptionShowAllToggle">
                        <span class="toggle-slider"></span>
                    </label>
                    <p class="show-all-text">Show all entries</p>
                </div>
            </div>
            <div class="card-body">
                <div class="table-responsive">
                    <table id="subscriptionTable" class="table table-striped table-bordered" style="width:100%">
                        <thead>
                            <tr>
                                <th>Subscription</th>
                                <th>Created Date</th>
                                <th>End Date</th>
                                <th>License Status</th>
                                <th>Consumed Units</th>
                                <th>Total Licenses</th>
                                <th>Available Licenses</th>
                            </tr>
                        </thead>
                        <tbody>
                            {{SUBSCRIPTION_DATA}}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
     
    <footer>
        <p>Generated by Roy Klooster - RK Solutions</p>
    </footer>
     
    <script>
        // Initialize DataTables
        $(document).ready(function() {
            // Theme toggling functionality
            const themeToggle = document.getElementById('themeToggle');
            const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
             
            // Function to update table colors for dark mode
            function updateTableColors() {
                // Force all table cells to have the correct background
                if (document.documentElement.getAttribute('data-theme') === 'dark') {
                    // Dark mode
                    $('table.dataTable tbody tr').css('background-color', 'var(--datatable-even-row-bg)');
                    $('table.dataTable tbody tr:nth-child(odd)').css('background-color', 'var(--datatable-odd-row-bg)');
                    $('table.dataTable tbody td').css('color', 'var(--text-color)');
                    $('table.dataTable thead th').css({
                        'background-color': 'var(--table-header-bg)',
                        'color': 'var(--table-header-color)'
                    });
                } else {
                    // Light mode
                    $('table.dataTable tbody tr').css('background-color', 'var(--datatable-even-row-bg)');
                    $('table.dataTable tbody tr:nth-child(odd)').css('background-color', 'var(--datatable-odd-row-bg)');
                    $('table.dataTable tbody td').css('color', 'var(--text-color)');
                    $('table.dataTable thead th').css({
                        'background-color': 'var(--table-header-bg)',
                        'color': 'var(--table-header-color)'
                    });
                }
            }
             
            // Check for saved user preference, or use system preference
            const savedTheme = localStorage.getItem('theme');
            if (savedTheme === 'dark' || (!savedTheme && prefersDarkScheme.matches)) {
                document.documentElement.setAttribute('data-theme', 'dark');
                themeToggle.checked = true;
            }
             
            // Add event listener for theme toggle
            themeToggle.addEventListener('change', function() {
                if (this.checked) {
                    document.documentElement.setAttribute('data-theme', 'dark');
                    localStorage.setItem('theme', 'dark');
                } else {
                    document.documentElement.setAttribute('data-theme', 'light');
                    localStorage.setItem('theme', 'light');
                }
                 
                // Apply the table color changes after theme switch
                setTimeout(updateTableColors, 50);
            });
             
            // Initialize DataTable for licenses
            const licensesTable = $('#licensesTable').DataTable({
                dom: 'Bfrtip',
                buttons: [
                    {
                        extend: 'collection',
                        text: '<i class="fas fa-download"></i> Export',
                        buttons: [
                            {
                                extend: 'excel',
                                text: '<i class="fas fa-file-excel"></i> Excel',
                                exportOptions: {
                                    columns: ':visible'
                                }
                            },
                            {
                                extend: 'csv',
                                text: '<i class="fas fa-file-csv"></i> CSV',
                                exportOptions: {
                                    columns: ':visible'
                                }
                            },
                            {
                                extend: 'pdf',
                                text: '<i class="fas fa-file-pdf"></i> PDF',
                                exportOptions: {
                                    columns: ':visible'
                                }
                            },
                            {
                                extend: 'print',
                                text: '<i class="fas fa-print"></i> Print',
                                exportOptions: {
                                    columns: ':visible'
                                }
                            }
                        ]
                    },
                    {
                        extend: 'colvis',
                        text: '<i class="fas fa-columns"></i> Columns'
                    }
                ],
                paging: true,
                searching: true,
                ordering: true,
                info: true,
                responsive: true,
                lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
                order: [[0, 'asc']],
                language: {
                    search: "<i class='fas fa-search'></i> _INPUT_",
                    searchPlaceholder: "Search records...",
                    lengthMenu: "Show _MENU_ entries",
                    info: "Showing _START_ to _END_ of _TOTAL_ entries",
                    paginate: {
                        first: "<i class='fas fa-angle-double-left'></i>",
                        last: "<i class='fas fa-angle-double-right'></i>",
                        next: "<i class='fas fa-angle-right'></i>",
                        previous: "<i class='fas fa-angle-left'></i>"
                    }
                },
                drawCallback: function() {
                    // Enforce the correct colors after DataTables redraws
                    updateTableColors();
                }
            });
             
            // Initialize DataTable for subscriptions
            const subscriptionTable = $('#subscriptionTable').DataTable({
                dom: 'Bfrtip',
                buttons: [
                    {
                        extend: 'collection',
                        text: '<i class="fas fa-download"></i> Export',
                        buttons: [
                            {
                                extend: 'excel',
                                text: '<i class="fas fa-file-excel"></i> Excel',
                                exportOptions: {
                                    columns: ':visible'
                                }
                            },
                            {
                                extend: 'csv',
                                text: '<i class="fas fa-file-csv"></i> CSV',
                                exportOptions: {
                                    columns: ':visible'
                                }
                            },
                            {
                                extend: 'pdf',
                                text: '<i class="fas fa-file-pdf"></i> PDF',
                                exportOptions: {
                                    columns: ':visible'
                                }
                            },
                            {
                                extend: 'print',
                                text: '<i class="fas fa-print"></i> Print',
                                exportOptions: {
                                    columns: ':visible'
                                }
                            }
                        ]
                    },
                    {
                        extend: 'colvis',
                        text: '<i class="fas fa-columns"></i> Columns'
                    }
                ],
                paging: true,
                searching: true,
                ordering: true,
                info: true,
                responsive: true,
                lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
                language: {
                    search: "<i class='fas fa-search'></i> _INPUT_",
                    searchPlaceholder: "Search records...",
                    lengthMenu: "Show _MENU_ entries",
                    info: "Showing _START_ to _END_ of _TOTAL_ entries",
                    paginate: {
                        first: "<i class='fas fa-angle-double-left'></i>",
                        last: "<i class='fas fa-angle-double-right'></i>",
                        next: "<i class='fas fa-angle-right'></i>",
                        previous: "<i class='fas fa-angle-left'></i>"
                    }
                },
                drawCallback: function() {
                    // Enforce the correct colors after DataTables redraws
                    updateTableColors();
                }
            });
             
            // Apply initial table colors
            setTimeout(updateTableColors, 100);
             
            // Show all toggle functionality for licenses table
            $('#licensesShowAllToggle').on('change', function() {
                if ($(this).is(':checked')) {
                    licensesTable.page.len(-1).draw();
                } else {
                    licensesTable.page.len(10).draw();
                }
            });
             
            // Show all toggle functionality for subscription table
            $('#subscriptionShowAllToggle').on('change', function() {
                if ($(this).is(':checked')) {
                    subscriptionTable.page.len(-1).draw();
                } else {
                    subscriptionTable.page.len(10).draw();
                }
            });
             
            // Custom filtering function
            $.fn.dataTable.ext.search.push(
                function(settings, data, dataIndex) {
                    // Only apply to licenses table
                    if (settings.nTable.id !== 'licensesTable') {
                        return true;
                    }
                     
                    // Get filter values
                    const accountStatus = $('#accountStatusFilter').val();
                    const assignmentType = $('#assignmentTypeFilter').val();
                    const licenseNameFilter = $('#licenseNameFilter').val().toLowerCase();
                     
                    // Get row data
                    const rowAccountStatus = data[2]; // Account Status column
                    const rowAssignmentType = data[4]; // Assignment Type column
                    const rowLicenseName = data[3].toLowerCase(); // License Name column
                     
                    // Filter by account status
                    if (accountStatus && accountStatus === 'Active' && !rowAccountStatus.includes('Active')) {
                        return false;
                    }
                    if (accountStatus && accountStatus === 'Inactive' && !rowAccountStatus.includes('Inactive')) {
                        return false;
                    }
                     
                    // Filter by assignment type
                    if (assignmentType && !rowAssignmentType.includes(assignmentType)) {
                        return false;
                    }
                     
                    // Filter by license name
                    if (licenseNameFilter && !rowLicenseName.includes(licenseNameFilter)) {
                        return false;
                    }
                     
                    return true;
                }
            );
             
            // Stats card filtering
            $('#directFilter').on('click', function() {
                $('#assignmentTypeFilter').val('Direct');
                updateActiveFilters('Assignment Type', 'Direct');
                applyFilters();
                toggleStatsCardActive('directFilter');
            });
             
            $('#inheritedFilter').on('click', function() {
                $('#assignmentTypeFilter').val('Inherited');
                updateActiveFilters('Assignment Type', 'Inherited');
                applyFilters();
                toggleStatsCardActive('inheritedFilter');
            });
             
            $('#bothFilter').on('click', function() {
                $('#assignmentTypeFilter').val('Both');
                updateActiveFilters('Assignment Type', 'Both');
                applyFilters();
                toggleStatsCardActive('bothFilter');
            });
             
            $('#inactiveFilter').on('click', function() {
                $('#accountStatusFilter').val('Inactive');
                updateActiveFilters('Account Status', 'Inactive');
                applyFilters();
                toggleStatsCardActive('inactiveFilter');
            });
             
            // Button filtering
            $('.filter-button').on('click', function() {
                const filterType = $(this).data('filter');
                 
                // Clear all filter button active states
                $('.filter-button').removeClass('active');
                $(this).addClass('active');
                 
                // Reset filters
                $('#accountStatusFilter').val('');
                $('#assignmentTypeFilter').val('');
                $('#licenseNameFilter').val('');
                clearActiveFilters();
                 
                // Apply selected filter
                switch(filterType) {
                    case 'direct':
                        $('#assignmentTypeFilter').val('Direct');
                        updateActiveFilters('Assignment Type', 'Direct');
                        toggleStatsCardActive('directFilter');
                        break;
                    case 'inherited':
                        $('#assignmentTypeFilter').val('Inherited');
                        updateActiveFilters('Assignment Type', 'Inherited');
                        toggleStatsCardActive('inheritedFilter');
                        break;
                    case 'both':
                        $('#assignmentTypeFilter').val('Both');
                        updateActiveFilters('Assignment Type', 'Both');
                        toggleStatsCardActive('bothFilter');
                        break;
                    case 'inactive':
                        $('#accountStatusFilter').val('Inactive');
                        updateActiveFilters('Account Status', 'Inactive');
                        toggleStatsCardActive('inactiveFilter');
                        break;
                    case 'all':
                    default:
                        // Reset all filters
                        $('.stats-card').removeClass('active');
                        break;
                }
                 
                applyFilters();
            });
             
            // Apply filters when select boxes change
            $('#accountStatusFilter, #assignmentTypeFilter').on('change', function() {
                const filterType = $(this).attr('id');
                const filterValue = $(this).val();
                 
                if (filterValue) {
                    if (filterType === 'accountStatusFilter') {
                        updateActiveFilters('Account Status', filterValue);
                    } else if (filterType === 'assignmentTypeFilter') {
                        updateActiveFilters('Assignment Type', filterValue);
                    }
                } else {
                    if (filterType === 'accountStatusFilter') {
                        removeActiveFilter('Account Status');
                    } else if (filterType === 'assignmentTypeFilter') {
                        removeActiveFilter('Assignment Type');
                    }
                }
                 
                applyFilters();
            });
             
            // Apply filter when license name input changes
            $('#licenseNameFilter').on('input', function() {
                const filterValue = $(this).val();
                 
                if (filterValue) {
                    updateActiveFilters('License Name', filterValue);
                } else {
                    removeActiveFilter('License Name');
                }
                 
                applyFilters();
            });
             
            // Clear all filters button
            $('#clearAllFilters').on('click', function() {
                $('#accountStatusFilter').val('');
                $('#assignmentTypeFilter').val('');
                $('#licenseNameFilter').val('');
                $('.filter-button').removeClass('active');
                $('.stats-card').removeClass('active');
                clearActiveFilters();
                applyFilters();
            });
             
            // Function to apply all filters
            function applyFilters() {
                licensesTable.draw();
            }
             
            // Function to toggle stats card active state
            function toggleStatsCardActive(cardId) {
                $('.stats-card').removeClass('active');
                $('#' + cardId).addClass('active');
            }
             
            // Function to update active filters
            function updateActiveFilters(filterType, filterValue) {
                // Remove existing filter of the same type
                removeActiveFilter(filterType);
                 
                // Add new filter tag
                const filterTag = `
                    <div class="filter-tag" data-filter-type="${filterType}">
                        <span>${filterType}: ${filterValue}</span>
                        <i class="fas fa-times-circle remove-filter" data-filter-type="${filterType}"></i>
                    </div>
                `;
                 
                $('#activeFilters').append(filterTag);
                 
                // Add click handler to remove filter
                $('.remove-filter').off('click').on('click', function() {
                    const filterTypeToRemove = $(this).data('filter-type');
                     
                    if (filterTypeToRemove === 'Account Status') {
                        $('#accountStatusFilter').val('');
                    } else if (filterTypeToRemove === 'Assignment Type') {
                        $('#assignmentTypeFilter').val('');
                    } else if (filterTypeToRemove === 'License Name') {
                        $('#licenseNameFilter').val('');
                    }
                     
                    $(this).closest('.filter-tag').remove();
                     
                    // Remove active state from stat cards and filter buttons
                    if (filterTypeToRemove === 'Account Status' && $('#inactiveFilter').hasClass('active')) {
                        $('#inactiveFilter').removeClass('active');
                    } else if (filterTypeToRemove === 'Assignment Type') {
                        $('#directFilter, #inheritedFilter, #bothFilter').removeClass('active');
                    }
                     
                    $('.filter-button').removeClass('active');
                     
                    applyFilters();
                });
            }
             
            // Function to remove active filter by type
            function removeActiveFilter(filterType) {
                $('.filter-tag[data-filter-type="' + filterType + '"]').remove();
            }
             
            // Function to clear all active filters
            function clearActiveFilters() {
                $('#activeFilters').empty();
            }
             
            // Force dark mode to take effect on page elements
            $(window).on('load', function() {
                setTimeout(updateTableColors, 200);
            });
             
            // Re-apply styles after DataTables operations
            licensesTable.on('draw.dt', function() {
                setTimeout(updateTableColors, 50);
            });
             
            subscriptionTable.on('draw.dt', function() {
                setTimeout(updateTableColors, 50);
            });
        });
    </script>
</body>
</html>
'@


    # Generate table rows for user licenses
    $tableRows = ""
    foreach ($item in $Report) {
        $accountStatusClass = if ($item.AccountEnabled -eq "No") { 'class="table-danger"' } else { '' }
        
        $assignmentTypeBadge = switch ($item.AssignmentType) {
            "Direct" { '<span class="badge badge-direct">Direct</span>' }
            "Inherited" { '<span class="badge badge-inherited">Inherited</span>' }
            "Both" { '<span class="badge badge-both">Both</span>' }
            default { '<span class="badge bg-secondary">Unknown</span>' }
        }
        
        $accountStatus = if ($item.AccountEnabled -eq "Yes") {
            '<span class="badge bg-success">Active</span>'
        } else {
            '<span class="badge badge-inactive">Inactive</span>'
        }
        
        $tableRows += @"
    <tr $accountStatusClass>
        <td>$($item.DisplayName)</td>
        <td>$($item.UserPrincipalName)</td>
        <td>$accountStatus</td>
        <td>$($item.AssignedLicensesFriendlyName)</td>
        <td>$assignmentTypeBadge</td>
        <td>$($item.Inheritence)</td>
    </tr>
"@

    }

    # Generate table rows for subscription overview
    $subscriptionRows = ""
    foreach ($item in $SubscriptionOverview) {
        $availabilityPercentage = if ($item.TotalLicenses -ne 0) { 
            [Math]::Round(($item.AvailableLicenses / $item.TotalLicenses) * 100) 
        } else { 
            0 
        }
        
        $availabilityBadge = if ($availabilityPercentage -lt 10) {
            '<span class="badge bg-danger">' + $item.AvailableLicenses + ' (' + $availabilityPercentage + '%)</span>'
        } elseif ($availabilityPercentage -lt 20) {
            '<span class="badge bg-warning text-dark">' + $item.AvailableLicenses + ' (' + $availabilityPercentage + '%)</span>'
        } else {
            '<span class="badge bg-success">' + $item.AvailableLicenses + ' (' + $availabilityPercentage + '%)</span>'
        }
        
        $licenseStatusBadge = if ($item.LicenseStatus -eq "Active") {
            '<span class="badge bg-success">Active</span>'
        } else {
            '<span class="badge bg-danger">Inactive</span>'
        }
        
        $subscriptionRows += @"
    <tr>
        <td>$($item.FriendlyName)</td>
        <td>$($item.CreatedDate)</td>
        <td>$($item.EndDate)</td>
        <td>$licenseStatusBadge</td>
        <td>$($item.ConsumedUnits)</td>
        <td>$($item.TotalLicenses)</td>
        <td>$availabilityBadge</td>
    </tr>
"@

    }

    # Get current date for report
    $currentDate = Get-Date -Format "dd-MM-yyyy HH:mm"

    # Replace placeholders in template with actual values
    $htmlContent = $htmlTemplate.Replace('$Organization', $Organization)
    $htmlContent = $htmlContent.Replace('$ReportDate', $currentDate)
    $htmlContent = $htmlContent.Replace('$directLicenses', $directLicenses)
    $htmlContent = $htmlContent.Replace('$inheritedLicenses', $inheritedLicenses)
    $htmlContent = $htmlContent.Replace('$bothLicenses', $bothLicenses)
    $htmlContent = $htmlContent.Replace('$inactiveUsersWithLicenses', $inactiveUsersWithLicenses)
    $htmlContent = $htmlContent.Replace('{{TABLE_DATA}}', $tableRows)
    $htmlContent = $htmlContent.Replace('{{SUBSCRIPTION_DATA}}', $subscriptionRows)

    # Add additional CSS for dark mode pagination
    $darkModePaginationCss = @"
    <style>
        /* Dark mode pagination buttons */
        [data-theme="dark"] .page-link {
            background-color: var(--button-bg) !important;
            color: var(--text-color) !important;
            border-color: var(--border-color) !important;
        }
         
        [data-theme="dark"] .page-item.active .page-link {
            background-color: var(--primary-color) !important;
            color: white !important;
            border-color: var(--primary-color) !important;
        }
         
        [data-theme="dark"] .page-item.disabled .page-link {
            background-color: var(--card-bg) !important;
            color: #6c757d !important;
            border-color: var(--border-color) !important;
        }
         
        [data-theme="dark"] .dataTables_paginate .paginate_button {
            background-color: var(--button-bg) !important;
            color: var(--text-color) !important;
            border-color: var(--border-color) !important;
        }
         
        [data-theme="dark"] .dataTables_paginate .paginate_button.current,
        [data-theme="dark"] .dataTables_paginate .paginate_button.current:hover {
            background: var(--primary-color) !important;
            color: white !important;
            border-color: var(--primary-color) !important;
        }
         
        [data-theme="dark"] .dataTables_paginate .paginate_button:hover {
            background: var(--button-hover-bg) !important;
            color: var(--text-color) !important;
            border-color: var(--button-border) !important;
        }
         
        [data-theme="dark"] .dataTables_paginate .paginate_button.disabled,
        [data-theme="dark"] .dataTables_paginate .paginate_button.disabled:hover {
            background-color: var(--card-bg) !important;
            color: #6c757d !important;
            border-color: var(--border-color) !important;
            opacity: 0.6;
        }
    </style>
"@

    
    # Insert the dark mode pagination CSS before the </head> tag
    $htmlContent = $htmlContent.Replace('</head>', "$darkModePaginationCss`n</head>")

    # Export to HTML file
    $htmlContent | Out-File -FilePath $ExportPath -Encoding utf8

    Write-Host "All actions completed successfully." -ForegroundColor Cyan
    Write-Host "Report saved to: $ExportPath" -ForegroundColor Cyan

    # Open the HTML file
    Invoke-Item $ExportPath
}

function Test-PSVersion {
    [CmdletBinding()]
    param()
    
    $minimumVersion = [Version]"7.0.0"
    $currentVersion = $PSVersionTable.PSVersion
    
    if ($currentVersion -lt $minimumVersion) {
        Write-Host "Error: This script requires PowerShell 7.0 or higher." -ForegroundColor Red
        Write-Host "Current PowerShell version: $($currentVersion)" -ForegroundColor Red
        Write-Host "Please install PowerShell 7 from https://github.com/PowerShell/PowerShell/releases" -ForegroundColor Yellow
        
        # Check if pwsh is installed but script was run in older version
        if (Get-Command pwsh -ErrorAction SilentlyContinue) {
            Write-Host "`nPowerShell 7 appears to be installed. You can run this script with:" -ForegroundColor Cyan
            Write-Host "pwsh -File `"$($MyInvocation.PSCommandPath)`"" -ForegroundColor Cyan

            # Ask if they want to relaunch with PowerShell 7
            do {
                $response = Read-Host "Would you like to run this script using PowerShell 7 now? (Y/N)"
            } while ($response -notmatch '^(Y|y|N|n)$')

            if ($response -match '^(Y|y)$') {
                Start-Process -FilePath "pwsh" -ArgumentList "-File `"$($MyInvocation.PSCommandPath)`"" -NoNewWindow
            } else {
                Write-Host "Script execution stopped." -ForegroundColor Yellow
            }
        }
        
        # Stop script execution
        exit
    }
    
    Write-Host "PowerShell version check passed: Running PowerShell $currentVersion" -ForegroundColor Green
}

Function Install-Requirements {
    # Check if the required modules are installed
    $requiredModules = @(
        "Microsoft.Graph.Authentication",
        "Microsoft.Graph.Beta.Identity.DirectoryManagement",
        "Microsoft.Graph.Beta.Users",
        "Microsoft.Graph.Beta.Groups"
    )
    foreach ($module in $requiredModules) {
        if (-not (Get-Module -ListAvailable -Name $module)) {
            Write-Host "Installing module: $module" -ForegroundColor Cyan
            Install-Module -Name $module -Scope CurrentUser -Force -RequiredVersion 2.25.0
        } else {
            Write-Host "Module $module is already installed." -ForegroundColor Green
        }
    }

    # Import the required modules
    foreach ($module in $requiredModules) {
        $ImportedModules = Get-Module -Name Microsoft.Graph*
        if (-not ($ImportedModules | Where-Object Name -EQ $module)) {
            try {
                Import-Module -Name $module -Force -RequiredVersion 2.25.0 -ErrorAction Stop
                Write-Host "Module $module imported successfully." -ForegroundColor Green
            } catch {
                Write-Host "Failed to import module $module $_" -ForegroundColor Red
                throw
            }
        } else {
            Write-Host "Module $module was already imported successfully." -ForegroundColor Green
        }
    }
}

function Test-MgGraphConnection {
    Clear-Host

    # Authentication
    $AuthenticationScope = @(
        "User.Read.All",
        "AuditLog.Read.All",
        "Organization.Read.All",
        "RoleManagement.Read.Directory"
    )

    Connect-MgGraph -Scopes $AuthenticationScope -NoWelcome

    # Check if already connected
    $Contextinfo = Get-MgContext -ErrorAction SilentlyContinue
    if (-not $Contextinfo) {
        # If not connected, connect now
        Connect-MgGraph -Scopes $AuthenticationScope -NoWelcome
    } else {
        Write-Host "Already connected to Microsoft Graph as $($Contextinfo.Account)." -ForegroundColor Green
    }
        
    Start-Sleep -Seconds 2
    Clear-Host
}

# Check PowerShell version
Test-PSVersion

# Install required modules
Install-Requirements

# Connect to Microsoft Graph
Test-MgGraphConnection

$Organization = (Get-MgBetaOrganization).displayName

# Import the Product names and service plan identifiers for licensing CSV file
[array]$Identifiers = Invoke-RestMethod -Method Get -Uri "https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-490a-9ada-c6089a1fc5b0/Product%20names%20and%20service%20plan%20identifiers%20for%20licensing.csv" | ConvertFrom-Csv

# Select all SKUs with friendly display name
[array]$SKU_friendly = $Identifiers | Select-Object GUID, String_Id, Product_Display_Name -Unique

# Get products used in tenant
[Array]$Skus = Get-MgBetaSubscribedSku

# Get subscriptions with their end dates
[Array]$Subscriptions = Get-MgBetaDirectorySubscription -Property *

# Create an overview of subscriptions with their end date
$SubscriptionOverview = @()

foreach ($subscription in $Subscriptions) {
    $sku = $Skus | Where-Object { $_.SkuId -eq $subscription.SkuId }
    $friendlyName = $SKU_friendly | Where-Object { $_.GUID -eq $sku.SkuId } | Select-Object -ExpandProperty Product_Display_Name

    $endDate = if ($subscription.NextLifecycleDateTime -eq $null) {
        "No end date found"
    } else {
        $subscription.NextLifecycleDateTime
    }

    # Format dates if they're not strings
    $formattedCreatedDate = if ($subscription.CreatedDateTime -is [DateTime]) {
        Get-Date $subscription.CreatedDateTime -Format "dd-MM-yyyy HH:mm"
    } else {
        $subscription.CreatedDateTime
    }

    $formattedEndDate = if ($endDate -is [DateTime]) {
        Get-Date $endDate -Format "dd-MM-yyyy HH:mm"
    } else {
        $endDate
    }

    # Determine license status based on end date
    $licenseStatus = if ($endDate -eq "No end date found") {
        "Active"
    } elseif ($endDate -is [DateTime] -and $endDate -gt (Get-Date)) {
        "Active"
    } else {
        "Inactive"
    }

    $SubscriptionOverview += [PSCustomObject]@{
        SubscriptionId    = $subscription.Id
        FriendlyName      = $friendlyName
        CreatedDate       = $formattedCreatedDate
        EndDate           = $formattedEndDate
        LicenseStatus     = $licenseStatus
        ConsumedUnits     = $sku.ConsumedUnits
        TotalLicenses     = $subscription.TotalLicenses
        AvailableLicenses = $subscription.TotalLicenses - $sku.ConsumedUnits
    }
}

# Output the overview
Write-Host "INFO: Generating subscription overview..." -ForegroundColor Cyan

# Generate CSV of all SKUs
$Report = @()
# Get all users with licenses
$users = Get-MgBetaUser -All -Select UserPrincipalName, AssignedLicenses, LicenseAssignmentStates, DisplayName, AccountEnabled | Select-Object UserPrincipalName, DisplayName, AssignedLicenses, LicenseAssignmentStates, AccountEnabled

# Get all groups and licenses
$groups = Get-MgBetaGroup -All
$groupsWithLicenses = @()
# Loop through each group and check if it has any licenses assigned
Write-Host "INFO: Checking groups for licenses..." -ForegroundColor Cyan
foreach ($group in $groups) {
    $licenses = Get-MgBetaGroup -GroupId $group.Id -Property "AssignedLicenses, Id, DisplayName" |
        Select-Object AssignedLicenses, DisplayName, Id
    if ($licenses.AssignedLicenses) {
        $groupData = [PSCustomObject]@{
            ObjectId    = $group.Id
            DisplayName = $group.DisplayName
            Licenses    = $licenses.AssignedLicenses
        }
        $groupsWithLicenses += $groupData
    }
}

$totalUsers = $users.Count
$currentIndex = 0

foreach ($user in $users) {
    $currentIndex++
    Write-Progress -Activity "Processing users" -Status "Processing $currentIndex of $totalUsers" -PercentComplete (($currentIndex / $totalUsers) * 100)

    $AssignmentDetails = $user | Select-Object -ExpandProperty licenseAssignmentStates
    $GroupedAssignmentDetails = $AssignmentDetails | Group-Object -Property SkuId

    foreach ($GroupedAssignmentDetail in $GroupedAssignmentDetails) {
        $SkuId = $GroupedAssignmentDetail.Name
        $AssignedByGroup = $GroupedAssignmentDetail.Group | Where-Object { $_.AssignedByGroup -ne $null }
        $DirectAssignment = $GroupedAssignmentDetail.Group | Where-Object { $_.AssignedByGroup -eq $null }
        $FriendlyName = ($SKU_friendly | Where-Object { $_.GUID -eq $SkuId }).Product_Display_Name

        $isDirect = if ($DirectAssignment) { $true } else { $false }
        $isInherited = if ($AssignedByGroup) { $true } else { $false }
        
        $assignmentType = if ($isDirect -and $isInherited) {
            "Both"
        } elseif ($isDirect) {
            "Direct"
        } elseif ($isInherited) {
            "Inherited"
        } else {
            "Unknown"
        }

        $AssignedGroups = @()
        if ($AssignedByGroup) {
            foreach ($Group in $AssignedByGroup) {
                $AssignedGroups += ($groupsWithLicenses | Where-Object { $_.ObjectId -eq $Group.AssignedByGroup }).DisplayName
            }
            $AssignedGroups = $AssignedGroups -join ", "
        }

        if ($DirectAssignment -and -not $AssignedGroups) {
            $inheritence = "Direct"
        } elseif (-not $DirectAssignment -and $AssignedGroups) {
            $inheritence = "$AssignedGroups"
        } elseif ($DirectAssignment -and $AssignedGroups) {
            $inheritence = "Direct, $AssignedGroups"
        }

        $licenseData = [PSCustomObject]@{
            UserPrincipalName            = $user.UserPrincipalName
            DisplayName                  = $user.DisplayName
            AccountEnabled               = if ($user.AccountEnabled) { "Yes" } else { "No" }
            AssignedLicenses             = $SkuId
            AssignedLicensesFriendlyName = $FriendlyName
            Inheritence                  = $inheritence
            AssignmentType               = $assignmentType
            IsDirect                     = $isDirect
            IsInherited                  = $isInherited
        }
        $Report += $licenseData
    }
}

# Calculate metrics for summary boxes
$directLicenses = ($Report | Where-Object { $_.IsDirect -eq $true }).Count
$inheritedLicenses = ($Report | Where-Object { $_.IsInherited -eq $true -and $_.IsDirect -eq $false }).Count
$bothLicenses = ($Report | Where-Object { $_.IsDirect -eq $true -and $_.IsInherited -eq $true }).Count
$inactiveUsersWithLicenses = ($Report | Where-Object { $_.AccountEnabled -eq "No" } | Select-Object UserPrincipalName -Unique).Count

# Output the report
Write-Host "INFO: Generating report..." -ForegroundColor Cyan

# Generate HTML report
New-HTMLReport -Organization $Organization -Report $Report -SubscriptionOverview $SubscriptionOverview

# Disconnect from Microsoft Graph
Disconnect-MgGraph | Out-Null
Write-Host "Disconnected from Microsoft Graph." -ForegroundColor Green