September 2026

 Here is the code.



<#
.SYNOPSIS
Collects drive space details from a list of Windows servers and emails an HTML report.

FIX NOTES (applied to match the SQL health-check report):
1. Container width now matches the other report: width="1000" with
   style="width:100%;max-width:1000px;" so it is fluid-responsive instead
   of a hard-coded 1100px block that can overflow narrow Outlook Web panes.
2. Rounded corners + border-collapse:collapse do not render together in
   Outlook Web (the browser drops the radius the moment collapse is on).
   The results table now uses the same "wrapper" trick as the SQL report:
   an outer table with border-radius + overflow:hidden clips the corners,
   and the inner table uses border-collapse:separate with per-cell
   bottom/right borders instead of collapsed borders.
3. Header <th> cells get bgcolor + explicit inline styles (not just a
   background on the parent <tr>), and the first/last header cells carry
   their own top-corner radius as a fallback for clients that strip
   overflow:hidden.
4. Server / DeviceID values are HTML-encoded before being written into the
   table, so a stray "&" or "<" in a name can't break the layout.
#>

# ---- CONFIG ----
$serverListPath = "C:\Scripts\servers.txt"

$servers = Get-Content $serverListPath |
           Where-Object { $_.Trim() -ne "" }

$smtpServer    = "smtp.yourcompany.com"
$from          = "monitoring@yourcompany.com"
$to            = "you@yourcompany.com"
$subject       = "Windows Servers - Drive Space Report - $(Get-Date -Format 'yyyy-MM-dd')"
$freeThreshold = 20   # percent free below which status = Check Now

# ---- HELPER: HTML-encode dynamic text ----
function ConvertTo-HtmlSafe {
    param([string]$Text)
    if ([string]::IsNullOrEmpty($Text)) { return $Text }
    return $Text.Replace('&','&amp;').Replace('<','&lt;').Replace('>','&gt;')
}

# ---- COLLECT DATA ----
$results = foreach ($server in $servers) {
    try {
        $disks = Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $server -Filter "DriveType=3" -ErrorAction Stop

        foreach ($disk in $disks) {
            $sizeGB    = [math]::Round($disk.Size / 1GB, 2)
            $freeGB    = [math]::Round($disk.FreeSpace / 1GB, 2)
            $usedGB    = [math]::Round($sizeGB - $freeGB, 2)
            $pctFree   = if ($sizeGB -gt 0) { [math]::Round(($freeGB / $sizeGB) * 100, 1) } else { 0 }
            $status    = if ($pctFree -lt $freeThreshold) { "Check Now" } else { "Healthy" }

            [PSCustomObject]@{
                Server      = $server
                DeviceID    = $disk.DeviceID
                SizeGB      = $sizeGB
                UsedGB      = $usedGB
                FreeGB      = $freeGB
                PercentFree = $pctFree
                Status      = $status
            }
        }
    }
    catch {
        [PSCustomObject]@{
            Server      = $server
            DeviceID    = "-"
            SizeGB      = $null
            UsedGB      = $null
            FreeGB      = $null
            PercentFree = $null
            Status      = "Server not reachable"
        }
    }
}

# ---- STYLE FRAGMENTS (reused per cell, Outlook-safe inline styles) ----
$font    = "font-family:'Segoe UI',Arial,sans-serif;"
$tdStyle = "padding:8px 12px;font-size:13px;color:#333333;border-bottom:1px solid #e0e0e0;border-right:1px solid #e0e0e0;$font"
$thStyle = "padding:10px 12px;text-align:left;font-size:12px;font-weight:600;color:#ffffff;border-right:1px solid #274fa3;$font"

