mirror of
https://github.com/Micke-K/IntuneManagement.git
synced 2026-09-28 19:05:38 +02:00
212 lines
8.3 KiB
PowerShell
212 lines
8.3 KiB
PowerShell
# Avalonia parallel of UI/WPF/ClassExtensions/IntuneApplicationClassUIExtensions.ps1.
|
|
# Attaches AddUIExportExtensions / AddUIDetailsExtension to ApplicationType
|
|
# only. Same scope-loss + R13 constraints documented in
|
|
# IntuneScriptClassUIExtension.ps1 — helpers captured up front, OpenFileDialog
|
|
# / SaveFileDialog routed through Host::OpenFilePicker / Host::SaveFilePicker.
|
|
#
|
|
# Two non-trivial differences from the script flow:
|
|
#
|
|
# 1. Export adds TWO checkboxes — "Export script" (shared with the script
|
|
# path; chains through Add-AvaloniaExportPropertyCheckbox under the
|
|
# `chkExportScript` name) and an Application-specific
|
|
# "Export application file" (`chkExportAppContent`). The latter's
|
|
# initial state comes from a persisted setting, not a hard-coded `$true`.
|
|
#
|
|
# 2. Download is a multi-step pipeline: SaveFilePicker for the encrypted
|
|
# content, Find-AppEncryptionFile to locate the matching .json,
|
|
# OpenFilePicker fallback when the json is missing, Start-DecryptFile to
|
|
# produce the unencrypted .zip, then delete the .encrypted intermediate.
|
|
|
|
##############################################
|
|
# Helpers
|
|
##############################################
|
|
|
|
function Invoke-UploadAppFileAvalonia
|
|
{
|
|
param($Row)
|
|
|
|
if (-not $Row -or -not $Row.Source) { return }
|
|
$appItem = $Row.Source
|
|
$obj = $appItem.Object
|
|
|
|
if ($obj.publishingState -ne "notPublished") {
|
|
$confirm = $script:UIProvider.ShowMessageBox("Are you sure you want to upload a new file for the app?`n`nApplication:`n$($appItem.Name)", "Update app file?", "YesNo", "Warning")
|
|
if ($confirm -ne "Yes") { return }
|
|
}
|
|
|
|
$pkgPath = Get-SettingValue "IntuneAppPackagesFolder"
|
|
$picked = (Get-AvaloniaHost)::OpenFilePicker(
|
|
$script:Window,
|
|
'Select Intune Win32 file',
|
|
$pkgPath,
|
|
'Intune Win32',
|
|
'*.intunewin')
|
|
if (-not $picked) { return }
|
|
|
|
Write-Status "Import $($obj.displayName) file"
|
|
Start-ApplicationImportFile $appItem $picked
|
|
Write-Status ""
|
|
}
|
|
|
|
function Invoke-DownloadAppFileAvalonia
|
|
{
|
|
param($Row)
|
|
|
|
if (-not $Row -or -not $Row.Source) { return }
|
|
$appItem = $Row.Source
|
|
$obj = $appItem.Object
|
|
|
|
# Prefer the package fileName; fall back to the app display name so the save
|
|
# dialog never defaults to a bare ".encrypted" (win32 list rows may not carry
|
|
# a fileName).
|
|
$baseName = if ($obj.FileName) { [string]$obj.FileName } elseif ($obj.displayName) { [string]$obj.displayName } else { 'app' }
|
|
|
|
Write-Status "Download file"
|
|
try {
|
|
$pkgPath = Get-SettingValue "IntuneAppDownloadFolder" (Get-SettingValue "IntuneAppPackagesFolder")
|
|
$picked = (Get-AvaloniaHost)::SaveFilePicker(
|
|
$script:Window,
|
|
'Save encrypted intunewin',
|
|
($baseName + ".encrypted"),
|
|
'encrypted',
|
|
'Encrypted intunewin',
|
|
'*.encrypted')
|
|
if (-not $picked) { return }
|
|
|
|
$contentFileObj = Start-DownloadAppContent $appItem $picked
|
|
|
|
if (-not [IO.File]::Exists($picked)) { return }
|
|
|
|
$fullPath = Find-AppEncryptionFile $obj $contentFileObj $pkgPath
|
|
if (-not [IO.File]::Exists($fullPath)) {
|
|
$browse = $script:UIProvider.ShowMessageBox("Could not find decryption file for $($obj.displayName)`nApp Id: $($obj.id)`nContent version $($obj.committedContentVersion)`n`nDo you want to browse for the file?", "Encryption file not found", "YesNo", "Warning")
|
|
if ($browse -eq "Yes") {
|
|
$alt = (Get-AvaloniaHost)::OpenFilePicker(
|
|
$script:Window,
|
|
'Select decryption json',
|
|
$pkgPath,
|
|
'JSON files',
|
|
'*.json')
|
|
if ($alt) { $fullPath = $alt }
|
|
}
|
|
}
|
|
|
|
if ([IO.File]::Exists($fullPath)) {
|
|
Write-Status "Decrypting file"
|
|
$encryptionInfo = ConvertFrom-Json ([IO.File]::ReadAllText($fullPath))
|
|
if ($encryptionInfo.fileEncryptionInfo) { $encryptionInfo = $encryptionInfo.fileEncryptionInfo }
|
|
$zipName = ($baseName -replace 'intunewin$', 'zip')
|
|
if ($zipName -eq $baseName) { $zipName = "$baseName.zip" }
|
|
$destination = [IO.Path]::Combine($pkgPath, $zipName)
|
|
Start-DecryptFile $picked $destination $encryptionInfo.encryptionKey $encryptionInfo.initializationVector
|
|
try { [IO.File]::Delete($picked) }
|
|
catch { Write-LogError "Failed to delete exported encrypted file" $_.Exception }
|
|
} else {
|
|
Write-Log "Decryption file for $($obj.displayName) not found. Skipping decryption" 2
|
|
}
|
|
}
|
|
finally {
|
|
# Always clear the status overlay - an error mid-download previously left
|
|
# it stuck on screen and looked like a hang.
|
|
Write-Status ""
|
|
}
|
|
}
|
|
|
|
##############################################
|
|
# Captures
|
|
##############################################
|
|
|
|
$sbAddCheckbox = ${function:Add-AvaloniaExportPropertyCheckbox}
|
|
$sbAddDetailsBtn = ${function:Add-AvaloniaDetailsButton}
|
|
$sbSetCache = ${function:Set-CacheObject}
|
|
$sbWriteLogError = ${function:Write-LogError}
|
|
$sbGetSetting = ${function:Get-SettingStoreValue}
|
|
$sbInvokeUploadApp = ${function:Invoke-UploadAppFileAvalonia}
|
|
$sbInvokeDownloadApp = ${function:Invoke-DownloadAppFileAvalonia}
|
|
|
|
##############################################
|
|
# ScriptBlocks
|
|
##############################################
|
|
|
|
$SBAddApplicationUIExportExtension = {
|
|
param($Form)
|
|
|
|
if (-not $Form) { return }
|
|
|
|
# "Export script" checkbox (shared with script-typed exports).
|
|
$chkScript = & $sbAddCheckbox -Form $Form `
|
|
-CheckboxName 'chkExportScript' `
|
|
-LabelText 'Export script' `
|
|
-ToolTip 'Export the script associated with selected profiles' `
|
|
-InitialChecked $true
|
|
if ($chkScript) {
|
|
& $sbSetCache "ExportScripts" $chkScript.IsChecked
|
|
$chkScript.add_IsCheckedChanged({
|
|
param($s, $e)
|
|
& $sbSetCache "ExportScripts" $s.IsChecked
|
|
}.GetNewClosure())
|
|
}
|
|
|
|
# "Export application file" checkbox — initial state from setting.
|
|
$initial = ((& $sbGetSetting "Intune" "ExportAppFile" "false") -eq "true")
|
|
$chkApp = & $sbAddCheckbox -Form $Form `
|
|
-CheckboxName 'chkExportAppContent' `
|
|
-LabelText 'Export application file' `
|
|
-ToolTip 'Export the application file. Note: Application file will only be exported if encryption file is found.' `
|
|
-InitialChecked $initial
|
|
if ($chkApp) {
|
|
& $sbSetCache "ExportAppContent" $chkApp.IsChecked
|
|
$chkApp.add_IsCheckedChanged({
|
|
param($s, $e)
|
|
& $sbSetCache "ExportAppContent" $s.IsChecked
|
|
}.GetNewClosure())
|
|
}
|
|
}.GetNewClosure()
|
|
|
|
$SBAddApplicationUIDetailsExtension = {
|
|
param($Form)
|
|
|
|
if (-not $Form) { return }
|
|
|
|
$onUpload = {
|
|
param($s, $e)
|
|
$row = $script:dgIntuneManagerObjects.SelectedItem
|
|
if (-not $row) { return }
|
|
try { & $sbInvokeUploadApp $row }
|
|
catch { & $sbWriteLogError "Upload application file failed" $_.Exception }
|
|
}.GetNewClosure()
|
|
|
|
$onDownload = {
|
|
param($s, $e)
|
|
$row = $script:dgIntuneManagerObjects.SelectedItem
|
|
if (-not $row) { return }
|
|
try { & $sbInvokeDownloadApp $row }
|
|
catch { & $sbWriteLogError "Download application file failed" $_.Exception }
|
|
}.GetNewClosure()
|
|
|
|
# Insert order matches the WPF original: Upload at 0 first, then Download
|
|
# at 0 — net layout left-to-right is Download, Upload, [existing buttons].
|
|
& $sbAddDetailsBtn -Form $Form -Name 'btnUploadAppfile' -Content 'Upload' `
|
|
-InsertIndex 0 -OnClick $onUpload | Out-Null
|
|
& $sbAddDetailsBtn -Form $Form -Name 'btnDownloadAppfile' -Content 'Download' `
|
|
-InsertIndex 0 -OnClick $onDownload | Out-Null
|
|
}.GetNewClosure()
|
|
|
|
##############################################
|
|
# Init
|
|
##############################################
|
|
|
|
function Invoke-InitializeApplicationUIExtensions
|
|
{
|
|
$typeClasses = @()
|
|
try { $typeClasses += Get-SingletonObject "ApplicationType" } catch {}
|
|
|
|
foreach ($typeClass in $typeClasses) {
|
|
if (-not $typeClass) { continue }
|
|
Add-ObjectMethod $typeClass "AddUIExportExtensions" $SBAddApplicationUIExportExtension
|
|
Add-ObjectMethod $typeClass "AddUIDetailsExtension" $SBAddApplicationUIDetailsExtension
|
|
}
|
|
}
|
|
|
|
Invoke-InitializeApplicationUIExtensions
|