mirror of
https://github.com/Micke-K/IntuneManagement.git
synced 2026-09-28 19:05:38 +02:00
209 lines
8.7 KiB
PowerShell
209 lines
8.7 KiB
PowerShell
# Avalonia port of the Export dialog from UI/WPF/Extensions/IntuneManagerUI.ps1
|
|
# (Show-IntuneManagerExportForm). New file because Export is a self-contained
|
|
# subsystem and we don't want to grow the giant IntuneManagerUI files further
|
|
# (architecture rule R9).
|
|
#
|
|
# Same closure-free design rationale as IntuneManagerImportUI.ps1: form state
|
|
# lives in $script:_imExportFormState so click handlers can be plain
|
|
# scriptblocks (no .GetNewClosure() — that puts the SB into a dynamic module
|
|
# with no module-private function resolution).
|
|
|
|
function Show-IntuneManagerExportForm
|
|
{
|
|
if (-not $script:dgIntuneManagerObjects) { return }
|
|
|
|
$ui = $script:UIProvider
|
|
|
|
$exportForm = $ui.GetXamlObject((Join-Path $script:AppUIRootFolder 'XAML/ExportForm.axaml'))
|
|
if (-not $exportForm) { return }
|
|
|
|
$hostType = Get-AvaloniaHost
|
|
$txtPath = $hostType::FindByName($exportForm, 'txtExportPath')
|
|
$browse = $hostType::FindByName($exportForm, 'browseExportPath')
|
|
$chkObj = $hostType::FindByName($exportForm, 'chkAddObjectType')
|
|
$chkComp = $hostType::FindByName($exportForm, 'chkAddCompanyName')
|
|
$chkAssign = $hostType::FindByName($exportForm, 'chkExportAssignments')
|
|
$btnSel = $hostType::FindByName($exportForm, 'btnExportSelected')
|
|
$btnAll = $hostType::FindByName($exportForm, 'btnExportAll')
|
|
$btnCancel = $hostType::FindByName($exportForm, 'btnCancel')
|
|
$lblSel = $hostType::FindByName($exportForm, 'lblSelectedObject')
|
|
|
|
# Build the settings instance and let the data-side hooks add their own
|
|
# NoteProperties (per-type extra export options). These reach onto the
|
|
# CLR class via Add-Member so we can still read them after Save().
|
|
$exportSettings = [IntuneManagerExportSettings]::new()
|
|
$policyTypes = Get-IntuneManagerSelectedPolicyTypes
|
|
$policyTypes | Add-IntuneManagerExportProperties -ExportSettings $exportSettings
|
|
$policyTypes | Add-IntuneManagerExportUIExtensions -Form $exportForm
|
|
|
|
# Avalonia bindings would render against IntuneManagerExportSettings
|
|
# but the class has no INotifyPropertyChanged, so two-way round-trip
|
|
# silently fails. Push current values into controls and read them back
|
|
# imperatively on click.
|
|
if ($txtPath) { $txtPath.Text = [string]$exportSettings.ExportFolder }
|
|
if ($chkObj) { $chkObj.IsChecked = [bool]$exportSettings.AddObjectType }
|
|
if ($chkComp) { $chkComp.IsChecked = [bool]$exportSettings.AddCompanyName }
|
|
if ($chkAssign) { $chkAssign.IsChecked = [bool]$exportSettings.ExportAssignments }
|
|
|
|
# Selection summary label + Export Selected enable state mirror the WPF
|
|
# behaviour: prefer IsSelected-checked rows over the highlighted row.
|
|
# Scan the grid's CURRENT (filtered) ItemsSource - a row checked before the
|
|
# filter was typed must not be exported while invisible.
|
|
$checkedRows = @(@($script:dgIntuneManagerObjects.ItemsSource) | Where-Object { $_ -and $_.IsSelected })
|
|
$highlighted = $script:dgIntuneManagerObjects.SelectedItem
|
|
|
|
if ($lblSel) {
|
|
if ($checkedRows.Count -gt 0) {
|
|
$lblSel.Content = "$($checkedRows.Count) selected object(s)"
|
|
} elseif ($highlighted) {
|
|
$lblSel.Content = "Selected object: $($highlighted.Name)"
|
|
}
|
|
}
|
|
if ($btnSel) {
|
|
$btnSel.IsEnabled = ($checkedRows.Count -gt 0) -or ($null -ne $highlighted)
|
|
}
|
|
|
|
# Module-scope state container. Click handlers reference by name —
|
|
# no .GetNewClosure() so they survive Avalonia delegate dispatch.
|
|
$script:_imExportFormState = @{
|
|
Settings = $exportSettings
|
|
TxtPath = $txtPath
|
|
ChkObj = $chkObj
|
|
ChkComp = $chkComp
|
|
ChkAssign = $chkAssign
|
|
CheckedRows = $checkedRows
|
|
Highlighted = $highlighted
|
|
Action = $null
|
|
}
|
|
|
|
if ($browse) {
|
|
$browse.add_Click({
|
|
$st = $script:_imExportFormState
|
|
$ui2 = $script:UIProvider
|
|
if (-not $st) { return }
|
|
$folder = $ui2.ShowFolderPicker('Select root folder for export')
|
|
if ($folder) {
|
|
$st.Settings.ExportFolder = $folder
|
|
if ($st.TxtPath) { $st.TxtPath.Text = $folder }
|
|
}
|
|
})
|
|
}
|
|
|
|
if ($btnSel) {
|
|
$btnSel.add_Click({
|
|
$st = $script:_imExportFormState
|
|
if (-not $st) { return }
|
|
$st.Action = 'Selected'
|
|
# Keep the dialog open when the export bailed out on validation
|
|
# (e.g. no folder picked) - it used to close and discard the input.
|
|
$ranOk = $false
|
|
try { $ranOk = [bool](Invoke-IntuneManagerExportExecute) } catch { Write-LogError "Export execution failed" $_.Exception }
|
|
if (-not $ranOk) { return }
|
|
$script:UIProvider.CloseTopModalObject()
|
|
$script:_imExportFormState = $null
|
|
if ($script:dgIntuneManagerObjects) { $script:dgIntuneManagerObjects.Focus() }
|
|
})
|
|
}
|
|
if ($btnAll) {
|
|
$btnAll.add_Click({
|
|
$st = $script:_imExportFormState
|
|
if (-not $st) { return }
|
|
$st.Action = 'All'
|
|
$ranOk = $false
|
|
try { $ranOk = [bool](Invoke-IntuneManagerExportExecute) } catch { Write-LogError "Export execution failed" $_.Exception }
|
|
if (-not $ranOk) { return }
|
|
$script:UIProvider.CloseTopModalObject()
|
|
$script:_imExportFormState = $null
|
|
if ($script:dgIntuneManagerObjects) { $script:dgIntuneManagerObjects.Focus() }
|
|
})
|
|
}
|
|
if ($btnCancel) {
|
|
$btnCancel.add_Click({
|
|
$script:UIProvider.CloseTopModalObject()
|
|
$script:_imExportFormState = $null
|
|
if ($script:dgIntuneManagerObjects) { $script:dgIntuneManagerObjects.Focus() }
|
|
})
|
|
}
|
|
|
|
$exportForm.add_KeyDown({
|
|
param($s, $e)
|
|
if ($e.Key -eq [Avalonia.Input.Key]::Escape) {
|
|
$script:UIProvider.CloseTopModalObject()
|
|
$script:_imExportFormState = $null
|
|
$e.Handled = $true
|
|
}
|
|
})
|
|
|
|
# ShowModalForm is non-blocking; export runs inside the button handlers via
|
|
# Invoke-IntuneManagerExportExecute while the form state is live.
|
|
$ui.ShowModalForm("Export $($script:IntuneManagerSelectedObject.Title) objects", $exportForm, $true)
|
|
}
|
|
|
|
function Invoke-IntuneManagerExportExecute
|
|
{
|
|
# Runs the export for the live $script:_imExportFormState. Called from the
|
|
# Export button handlers (ShowModalForm does not block).
|
|
$st = $script:_imExportFormState
|
|
if (-not $st -or -not $st.Action -or $st.Action -eq 'Cancel') { return }
|
|
$ui = $script:UIProvider
|
|
$exportSettings = $st.Settings
|
|
$txtPath = $st.TxtPath
|
|
$chkObj = $st.ChkObj
|
|
$chkComp = $st.ChkComp
|
|
$chkAssign = $st.ChkAssign
|
|
$checkedRows = @($st.CheckedRows)
|
|
$highlighted = $st.Highlighted
|
|
|
|
# Pull form state back into the settings object before exporting.
|
|
if ($txtPath) { $exportSettings.ExportFolder = [string]$txtPath.Text }
|
|
if ($chkObj) { $exportSettings.AddObjectType = [bool]$chkObj.IsChecked }
|
|
if ($chkComp) { $exportSettings.AddCompanyName = [bool]$chkComp.IsChecked }
|
|
if ($chkAssign) { $exportSettings.ExportAssignments = [bool]$chkAssign.IsChecked }
|
|
|
|
if ([string]::IsNullOrWhiteSpace($exportSettings.ExportFolder)) {
|
|
$ui.ShowMessageBox("Pick an export root folder first.", "Export", "OK", "Error") | Out-Null
|
|
return $false
|
|
}
|
|
|
|
$rowsToExport = @()
|
|
if ($st.Action -eq 'Selected') {
|
|
if ($checkedRows.Count -gt 0) {
|
|
$rowsToExport = $checkedRows
|
|
} elseif ($highlighted) {
|
|
$rowsToExport = @($highlighted)
|
|
}
|
|
} else {
|
|
# Export All — use the current ItemsSource (filtered) to match what
|
|
# the user sees.
|
|
if ($script:dgIntuneManagerObjects.ItemsSource) {
|
|
$rowsToExport = @($script:dgIntuneManagerObjects.ItemsSource)
|
|
}
|
|
}
|
|
|
|
if ($rowsToExport.Count -eq 0) {
|
|
Write-Log "No rows to export" 2
|
|
return $false
|
|
}
|
|
|
|
Write-Status "Export $($script:IntuneManagerSelectedObject.Title)"
|
|
|
|
# Export-GraphPolicy expects IntunePolicyBase, not the CLR row wrapper —
|
|
# pull .Source off each row before piping.
|
|
$policiesToExport = @($rowsToExport | ForEach-Object { $_.Source } | Where-Object { $_ })
|
|
|
|
try {
|
|
$policiesToExport | Export-GraphPolicy -ExportSettings $exportSettings
|
|
} catch {
|
|
Write-LogError "Export-GraphPolicy failed" $_.Exception
|
|
$ui.ShowMessageBox("Export failed: $($_.Exception.Message)", "Error", "OK", "Error") | Out-Null
|
|
Write-Status ""
|
|
return $false
|
|
}
|
|
|
|
$exportSettings.Save()
|
|
|
|
Write-Status ""
|
|
if ($script:dgIntuneManagerObjects) { $script:dgIntuneManagerObjects.Focus() }
|
|
return $true
|
|
}
|