Tag Archive for: Remote Desktop

RDS License Audit Toolkit

<#
.SYNOPSIS
RDS License Audit Toolkit

.DESCRIPTION
This script performs a comprehensive audit of Remote Desktop Services (RDS) licensing,
including license server configuration, available licenses, and usage statistics.

.NOTES
File Name      : RDSLicenseAuditToolkit.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V5.1 or later, administrator rights, and RDS management tools
Version        : 1.0
Date           : [Current Date]

.EXAMPLE
.\RDSLicenseAuditToolkit.ps1
#>

# Global variables
$global:reportPath = "$env:USERPROFILE\Desktop\RDS_License_Audit_Report_$(Get-Date -Format 'yyyyMMdd_HHmmss').html"
$global:licenseServer = $env:COMPUTERNAME  # Default to local machine

function Show-Menu {
    Clear-Host
    Write-Host "=== RDS License Audit Toolkit ===" -ForegroundColor Cyan
    Write-Host "Current License Server: $global:licenseServer"
    Write-Host "1. Set License Server"
    Write-Host "2. Check License Server Configuration"
    Write-Host "3. List Available Licenses"
    Write-Host "4. Analyze License Usage"
    Write-Host "5. Check RDS Server Configuration"
    Write-Host "6. Verify CAL Compliance"
    Write-Host "7. Review License Policies"
    Write-Host "8. Check License Server Health"
    Write-Host "9. Generate Comprehensive HTML Report"
    Write-Host "10. Exit"
}

function Set-LicenseServer {
    $server = Read-Host "Enter the RDS License Server name (or press Enter for localhost)"
    if ([string]::IsNullOrWhiteSpace($server)) {
        $global:licenseServer = $env:COMPUTERNAME
    } else {
        $global:licenseServer = $server
    }
    Write-Host "License server set to: $global:licenseServer" -ForegroundColor Green
}

function Check-LicenseServerConfiguration {
    Write-Host "`nChecking License Server Configuration..." -ForegroundColor Yellow
    try {
        $config = Invoke-Command -ComputerName $global:licenseServer -ScriptBlock {
            Import-Module RemoteDesktopServices
            $serverInfo = Get-RDLicenseConfiguration
            $serverStatus = Get-RDLicenseServerStatus
            return @{
                ServerInfo = $serverInfo
                ServerStatus = $serverStatus
            }
        }
        
        $result = [PSCustomObject]@{
            Mode = $config.ServerInfo.Mode
            LicensingType = $config.ServerInfo.LicensingType
            IsActivated = $config.ServerStatus.IsActivated
            LastIssuedLicenseDate = $config.ServerStatus.LastIssuedLicenseDate
            GracePeriodDays = $config.ServerStatus.GracePeriodDays
        }
        
        $result | Format-List
        return $result
    }
    catch {
        Write-Host "Error checking license server configuration: $_" -ForegroundColor Red
        return $null
    }
}

function List-AvailableLicenses {
    Write-Host "`nListing Available Licenses..." -ForegroundColor Yellow
    try {
        $licenses = Invoke-Command -ComputerName $global:licenseServer -ScriptBlock {
            Import-Module RemoteDesktopServices
            Get-RDLicense
        }
        
        $licenses | Format-Table -AutoSize
        return $licenses
    }
    catch {
        Write-Host "Error listing available licenses: $_" -ForegroundColor Red
        return $null
    }
}

function Analyze-LicenseUsage {
    Write-Host "`nAnalyzing License Usage..." -ForegroundColor Yellow
    try {
        $usage = Invoke-Command -ComputerName $global:licenseServer -ScriptBlock {
            Import-Module RemoteDesktopServices
            Get-RDLicenseUsage
        }
        
        $usage | Format-Table -AutoSize
        return $usage
    }
    catch {
        Write-Host "Error analyzing license usage: $_" -ForegroundColor Red
        return $null
    }
}

function Check-RDSServerConfiguration {
    Write-Host "`nChecking RDS Server Configuration..." -ForegroundColor Yellow
    try {
        $config = Invoke-Command -ComputerName $global:licenseServer -ScriptBlock {
            Import-Module RemoteDesktopServices
            $deployment = Get-RDDeploymentGatewayConfiguration
            $collection = Get-RDSessionCollection
            return @{
                Deployment = $deployment
                Collection = $collection
            }
        }
        
        $result = [PSCustomObject]@{
            GatewayMode = $config.Deployment.GatewayMode
            CollectionName = $config.Collection.CollectionName
            CollectionDescription = $config.Collection.CollectionDescription
        }
        
        $result | Format-List
        return $result
    }
    catch {
        Write-Host "Error checking RDS server configuration: $_" -ForegroundColor Red
        return $null
    }
}