# ---- BUILD HTML OUTPUT WITH INLINE STYLES ----
$rows = foreach ($r in $results) {

    $statusStyle = switch ($r.Status) {
        "Healthy"              { "color:#2e7d32;font-weight:bold;" }
        "Check Now"            { "color:#c62828;font-weight:bold;" }
        "Server not reachable" { "color:#c62828;font-weight:bold;background-color:#ffebee;" }
        default                { "" }
    }

    $serverSafe   = ConvertTo-HtmlSafe $r.Server
    $deviceIdSafe = ConvertTo-HtmlSafe $r.DeviceID

    "<tr>
        <td style='$tdStyle'>$serverSafe</td>
        <td style='$tdStyle'>$deviceIdSafe</td>
        <td style='$tdStyle'>$($r.SizeGB)</td>
        <td style='$tdStyle'>$($r.UsedGB)</td>
        <td style='$tdStyle'>$($r.FreeGB)</td>
        <td style='$tdStyle'>$($r.PercentFree)</td>
        <td style='padding:8px 12px;font-size:13px;border-bottom:1px solid #e0e0e0;border-right:1px solid #e0e0e0;$font $statusStyle'>$($r.Status)</td>
    </tr>"
}

$html = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body style="margin:0;padding:20px;background-color:#f4f6f8;$font">

    <!-- Main Container Table (matches SQL health-check report: fluid, max 1000px) -->
    <table align="center" width="1000" border="0" cellpadding="0" cellspacing="0" style="width:100%;max-width:1000px;margin:0 auto;">

        <!-- HEADER SECTION (BLUE BACKGROUND) -->
        <tr>
            <td bgcolor="#1e40af" style="background-color:#1e40af;border-radius:8px;padding:18px 20px;text-align:center;">
                <h2 style="color:#ffffff;margin:0;font-size:18px;font-weight:600;$font">
                    Windows Server Drive Space Report - $(Get-Date -Format 'yyyy-MM-dd')
                </h2>
            </td>
        </tr>

        <!-- SPACER -->
        <tr><td height="16" style="height:16px;font-size:1px;line-height:1px;">&nbsp;</td></tr>

        <!-- RESULTS TABLE SECTION -->
        <tr>
            <td align="center">
                <!-- Rounded-corner wrapper: outer table clips (radius + overflow:hidden), inner table uses
                     separate borders. This combination is required for Outlook Web to render the radius -
                     border-collapse:collapse and border-radius do not work together in OWA. -->
                <table width="100%" border="0" cellpadding="0" cellspacing="0" style="width:100%;border-collapse:separate;border-spacing:0;background-color:#ffffff;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.1);">
                    <tr><td style="padding:0;">
                    <!-- Horizontal-scroll wrapper: when the reading pane / window is narrower than the
                         table's minimum readable width, Outlook Web and mobile scroll this row sideways
                         instead of squeezing every column illegible. Classic desktop Outlook ignores
                         overflow-x and just lets the table run past the edge - same as before, but with
                         a defined floor width instead of wrapped, cramped text. -->
                    <div style="width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;">
                    <table width="100%" border="0" cellpadding="0" cellspacing="0" style="width:100%;min-width:650px;border-collapse:separate;border-spacing:0;margin:0 -1px -1px 0;">
                        <thead>
                            <tr>
                                <th bgcolor="#1e3a8a" style="background-color:#1e3a8a;$thStyle border-top-left-radius:7px;">Server</th>
                                <th bgcolor="#1e3a8a" style="background-color:#1e3a8a;$thStyle">DeviceID</th>
                                <th bgcolor="#1e3a8a" style="background-color:#1e3a8a;$thStyle">Size (GB)</th>
                                <th bgcolor="#1e3a8a" style="background-color:#1e3a8a;$thStyle">Used (GB)</th>
                                <th bgcolor="#1e3a8a" style="background-color:#1e3a8a;$thStyle">Free (GB)</th>
                                <th bgcolor="#1e3a8a" style="background-color:#1e3a8a;$thStyle">% Free</th>
                                <th bgcolor="#1e3a8a" style="background-color:#1e3a8a;padding:10px 12px;text-align:left;font-size:12px;font-weight:600;color:#ffffff;$font border-top-right-radius:7px;">Status</th>
                            </tr>
                        </thead>
                        <tbody>
                            $($rows -join "`n")
                        </tbody>
                    </table>
                    </div>
                    </td></tr>
                </table>
            </td>
        </tr>

        <!-- SPACER -->
        <tr><td height="16" style="height:16px;font-size:1px;line-height:1px;">&nbsp;</td></tr>

        <!-- SEPARATE AUTOMATED DISCLAIMER BOX -->
        <tr>
            <td bgcolor="#eff6ff" style="background-color:#eff6ff;border:1px solid #bfdbfe;border-left:4px solid #1e40af;border-radius:6px;padding:10px 14px;text-align:center;">
                <span style="font-size:12px;color:#1e40af;font-weight:600;$font">
                    Note: This is an automated report do not reply to this email.
                </span>
            </td>
        </tr>

        <!-- SPACER -->
        <tr><td height="16" style="height:16px;font-size:1px;line-height:1px;">&nbsp;</td></tr>

        <!-- SIGNATURE SECTION (BLUE BACKGROUND) -->
        <tr>
            <td bgcolor="#1e40af" style="background-color:#1e40af;border-radius:8px;padding:14px 20px;text-align:left;">
                <p style="color:#ffffff;margin:0;font-size:13px;line-height:1.5;$font">
                    Regards,<br>
                    <strong style="color:#ffffff;font-size:14px;">SQL DBA Team</strong><br>
                    <span style="color:#dbeafe;">Database Administration</span>
                </p>
            </td>
        </tr>

    </table>

