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,20 @@
|
||||
# WPF UI extension for the Atlassian documentation output provider.
|
||||
#
|
||||
# Attaches file-browse metadata onto the registered [DocumentationRegistry]
|
||||
# entry so the bulk-doc form's browse-button-wiring loop can build a WinForms
|
||||
# SaveFileDialog handler. Format matches Add-WpfDocumentationFileBrowse
|
||||
# (Button/TextBox/Save/Filter). The provider file itself
|
||||
# (Internal/Documentation/OutputProviders/DocumentationOutputAtlassian.ps1)
|
||||
# stays free of XAML control names and Windows-Forms filter strings — only the
|
||||
# active UI backend's ClassExtensions load per session, so the Avalonia
|
||||
# counterpart won't conflict.
|
||||
#
|
||||
# Unlike HTML there is no CSS row: Confluence storage format carries no
|
||||
# stylesheet, so the panel has a single browse control.
|
||||
|
||||
$provider = [DocumentationRegistry]::FindOutput('atlassian')
|
||||
if ($provider) {
|
||||
Add-Member -InputObject $provider -MemberType NoteProperty -Force -Name FileBrowseControls -Value @(
|
||||
@{ Button='browseAtlassianDocumentName'; TextBox='txtAtlassianDocumentName'; Save=$true; Filter='Confluence storage format (*.html)|*.html|All files (*.*)|*.*' }
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# WPF UI extension for the HTML documentation output provider.
|
||||
#
|
||||
# Attaches file-browse metadata onto the registered [DocumentationRegistry]
|
||||
# entry so the bulk-doc form's browse-button-wiring loop can build WinForms
|
||||
# SaveFileDialog / OpenFileDialog handlers. Format matches Add-WpfDocumentationFileBrowse
|
||||
# (Button/TextBox/Save/Filter). The provider file itself
|
||||
# (Internal/Documentation/OutputProviders/DocumentationOutputHTML.ps1) stays
|
||||
# free of XAML control names and Windows-Forms filter strings — only the
|
||||
# active UI backend's ClassExtensions load per session, so the Avalonia
|
||||
# counterpart won't conflict.
|
||||
|
||||
$provider = [DocumentationRegistry]::FindOutput('html')
|
||||
if ($provider) {
|
||||
Add-Member -InputObject $provider -MemberType NoteProperty -Force -Name FileBrowseControls -Value @(
|
||||
@{ Button='browseHTMLDocumentName'; TextBox='txtHTMLDocumentName'; Save=$true; Filter='HTML files (*.html)|*.html|All files (*.*)|*.*' }
|
||||
@{ Button='browseHTMLCSSFile'; TextBox='txtHTMLCSSFile'; Save=$false; Filter='CSS files (*.css)|*.css|All files (*.*)|*.*' }
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# WPF UI extension for the Markdown documentation output provider.
|
||||
# See DocumentationOutputHTMLUIExtension.ps1 for the rationale + pattern.
|
||||
|
||||
$provider = [DocumentationRegistry]::FindOutput('md')
|
||||
if ($provider) {
|
||||
Add-Member -InputObject $provider -MemberType NoteProperty -Force -Name FileBrowseControls -Value @(
|
||||
@{ Button='browseMDDocumentName'; TextBox='txtMDDocumentName'; Save=$true; Filter='Markdown files (*.md)|*.md|All files (*.*)|*.*' }
|
||||
@{ Button='browseMDCSSFile'; TextBox='txtMDCSSFile'; Save=$false; Filter='CSS files (*.css)|*.css|All files (*.*)|*.*' }
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# WPF UI extension for the Word documentation output provider.
|
||||
# See DocumentationOutputHTMLUIExtension.ps1 for the rationale + pattern.
|
||||
#
|
||||
# Note: WordDocumentName's original filter included a PDF entry because Word
|
||||
# can save PDFs directly. Preserved here for parity with the pre-refactor
|
||||
# Add-WpfDocumentationFileBrowse call.
|
||||
|
||||
$provider = [DocumentationRegistry]::FindOutput('word')
|
||||
if ($provider) {
|
||||
Add-Member -InputObject $provider -MemberType NoteProperty -Force -Name FileBrowseControls -Value @(
|
||||
@{ Button='browseWordDocumentName'; TextBox='txtWordDocumentName'; Save=$true; Filter='Word files (*.docx)|*.docx|PDF files (*.pdf)|*.pdf|All files (*.*)|*.*' }
|
||||
@{ Button='browseWordDocumentTemplate'; TextBox='txtWordDocumentTemplate'; Save=$false; Filter='Word templates (*.dotx;*.dotm)|*.dotx;*.dotm|All files (*.*)|*.*' }
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
##############################################
|
||||
# ScriptBlocks
|
||||
##############################################
|
||||
|
||||
$SBAddApplicationUIExportExtension = [scriptblock] {
|
||||
param($Form)
|
||||
|
||||
if (-not $Form) { return }
|
||||
|
||||
Add-UIScriptExportExtensions $Form
|
||||
|
||||
$grdExportProperties = $null
|
||||
try {
|
||||
$grdExportProperties = $Form.FindName("grdExportProperties")
|
||||
}
|
||||
catch {}
|
||||
if (-not $grdExportProperties) { return }
|
||||
|
||||
if ($grdExportProperties.FindName("chkExportAppContent")) {
|
||||
return # Already added
|
||||
}
|
||||
|
||||
$xaml = @"
|
||||
<StackPanel $($script:wpfNS) Orientation="Horizontal" Margin="0,0,5,0">
|
||||
<Label Content="Export application file" />
|
||||
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Export the application file. Note: Application file will only be exported if ecryption file is found." />
|
||||
</StackPanel>
|
||||
"@
|
||||
try {
|
||||
$label = [Windows.Markup.XamlReader]::Parse($xaml)
|
||||
|
||||
$chkExportAppContent = [System.Windows.Controls.CheckBox]::new()
|
||||
$chkExportAppContent.IsChecked = ((Get-SettingStoreValue "Intune" "ExportAppFile" "false") -eq "true")
|
||||
$chkExportAppContent.VerticalAlignment = "Center"
|
||||
$chkExportAppContent.Name = "chkExportAppContent"
|
||||
|
||||
Set-CacheObject "ExportAppContent" $chkExportAppContent.IsChecked
|
||||
|
||||
$rd = [System.Windows.Controls.RowDefinition]::new()
|
||||
$rd.Height = [double]::NaN
|
||||
$grdExportProperties.RowDefinitions.Add($rd)
|
||||
|
||||
$label.SetValue([System.Windows.Controls.Grid]::RowProperty, $grdExportProperties.RowDefinitions.Count - 1)
|
||||
$chkExportAppContent.SetValue([System.Windows.Controls.Grid]::RowProperty, $grdExportProperties.RowDefinitions.Count - 1)
|
||||
$chkExportAppContent.SetValue([System.Windows.Controls.Grid]::ColumnProperty, 1)
|
||||
|
||||
$grdExportProperties.Children.Add($label)
|
||||
$grdExportProperties.Children.Add($chkExportAppContent)
|
||||
|
||||
$Form.RegisterName($chkExportAppContent.Name, $chkExportAppContent)
|
||||
|
||||
$changed = [scriptblock] {
|
||||
param($S, $E)
|
||||
Set-CacheObject "ExportAppContent" $this.IsChecked
|
||||
}
|
||||
|
||||
$chkExportAppContent.Add_Checked($changed)
|
||||
$chkExportAppContent.Add_Unchecked($changed)
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
$SBAddApplicationUIDetailsExtension = [scriptblock] {
|
||||
param($Form)
|
||||
|
||||
$buttonPanel = $Form.FindName("pnlButtons")
|
||||
if (-not $buttonPanel) { return }
|
||||
|
||||
$btnUpload = New-Object System.Windows.Controls.Button
|
||||
$btnUpload.Content = 'Upload'
|
||||
$btnUpload.Name = 'btnUploadAppfile'
|
||||
$btnUpload.Margin = "0,0,5,0"
|
||||
$btnUpload.Width = "100"
|
||||
|
||||
$btnUpload.Add_Click({
|
||||
if ($script:dgIntuneManagerObjects.SelectedItem.Object.publishingState -ne "notPublished") {
|
||||
# Only allow upload of not published apps
|
||||
# Use portal to replace app file...
|
||||
if (([System.Windows.MessageBox]::Show("Are you sure you want to upload a new file for the app?`n`nApplication:`n$($script:dgIntuneManagerObjects.SelectedItem.Name)", "Update app file?", "YesNo", "Warning")) -ne "Yes") {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
$pkgPath = Get-SettingValue "IntuneAppPackagesFolder"
|
||||
|
||||
$of = [System.Windows.Forms.OpenFileDialog]::new()
|
||||
$of.FileName = $script:dgIntuneManagerObjects.SelectedItem.Object.fileName
|
||||
$of.DefaultExt = "*.intunewin"
|
||||
$of.Filter = "Intune Win32 (*.intunewin)|*.*"
|
||||
$of.Multiselect = $false
|
||||
|
||||
if ($pkgPath -and [IO.Directory]::Exists($pkgPath)) {
|
||||
$of.InitialDirectory = $pkgPath
|
||||
}
|
||||
|
||||
if ($of.ShowDialog() -eq "OK") {
|
||||
Write-Status "Import $($script:dgIntuneManagerObjects.SelectedItem.Object.displayName) file"
|
||||
Start-ApplicationImportFile $script:dgIntuneManagerObjects.SelectedItem $of.FileName
|
||||
Write-Status ""
|
||||
}
|
||||
})
|
||||
|
||||
$buttonPanel.Children.Insert(0, $btnUpload)
|
||||
|
||||
$btnDownload = New-Object System.Windows.Controls.Button
|
||||
$btnDownload.Content = 'Download'
|
||||
$btnDownload.Name = 'btnDownloadAppfile'
|
||||
$btnDownload.Margin = "0,0,5,0"
|
||||
$btnDownload.Width = "100"
|
||||
|
||||
$btnDownload.Add_Click({
|
||||
Write-Status "Download file"
|
||||
$obj = $script:dgIntuneManagerObjects.SelectedItem.Object
|
||||
#$obj = Invoke-MSGraphAPI -Url "/deviceAppManagement/mobileApps/$($obj.id)"
|
||||
|
||||
$pkgPath = Get-SettingValue "IntuneAppDownloadFolder" (Get-SettingValue "IntuneAppPackagesFolder")
|
||||
|
||||
$dlgSave = [System.Windows.Forms.SaveFileDialog]::new()
|
||||
$dlgSave.InitialDirectory = $pkgPath
|
||||
$dlgSave.FileName = ($obj.FileName + ".encrypted")
|
||||
$dlgSave.DefaultExt = "*.encrypted"
|
||||
$dlgSave.Filter = "Encrypted intunewin (*.encrypted)|*.encrypted|All files (*.*)|*.*"
|
||||
|
||||
if ($dlgSave.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK -and $dlgSave.Filename) {
|
||||
$contentFileObj = Start-DownloadAppContent $script:dgIntuneManagerObjects.SelectedItem $dlgSave.FileName
|
||||
|
||||
if ([IO.File]::Exists($dlgSave.FileName)) {
|
||||
$fullPath = Find-AppEncryptionFile $obj $contentFileObj $pkgPath
|
||||
if ([IO.File]::Exists($fullPath) -eq $false) {
|
||||
if (([System.Windows.MessageBox]::Show("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")) -eq "Yes") {
|
||||
$of = [System.Windows.Forms.OpenFileDialog]::new()
|
||||
$of.InitialDirectory = $pkgPath
|
||||
$of.DefaultExt = "*.json"
|
||||
$of.Filter = "Json (*.json)|*.json"
|
||||
$of.Multiselect = $false
|
||||
|
||||
if ($of.ShowDialog() -eq "OK") {
|
||||
$fullPath = $of.FileName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([IO.File]::Exists($fullPath)) {
|
||||
Write-Status "Decrypting file"
|
||||
$encryptionInfo = ConvertFrom-Json ([IO.File]::ReadAllText($fullPath))
|
||||
if ($encryptionInfo.fileEncryptionInfo) {
|
||||
$encryptionInfo = $encryptionInfo.fileEncryptionInfo
|
||||
}
|
||||
$destination = $pkgPath + ("\$($obj.FileName)" -replace 'intunewin$', 'zip')
|
||||
Start-DecryptFile $dlgSave.Filename $destination $encryptionInfo.encryptionKey $encryptionInfo.initializationVector
|
||||
try { [IO.File]::Delete($dlgSave.Filename) }
|
||||
catch {
|
||||
Write-LogError "Failed to delete exported encrypted file" $_.Exception
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Log "Decryption file for $($obj.displayName) not found. Skipping decryption" 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Status ""
|
||||
})
|
||||
|
||||
$buttonPanel.Children.Insert(0, $btnDownload)
|
||||
}
|
||||
|
||||
##############################################
|
||||
# Functions
|
||||
##############################################
|
||||
|
||||
function Invoke-InitializeApplicationUIExtensions {
|
||||
$typeClasses = @()
|
||||
|
||||
$typeClasses += Get-SingletonObject "ApplicationType"
|
||||
|
||||
foreach ($typeClass in $typeClasses) {
|
||||
Add-ObjectMethod $typeClass "AddUIExportExtensions" $SBAddApplicationUIExportExtension
|
||||
Add-ObjectMethod $typeClass "AddUIDetailsExtension" $SBAddApplicationUIDetailsExtension
|
||||
}
|
||||
}
|
||||
|
||||
##############################################
|
||||
# Initialize
|
||||
##############################################
|
||||
|
||||
Invoke-InitializeApplicationUIExtensions
|
||||
@@ -0,0 +1,69 @@
|
||||
##############################################
|
||||
# ScriptBlocks
|
||||
##############################################
|
||||
|
||||
$SBAddCommonUILoadImage = [scriptblock] {
|
||||
try {
|
||||
$this.IconImage = $this.GetImage()
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
# Capture the module-bound Get-XamlObject + UI root path at attachment time.
|
||||
# Per [[scriptmethod-loses-module-scope]], Add-Member ScriptMethod scriptblocks
|
||||
# can't reliably resolve module-scoped vars/functions by name. Routing through
|
||||
# $script:UIProvider here also fails because the methods are attached at module
|
||||
# load, *before* the loader instantiates the provider.
|
||||
#
|
||||
# Only the methods are attached here. The icons themselves are parsed later, by
|
||||
# Initialize-MenuItemIcons (Extensions/UIMenuIcons*.ps1) when a menu is built -
|
||||
# after the splash is up, not on the Import-Module critical path.
|
||||
$_getXamlObjectFn = ${function:Get-XamlObject}
|
||||
$_uiRootFolder = $script:AppUIRootFolder
|
||||
|
||||
$SBAddCommonUIGetImage = [scriptblock] {
|
||||
$fi = [IO.FileInfo]($_uiRootFolder + "\Xaml\Icons\$($this.Icon).xaml")
|
||||
if($fi.Exists) {
|
||||
return (& $_getXamlObjectFn ($_uiRootFolder + "\Xaml\Icons\$($this.Icon).xaml"))
|
||||
}
|
||||
return $null
|
||||
}.GetNewClosure()
|
||||
|
||||
|
||||
##############################################
|
||||
# Functions
|
||||
##############################################
|
||||
|
||||
function Invoke-InitializeCommonUIExtensions {
|
||||
$typeClasses = @()
|
||||
$groupClasses = @()
|
||||
|
||||
Get-SubClasses "IntunePolicyTypeBase" | ForEach-Object {
|
||||
if(Test-ClassIsAbstract $_) { return }
|
||||
$policyTypeName = $_.Name
|
||||
try {
|
||||
$tmpClass = Get-SingletonObject $_.Name
|
||||
if ($null -ne $tmpClass.PolicyGroup) {
|
||||
$typeClasses += $tmpClass
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-LogError "Failed to initialize class $($policyTypeName)." $_.Exception
|
||||
}
|
||||
}
|
||||
|
||||
Get-SubClasses "IntunePolicyGroupBase" | ForEach-Object {
|
||||
$groupClasses += Get-SingletonObject $_.Name
|
||||
}
|
||||
|
||||
foreach ($class in ($typeClasses + $groupClasses)) {
|
||||
Add-ObjectMethod $class "LoadIconImage" $SBAddCommonUILoadImage
|
||||
Add-ObjectMethod $class "GetImage" $SBAddCommonUIGetImage
|
||||
}
|
||||
}
|
||||
|
||||
##############################################
|
||||
# Initialize
|
||||
##############################################
|
||||
|
||||
Invoke-InitializeCommonUIExtensions
|
||||
@@ -0,0 +1,243 @@
|
||||
##############################################
|
||||
# ScriptBlocks
|
||||
##############################################
|
||||
|
||||
$SBAddPolicyFileUIExportExtension = [scriptblock] {
|
||||
param($Form)
|
||||
|
||||
if (-not $Form) { return }
|
||||
|
||||
Add-UIPolicyFileExportExtensions $Form
|
||||
}
|
||||
|
||||
$SBAddPolicyFileUIDetailsExtension = [scriptblock] {
|
||||
param($Form)
|
||||
|
||||
$buttonPanel = $Form.FindName("pnlButtons")
|
||||
if (-not $buttonPanel) { return }
|
||||
|
||||
$btn = New-Object System.Windows.Controls.Button
|
||||
$btn.Content = 'Download'
|
||||
$btn.Name = 'btnDownload'
|
||||
$btn.Margin = "0,0,5,0"
|
||||
$btn.Width = "100"
|
||||
|
||||
$btn.Add_Click({
|
||||
Invoke-DownloadPolicyFile $script:dgIntuneManagerObjects.SelectedItem
|
||||
})
|
||||
|
||||
$buttonPanel.Children.Insert(0, $btn)
|
||||
|
||||
$btn = New-Object System.Windows.Controls.Button
|
||||
$btn.Content = 'Edit'
|
||||
$btn.Name = 'btnEdit'
|
||||
$btn.Margin = "0,0,5,0"
|
||||
$btn.Width = "100"
|
||||
|
||||
$btn.Add_Click({
|
||||
Invoke-EditPolicyFile $script:dgIntuneManagerObjects.SelectedItem
|
||||
})
|
||||
|
||||
$buttonPanel.Children.Insert(1, $btn)
|
||||
}
|
||||
|
||||
##############################################
|
||||
# Functions
|
||||
##############################################
|
||||
|
||||
function Invoke-InitializePolicyFileUIExtensions {
|
||||
$typeClasses = @()
|
||||
|
||||
Get-SubClasses "IntunePolicyTypeBase" | ForEach-Object {
|
||||
if(Test-ClassIsAbstract $_) { return }
|
||||
try {
|
||||
$tmpClass = Get-SingletonObject $_.Name
|
||||
if ($null -ne $tmpClass.PolicyGroup -and $tmpClass._PolicyFileAttributes.Count -gt 0) {
|
||||
$typeClasses += $tmpClass
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
foreach ($typeClass in $typeClasses) {
|
||||
Add-ObjectMethod $typeClass "AddUIExportExtensions" $SBAddPolicyFileUIExportExtension
|
||||
Add-ObjectMethod $typeClass "AddUIDetailsExtension" $SBAddPolicyFileUIDetailsExtension
|
||||
}
|
||||
}
|
||||
|
||||
function Add-UIPolicyFileExportExtensions {
|
||||
param(
|
||||
$Form,
|
||||
$Description = "Export the files associated with selected profiles"
|
||||
)
|
||||
|
||||
$grdExportProperties = $null
|
||||
try {
|
||||
$grdExportProperties = $Form.FindName("grdExportProperties")
|
||||
}
|
||||
catch {}
|
||||
if (-not $grdExportProperties) { return }
|
||||
|
||||
if ($grdExportProperties.FindName("chkExportPolicyFile")) {
|
||||
return # Already added
|
||||
}
|
||||
|
||||
$xaml = @"
|
||||
<StackPanel $($script:wpfNS) Orientation="Horizontal" Margin="0,0,5,0">
|
||||
<Label Content="Export file" />
|
||||
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="$Description" />
|
||||
</StackPanel>
|
||||
"@
|
||||
try {
|
||||
$label = [Windows.Markup.XamlReader]::Parse($xaml)
|
||||
|
||||
$chkExportPolicyFiles = [System.Windows.Controls.CheckBox]::new()
|
||||
$chkExportPolicyFiles.IsChecked = $true
|
||||
$chkExportPolicyFiles.VerticalAlignment = "Center"
|
||||
$chkExportPolicyFiles.Name = "chkExportPolicyFiles"
|
||||
|
||||
Set-CacheObject "ExportPolicyFiles" $chkExportPolicyFiles.IsChecked
|
||||
|
||||
$rd = [System.Windows.Controls.RowDefinition]::new()
|
||||
$rd.Height = [double]::NaN
|
||||
$grdExportProperties.RowDefinitions.Add($rd)
|
||||
|
||||
$label.SetValue([System.Windows.Controls.Grid]::RowProperty, $grdExportProperties.RowDefinitions.Count - 1)
|
||||
$chkExportPolicyFiles.SetValue([System.Windows.Controls.Grid]::RowProperty, $grdExportProperties.RowDefinitions.Count - 1)
|
||||
$chkExportPolicyFiles.SetValue([System.Windows.Controls.Grid]::ColumnProperty, 1)
|
||||
|
||||
$grdExportProperties.Children.Add($label)
|
||||
$grdExportProperties.Children.Add($chkExportPolicyFiles)
|
||||
|
||||
$Form.RegisterName($chkExportPolicyFiles.Name, $chkExportPolicyFiles)
|
||||
|
||||
$changed = [scriptblock] {
|
||||
param($S, $E)
|
||||
Set-CacheObject "ExportPolicyFiles" $this.IsChecked
|
||||
}
|
||||
|
||||
$chkExportPolicyFiles.Add_Checked($changed)
|
||||
$chkExportPolicyFiles.Add_Unchecked($changed)
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
function Invoke-EditPolicyFile {
|
||||
param($Policy)
|
||||
|
||||
if (-not $Policy) { return }
|
||||
|
||||
if ($Policy.IsFullObject -eq $false) {
|
||||
[void]$Policy.Get()
|
||||
}
|
||||
|
||||
$attribute = $Policy.PolicyType._PolicyFileAttributes[0] # TODO: Support multiple attributes
|
||||
|
||||
if (-not $Policy.JsonObject.$attribute) { return }
|
||||
$script:currentPolicyFileObject = $Policy
|
||||
|
||||
$script:editForm = $script:UIProvider.GetXamlObject(($script:AppUIRootFolder + "\Xaml\EditScriptDialog.xaml"))
|
||||
|
||||
if (-not $script:editForm) { return }
|
||||
|
||||
$script:UIProvider.SetXamlProperty($script:editForm, "txtEditScriptTitle", "Text", "Edit: $($Policy.JsonObject.displayName)")
|
||||
|
||||
$policyFileText = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Policy.JsonObject.$attribute))
|
||||
$script:UIProvider.SetXamlProperty($script:editForm, "txtScriptText", "Text", $policyFileText)
|
||||
|
||||
$script:currentModal = $null
|
||||
if ($script:grdModal.Children.Count -gt 0) {
|
||||
$script:currentModal = $script:grdModal.Children[0]
|
||||
}
|
||||
|
||||
$script:UIProvider.AddXamlEvent($script:editForm, "btnSaveScriptEdit", "add_click", {
|
||||
$policyFileText = $script:UIProvider.GetXamlProperty($script:editForm, "txtScriptText", "Text")
|
||||
$pre = [System.Text.Encoding]::UTF8.GetPreamble()
|
||||
$utfBOM = [System.Text.Encoding]::UTF8.GetString($pre)
|
||||
if ($policyFileText.startsWith($utfBOM)) {
|
||||
# Remove UTF8 BOM bytes
|
||||
$policyFileText = $policyFileText.Remove(0, $utfBOM.Length)
|
||||
}
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($policyFileText)
|
||||
$encodedText = [Convert]::ToBase64String($bytes)
|
||||
$attribute = $script:currentPolicyFileObject.PolicyType._PolicyFileAttributes[0]
|
||||
|
||||
if ($script:currentPolicyFileObject.JsonObject.$attribute -ne $encodedText) {
|
||||
# Save script
|
||||
if (($script:UIProvider.ShowMessageBox("Are you sure you want to update the file?`n`nObject:`n$($script:currentPolicyFileObject.Name)", "Update file?", "YesNo", "Warning")) -eq "Yes") {
|
||||
Write-Status "Update $($script:currentPolicyFileObject.Name)"
|
||||
$clonedObject = $script:currentPolicyFileObject.Clone()
|
||||
$clonedObject.JsonObject.$attribute = $encodedText
|
||||
Remove-GraphPropertiesForImport $clonedObject $clonedObject.JsonObject
|
||||
foreach ($prop in $script:currentPolicyFileObject.PolicyType.PropertiesToRemoveForUpdate) {
|
||||
Remove-Property $clonedObject.JsonObject $prop
|
||||
}
|
||||
Remove-Property $clonedObject.JsonObject "Assignments"
|
||||
Remove-Property $clonedObject.JsonObject "isAssigned"
|
||||
|
||||
if ($script:currentPolicyFileObject.Set($null, $clonedObject.JsonString, "PATCH", $null)) {
|
||||
Write-Log "File saved successfully"
|
||||
}
|
||||
else {
|
||||
Write-Log "Failed to save script" 3
|
||||
}
|
||||
Write-Status ""
|
||||
}
|
||||
}
|
||||
|
||||
$script:grdModal.Children.Clear()
|
||||
if ($script:currentModal) {
|
||||
$script:grdModal.Children.Add($script:currentModal)
|
||||
}
|
||||
[System.Windows.Forms.Application]::DoEvents()
|
||||
})
|
||||
|
||||
$script:UIProvider.AddXamlEvent($script:editForm, "btnCancelScriptEdit", "add_click", {
|
||||
$script:grdModal.Children.Clear()
|
||||
if ($script:currentModal) {
|
||||
$script:grdModal.Children.Add($script:currentModal)
|
||||
}
|
||||
[System.Windows.Forms.Application]::DoEvents()
|
||||
})
|
||||
|
||||
$script:grdModal.Children.Clear()
|
||||
$script:editForm.SetValue([System.Windows.Controls.Grid]::RowProperty, 1)
|
||||
$script:editForm.SetValue([System.Windows.Controls.Grid]::ColumnProperty, 1)
|
||||
$script:grdModal.Children.Add($script:editForm) | Out-Null
|
||||
[System.Windows.Forms.Application]::DoEvents()
|
||||
}
|
||||
|
||||
function Invoke-DownloadPolicyFile
|
||||
{
|
||||
param($Policy)
|
||||
|
||||
if(-not $Policy) { return }
|
||||
|
||||
if($Policy.IsFullObject -eq $false) {
|
||||
[void]$Policy.Get()
|
||||
}
|
||||
Write-Status ""
|
||||
|
||||
$attribute = $Policy.PolicyType._PolicyFileAttributes[0]
|
||||
|
||||
if($Policy.JsonObject.$attribute)
|
||||
{
|
||||
$fileName = ?? $Policy.JsonObject.FileName "$($attribute).json"
|
||||
Write-Log "Download PowerShell file '$($fileName)' from $($Policy.Name)"
|
||||
|
||||
$dlgSave = [System.Windows.Forms.SaveFileDialog]::new()
|
||||
$dlgSave.InitialDirectory = Get-SettingValue "RootFolder" $env:Temp
|
||||
$dlgSave.FileName = $fileName
|
||||
if($dlgSave.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK -and $dlgSave.Filename)
|
||||
{
|
||||
# Changed to WriteAllBytes to get rid of BOM characters from Custom Attribute file
|
||||
[IO.File]::WriteAllBytes($dlgSave.FileName, ([System.Convert]::FromBase64String($Policy.JsonObject.$attribute)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
##############################################
|
||||
# Initialize
|
||||
##############################################
|
||||
|
||||
Invoke-InitializePolicyFileUIExtensions
|
||||
@@ -0,0 +1,232 @@
|
||||
##############################################
|
||||
# ScriptBlocks
|
||||
##############################################
|
||||
|
||||
$SBAddScriptUIExportExtension = [scriptblock] {
|
||||
param($Form)
|
||||
|
||||
if (-not $Form) { return }
|
||||
|
||||
Add-UIScriptExportExtensions $Form
|
||||
}
|
||||
|
||||
$SBAddScriptUIDetailsExtension = [scriptblock] {
|
||||
param($Form)
|
||||
|
||||
$buttonPanel = $Form.FindName("pnlButtons")
|
||||
if (-not $buttonPanel) { return }
|
||||
|
||||
$btn = New-Object System.Windows.Controls.Button
|
||||
$btn.Content = 'Download'
|
||||
$btn.Name = 'btnDownload'
|
||||
$btn.Margin = "0,0,5,0"
|
||||
$btn.Width = "100"
|
||||
|
||||
$btn.Add_Click({
|
||||
Invoke-DownloadScript $script:dgIntuneManagerObjects.SelectedItem
|
||||
})
|
||||
|
||||
$buttonPanel.Children.Insert(0, $btn)
|
||||
|
||||
$btn = New-Object System.Windows.Controls.Button
|
||||
$btn.Content = 'Edit'
|
||||
$btn.Name = 'btnEdit'
|
||||
$btn.Margin = "0,0,5,0"
|
||||
$btn.Width = "100"
|
||||
|
||||
$btn.Add_Click({
|
||||
Invoke-EditScript $script:dgIntuneManagerObjects.SelectedItem
|
||||
})
|
||||
|
||||
$buttonPanel.Children.Insert(1, $btn)
|
||||
}
|
||||
|
||||
##############################################
|
||||
# Functions
|
||||
##############################################
|
||||
|
||||
function Invoke-InitializeScriptUIExtensions {
|
||||
$typeClasses = @()
|
||||
|
||||
Get-SubClasses "ScriptTypeBase" | ForEach-Object {
|
||||
try {
|
||||
$tmpClass = Get-SingletonObject $_.Name
|
||||
if ($null -ne $tmpClass.PolicyGroup) {
|
||||
$typeClasses += $tmpClass
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
foreach ($typeClass in $typeClasses) {
|
||||
Add-ObjectMethod $typeClass "AddUIExportExtensions" $SBAddScriptUIExportExtension
|
||||
Add-ObjectMethod $typeClass "AddUIDetailsExtension" $SBAddScriptUIDetailsExtension
|
||||
}
|
||||
}
|
||||
|
||||
function Add-UIScriptExportExtensions {
|
||||
param(
|
||||
$Form,
|
||||
$Description = "Export the script associated with selected profiles"
|
||||
)
|
||||
|
||||
$grdExportProperties = $null
|
||||
try {
|
||||
$grdExportProperties = $Form.FindName("grdExportProperties")
|
||||
}
|
||||
catch {}
|
||||
if (-not $grdExportProperties) { return }
|
||||
|
||||
if ($grdExportProperties.FindName("chkExportScript")) {
|
||||
return # Already added
|
||||
}
|
||||
|
||||
$xaml = @"
|
||||
<StackPanel $($script:wpfNS) Orientation="Horizontal" Margin="0,0,5,0">
|
||||
<Label Content="Export script" />
|
||||
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="$Description" />
|
||||
</StackPanel>
|
||||
"@
|
||||
try {
|
||||
$label = [Windows.Markup.XamlReader]::Parse($xaml)
|
||||
|
||||
$chkExportScript = [System.Windows.Controls.CheckBox]::new()
|
||||
$chkExportScript.IsChecked = $true
|
||||
$chkExportScript.VerticalAlignment = "Center"
|
||||
$chkExportScript.Name = "chkExportScript"
|
||||
|
||||
Set-CacheObject "ExportScripts" $chkExportScript.IsChecked
|
||||
|
||||
$rd = [System.Windows.Controls.RowDefinition]::new()
|
||||
$rd.Height = [double]::NaN
|
||||
$grdExportProperties.RowDefinitions.Add($rd)
|
||||
|
||||
$label.SetValue([System.Windows.Controls.Grid]::RowProperty, $grdExportProperties.RowDefinitions.Count - 1)
|
||||
$chkExportScript.SetValue([System.Windows.Controls.Grid]::RowProperty, $grdExportProperties.RowDefinitions.Count - 1)
|
||||
$chkExportScript.SetValue([System.Windows.Controls.Grid]::ColumnProperty, 1)
|
||||
|
||||
$grdExportProperties.Children.Add($label)
|
||||
$grdExportProperties.Children.Add($chkExportScript)
|
||||
|
||||
$Form.RegisterName($chkExportScript.Name, $chkExportScript)
|
||||
|
||||
$changed = [scriptblock] {
|
||||
param($S, $E)
|
||||
Set-CacheObject "ExportScripts" $this.IsChecked
|
||||
}
|
||||
|
||||
$chkExportScript.Add_Checked($changed)
|
||||
$chkExportScript.Add_Unchecked($changed)
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
function Invoke-DownloadScript {
|
||||
param($ScriptPolicy)
|
||||
|
||||
if (-not $ScriptPolicy) { return }
|
||||
|
||||
if ($ScriptPolicy.IsFullObject -eq $false) {
|
||||
[void]$ScriptPolicy.Get()
|
||||
}
|
||||
|
||||
if (-not $ScriptPolicy.JsonObject.scriptContent) { return }
|
||||
|
||||
Write-Status ""
|
||||
|
||||
$dlgSave = [System.Windows.Forms.SaveFileDialog]::new()
|
||||
$dlgSave.InitialDirectory = Get-SettingValue "RootFolder" $env:Temp
|
||||
$dlgSave.FileName = $ScriptPolicy.JsonObject.FileName
|
||||
if($dlgSave.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK -and $dlgSave.Filename)
|
||||
{
|
||||
Save-IntuneScriptContent $ScriptPolicy $dlgSave.FileName | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-EditScript {
|
||||
param($ScriptPolicy)
|
||||
|
||||
if (-not $ScriptPolicy) { return }
|
||||
|
||||
if ($ScriptPolicy.IsFullObject -eq $false) {
|
||||
[void]$ScriptPolicy.Get()
|
||||
}
|
||||
|
||||
if (-not $ScriptPolicy.JsonObject.scriptContent) { return }
|
||||
$script:currentScriptObject = $ScriptPolicy
|
||||
|
||||
$script:editForm = $script:UIProvider.GetXamlObject(($script:AppUIRootFolder + "\Xaml\EditScriptDialog.xaml"))
|
||||
|
||||
if (-not $script:editForm) { return }
|
||||
|
||||
$script:UIProvider.SetXamlProperty($script:editForm, "txtEditScriptTitle", "Text", "Edit: $($ScriptPolicy.JsonObject.displayName)")
|
||||
|
||||
$scriptText = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($ScriptPolicy.JsonObject.scriptContent))
|
||||
$script:UIProvider.SetXamlProperty($script:editForm, "txtScriptText", "Text", $scriptText)
|
||||
|
||||
$script:currentModal = $null
|
||||
if ($script:grdModal.Children.Count -gt 0) {
|
||||
$script:currentModal = $script:grdModal.Children[0]
|
||||
}
|
||||
|
||||
$script:UIProvider.AddXamlEvent($script:editForm, "btnSaveScriptEdit", "add_click", {
|
||||
$scriptText = $script:UIProvider.GetXamlProperty($script:editForm, "txtScriptText", "Text")
|
||||
$pre = [System.Text.Encoding]::UTF8.GetPreamble()
|
||||
$utfBOM = [System.Text.Encoding]::UTF8.GetString($pre)
|
||||
if ($scriptText.startsWith($utfBOM)) {
|
||||
# Remove UTF8 BOM bytes
|
||||
$scriptText = $scriptText.Remove(0, $utfBOM.Length)
|
||||
}
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($scriptText)
|
||||
$encodedText = [Convert]::ToBase64String($bytes)
|
||||
|
||||
if ($script:currentScriptObject.JsonObject.scriptContent -ne $encodedText) {
|
||||
# Save script
|
||||
if (($script:UIProvider.ShowMessageBox("Are you sure you want to update the script?`n`nObject:`n$($script:currentScriptObject.Name)", "Update script?", "YesNo", "Warning")) -eq "Yes") {
|
||||
Write-Status "Update $($script:currentScriptObject.Name)"
|
||||
$clonedObject = $script:currentScriptObject.Clone()
|
||||
$clonedObject.JsonObject.scriptContent = $encodedText
|
||||
Remove-GraphPropertiesForImport $clonedObject $clonedObject.JsonObject
|
||||
foreach ($prop in $script:currentScriptObject.PolicyType.PropertiesToRemoveForUpdate) {
|
||||
Remove-Property $clonedObject.JsonObject $prop
|
||||
}
|
||||
Remove-Property $clonedObject.JsonObject "Assignments"
|
||||
Remove-Property $clonedObject.JsonObject "isAssigned"
|
||||
|
||||
if ($script:currentScriptObject.Set($null, $clonedObject.JsonString, "PATCH", $null)) {
|
||||
Write-Log "Script saved successfully"
|
||||
}
|
||||
else {
|
||||
Write-Log "Failed to save script" 3
|
||||
}
|
||||
Write-Status ""
|
||||
}
|
||||
}
|
||||
|
||||
$script:grdModal.Children.Clear()
|
||||
if ($script:currentModal) {
|
||||
$script:grdModal.Children.Add($script:currentModal)
|
||||
}
|
||||
[System.Windows.Forms.Application]::DoEvents()
|
||||
})
|
||||
|
||||
$script:UIProvider.AddXamlEvent($script:editForm, "btnCancelScriptEdit", "add_click", {
|
||||
$script:grdModal.Children.Clear()
|
||||
if ($script:currentModal) {
|
||||
$script:grdModal.Children.Add($script:currentModal)
|
||||
}
|
||||
[System.Windows.Forms.Application]::DoEvents()
|
||||
})
|
||||
|
||||
$script:grdModal.Children.Clear()
|
||||
$script:editForm.SetValue([System.Windows.Controls.Grid]::RowProperty, 1)
|
||||
$script:editForm.SetValue([System.Windows.Controls.Grid]::ColumnProperty, 1)
|
||||
$script:grdModal.Children.Add($script:editForm) | Out-Null
|
||||
[System.Windows.Forms.Application]::DoEvents()
|
||||
}
|
||||
|
||||
##############################################
|
||||
# Initialize
|
||||
##############################################
|
||||
|
||||
Invoke-InitializeScriptUIExtensions
|
||||
Reference in New Issue
Block a user