mirror of
https://github.com/Micke-K/IntuneManagement.git
synced 2026-09-28 19:05:38 +02:00
IntuneManagement 4.0.0-beta1
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
# 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
|
||||
}
|
||||
Reference in New Issue
Block a user