</body>
</html>
"@

# ---- SEND EMAIL ----
Send-MailMessage -From $from -To $to -Subject $subject -Body $html -BodyAsHtml -SmtpServer $smtpServer

<#
---- PS7 NOTE ----
Send-MailMessage is deprecated but still functional on Windows PowerShell 5.1 (default on Server OS).
On PowerShell 7+, replace the Send-MailMessage line with a System.Net.Mail.SmtpClient call, e.g.:

$msg = New-Object System.Net.Mail.MailMessage($from, $to, $subject, $html)
$msg.IsBodyHtml = $true
$smtp = New-Object System.Net.Mail.SmtpClient($smtpServer)
$smtp.Send($msg)

For all the disks" 
$disks = Get-CimInstance -ClassName Win32_LogicalDisk `
    -ComputerName $server `
    -Filter "DriveType=3" `
    -ErrorAction Stop
ONLY C: drive
$disks = Get-CimInstance -ClassName Win32_LogicalDisk `
    -ComputerName $server `
    -Filter "DeviceID='C:'" `
    -ErrorAction Stop
#>

 Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase

# ==============================================================================
# CONFIGURATION: ADD, REMOVE, OR MODIFY YOUR BLOCKS HERE
# ==============================================================================
$ReportCards = @(
    @{
        Title       = "AWS Disk Info"
        Description = "Get disk usage and storage details for AWS EC2 instances."
        Script      = "AWSDiskInfo.ps1"
        Color       = "#F5A623" # Orange Accent
        BgColor     = "#FFF8F0"
    },
    @{
        Title       = "Azure Disk Info"
        Description = "Get disk usage and storage details for Azure VMs."
        Script      = "AzureDiskInfo.ps1"
        Color       = "#0078D4" # Blue Accent
        BgColor     = "#F0F7FF"
    },
    @{
        Title       = "MS SQL Disk Info"
        Description = "Get disk usage and storage details for SQL Server instances."
        Script      = "MSSQLDiskInfo.ps1"
        Color       = "#D9534F" # Red Accent
        BgColor     = "#FFF0F0"
    },
    @{
        Title       = "SQL Backup Info"
        Description = "Get backup details, status and history for SQL Server."
        Script      = "SQLBackupInfo.ps1"
        Color       = "#6F42C1" # Purple Accent
        BgColor     = "#F5F0FF"
    },
    @{
        Title       = "SQL Health Status"
        Description = "Get overall health status of SQL Server instances and databases."
        Script      = "SQLHealthStatus.ps1"
        Color       = "#28A745" # Green Accent
        BgColor     = "#F0FFF4"
    }
)

