Private/Show-DeviceSelectionGui.ps1

Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName PresentationCore
Add-Type -AssemblyName WindowsBase

function Show-DeviceSelectionGui {
    param([array]$AllDevices)

    $script:SelectedDevices = @()
    $script:CurrentPage = 1
    $script:AllDeviceObjects = @()
    $script:FilteredDeviceObjects = @()

    $xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Select Devices for Remediation" Height="600" Width="900"
        WindowStartupLocation="CenterScreen" Topmost="True"
        Background="#1E1E1E">
    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="#2D2D30"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="BorderBrush" Value="#3F3F46"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Padding" Value="12,6"/>
            <Setter Property="FontSize" Value="13"/>
            <Setter Property="Cursor" Value="Hand"/>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="#3E3E42"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <Style TargetType="TextBox">
            <Setter Property="Background" Value="#2D2D30"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="BorderBrush" Value="#3F3F46"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="CaretBrush" Value="White"/>
        </Style>
        <Style TargetType="TextBlock">
            <Setter Property="Foreground" Value="White"/>
        </Style>
        <Style TargetType="DataGrid">
            <Setter Property="Background" Value="#252526"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="BorderBrush" Value="#3F3F46"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="RowBackground" Value="#2D2D30"/>
            <Setter Property="AlternatingRowBackground" Value="#252526"/>
            <Setter Property="GridLinesVisibility" Value="None"/>
            <Setter Property="HeadersVisibility" Value="Column"/>
        </Style>
        <Style TargetType="DataGridColumnHeader">
            <Setter Property="Background" Value="#2D2D30"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="BorderBrush" Value="#3F3F46"/>
            <Setter Property="BorderThickness" Value="0,0,1,1"/>
            <Setter Property="Padding" Value="8,6"/>
            <Setter Property="FontWeight" Value="SemiBold"/>
        </Style>
        <Style TargetType="DataGridCell">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="#094771"/>
                    <Setter Property="Foreground" Value="White"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <Style TargetType="DataGridRow">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="#2D2D30"/>
                </Trigger>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="#094771"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <Style TargetType="CheckBox">
            <Setter Property="Foreground" Value="White"/>
        </Style>
    </Window.Resources>
    <Grid Margin="15">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- Header -->
        <TextBlock Grid.Row="0" Text="Select Devices for Remediation" FontSize="18" FontWeight="Bold" Margin="0,0,0,10"/>

        <!-- Search -->
        <Grid Grid.Row="1" Margin="0,0,0,10">
            <TextBox Name="SearchBox" Width="300" HorizontalAlignment="Left" Padding="5" FontSize="14"/>
            <TextBlock Name="SearchPlaceholder" Text="Search devices..."
                       Margin="5,5,0,0" Foreground="#808080" IsHitTestVisible="False"
                       HorizontalAlignment="Left" Width="300"/>
        </Grid>

        <!-- Device Grid -->
        <DataGrid Name="DeviceGrid" Grid.Row="2" AutoGenerateColumns="False"
                  SelectionMode="Single" CanUserAddRows="False"
                  VerticalScrollBarVisibility="Auto" IsReadOnly="True" RowHeight="32">
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Select" Width="70">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                      HorizontalAlignment="Center" VerticalAlignment="Center" Tag="{Binding Id}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="Device Name" Binding="{Binding DeviceName}" Width="200">
                    <DataGridTextColumn.ElementStyle>
                        <Style TargetType="TextBlock">
                            <Setter Property="Padding" Value="8,0,0,0"/>
                            <Setter Property="VerticalAlignment" Value="Center"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>
                <DataGridTextColumn Header="User" Binding="{Binding UserPrincipalName}" Width="240">
                    <DataGridTextColumn.ElementStyle>
                        <Style TargetType="TextBlock">
                            <Setter Property="Padding" Value="8,0,0,0"/>
                            <Setter Property="VerticalAlignment" Value="Center"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>
                <DataGridTextColumn Header="Compliance" Binding="{Binding ComplianceState}" Width="110">
                    <DataGridTextColumn.ElementStyle>
                        <Style TargetType="TextBlock">
                            <Setter Property="Padding" Value="8,0,0,0"/>
                            <Setter Property="VerticalAlignment" Value="Center"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>
                <DataGridTextColumn Header="Last Sync" Binding="{Binding LastSyncDisplay}" Width="*">
                    <DataGridTextColumn.ElementStyle>
                        <Style TargetType="TextBlock">
                            <Setter Property="Padding" Value="8,0,0,0"/>
                            <Setter Property="VerticalAlignment" Value="Center"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>

        <!-- Pagination -->
        <Grid Grid.Row="3" Margin="0,10,0,10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Name="SelectionCount" Grid.Column="0" Text="0 devices selected" VerticalAlignment="Center" FontWeight="Bold" FontSize="13"/>
            <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center">
                <Button Name="FirstPageBtn" Content="⏮ First" Width="70" Margin="2" FontSize="12"/>
                <Button Name="PrevPageBtn" Content="◀ Prev" Width="70" Margin="2" FontSize="12"/>
                <TextBlock Name="PageInfo" Text="Page 1 of 1" VerticalAlignment="Center" Margin="15,0" FontSize="13" FontWeight="SemiBold"/>
                <Button Name="NextPageBtn" Content="Next ▶" Width="70" Margin="2" FontSize="12"/>
                <Button Name="LastPageBtn" Content="Last ⏭" Width="70" Margin="2" FontSize="12"/>
            </StackPanel>
            <TextBlock Name="TotalDevices" Grid.Column="2" Text="Total: 0 devices" VerticalAlignment="Center" HorizontalAlignment="Right" FontSize="13"/>
        </Grid>

        <!-- Action Buttons -->
        <Grid Grid.Row="4" Margin="0,10,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <!-- Left side buttons -->
            <StackPanel Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Left">
                <Button Name="SelectAllPageBtn" Content="✓ Select All on Page" Width="150" Margin="0,0,8,0" FontSize="13" Padding="10,8"/>
                <Button Name="DeselectAllBtn" Content="✗ Deselect All" Width="120" Margin="0,0,8,0" FontSize="13" Padding="10,8"/>
            </StackPanel>

            <!-- Right side buttons -->
            <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
                <Button Name="ExitBtn" Content="Exit Tool" Width="100" Margin="0,0,8,0" FontSize="13" Padding="10,8">
                    <Button.Style>
                        <Style TargetType="Button">
                            <Setter Property="Background" Value="#C42B1C"/>
                            <Setter Property="Foreground" Value="White"/>
                            <Setter Property="BorderBrush" Value="#A52A2A"/>
                            <Setter Property="BorderThickness" Value="1"/>
                            <Setter Property="FontWeight" Value="SemiBold"/>
                            <Setter Property="Cursor" Value="Hand"/>
                            <Style.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Background" Value="#D13438"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Button.Style>
                </Button>
                <Button Name="CancelBtn" Content="Cancel" Width="100" Margin="0,0,8,0" FontSize="13" Padding="10,8"/>
                <Button Name="ConfirmBtn" Content="Run" Width="100" Margin="0" FontSize="14" Padding="12,10" IsEnabled="False">
                    <Button.Style>
                        <Style TargetType="Button">
                            <Setter Property="Background" Value="#0078D4"/>
                            <Setter Property="Foreground" Value="White"/>
                            <Setter Property="BorderBrush" Value="#005A9E"/>
                            <Setter Property="BorderThickness" Value="1"/>
                            <Setter Property="FontWeight" Value="Bold"/>
                            <Setter Property="Cursor" Value="Hand"/>
                            <Style.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Background" Value="#1084D8"/>
                                </Trigger>
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter Property="Background" Value="#3E3E42"/>
                                    <Setter Property="Foreground" Value="#808080"/>
                                    <Setter Property="BorderBrush" Value="#3F3F46"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Button.Style>
                </Button>
            </StackPanel>
        </Grid>
    </Grid>
</Window>
"@


    $reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
    $window = [System.Windows.Markup.XamlReader]::Load($reader)

    # Get controls
    $searchBox = $window.FindName("SearchBox")
    $searchPlaceholder = $window.FindName("SearchPlaceholder")
    $deviceGrid = $window.FindName("DeviceGrid")
    $pageInfo = $window.FindName("PageInfo")
    $firstPageBtn = $window.FindName("FirstPageBtn")
    $prevPageBtn = $window.FindName("PrevPageBtn")
    $nextPageBtn = $window.FindName("NextPageBtn")
    $lastPageBtn = $window.FindName("LastPageBtn")
    $selectAllPageBtn = $window.FindName("SelectAllPageBtn")
    $deselectAllBtn = $window.FindName("DeselectAllBtn")
    $exitBtn = $window.FindName("ExitBtn")
    $cancelBtn = $window.FindName("CancelBtn")
    $confirmBtn = $window.FindName("ConfirmBtn")
    $selectionCount = $window.FindName("SelectionCount")
    $totalDevices = $window.FindName("TotalDevices")

    # Create device objects with selection state
    foreach ($device in $AllDevices) {
        $lastSync = if ($device.lastSyncDateTime) {
            ([DateTime]$device.lastSyncDateTime).ToString("yyyy-MM-dd HH:mm")
        } else { "Never" }

        $obj = [PSCustomObject]@{
            Id = $device.id
            DeviceName = $device.deviceName
            UserPrincipalName = $device.userPrincipalName
            OperatingSystem = $device.operatingSystem
            ComplianceState = $device.complianceState
            LastSyncDateTime = $device.lastSyncDateTime
            LastSyncDisplay = $lastSync
            IsSelected = $false
        }
        $script:AllDeviceObjects += $obj
    }

    $script:FilteredDeviceObjects = $script:AllDeviceObjects

    # Functions
    function Update-SelectionCount {
        $count = ($script:AllDeviceObjects | Where-Object { $_.IsSelected -eq $true }).Count
        $selectionCount.Text = "$count device$(if($count -ne 1){'s'}) selected"
        $confirmBtn.IsEnabled = $count -gt 0
    }

    function Update-DeviceGrid {
        $totalPages = [Math]::Max(1, [Math]::Ceiling($script:FilteredDeviceObjects.Count / $script:PageSize))
        $script:CurrentPage = [Math]::Min($script:CurrentPage, $totalPages)
        $script:CurrentPage = [Math]::Max(1, $script:CurrentPage)

        $startIndex = ($script:CurrentPage - 1) * $script:PageSize
        $pageDevices = @($script:FilteredDeviceObjects | Select-Object -Skip $startIndex -First $script:PageSize)

        $deviceGrid.ItemsSource = $pageDevices
        $pageInfo.Text = "Page $($script:CurrentPage) of $totalPages"
        $totalDevices.Text = "Total: $($script:FilteredDeviceObjects.Count) devices"

        # Update pagination buttons
        $firstPageBtn.IsEnabled = $script:CurrentPage -gt 1
        $prevPageBtn.IsEnabled = $script:CurrentPage -gt 1
        $nextPageBtn.IsEnabled = $script:CurrentPage -lt $totalPages
        $lastPageBtn.IsEnabled = $script:CurrentPage -lt $totalPages
    }

    function Apply-Filter {
        $filterText = $searchBox.Text.Trim().ToLower()
        if ([string]::IsNullOrEmpty($filterText)) {
            $script:FilteredDeviceObjects = $script:AllDeviceObjects
        } else {
            $script:FilteredDeviceObjects = @($script:AllDeviceObjects | Where-Object {
                $_.DeviceName -like "*$filterText*" -or $_.UserPrincipalName -like "*$filterText*"
            })
        }
        $script:CurrentPage = 1
        Update-DeviceGrid
    }

    # Allow space key in search box
    $window.Add_PreviewKeyDown({
        param($src, $e)
        if ($e.Key -eq [System.Windows.Input.Key]::Space) {
            $focused = [System.Windows.Input.Keyboard]::FocusedElement
            if ($focused -eq $searchBox) {
                $caretIndex = $searchBox.CaretIndex
                $searchBox.Text = $searchBox.Text.Insert($caretIndex, " ")
                $searchBox.CaretIndex = $caretIndex + 1
                $e.Handled = $true
            }
        }
    })

    # Search box with live filtering and placeholder
    $searchBox.Add_TextChanged({
        $searchText = $searchBox.Text
        $searchPlaceholder.Visibility = if ($searchText) { "Collapsed" } else { "Visible" }
        Apply-Filter
    })

    $firstPageBtn.Add_Click({
        $script:CurrentPage = 1
        Update-DeviceGrid
    })

    $prevPageBtn.Add_Click({
        if ($script:CurrentPage -gt 1) {
            $script:CurrentPage--
            Update-DeviceGrid
        }
    })

    $nextPageBtn.Add_Click({
        $totalPages = [Math]::Ceiling($script:FilteredDeviceObjects.Count / $script:PageSize)
        if ($script:CurrentPage -lt $totalPages) {
            $script:CurrentPage++
            Update-DeviceGrid
        }
    })

    $lastPageBtn.Add_Click({
        $script:CurrentPage = [Math]::Max(1, [Math]::Ceiling($script:FilteredDeviceObjects.Count / $script:PageSize))
        Update-DeviceGrid
    })

    $selectAllPageBtn.Add_Click({
        foreach ($item in $deviceGrid.ItemsSource) {
            $item.IsSelected = $true
        }
        $deviceGrid.Items.Refresh()
        Update-SelectionCount
    })

    $deselectAllBtn.Add_Click({
        foreach ($item in $script:AllDeviceObjects) {
            $item.IsSelected = $false
        }
        $deviceGrid.Items.Refresh()
        Update-SelectionCount
    })

    $exitBtn.Add_Click({
        $script:SelectedDevices = @()
        $script:exitRequested = $true
        $window.DialogResult = $false
        $window.Close()
    })

    $cancelBtn.Add_Click({
        $script:SelectedDevices = @()
        $window.DialogResult = $false
        $window.Close()
    })

    $confirmBtn.Add_Click({
        $script:SelectedDevices = @($script:AllDeviceObjects | Where-Object { $_.IsSelected -eq $true })
        $window.DialogResult = $true
        $window.Close()
    })

    # Handle checkbox clicks
    $deviceGrid.Add_PreviewMouseLeftButtonUp({
        param($s, $e)
        $source = $e.OriginalSource

        if ($source -is [System.Windows.Controls.Primitives.ToggleButton] -or
            $source.TemplatedParent -is [System.Windows.Controls.CheckBox]) {

            $row = [System.Windows.Controls.DataGridRow]::GetRowContainingElement($source)
            if ($row -and $row.Item) {
                $item = $row.Item
                # Toggle the selection
                $item.IsSelected = -not $item.IsSelected
                $deviceGrid.Items.Refresh()
                Update-SelectionCount
            }
        }
    })

    # Initialize
    Update-DeviceGrid
    Update-SelectionCount

    $result = $window.ShowDialog()

    if ($result -and $script:SelectedDevices.Count -gt 0) {
        return $script:SelectedDevices
    }
    return $null
}