function Verify-CALCompliance {
    Write-Host "`nVerifying CAL Compliance..." -ForegroundColor Yellow
    try {
        $compliance = Invoke-Command -ComputerName $global:licenseServer -ScriptBlock {
            Import-Module RemoteDesktopServices
            $licenses = Get-RDLicense
            $usage = Get-RDLicenseUsage
            
            $totalLicenses = ($licenses | Measure-Object -Property TotalLicenses -Sum).Sum
            $usedLicenses = ($usage | Measure-Object -Property IssuedLicenses -Sum).Sum
            
            return @{
                TotalLicenses = $totalLicenses
                UsedLicenses = $usedLicenses
                IsCompliant = $totalLicenses -ge $usedLicenses
            }
        }
        
        $result = [PSCustomObject]@{
            TotalLicenses = $compliance.TotalLicenses
            UsedLicenses = $compliance.UsedLicenses
            IsCompliant = $compliance.IsCompliant
            ComplianceStatus = if ($compliance.IsCompliant) { "Compliant" } else { "Non-Compliant" }
        }
        
        $result | Format-List
        return $result
    }
    catch {
        Write-Host "Error verifying CAL compliance: $_" -ForegroundColor Red
        return $null
    }
}

function Review-LicensePolicies {
    Write-Host "`nReviewing License Policies..." -ForegroundColor Yellow
    try {
        $policies = Invoke-Command -ComputerName $global:licenseServer -ScriptBlock {
            Import-Module RemoteDesktopServices
            Get-RDLicenseConfiguration
        }
        
        $result = [PSCustomObject]@{
            Mode = $policies.Mode
            LicensingType = $policies.LicensingType
            PolicyExpirationDays = $policies.PolicyExpirationDays
            PolicyOverrideAllowed = $policies.PolicyOverrideAllowed
        }
        
        $result | Format-List
        return $result
    }
    catch {
        Write-Host "Error reviewing license policies: $_" -ForegroundColor Red
        return $null
    }
}

function Check-LicenseServerHealth {
    Write-Host "`nChecking License Server Health..." -ForegroundColor Yellow
    try {
        $health = Invoke-Command -ComputerName $global:licenseServer -ScriptBlock {
            Import-Module RemoteDesktopServices
            $status = Get-RDLicenseServerStatus
            $service = Get-Service -Name TermServLicensing
            
            return @{
                Status = $status
                ServiceStatus = $service.Status
            }
        }
        
        $result = [PSCustomObject]@{
            IsActivated = $health.Status.IsActivated
            LastIssuedLicenseDate = $health.Status.LastIssuedLicenseDate
            GracePeriodDays = $health.Status.GracePeriodDays
            ServiceStatus = $health.ServiceStatus
        }
        
        $result | Format-List
        return $result
    }
    catch {
        Write-Host "Error checking license server health: $_" -ForegroundColor Red
        return $null
    }
}

function Generate-HTMLReport {
    param([hashtable]$AllResults)

    Write-Host "`nGenerating Comprehensive HTML Report..." -ForegroundColor Yellow
    $reportContent = @"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RDS License Audit Report</title>
    <style>
        body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 1200px; margin: 0 auto; padding: 20px; }
        h1, h2, h3 { color: #0078D4; }
        table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        .warning { color: orange; }
        .critical { color: red; }
        .success { color: green; }
    </style>
</head>
<body>
    <h1>RDS License Audit Report</h1>
    <p>Generated on: $(Get-Date)</p>
    <p>License Server: $global:licenseServer</p>

    <h2>License Server Configuration</h2>
    $($AllResults.ServerConfig | ConvertTo-Html -Fragment)

    <h2>Available Licenses</h2>
    $($AllResults.AvailableLicenses | ConvertTo-Html -Fragment)

    <h2>License Usage</h2>
    $($AllResults.LicenseUsage | ConvertTo-Html -Fragment)

    <h2>RDS Server Configuration</h2>
    $($AllResults.RDSConfig | ConvertTo-Html -Fragment)

    <h2>CAL Compliance</h2>
    $($AllResults.CALCompliance | ConvertTo-Html -Fragment)

    <h2>License Policies</h2>
    $($AllResults.LicensePolicies | ConvertTo-Html -Fragment)

    <h2>License Server Health</h2>
    $($AllResults.ServerHealth | ConvertTo-Html -Fragment)
</body>
</html>
"@

    $reportContent | Out-File -FilePath $global:reportPath
    Write-Host "Report generated and saved to: $global:reportPath" -ForegroundColor Green
}