# Base Window XAML Template (Fully Compatible with Windows Server 2016)
[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Server Report Center" Height="550" Width="1100"
        WindowStartupLocation="CenterScreen"
        WindowStyle="None" AllowsTransparency="False"
        Background="#F8F9FA" Foreground="#212529"
        FontFamily="Segoe UI" SnapsToDevicePixels="True">

    <Window.Resources>
        <!-- Style for Window Control Buttons (Min/Max/Close) -->
        <Style x:Key="CaptionBtnStyle" TargetType="Button">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="Width" Value="45"/>
            <Setter Property="Height" Value="40"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border x:Name="border" Background="{TemplateBinding Background}">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="border" Property="Background" Value="#106EBE"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- Specific Hover style for Close Button (Red) -->
        <Style x:Key="CloseBtnStyle" TargetType="Button" BasedOn="{StaticResource CaptionBtnStyle}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="#E81123"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <!-- Outer Border with Background and Border -->
    <Border Background="#F8F9FA" BorderBrush="#0078D4" BorderThickness="1">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="60"/>   <!-- Header & Window Title Bar -->
                <RowDefinition Height="250"/>  <!-- Cards Area -->
                <RowDefinition Height="*"/>    <!-- Terminal / Status Log -->
            </Grid.RowDefinitions>

            <!-- Blue Top Header Bar -->
            <Border Grid.Row="0" Background="#0078D4" x:Name="TitleBar">
                <Grid>
                    <!-- App Title Text -->
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                        <TextBlock Text="Server Report Center" FontSize="20" FontWeight="Bold" Foreground="White"/>
                    </StackPanel>

                    <!-- Custom Window Control Buttons using XAML Path vector graphics -->
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top">
                        <Button x:Name="BtnMinimize" Style="{StaticResource CaptionBtnStyle}">
                            <Path Data="M0,8 L10,8" Stroke="White" StrokeThickness="1.5" />
                        </Button>
                        <Button x:Name="BtnMaximize" Style="{StaticResource CaptionBtnStyle}">
                            <Path Data="M0,0 L10,0 L10,10 L0,10 Z" Stroke="White" StrokeThickness="1" Fill="Transparent" />
                        </Button>
                        <Button x:Name="BtnClose" Style="{StaticResource CloseBtnStyle}">
                            <Path Data="M0,0 L10,10 M10,0 L0,10" Stroke="White" StrokeThickness="1.5" />
                        </Button>
                    </StackPanel>
                </Grid>
            </Border>

            <!-- Dynamic Cards Grid Container -->
            <Grid x:Name="CardGrid" Grid.Row="1" Margin="15,15,15,5">
                <!-- Columns generated dynamically in PowerShell -->
            </Grid>

            <!-- Status & Console Log View -->
            <Border Grid.Row="2" Background="#1E1E1E" CornerRadius="4" Margin="20,5,20,15" Padding="10">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <TextBlock Text="Status Information" Foreground="#89B4FA" FontWeight="Bold" FontSize="12" Margin="0,0,0,5"/>
                    <TextBox x:Name="TxtLog" Grid.Row="1" Background="Transparent" Foreground="#DCDCDC" BorderThickness="0" 
                             FontFamily="Consolas" FontSize="12" IsReadOnly="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap"/>
                </Grid>
            </Border>
        </Grid>
    </Border>
</Window>
"@

# Read XML
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)

# Get Controls
$CardGrid    = $window.FindName("CardGrid")
$TxtLog      = $window.FindName("TxtLog")
$TitleBar    = $window.FindName("TitleBar")
$BtnMinimize = $window.FindName("BtnMinimize")
$BtnMaximize = $window.FindName("BtnMaximize")
$BtnClose    = $window.FindName("BtnClose")

# Enable Window Dragging on the Blue Header Bar
$TitleBar.Add_MouseLeftButtonDown({ $window.DragMove() })

# Handle Custom Window Buttons
$BtnMinimize.Add_Click({ $window.WindowState = [System.Windows.WindowState]::Minimized })
$BtnMaximize.Add_Click({
    if ($window.WindowState -eq [System.Windows.WindowState]::Maximized) {
        $window.WindowState = [System.Windows.WindowState]::Normal
    } else {
        $window.WindowState = [System.Windows.WindowState]::Maximized
    }
})
$BtnClose.Add_Click({ $window.Close() })

# Output Logger Helper
function Write-Log {
    param([string]$Message)
    $TimeStamp = Get-Date -Format "HH:mm:ss"
    $TxtLog.AppendText("[$TimeStamp] $Message`n")
    $TxtLog.ScrollToEnd()
    $window.Dispatcher.Invoke([Action]{}, [System.Windows.Threading.DispatcherPriority]::Background)
}

