# Scoped policy picker (Avalonia). # # Avalonia port of UI/WPF/Extensions/IntuneManagerPolicySearchUIWPF.ps1. Thin # wrapper over Show-ObjectPickerDialog: it supplies the scope list and a search # handler, so the dialog queries Graph for the typed name inside the selected # policy group / policy type instead of enumerating the whole tenant up front. # The search itself lives in Internal/PolicySearch.ps1 and is shared with WPF # (R10 - this file only collects input and renders). function Show-PolicySearchDialog { param( [string] $Title = "Select policy", # Preselects this policy type in the "Search in" dropdown. [string] $DefaultPolicyTypeId, # Ids to keep out of the results (e.g. the policy being compared). [string[]] $ExcludeIds, # Rows to show before the first search. The compare flows seed this # from the main view's already-loaded list so the dialog opens with # something useful in it. [object[]] $InitialItems ) $scopes = Get-PolicySearchScopes -DefaultPolicyTypeId $DefaultPolicyTypeId if (@($scopes).Count -eq 0) { Show-MessageBox "No policy types are available to search." "Select policy" "OK" "Warning" | Out-Null return $null } $defaultKey = Get-PolicySearchDefaultScopeKey -Scopes $scopes -PolicyTypeId $DefaultPolicyTypeId # Empty unless more than one tenant is signed in; the dialog hides the combo # in that case and every search runs against the default token. $tenants = Get-PolicySearchTenants $defaultTenantKey = Get-PolicySearchDefaultTenantKey -Tenants $tenants $cols = @( [PSCustomObject]@{ Header = "Name"; Binding = "Name" } [PSCustomObject]@{ Header = "Type"; Binding = "PolicyType.Title" } ) # Handler inputs go on module scope, not into a closure: the handlers are # rebound to the module, which strips captured locals (see the note in # Show-ObjectPickerDialog). $script:_policySearchState = @{ ExcludeIds = $ExcludeIds MinLength = Get-PolicySearchMinLength } $searchHandler = (ConvertTo-AvaloniaEventScriptBlock { param($SearchText, $Scope) $st = $script:_policySearchState if (-not $Scope) { return @() } if ([String]::IsNullOrWhiteSpace($SearchText) -or $SearchText.Trim().Length -lt $st.MinLength) { Set-PickerStatusText "Type at least $($st.MinLength) characters, or use 'Load all in scope'." return @() } # $null when the dialog is single-tenant, in which case the default # token is used. $tenant = Get-PickerSelectedTenant $tokenId = if ($tenant) { [int]$tenant.TokenId } else { Get-DefaultTokenId } $where = if ($tenant) { " in $($tenant.Title)" } else { "" } Write-Status "Searching $($Scope.Title.Trim())$where..." try { $found = @(Search-IntunePolicies -Scope $Scope -SearchText $SearchText.Trim() -ExcludeIds $st.ExcludeIds -TokenId $tokenId) if ($found.Count -eq 0) { Set-PickerStatusText "No object in $($Scope.Title.Trim())$where matches '$($SearchText.Trim())'." } else { Set-PickerStatusText "$($found.Count) object(s) found$where." } return $found } finally { Write-Status "" } }) $loadHandler = (ConvertTo-AvaloniaEventScriptBlock { $st = $script:_policySearchState $scope = Get-PickerSelectedScope if (-not $scope) { return @() } $tenant = Get-PickerSelectedTenant $tokenId = if ($tenant) { [int]$tenant.TokenId } else { Get-DefaultTokenId } $where = if ($tenant) { " in $($tenant.Title)" } else { "" } Write-Status "Loading all objects in $($scope.Title.Trim())$where..." try { $loaded = @(Search-IntunePolicies -Scope $scope -ExcludeIds $st.ExcludeIds -TokenId $tokenId) Set-PickerStatusText "$($loaded.Count) object(s) in $($scope.Title.Trim())$where." return $loaded } finally { Write-Status "" } }) try { return Show-ObjectPickerDialog ` -Title $Title ` -Items $InitialItems ` -DisplayColumns $cols ` -Scopes $scopes ` -SelectedScopeKey $defaultKey ` -Tenants $tenants ` -SelectedTenantKey $defaultTenantKey ` -SearchHandler $searchHandler ` -LoadHandler $loadHandler ` -LoadLabel "Load all in scope" } finally { $script:_policySearchState = $null } }