# Main program loop
$allResults = @{}

do {
    Show-Menu
    $choice = Read-Host "`nEnter your choice (1-10)"

    switch ($choice) {
        "1" { Set-LicenseServer }
        "2" { $allResults.ServerConfig = Check-LicenseServerConfiguration }
        "3" { $allResults.AvailableLicenses = List-AvailableLicenses }
        "4" { $allResults.LicenseUsage = Analyze-LicenseUsage }
        "5" { $allResults.RDSConfig = Check-RDSServerConfiguration }
        "6" { $allResults.CALCompliance = Verify-CALCompliance }
        "7" { $allResults.LicensePolicies = Review-LicensePolicies }
        "8" { $allResults.ServerHealth = Check-LicenseServerHealth }
        "9" { Generate-HTMLReport -AllResults $allResults }
        "10" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

    if ($choice -ne "10") {
        Read-Host "`nPress Enter to continue..."
    }
} while ($choice -ne "10")

This RDS License Audit Toolkit includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to analyze various aspects of RDS licensing:
    • License Server Configuration Check
    • Available Licenses Listing
    • License Usage Analysis
    • RDS Server Configuration Check
    • CAL Compliance Verification
    • License Policies Review
    • License Server Health Check
  3. Option to set a target license server (local or remote)
  4. HTML report generation for easy sharing and viewing of results

Key features:

  • Comprehensive RDS license server configuration analysis
  • Detailed listing of available licenses and their types
  • Analysis of current license usage
  • Verification of Client Access License (CAL) compliance
  • Review of RDS deployment and collection configurations
  • Examination of license policies and server health

This tool is particularly useful for:

  • RDS administrators managing license servers
  • IT professionals auditing RDS environments
  • System administrators troubleshooting RDS licensing issues
  • Anyone needing to quickly gather comprehensive information about RDS licensing configuration and usage

To use this script effectively:

  1. Run PowerShell as an administrator
  2. Ensure you have the Remote Desktop Services PowerShell module installed
  3. Have the necessary permissions to query RDS license information (local admin rights on the license server or appropriate delegated permissions)
  4. Review the generated HTML report for a comprehensive overview of the RDS licensing status and configuration

This script provides a thorough analysis of RDS licensing, helping to identify potential issues, compliance concerns, or areas that need attention. It’s designed to give administrators a quick but comprehensive view of their RDS licensing health and configuration.

RDS Login and Logout Logging Script

<#
.SYNOPSIS
RDS Login and Logout Logging Script

.DESCRIPTION
This script automatically logs user login and logout events for Remote Desktop Services.
It runs continuously as a background job, monitoring the Windows Event Log for relevant events.

.NOTES
File Name      : RDSLoginLogoutLogger.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V3 or later, admin rights on the RDS server
Version        : 1.0
Date           : [Current Date]

.EXAMPLE
Start-Job -FilePath .\RDSLoginLogoutLogger.ps1
#>

# Configuration
$logFilePath = "C:\Logs\RDSLoginLogout.log"
$lastRunFile = "C:\Logs\RDSLoginLogoutLastRun.txt"

# Ensure log directory exists
$logDir = Split-Path $logFilePath -Parent
if (-not (Test-Path $logDir)) {
    New-Item -ItemType Directory -Path $logDir | Out-Null
}

# Function to write log entries
function Write-Log {
    param (
        [string]$Message
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $Message"
    Add-Content -Path $logFilePath -Value $logEntry
}

# Function to get the last run time
function Get-LastRunTime {
    if (Test-Path $lastRunFile) {
        return Get-Content $lastRunFile
    }
    return (Get-Date).AddDays(-1).ToString("o")  # Default to 1 day ago if no last run time
}

# Function to save the last run time
function Save-LastRunTime {
    param (
        [DateTime]$LastRunTime
    )
    $LastRunTime.ToString("o") | Set-Content $lastRunFile
}

# Main logging loop
try {
    Write-Log "RDS Login/Logout logging started."

    while ($true) {
        $lastRunTime = Get-LastRunTime
        $currentTime = Get-Date

        # Query for login events
        $loginEvents = Get-WinEvent -FilterHashtable @{
            LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'
            ID = 21  # Event ID for session logon
            StartTime = $lastRunTime
        } -ErrorAction SilentlyContinue

        # Query for logout events
        $logoutEvents = Get-WinEvent -FilterHashtable @{
            LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'
            ID = 23  # Event ID for session logoff
            StartTime = $lastRunTime
        } -ErrorAction SilentlyContinue

        # Process login events
        foreach ($event in $loginEvents) {
            $username = $event.Properties[0].Value
            $sessionId = $event.Properties[1].Value
            Write-Log "User logged in: $username (Session ID: $sessionId)"
        }

        # Process logout events
        foreach ($event in $logoutEvents) {
            $username = $event.Properties[0].Value
            $sessionId = $event.Properties[1].Value
            Write-Log "User logged out: $username (Session ID: $sessionId)"
        }

        # Save the current time as the last run time
        Save-LastRunTime $currentTime

        # Wait for a minute before the next check
        Start-Sleep -Seconds 60
    }
}
catch {
    Write-Log "An error occurred: $_"
}
finally {
    Write-Log "RDS Login/Logout logging stopped."
}

To use this script:

  1. Save the script as RDSLoginLogoutLogger.ps1 in a suitable location on your RDS server.
  2. Modify the $logFilePath and $lastRunFile variables at the beginning of the script if you want to change the default log locations.
  3. To run the script as a background job, open PowerShell as an administrator and use the following command:
    Start-Job -FilePath C:\Path\To\RDSLoginLogoutLogger.ps1
    Replace C:\Path\To\ with the actual path where you saved the script.
  4. To check the status of the job: Get-Job
  5. To stop the job when needed: Stop-Job -Id <JobId>
  6. Replace <JobId> with the ID of the job from the Get-Job command.

Key features of this script:

  1. Continuous Monitoring: Runs as a background job, continuously checking for new login and logout events.
  2. Efficient Event Querying: Uses the last run time to query only for new events since the last check.
  3. Separate Log File: Logs events to a dedicated file for easy review and analysis.
  4. Error Handling: Includes basic error handling to log any issues that occur during execution.
  5. Low Resource Usage: Checks for new events every minute, balancing timeliness with system resource usage.

Notes:

  • This script needs to be run with administrator privileges on the RDS server.
  • The script creates a log file and a last run time file. Ensure the specified paths are accessible and writable.
  • For long-term use, consider implementing a log rotation mechanism to manage log file sizes.
  • You may need to adjust the event IDs (21 for login, 23 for logout) if your RDS environment uses different event IDs for these actions.
  • Always test the script in a non-production environment before deploying it to production servers.

This script provides a robust solution for automatically logging RDS login and logout events, which can be valuable for security auditing, user activity tracking, and compliance purposes.

RDS Toolkit – Remote Desktop Services Management Script

<#
.SYNOPSIS
RDS Toolkit - Comprehensive Remote Desktop Services Management Script

.DESCRIPTION
This script provides a set of tools for managing and monitoring Remote Desktop Services environments.
It includes functions for session management, user monitoring, performance analysis, and reporting.

.NOTES
File Name      : RDSToolkit.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V5.1 or later, admin rights on the RDS server
Version        : 1.0
Date           : [Current Date]

.EXAMPLE
.\RDSToolkit.ps1
#>

# Import required modules
Import-Module RemoteDesktop

# Global variables
$global:logFile = "$env:USERPROFILE\Desktop\RDS_Toolkit_Log_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"

function Write-Log {
    param (
        [string]$Message
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $Message"
    Add-Content -Path $global:logFile -Value $logEntry
    Write-Host $logEntry
}

function Show-Menu {
    Clear-Host
    Write-Host "=== RDS Toolkit ===" -ForegroundColor Cyan
    Write-Host "1. List Active Sessions"
    Write-Host "2. Disconnect User"
    Write-Host "3. Log Off User"
    Write-Host "4. Send Message to Users"
    Write-Host "5. Monitor Disconnected Sessions"
    Write-Host "6. View RDS Server Performance"
    Write-Host "7. Generate RDS Usage Report"
    Write-Host "8. Manage RDS Collections"
    Write-Host "9. Exit"
}

function Get-ActiveSessions {
    $sessions = quser | Where-Object { $_ -match 'Active' }
    $activeSessions = @()
    foreach ($session in $sessions) {
        $sessionInfo = $session -split '\s+'
        $activeSessions += [PSCustomObject]@{
            Username = $sessionInfo[1]
            SessionID = $sessionInfo[2]
            State = $sessionInfo[3]
            IdleTime = $sessionInfo[4]
            LogonTime = $sessionInfo[5..($sessionInfo.Length-1)] -join ' '
        }
    }
    return $activeSessions
}

function Disconnect-RDSUser {
    $username = Read-Host "Enter username to disconnect"
    $sessions = quser | Where-Object { $_ -match $username }
    if ($sessions) {
        $sessionId = ($sessions -split '\s+')[2]
        tsdiscon $sessionId
        Write-Log "Disconnected user: $username (Session ID: $sessionId)"
    } else {
        Write-Host "User not found or not connected." -ForegroundColor Yellow
    }
}

function LogOff-RDSUser {
    $username = Read-Host "Enter username to log off"
    $sessions = quser | Where-Object { $_ -match $username }
    if ($sessions) {
        $sessionId = ($sessions -split '\s+')[2]
        logoff $sessionId
        Write-Log "Logged off user: $username (Session ID: $sessionId)"
    } else {
        Write-Host "User not found or not connected." -ForegroundColor Yellow
    }
}

function Send-MessageToUsers {
    $message = Read-Host "Enter message to send"
    $users = Get-ActiveSessions
    foreach ($user in $users) {
        msg $user.Username $message
    }
    Write-Log "Sent message to all active users: $message"
}

function Monitor-DisconnectedSessions {
    $duration = Read-Host "Enter monitoring duration in minutes (0 for continuous)"
    $startTime = Get-Date
    Write-Host "Monitoring disconnected sessions. Press Ctrl+C to stop." -ForegroundColor Yellow
    
    try {
        while ($true) {
            $disconnectedSessions = quser | Where-Object { $_ -match 'Disc' }
            foreach ($session in $disconnectedSessions) {
                $sessionInfo = $session -split '\s+'
                Write-Host "Disconnected: $($sessionInfo[1]) (Session ID: $($sessionInfo[2]))" -ForegroundColor Red
                Write-Log "Disconnected session detected: $($sessionInfo[1]) (Session ID: $($sessionInfo[2]))"
            }
            
            if ($duration -ne "0" -and ((Get-Date) - $startTime).TotalMinutes -ge $duration) {
                break
            }
            
            Start-Sleep -Seconds 30
        }
    }
    catch {
        Write-Host "Monitoring stopped." -ForegroundColor Yellow
    }
}

function View-RDSServerPerformance {
    $duration = Read-Host "Enter monitoring duration in minutes"
    $interval = Read-Host "Enter sampling interval in seconds"
    $startTime = Get-Date
    $endTime = $startTime.AddMinutes($duration)
    
    Write-Host "Monitoring RDS server performance. This may take $duration minutes." -ForegroundColor Yellow
    
    $performanceData = @()
    
    while ((Get-Date) -lt $endTime) {
        $cpu = (Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue
        $memory = (Get-Counter '\Memory\% Committed Bytes In Use').CounterSamples.CookedValue
        $disk = (Get-Counter '\PhysicalDisk(_Total)\% Disk Time').CounterSamples.CookedValue
        $network = (Get-Counter '\Network Interface(*)\Bytes Total/sec').CounterSamples.CookedValue | Measure-Object -Sum | Select-Object -ExpandProperty Sum
        
        $performanceData += [PSCustomObject]@{
            Timestamp = Get-Date
            CPU = [math]::Round($cpu, 2)
            Memory = [math]::Round($memory, 2)
            Disk = [math]::Round($disk, 2)
            Network = [math]::Round($network / 1MB, 2)  # Convert to MB/s
        }
        
        Start-Sleep -Seconds $interval
    }
    
    $performanceData | Format-Table -AutoSize
    $performanceData | Export-Csv -Path "$env:USERPROFILE\Desktop\RDS_Performance_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" -NoTypeInformation
    Write-Host "Performance data exported to desktop." -ForegroundColor Green
}

function Generate-RDSUsageReport {
    $days = Read-Host "Enter number of days for the report"
    $startDate = (Get-Date).AddDays(-$days)
    $events = Get-WinEvent -FilterHashtable @{
        LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'
        ID = 21, 23, 24, 25  # Logon, Logoff, Disconnect, Reconnect
        StartTime = $startDate
    }
    
    $report = @()
    foreach ($event in $events) {
        $report += [PSCustomObject]@{
            Timestamp = $event.TimeCreated
            Username = $event.Properties[0].Value
            EventType = switch ($event.Id) {
                21 { "Logon" }
                23 { "Logoff" }
                24 { "Disconnect" }
                25 { "Reconnect" }
            }
        }
    }
    
    $report | Format-Table -AutoSize
    $report | Export-Csv -Path "$env:USERPROFILE\Desktop\RDS_Usage_Report_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" -NoTypeInformation
    Write-Host "Usage report exported to desktop." -ForegroundColor Green
}

function Manage-RDSCollections {
    Write-Host "RDS Collections Management" -ForegroundColor Cyan
    Write-Host "1. List Collections"
    Write-Host "2. Create New Collection"
    Write-Host "3. Add Server to Collection"
    Write-Host "4. Remove Server from Collection"
    Write-Host "5. Back to Main Menu"
    
    $choice = Read-Host "Enter your choice"
    
    switch ($choice) {
        "1" {
            Get-RDSessionCollection | Format-Table -AutoSize
        }
        "2" {
            $name = Read-Host "Enter new collection name"
            $sessionHost = Read-Host "Enter session host server name"
            New-RDSessionCollection -CollectionName $name -SessionHost $sessionHost
            Write-Log "Created new RDS collection: $name"
        }
        "3" {
            $collection = Read-Host "Enter collection name"
            $server = Read-Host "Enter server to add"
            Add-RDSessionHost -CollectionName $collection -SessionHost $server
            Write-Log "Added server $server to collection $collection"
        }
        "4" {
            $collection = Read-Host "Enter collection name"
            $server = Read-Host "Enter server to remove"
            Remove-RDSessionHost -CollectionName $collection -SessionHost $server
            Write-Log "Removed server $server from collection $collection"
        }
        "5" {
            return
        }
        default {
            Write-Host "Invalid choice. Please try again." -ForegroundColor Red
        }
    }
    
    Pause
    Manage-RDSCollections
}

# Main program loop
do {
    Show-Menu
    $choice = Read-Host "`nEnter your choice (1-9)"

    switch ($choice) {
        "1" { Get-ActiveSessions | Format-Table -AutoSize }
        "2" { Disconnect-RDSUser }
        "3" { LogOff-RDSUser }
        "4" { Send-MessageToUsers }
        "5" { Monitor-DisconnectedSessions }
        "6" { View-RDSServerPerformance }
        "7" { Generate-RDSUsageReport }
        "8" { Manage-RDSCollections }
        "9" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

    if ($choice -ne "9") {
        Read-Host "`nPress Enter to continue..."
    }
} while ($choice -ne "9")

This RDS Toolkit script provides a comprehensive set of tools for managing and monitoring Remote Desktop Services environments. Here’s a breakdown of its features:

  1. List Active Sessions: Displays all currently active RDS sessions.
  2. Disconnect User: Allows you to disconnect a specific user.
  3. Log Off User: Allows you to log off a specific user.
  4. Send Message to Users: Sends a broadcast message to all active users.
  5. Monitor Disconnected Sessions: Continuously monitors and reports on disconnected sessions.
  6. View RDS Server Performance: Monitors and reports on server performance metrics (CPU, Memory, Disk, Network).
  7. Generate RDS Usage Report: Creates a report of RDS usage over a specified number of days.
  8. Manage RDS Collections: Provides options to list, create, and modify RDS collections.

To use this script:

  1. Save it as RDSToolkit.ps1.
  2. Open PowerShell as an administrator on the RDS server.
  3. Navigate to the directory containing the script.
  4. Run the script:

.\RDSToolkit.ps1

Notes:

  • This script requires administrative privileges on the RDS server.
  • Some functions may require additional modules or permissions depending on your RDS setup.
  • The script creates log files and exports reports to the desktop by default. You may want to modify these paths for production use.
  • Always test the script in a non-production environment before using it in production.

This toolkit provides a solid foundation for managing RDS environments and can be further customized based on specific organizational needs or more complex RDS setups.

RDS User Disconnected Monitor and Action Script

<#
.SYNOPSIS
RDS User Disconnected Monitor and Action Script

.DESCRIPTION
This script monitors Remote Desktop Services for disconnected user sessions
and performs specified actions when a user disconnects.

.PARAMETER Action
The action to perform when a user disconnects. Options are 'Log', 'Logoff', or 'Both'.

.PARAMETER LogFile
The path of the log file where disconnect events will be recorded.

.EXAMPLE
.\RDSDisconnectMonitor.ps1 -Action "Log" -LogFile "C:\Logs\RDSDisconnects.log"

.NOTES
File Name      : RDSDisconnectMonitor.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V3 or later, admin rights on the RDS server
Version        : 1.0
Date           : [Current Date]
#>

param (
    [Parameter(Mandatory=$true)]
    [ValidateSet("Log", "Logoff", "Both")]
    [string]$Action,

    [Parameter(Mandatory=$true)]
    [string]$LogFile
)

# Function to write log entries
function Write-Log {
    param (
        [string]$Message
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $Message"
    Add-Content -Path $LogFile -Value $logEntry
    Write-Host $logEntry
}

# Function to get disconnected sessions
function Get-DisconnectedSessions {
    $sessions = quser | Where-Object { $_ -match 'Disc' }
    $disconnectedUsers = @()
    foreach ($session in $sessions) {
        $sessionInfo = $session -split '\s+'
        $disconnectedUsers += [PSCustomObject]@{
            Username = $sessionInfo[1]
            SessionID = $sessionInfo[2]
        }
    }
    return $disconnectedUsers
}

# Function to perform action on disconnected session
function Perform-Action {
    param (
        [string]$Username,
        [string]$SessionID
    )

    switch ($Action) {
        "Log" {
            Write-Log "User disconnected: $Username (Session ID: $SessionID)"
        }
        "Logoff" {
            logoff $SessionID
            Write-Log "User logged off: $Username (Session ID: $SessionID)"
        }
        "Both" {
            Write-Log "User disconnected: $Username (Session ID: $SessionID)"
            logoff $SessionID
            Write-Log "User logged off: $Username (Session ID: $SessionID)"
        }
    }
}

# Create the log file if it doesn't exist
if (-not (Test-Path $LogFile)) {
    New-Item -Path $LogFile -ItemType File -Force
}

Write-Log "Starting RDS disconnect monitoring..."

# Main monitoring loop
try {
    $previousSessions = @()
    while ($true) {
        $currentSessions = Get-DisconnectedSessions
        
        # Check for new disconnections
        foreach ($session in $currentSessions) {
            if ($session.Username -notin $previousSessions.Username) {
                Perform-Action -Username $session.Username -SessionID $session.SessionID
            }
        }

        $previousSessions = $currentSessions
        Start-Sleep -Seconds 30  # Check every 30 seconds
    }
}
catch {
    Write-Log "An error occurred: $_"
}
finally {
    Write-Log "RDS disconnect monitoring stopped."
}

To use this script:

  1. Save it as RDSDisconnectMonitor.ps1.
  2. Open PowerShell as an administrator on the RDS server.
  3. Navigate to the directory containing the script.
  4. Run the script with the required parameters:

.\RDSDisconnectMonitor.ps1 -Action "Log" -LogFile "C:\Logs\RDSDisconnects.log"

You can replace “Log” with “Logoff” to automatically log off disconnected users, or “Both” to log and then log off.

Key features of this script:

  1. Monitoring: Continuously checks for disconnected RDS sessions.
  2. Flexible Actions: Can log disconnections, automatically log off disconnected users, or both.
  3. Logging: Records all actions and events to a specified log file.
  4. Customizable: Easy to modify for additional actions or different checking intervals.

Notes:

  • This script needs to be run with administrator privileges on the RDS server.
  • The script will continue running until manually stopped (e.g., by pressing Ctrl+C).
  • For production use, consider running this script as a Windows Service or scheduled task.
  • The script checks for disconnections every 30 seconds by default. You can adjust this interval by changing the Start-Sleep -Seconds 30 line.
  • Be cautious when using the “Logoff” action, as it will forcibly close user sessions, which might result in data loss if users have unsaved work.

This script provides a foundation for monitoring and managing disconnected RDS sessions. You can further customize it based on your specific requirements, such as sending notifications, integrating with other systems, or implementing more complex decision logic for when to log off users.