# Run Script Helper
function Execute-ReportScript {
    param([string]$ScriptName, [string]$ReportTitle)
    
    $ScriptPath = "C:\Test\PowerShellScripts\$ScriptName"
    Write-Log "Initiating: $ReportTitle..."

    if (Test-Path $ScriptPath) {
        try {
            $output = & $ScriptPath | Out-String
            if ($output) { Write-Log $output.Trim() }
            Write-Log "SUCCESS: $ReportTitle executed successfully."
        } catch {
            Write-Log "ERROR: Failed to run $ReportTitle.`n$_"
        }
    } else {
        Write-Log "WARNING: Could not locate file at $ScriptPath"
    }
}

# Dynamic Card Generation
for ($i = 0; $i -lt $ReportCards.Count; $i++) {
    $card = $ReportCards[$i]

    # Add Column Definition
    $colDef = New-Object System.Windows.Controls.ColumnDefinition
    $colDef.Width = New-Object System.Windows.GridLength(1, [System.Windows.GridUnitType]::Star)
    $CardGrid.ColumnDefinitions.Add($colDef)

    # Build Card XML Template Dynamically with Compatible Vector Button Icons
    [xml]$cardXaml = @"
    <Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Background="$($card.BgColor)" BorderBrush="$($card.Color)" BorderThickness="1.5" CornerRadius="6" Margin="5">
        <Grid Margin="12">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="0" HorizontalAlignment="Center">
                <TextBlock Text="$($card.Title)" FontSize="14" FontWeight="Bold" Foreground="#212529" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"/>
                <Rectangle Height="3" Width="30" Fill="$($card.Color)" Margin="0,5,0,0"/>
            </StackPanel>
            <TextBlock Grid.Row="1" Text="$($card.Description)" TextWrapping="Wrap" TextAlignment="Center" FontSize="11" Foreground="#6C757D" VerticalAlignment="Center"/>
            
            <Button Grid.Row="2" Foreground="White" FontWeight="Bold" FontSize="13" Height="36" Cursor="Hand" BorderThickness="0">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Border Background="$($card.Color)" CornerRadius="4">
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                                <Path Data="M0,0 L8,5 L0,10 Z" Fill="White" Margin="0,0,6,0" />
                                <TextBlock Text="Run Report" Foreground="White" FontWeight="Bold" FontSize="12"/>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </Grid>
    </Border>
"@

    $cardReader = (New-Object System.Xml.XmlNodeReader $cardXaml)
    $borderElement = [Windows.Markup.XamlReader]::Load($cardReader)

    [System.Windows.Controls.Grid]::SetColumn($borderElement, $i)

    $btn = $borderElement.Child.Children[2]
    $btn.Add_Click({
        Execute-ReportScript -ScriptName $card.Script -ReportTitle $card.Title
    }.GetNewClosure())

    $CardGrid.Children.Add($borderElement) | Out-Null
}

Write-Log "System initialized with $($ReportCards.Count) report modules."

# Render Window
$window.ShowDialog() | Out-Null

 Here is the script.

Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase

# ==============================================================================
# CONFIGURATION: ADD, REMOVE, OR MODIFY YOUR BLOCKS HERE
# ==============================================================================
$ReportCards = @(
    @{
        Title       = "AWS Disk Info"
        Description = "Get disk usage and storage details for AWS EC2 instances."
        Script      = "AWSDiskInfo.ps1"
        Color       = "#F5A623" # Orange Accent
        BgColor     = "#FFF8F0"
    },
    @{
        Title       = "Azure Disk Info"
        Description = "Get disk usage and storage details for Azure VMs."
        Script      = "AzureDiskInfo.ps1"
        Color       = "#0078D4" # Blue Accent
        BgColor     = "#F0F7FF"
    },
    @{
        Title       = "MS SQL Disk Info"
        Description = "Get disk usage and storage details for SQL Server instances."
        Script      = "MSSQLDiskInfo.ps1"
        Color       = "#D9534F" # Red Accent
        BgColor     = "#FFF0F0"
    },
    @{
        Title       = "SQL Backup Info"
        Description = "Get backup details, status and history for SQL Server."
        Script      = "SQLBackupInfo.ps1"
        Color       = "#6F42C1" # Purple Accent
        BgColor     = "#F5F0FF"
    },
    @{
        Title       = "SQL Health Status"
        Description = "Get overall health status of SQL Server instances and databases."
        Script      = "SQLHealthStatus.ps1"
        Color       = "#28A745" # Green Accent
        BgColor     = "#F0FFF4"
    }
)

# Base Window XAML Template with Custom Frameless Title Bar
[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Server Report Center" Height="550" Width="1100"
        WindowStartupLocation="CenterScreen"
        WindowStyle="None" AllowsTransparency="True"
        Background="Transparent" Foreground="#212529">

    <Window.Resources>
        <!-- Style for Window Control Buttons (Min/Max/Close) -->
        <Style x:Key="CaptionBtnStyle" TargetType="Button">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="Width" Value="45"/>
            <Setter Property="Height" Value="40"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border x:Name="border" Background="{TemplateBinding Background}">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="border" Property="Background" Value="#106EBE"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- Specific Hover style for Close Button (Red) -->
        <Style x:Key="CloseBtnStyle" TargetType="Button" BasedOn="{StaticResource CaptionBtnStyle}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="#E81123"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <!-- Outer Border with Background, Border, and CornerRadius for the whole window -->
    <Border Background="#F8F9FA" BorderBrush="#0078D4" BorderThickness="1" CornerRadius="12">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="60"/>   <!-- Header & Window Title Bar -->
                <RowDefinition Height="250"/>  <!-- Cards Area -->
                <RowDefinition Height="*"/>    <!-- Terminal / Status Log -->
            </Grid.RowDefinitions>

            <!-- Seamless Blue Top Header Bar (Clipped by parent Border's CornerRadius) -->
            <Border Grid.Row="0" Background="#0078D4" x:Name="TitleBar" CornerRadius="12,12,0,0">
                <Grid>
                    <!-- App Title Text (CENTERED) -->
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                        <TextBlock Text="Server Report Center" FontSize="20" FontWeight="Bold" Foreground="White"/>
                    </StackPanel>

                    <!-- Custom Window Control Buttons using XAML Path vector graphics -->
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top">
                        <Button x:Name="BtnMinimize" Style="{StaticResource CaptionBtnStyle}">
                            <Path Data="M0,8 L10,8" Stroke="White" StrokeThickness="1.5" />
                        </Button>
                        <Button x:Name="BtnMaximize" Style="{StaticResource CaptionBtnStyle}">
                            <Path Data="M0,0 L10,0 L10,10 L0,10 Z" Stroke="White" StrokeThickness="1" Fill="Transparent" />
                        </Button>
                        <Button x:Name="BtnClose" Style="{StaticResource CloseBtnStyle}">
                            <Path Data="M0,0 L10,10 M10,0 L0,10" Stroke="White" StrokeThickness="1.5" />
                        </Button>
                    </StackPanel>
                </Grid>
            </Border>

            <!-- Dynamic Cards Grid Container -->
            <Grid x:Name="CardGrid" Grid.Row="1" Margin="15,15,15,5">
                <!-- Columns generated dynamically in PowerShell -->
            </Grid>

            <!-- Status & Console Log View -->
            <Border Grid.Row="2" Background="#1E1E1E" CornerRadius="6" Margin="20,5,20,15" Padding="10">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <TextBlock Text="Status Information" Foreground="#89B4FA" FontWeight="Bold" FontSize="12" Margin="0,0,0,5"/>
                    <TextBox x:Name="TxtLog" Grid.Row="1" Background="Transparent" Foreground="#DCDCDC" BorderThickness="0" 
                             FontFamily="Consolas" FontSize="12" IsReadOnly="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap"/>
                </Grid>
            </Border>
        </Grid>
    </Border>
</Window>
"@

# Read XML
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)

# Get Controls
$CardGrid    = $window.FindName("CardGrid")
$TxtLog      = $window.FindName("TxtLog")
$TitleBar    = $window.FindName("TitleBar")
$BtnMinimize = $window.FindName("BtnMinimize")
$BtnMaximize = $window.FindName("BtnMaximize")
$BtnClose    = $window.FindName("BtnClose")

# Enable Window Dragging on the Blue Header Bar
$TitleBar.Add_MouseLeftButtonDown({ $window.DragMove() })

# Handle Custom Window Buttons
$BtnMinimize.Add_Click({ $window.WindowState = [System.Windows.WindowState]::Minimized })
$BtnMaximize.Add_Click({
    if ($window.WindowState -eq [System.Windows.WindowState]::Maximized) {
        $window.WindowState = [System.Windows.WindowState]::Normal
    } else {
        $window.WindowState = [System.Windows.WindowState]::Maximized
    }
})
$BtnClose.Add_Click({ $window.Close() })

# Output Logger Helper
function Write-Log {
    param([string]$Message)
    $TimeStamp = Get-Date -Format "HH:mm:ss"
    $TxtLog.AppendText("[$TimeStamp] $Message`n")
    $TxtLog.ScrollToEnd()
    $window.Dispatcher.Invoke([Action]{}, [System.Windows.Threading.DispatcherPriority]::Background)
}

# Run Script Helper
function Execute-ReportScript {
    param([string]$ScriptName, [string]$ReportTitle)
    
    $ScriptPath = "C:\Test\PowerShellScripts\$ScriptName"
    Write-Log "Initiating: $ReportTitle..."

    if (Test-Path $ScriptPath) {
        try {
            $output = & $ScriptPath | Out-String
            if ($output) { Write-Log $output.Trim() }
            Write-Log "SUCCESS: $ReportTitle executed successfully."
        } catch {
            Write-Log "ERROR: Failed to run $ReportTitle.`n$_"
        }
    } else {
        Write-Log "WARNING: Could not locate file at $ScriptPath"
    }
}

# Dynamic Card Generation
for ($i = 0; $i -lt $ReportCards.Count; $i++) {
    $card = $ReportCards[$i]

    # Add Column Definition
    $colDef = New-Object System.Windows.Controls.ColumnDefinition
    $colDef.Width = New-Object System.Windows.GridLength(1, [System.Windows.GridUnitType]::Star)
    $CardGrid.ColumnDefinitions.Add($colDef)

    # Build Card XML Template Dynamically with Rounded Buttons
    [xml]$cardXaml = @"
    <Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Background="$($card.BgColor)" BorderBrush="$($card.Color)" BorderThickness="1.5" CornerRadius="8" Margin="5">
        <Grid Margin="12">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="0" HorizontalAlignment="Center">
                <TextBlock Text="$($card.Title)" FontSize="14" FontWeight="Bold" Foreground="#212529" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"/>
                <Rectangle Height="3" Width="30" Fill="$($card.Color)" Margin="0,5,0,0"/>
            </StackPanel>
            <TextBlock Grid.Row="1" Text="$($card.Description)" TextWrapping="Wrap" TextAlignment="Center" FontSize="11" Foreground="#6C757D" VerticalAlignment="Center"/>
            
            <Button Grid.Row="2" Content="► Run Report" Foreground="White" FontWeight="Bold" FontSize="13" Height="36" Cursor="Hand" BorderThickness="0">
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <Border Background="$($card.Color)" CornerRadius="6">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </Grid>
    </Border>
"@

    $cardReader = (New-Object System.Xml.XmlNodeReader $cardXaml)
    $borderElement = [Windows.Markup.XamlReader]::Load($cardReader)

    [System.Windows.Controls.Grid]::SetColumn($borderElement, $i)

    $btn = $borderElement.Child.Children[2]
    $btn.Add_Click({
        Execute-ReportScript -ScriptName $card.Script -ReportTitle $card.Title
    }.GetNewClosure())

    $CardGrid.Children.Add($borderElement) | Out-Null
}

Write-Log "System initialized with $($ReportCards.Count) report modules."

# Render Window
$window.ShowDialog() | Out-Null


Author Name

Contact Form

Name

Email *

Message *

Powered by Blogger.