Compare commits

..
2 Commits
Author SHA1 Message Date
Mikael Karlsson 1556c447c5 3.1.2
Support for deleting profiles/policies
2021-06-20 19:25:27 +10:00
Mikael Karlsson a495b0f0df 3.1.1 fixes
Fix issue with getting user information calling the ME API with full ODATA info
2021-06-16 12:14:01 +10:00
18 changed files with 980 additions and 106 deletions
+5 -13
View File
@@ -12,7 +12,7 @@ This module handles the WPF UI
function Get-ModuleVersion
{
'3.0.0'
'3.0.1'
}
function Start-CoreApp
@@ -1138,8 +1138,8 @@ function Add-ViewItem
{
param($viewItem)
$objSection = $global:viewObjects | Where { $_.ViewInfo.Id -eq $viewItem.ViewID }
if(-not $objSection)
$viewObject = $global:viewObjects | Where { $_.ViewInfo.Id -eq $viewItem.ViewID }
if(-not $viewObject)
{
if(($arrMenuInlcude -and $arrMenuInlcude -notcontains $viewItem.ViewID) -or ($arrMenuExlcude -and $arrMenuExlcude -contains $viewItem.ViewID)) { return }
@@ -1153,17 +1153,9 @@ function Add-ViewItem
$viewItem | Add-Member -NotePropertyName "ImportOrder" -NotePropertyValue 1000
}
if(-not $global:PermissionScope) { $global:PermissionScope = @() }
foreach($scope in $viewItem.Permissons)
{
if($global:PermissionScope -notcontains $scope) { $global:PermissionScope += $scope }
}
foreach($required in @("openid","profile","email","User.ReadWrite.All","Group.ReadWrite.All")) #,"https://management.azure.com/user_impersonation") )
{
if($required -in $global:PermissionScope) { continue }
$global:PermissionScope += $required
Write-LogDebug "Adding required scope $required"
if($viewObject.ViewInfo.Permissions -is [Object[]] -and $viewObject.ViewInfo.Permissions -notcontains $scope) { $viewObject.ViewInfo.Permissions += $scope }
}
if($viewItem.Icon -or [IO.File]::Exists(($global:AppRootFolder + "\Xaml\Icons\$($viewItem.Id).xaml")))
@@ -1172,7 +1164,7 @@ function Add-ViewItem
$viewItem | Add-Member -NotePropertyName "IconImage" -NotePropertyValue $ctrl
}
$objSection.ViewItems += $viewItem
$viewObject.ViewItems += $viewItem
}
function Show-View
@@ -0,0 +1,23 @@
[
{
"dataType": 8,
"booleanActions": 0,
"category": "SettingDetails.deviceLimit"
},
{
"nameResourceKey": "SettingDetails.deviceLimit",
"descriptionResourceKey": "",
"entityKey": "limit",
"dataType": 14,
"booleanActions": 0,
"category": "SettingDetails.deviceLimit"
},
{
"nameResourceKey": "TableHeaders.priority",
"descriptionResourceKey": "",
"entityKey": "priority",
"dataType": 14,
"booleanActions": 0,
"category": "SettingDetails.deviceLimit"
}
]
@@ -0,0 +1,417 @@
[
{
"dataType": 8,
"booleanActions": 0,
"nameResourceKey": "Devices.androidWorkProfile"
},
{
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "androidForWorkRestriction",
"dataType": 6,
"booleanActions": 0,
"category": "",
"complexOptions": [
{
"nameResourceKey": "TableHeaders.platform",
"descriptionResourceKey": "",
"entityKey": "platformBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Children": {
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "",
"dataType": 5,
"booleanActions": 0,
"category": "",
"Condition": {
"Expressions": [
{
"property": "platformBlocked",
"value": false
}
]
},
"complexOptions": [
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.versions",
"descriptionResourceKey": "",
"entityKey": ".",
"dataType": 21,
"separator": "-",
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Condition": {
"type": "and",
"Expressions": [
{
"property": "osMinimumVersion"
},
{
"property": "osMaximumVersion"
}
]
},
"Columns": [
{
"metadata": {
"entityKey": "osMinimumVersion"
}
},
{
"metadata": {
"entityKey": "osMaximumVersion"
}
}
]
},
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.personal",
"descriptionResourceKey": "",
"entityKey": "personalDeviceEnrollmentBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings"
},
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.blockManufacturersHeader",
"descriptionResourceKey": "",
"entityKey": "blockedManufacturers",
"dataType": 21,
"separator": "-",
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Condition": {
"type": "and",
"Expressions": [
{
"property": "blockedManufacturers"
}
]
},
"Columns": [
{
"metadata": {
"entityKey": "unusedForSingleItems"
}
}
]
}
]
}
}
]
},
{
"dataType": 8,
"booleanActions": 0,
"nameResourceKey": "Devices.android"
},
{
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "androidRestriction",
"dataType": 6,
"booleanActions": 0,
"category": "",
"complexOptions": [
{
"nameResourceKey": "TableHeaders.platform",
"descriptionResourceKey": "",
"entityKey": "platformBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Children": {
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "",
"dataType": 5,
"booleanActions": 0,
"category": "",
"Condition": {
"Expressions": [
{
"property": "platformBlocked",
"value": false
}
]
},
"complexOptions": [
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.versions",
"descriptionResourceKey": "",
"entityKey": ".",
"dataType": 21,
"separator": "-",
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Condition": {
"type": "and",
"Expressions": [
{
"property": "osMinimumVersion"
},
{
"property": "osMaximumVersion"
}
]
},
"Columns": [
{
"metadata": {
"entityKey": "osMinimumVersion"
}
},
{
"metadata": {
"entityKey": "osMaximumVersion"
}
}
]
},
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.personal",
"descriptionResourceKey": "",
"entityKey": "personalDeviceEnrollmentBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings"
},
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.blockManufacturersHeader",
"descriptionResourceKey": "",
"entityKey": "blockedManufacturers",
"dataType": 21,
"separator": "-",
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Condition": {
"type": "and",
"Expressions": [
{
"property": "blockedManufacturers"
}
]
},
"Columns": [
{
"metadata": {
"entityKey": "unusedForSingleItems"
}
}
]
}
]
}
}
]
},
{
"dataType": 8,
"booleanActions": 0,
"nameResourceKey": "Devices.iOS"
},
{
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "iosRestriction",
"dataType": 6,
"booleanActions": 0,
"category": "",
"complexOptions": [
{
"nameResourceKey": "TableHeaders.platform",
"descriptionResourceKey": "",
"entityKey": "platformBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Children": {
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "",
"dataType": 5,
"booleanActions": 0,
"category": "",
"Condition": {
"Expressions": [
{
"property": "platformBlocked",
"value": false
}
]
},
"complexOptions": [
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.versions",
"descriptionResourceKey": "",
"entityKey": ".",
"dataType": 21,
"separator": "-",
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Condition": {
"type": "and",
"Expressions": [
{
"property": "osMinimumVersion"
},
{
"property": "osMaximumVersion"
}
]
},
"Columns": [
{
"metadata": {
"entityKey": "osMinimumVersion"
}
},
{
"metadata": {
"entityKey": "osMaximumVersion"
}
}
]
},
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.personal",
"descriptionResourceKey": "",
"entityKey": "personalDeviceEnrollmentBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings"
}
]
}
}
]
},
{
"dataType": 8,
"booleanActions": 0,
"nameResourceKey": "Devices.mac"
},
{
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "macRestriction",
"dataType": 6,
"booleanActions": 0,
"category": "",
"complexOptions": [
{
"nameResourceKey": "TableHeaders.platform",
"descriptionResourceKey": "",
"entityKey": "platformBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Children": {
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "",
"dataType": 5,
"booleanActions": 0,
"category": "",
"Condition": {
"Expressions": [
{
"property": "platformBlocked",
"value": false
}
]
},
"complexOptions": [
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.personal",
"descriptionResourceKey": "",
"entityKey": "personalDeviceEnrollmentBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings"
}
]
}
}
]
},
{
"dataType": 8,
"booleanActions": 0,
"nameResourceKey": "Devices.windows"
},
{
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "windowsRestriction",
"dataType": 6,
"booleanActions": 0,
"category": "",
"complexOptions": [
{
"nameResourceKey": "TableHeaders.platform",
"descriptionResourceKey": "",
"entityKey": "platformBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Children": {
"nameResourceKey": "",
"descriptionResourceKey": "",
"entityKey": "",
"dataType": 5,
"booleanActions": 0,
"category": "",
"Condition": {
"Expressions": [
{
"property": "platformBlocked",
"value": false
}
]
},
"complexOptions": [
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.versions",
"descriptionResourceKey": "",
"entityKey": ".",
"dataType": 21,
"separator": "-",
"category": "EnrollmentRestrictions.DeviceType.platformSettings",
"Condition": {
"type": "and",
"Expressions": [
{
"property": "osMinimumVersion"
},
{
"property": "osMaximumVersion"
}
]
},
"Columns": [
{
"metadata": {
"entityKey": "osMinimumVersion"
}
},
{
"metadata": {
"entityKey": "osMaximumVersion"
}
}
]
},
{
"nameResourceKey": "EnrollmentRestrictions.DeviceType.personal",
"descriptionResourceKey": "",
"entityKey": "personalDeviceEnrollmentBlocked",
"dataType": 0,
"booleanActions": 100,
"category": "EnrollmentRestrictions.DeviceType.platformSettings"
}
]
}
}
]
}
]
Binary file not shown.
Binary file not shown.
+27 -13
View File
@@ -11,7 +11,7 @@ Objects can be compared based on Properties or Documentatation info.
function Get-ModuleVersion
{
'1.0.0'
'1.0.1'
}
function Invoke-InitializeModule
@@ -168,18 +168,18 @@ function Invoke-CompareObjects
}
function Set-ColumnVisibility
{
param($show)
param($showCategory = $false, $showSubCategory = $false)
$colTmp = $global:dgCompareInfo.Columns | Where { $_.Binding.Path.Path -eq "Category" }
if($colTmp)
{
$colTmp.Visibility = (?: ($show -eq $true) "Visible" "Collapsed")
$colTmp.Visibility = (?: ($showCategory -eq $true) "Visible" "Collapsed")
}
$colTmp = $global:dgCompareInfo.Columns | Where { $_.Binding.Path.Path -eq "SubCategory" }
if($colTmp)
{
$colTmp.Visibility = (?: ($show -eq $true) "Visible" "Collapsed")
$colTmp.Visibility = (?: ($showSubCategory -eq $true) "Visible" "Collapsed")
}
}
@@ -265,11 +265,25 @@ function Compare-ObjectsBasedonProperty
}
}
function Get-CompareCustomColumnsDoc
{
param($objInfo)
if($objInfo.Object.'@OData.Type' -eq "#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration")
{
Set-ColumnVisibility $true $true
}
else
{
Set-ColumnVisibility $true $false
}
}
function Compare-ObjectsBasedonDocumentation
{
param($obj1, $obj2)
Set-ColumnVisibility $true
Get-CompareCustomColumnsDoc $obj
# ToDo: set this based on configuration value
$script:assignmentOutput = "simpleFullCompare"
@@ -353,25 +367,25 @@ function Compare-ObjectsBasedonDocumentation
{
foreach ($prop in $docObj1.Settings)
{
if(($prop.EntityKey) -in $addedProperties) { continue }
if(($prop.EntityKey + $prop.Category + $prop.SubCategory) -in $addedProperties) { continue }
$addedProperties += $prop.EntityKey
$addedProperties += ($prop.EntityKey + $prop.Category + $prop.SubCategory)
$val1 = $prop.$settingsValue
$prop2 = $docObj2.Settings | Where { $_.EntityKey -eq $prop.EntityKey }
$prop2 = $docObj2.Settings | Where { $_.EntityKey -eq $prop.EntityKey -and $_.Category -eq $prop.Category -and $_.SubCategory -eq $prop.SubCategory }
$val2 = $prop2.$settingsValue
Add-CompareProperty $prop.Name $val1 $val2 $prop.Category
Add-CompareProperty $prop.Name $val1 $val2 $prop.Category $prop.SubCategory
}
# These objects are defined only on Object 2. They will be last in the table
foreach ($prop in $docObj2.Settings)
{
if(($prop.EntityKey) -in $addedProperties) { continue }
if(($prop.EntityKey + $prop.Category + $prop.SubCategory) -in $addedProperties) { continue }
$addedProperties += $prop.EntityKey
$addedProperties += ($prop.EntityKey + $prop.Category + $prop.SubCategory)
$val2 = $prop.$settingsValue
$prop2 = $docObj1.Settings | Where { $_.EntityKey -eq $prop.EntityKey }
$prop2 = $docObj1.Settings | Where { $_.EntityKey -eq $prop.EntityKey -and $_.Category -eq $prop.Category -and $_.SubCategory -eq $prop.SubCategory }
$val1 = $prop2.$settingsValue
Add-CompareProperty $prop.Name $val1 $val2 $prop.Category
Add-CompareProperty $prop.Name $val1 $val2 $prop.Category $prop.SubCategory
}
}
+32 -9
View File
@@ -20,7 +20,7 @@ $global:documentationProviders = @()
function Get-ModuleVersion
{
'1.0.0'
'1.0.1'
}
function Invoke-InitializeModule
@@ -207,7 +207,7 @@ function Get-ObjectDocumentation
elseif($type -eq "#microsoft.graph.deviceManagementIntent")
{
Invoke-TranslateIntentObject $obj $objectType | Out-Null
$properties = @("Name","Value","Category","RawValue","Description")
$properties = @("Name","Value","Category","RawValue","SettingId","Description")
}
#endregion
#region Administrative Templates
@@ -411,6 +411,10 @@ function Get-ObjectTypeString
{
return (Get-LanguageString "SecurityTemplate.conditionalAccess")
}
elseif($objTypeId -eq "EndpointAnalytics")
{
return (Get-LanguageString "SettingDetails.healthMonScopeBootPerf")
}
elseif($objTypeId -eq "EndpointSecurity")
{
return (Get-LanguageString "PolicyType.EndpointSecurityTemplate.default")
@@ -1586,10 +1590,10 @@ function Invoke-VerifyCondition
return $false
}
if(!$expression.value)
if($expression.value -eq $null)
{
# Value not specified. Check that property exists
$tmpRet = $tmpProp -ne $null
# Value not specified. Check if the property is set
$tmpRet = $tmpProp.Value -ne $null
}
elseif($expression.operator -eq "ne")
{
@@ -1644,7 +1648,11 @@ function Invoke-TranslateSection
#if($prop.enabled -eq $false -and $objInfo.ShowDisabled -ne $true) { continue }
if((Invoke-VerifyCondition $obj $prop $objInfo) -eq $false) { continue }
if((Invoke-VerifyCondition $obj $prop $objInfo) -eq $false)
{
Write-LogDebug "Condition returned false: $(($prop.Condition | ConvertTo-Json -Depth 10 -Compress))" 2
continue
}
$obj = Get-CustomPropertyObject $obj $prop
@@ -1779,10 +1787,11 @@ function Invoke-TranslateSection
$value = Get-LanguageString $prop.entityKey
}
elseif(($prop.allowMissing -ne $true) -and
($prop.entityKey -ne ".") -and
(-not ($obj.PSObject.Properties | Where Name -eq $prop.entityKey)) -and
(-not ($obj.PSObject.Properties | Where Name -eq "$($prop.entityKey)@odata.navigationLink")))
{
if($prop.enabled -eq $true)
if($prop.enabled -ne $false)
{
Write-Log "Property with EntityKey $($prop.entityKey) is missing. Property will not be added!" 2
}
@@ -2508,7 +2517,14 @@ function Invoke-TranslateTable
{
param($obj, $prop)
$propValue = $obj."$($prop.entityKey)"
if($prop.entityKey -eq ".")
{
$propValue = $obj
}
else
{
$propValue = $obj."$($prop.entityKey)"
}
$items = @()
foreach($item in $propValue)
@@ -2535,7 +2551,14 @@ function Invoke-TranslateTable
$itemValues += (?? $item."$($column.metadata.entityKey)" $obj."$($column.metadata.entityKey)")
}
}
$items += $itemValues -join $script:propertySeparator
if($prop.separator)
{
$items += $itemValues -join $prop.separator
}
else
{
$items += $itemValues -join $script:propertySeparator
}
}
if($items.Count -gt 0)
+97 -3
View File
@@ -10,7 +10,7 @@ This module is for the Endpoint Manager/Intune View. It manages Export/Import/Co
#>
function Get-ModuleVersion
{
'3.1.0'
'3.1.2'
}
function Invoke-InitializeModule
@@ -72,6 +72,22 @@ function Invoke-InitializeModule
SubPath = "EndpointManager"
}) "EndpointManager"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Show Delete button"
Key = "EMAllowDelete"
Type = "Boolean"
DefaultValue = $false
Description = "Allow deleting individual objectes"
}) "EndpointManager"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Show Bulk Delete "
Key = "EMAllowBulkDelete"
Type = "Boolean"
DefaultValue = $false
Description = "Allow using bulk delete to delete all objects of selected types"
}) "EndpointManager"
$viewPanel = Get-XamlObject ($global:AppRootFolder + "\Xaml\EndpointManagerPanel.xaml") -AddVariables
Set-EMViewPanel $viewPanel
@@ -89,6 +105,8 @@ function Invoke-InitializeModule
Authenticate = { Invoke-EMAuthenticateToMSAL }
AppInfo = (Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547")
SaveSettings = { Invoke-EMSaveSettings }
Permissions = @()
})
Add-ViewObject $global:EMViewObject
@@ -166,6 +184,7 @@ function Invoke-InitializeModule
PostImportCommand = { Start-PostImportIntuneBranding @args }
PostGetCommand = { Start-PostGetIntuneBranding @args }
PostExportCommand = { Start-PostExportIntuneBranding @args }
PreDeleteCommand = { Start-PreDeleteIntuneBranding @args }
Permissons=@("DeviceManagementApps.ReadWrite.All")
Icon = "Branding"
SkipRemoveProperties = @('Id') # Id is removed by PreImport. Required for default profile
@@ -202,6 +221,7 @@ function Invoke-InitializeModule
ViewID = "IntuneGraphAPI"
PreImportCommand = { Start-PreImportESP @args }
PostExportCommand = { Start-PostExportESP @args }
PreDeleteCommand = { Start-PreDeleteEnrollmentRestrictions @args } # Note: Uses same PreDelete as restrictions
QUERYLIST = "`$filter=endsWith(id,'Windows10EnrollmentCompletionPageConfiguration')"
Permissons=@("DeviceManagementServiceConfig.ReadWrite.All")
SkipRemoveProperties = @('Id')
@@ -217,6 +237,7 @@ function Invoke-InitializeModule
QUERYLIST = "`$filter=not endsWith(id,'Windows10EnrollmentCompletionPageConfiguration')"
PostExportCommand = { Start-PostExportEnrollmentRestrictions @args }
PreImportCommand = { Start-PreImportEnrollmentRestrictions @args }
PreDeleteCommand = { Start-PreDeleteEnrollmentRestrictions @args }
Permissons=@("DeviceManagementServiceConfig.ReadWrite.All")
SkipRemoveProperties = @('Id')
AssignmentsType = "enrollmentConfigurationAssignments"
@@ -275,6 +296,7 @@ function Invoke-InitializeModule
AssignmentsType = "deviceManagementScriptAssignments"
Icon="CustomAttributes"
GroupId = "CustomAttributes" # MacOS Settings
DetailExtension = { Add-ScriptExtensions @args }
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -521,13 +543,26 @@ function Invoke-InitializeModule
ImportOrder = 15
GroupId = "TenantAdmin"
})
Add-ViewItem (New-Object PSObject -Property @{
Title = "Health Scripts"
Id = "DeviceHealthScripts"
ViewID = "IntuneGraphAPI"
QUERYLIST = "`$filter=isGlobalScript%20eq%20false" # Looks like filters are not working for deviceHealthScripts
API = "/deviceManagement/deviceHealthScripts"
PreDeleteCommand = { Start-PreDeleteDeviceHealthScripts @args }
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
GroupId = "EndpointAnalytics"
Icon = "Report"
AssignmentsType = "deviceHealthScriptAssignments"
})
}
function Invoke-EMAuthenticateToMSAL
{
$global:EMViewObject.AppInfo = Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
Set-MSALCurrentApp $global:EMViewObject.AppInfo
& $global:msalAuthenticator.Login -Account (?? $global:MSALToken.Account.UserName (Get-Setting "" "LastLoggedOnUser"))
& $global:msalAuthenticator.Login -Account (?? $global:MSALToken.Account.UserName (Get-Setting "" "LastLoggedOnUser")) -Permissions $global:EMViewObject.Permissions
}
function Invoke-EMDeactivateView
@@ -565,16 +600,38 @@ function Invoke-EMSaveSettings
Connect-MSALUser -Account $global:MSALToken.Account.Username
Write-Status ""
}
# Hide/Show Delete button
$allowDelete = Get-SettingValue "EMAllowDelete"
$global:btnDelete.Visibility = (?: ($allowDelete -eq $true) "Visible" "Collapsed")
# Hide/Show Delete on Bulk menu
$allowBulkDelete = Get-SettingValue "EMAllowBulkDelete"
$mnuBulk = $mnuMain.Items | Where Name -eq "EMBulk"
if($mnuBulk)
{
$mnuBulkDelete = $mnuBulk.Items | Where Name -eq "mnuBulkDelete"
if($mnuBulkDelete)
{
$mnuBulkDelete.Visibility = (?: ($allowBulkDelete -eq $true) "Visible" "Collapsed")
}
}
}
function Set-EMViewPanel
{
param($panel)
# ToDo: Create View specific pannel and move this to graph
Add-XamlEvent $panel "btnView" "Add_Click" -scriptBlock ([scriptblock]{
Show-GraphObjectInfo
})
Add-XamlEvent $panel "btnDelete" "Add_Click" -scriptBlock ([scriptblock]{
Remove-GraphObjects
})
Add-XamlEvent $panel "btnCopy" "Add_Click" -scriptBlock ([scriptblock]{
Copy-GraphObject
})
@@ -603,10 +660,13 @@ function Set-EMViewPanel
Invoke-FiterBoxChanged ($panel.FindName("txtFilter"))
$allowDelete = Get-SettingValue "EMAllowDelete"
Set-XamlProperty $panel "btnDelete" "Visibility" (?: ($allowDelete -eq $true) "Visible" "Collapsed")
$global:dgObjects.add_selectionChanged({
Set-XamlProperty $this.Parent "btnView" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null) $false $true)
Set-XamlProperty $this.Parent "btnCopy" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null) $false $true)
Set-XamlProperty $this.Parent "btnDelete" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null -and $global:curObjectType.AllowDelete -ne $false) $false $true)
})
# ToDo: Move this to the view object
@@ -921,6 +981,15 @@ function Start-PostExportIntuneBranding
}
}
function Start-PreDeleteIntuneBranding
{
param($obj, $objectType)
if($obj.isDefaultProfile -eq $true)
{
@{ "Delete" = $false }
}
}
#endregion
@@ -1045,7 +1114,8 @@ function Invoke-DownloadScript
$dlgSave.FileName = $obj.FileName
if($dlgSave.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK -and $dlgSave.Filename)
{
[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($obj.scriptContent)) | Out-File $dlgSave.Filename -Force
# Changed to WriteAllBytes to get rid of BOM characters from Custom Attribute file
[IO.File]::WriteAllBytes($dlgSave.FileName, ([System.Convert]::FromBase64String($obj.scriptContent)))
}
}
}
@@ -1611,6 +1681,16 @@ function Start-PreImportEnrollmentRestrictions
Remove-Property $obj "Id"
}
}
function Start-PreDeleteEnrollmentRestrictions
{
param($obj, $objectType)
if($obj.Priority -eq 0)
{
@{ "Delete" = $false }
}
}
#endregion
#region ScopeTags
@@ -1631,6 +1711,20 @@ function Start-PreImportAssignmentsAutoPilot
}
#endregion
#region Health Scripts
function Start-PreDeleteDeviceHealthScripts
{
param($obj, $objectType)
if($obj.IsGlobal -eq $true)
{
@{ "Delete" = $false }
}
}
#endregion
#region Generic functions
function Save-EMDefaultPolicy
+3 -2
View File
@@ -10,7 +10,7 @@ This module is for the Endpoint Info View. It shows read-only objects in Intune
#>
function Get-ModuleVersion
{
'3.1.0'
'3.1.1'
}
function Invoke-InitializeModule
@@ -27,6 +27,7 @@ function Invoke-InitializeModule
Authenticate = { Invoke-EMInfoAuthenticateToMSAL }
AppInfo = (Get-GraphAppInfo "EM" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547")
SaveSettings = { Invoke-EMSaveSettings }
Permissions = @()
})
Add-ViewObject $global:EMInfoViewObject
@@ -99,6 +100,6 @@ function Invoke-EMInfoAuthenticateToMSAL
$usr = (?? $global:MSALToken.Account.UserName (Get-Setting "" "LastLoggedOnUser"))
if($usr)
{
& $global:msalAuthenticator.Login -Account $usr
& $global:msalAuthenticator.Login -Account $usr -Permissions $global:EMInfoViewObject.Permissions
}
}
+43 -10
View File
@@ -10,7 +10,7 @@ This module manages Authentication for the application with MSAL. It is also res
#>
function Get-ModuleVersion
{
'3.0.0'
'3.0.1'
}
$global:msalAuthenticator = $null
@@ -59,6 +59,14 @@ function Invoke-InitializeModule
Description = "Default permissions of the selected app will be used when logging on. Some objects might not be accessable"
}) "MSAL"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Add Azure Role Read permissions"
Key = "AzureADRoleRead"
Type = "Boolean"
DefaultValue = $false
Description = "Request Azure AD Role read permission when getting the token. This can be use to resolve the SIDs to Azure Roles for the wids property on the Access Token. Note: This might trigger a consent prompt"
}) "MSAL"
Add-MSALPrereq
#$script:MSALDLLMissing = $true #!!!!
@@ -75,6 +83,7 @@ function Get-MSALAuthenticationObject
Logout = { Disconnect-MSALUser }
ProfilePicture = { Get-MSALProfileEllipse @args }
ShowErrors = { Show-MSALError }
Permissions = @("openid","profile","email","User.ReadWrite.All","Group.ReadWrite.All") #"RoleManagement.Read.Directory"
}
}
@@ -103,7 +112,7 @@ function Get-MSALUserInfo
if($global:MSALToken)
{
Write-Log "Get current user"
$tmpMe = MSGraph\Invoke-GraphRequest -Url "ME" -SkipAuthentication
$tmpMe = MSGraph\Invoke-GraphRequest -Url "ME" -SkipAuthentication -ODataMetadata "Skip"
if($tmpMe.creationType -ne "Invitation")
{
### Only get user info from home tenant
@@ -114,7 +123,7 @@ function Get-MSALUserInfo
}
Write-Log "Get organization info"
$global:Organization = (MSGraph\Invoke-GraphRequest -Url "Organization" -SkipAuthentication).Value
$global:Organization = (MSGraph\Invoke-GraphRequest -Url "Organization" -SkipAuthentication -ODataMetadata "Skip").Value
}
else
{
@@ -511,7 +520,9 @@ function Connect-MSALUser
[switch]
$Interactive,
$Account
$Account,
$Permissions = @() # Addidional permissions required by the current view object
)
# No login during first time the app is started
@@ -559,8 +570,29 @@ function Connect-MSALUser
}
else
{
$Scopes = [string[]]$global:PermissionScope
#$Scopes = [string[]]$global:PermissionScope
$reqScopes = [string[]]$global:msalAuthenticator.Permissions
$useDefaultPermissions = $false
$resolveRoles = ((Get-SettingValue "AzureADRoleRead" $false) -eq $true)
if($resolveRoles -and $global:msalAuthenticator.Permissions -notcontains "RoleManagement.Read.Directory")
{
# Adds the required permission for reading AAD directory roles
$reqScopes += "RoleManagement.Read.Directory"
}
if($Permissions.Count -gt 0)
{
$script:curViewPermissions = $Permissions
}
$reqScopes += $script:curViewPermissions
foreach($tmpScope in $script:curViewPermissions)
{
if($reqScopes -notcontains $tmpScope) { $reqScopes += $tmpScope }
}
$Scopes = [String[]]$reqScopes
}
$global:MSALApp = Get-MSALApp $global:appObj
@@ -645,14 +677,14 @@ function Connect-MSALUser
#AADSTS65001
if($script:authenticationFailure.Classification -eq "ConsentRequired")
{
$Scopes = [string[]]$global:PermissionScope
$Scopes = [string[]]$reqScopes
}
else
{
if($useDefaultPermissions -eq $false -and $authResult -and ($global:PermissionScope | measure).Count -gt 0 -and $global:promptConsentRequested -notcontains $authResult.TenantId)
if($useDefaultPermissions -eq $false -and $authResult -and ($reqScopes | measure).Count -gt 0 -and $global:promptConsentRequested -notcontains $authResult.TenantId)
{
$missingScopes = @()
foreach($scope in $global:PermissionScope)
foreach($scope in $reqScopes)
{
$tmpScope = $scope.Split('/')[-1]
if($tmpScope -eq ".default") { continue }
@@ -993,7 +1025,7 @@ function Get-MSALProfileEllipse
{
$initials = "$($global:me.givenName[0])$($global:me.surname[0])".ToUpper()
}
else
elseif($global:me.userPrincipalName)
{
$initials = "$($global:me.userPrincipalName[0])".ToUpper()
}
@@ -1340,7 +1372,8 @@ function Show-MSALDecodedToken {
{
if(-not $script:aadRoles)
{
$script:aadRoles =(Invoke-GraphRequest -url "/directoryRoles?`$select=roleTemplateId,displayName" -ODataMetadata "minimal").value
# This will fail if RoleManagement.Read.Directory permission is not granted. Use -NoError to hide any problems
$script:aadRoles = (Invoke-GraphRequest -url "/directoryRoles?`$select=roleTemplateId,displayName" -ODataMetadata "minimal" -Noerror).value
}
$wids = @()
foreach($wid in $tokenData.Payload."$($prop.Name)")
+246 -21
View File
@@ -10,7 +10,7 @@ This module manages Microsoft Grap fuctions like calling APIs, managing graph ob
#>
function Get-ModuleVersion
{
'3.1.0'
'3.1.1'
}
$global:MSGraphGlobalApps = @(
@@ -697,19 +697,28 @@ function Show-GraphBulkExportForm
Add-GraphExportExtensions $script:exportForm 0
$script:lstObjectsToExport = $script:exportForm.FindName("lstObjectsToExport")
if($script:lstObjectsToExport)
{
$script:lstObjectsToExport.ItemsSource = $script:exportObjects
$column = Get-GridCheckboxColumn "Selected"
$global:dgObjectsToExport.Columns.Add($column)
Add-XamlEvent $script:exportForm "chkCheckAll" "add_click" ({
foreach($item in $script:exportObjects)
$column.Header.IsChecked = $true # All items are checked by default
$column.Header.add_Click({
foreach($item in $global:dgObjectsToExport.ItemsSource)
{
$item.Selected = $this.IsChecked
}
$script:lstObjectsToExport.Items.Refresh()
})
}
$global:dgObjectsToExport.Items.Refresh()
}
)
# Add Object type column
$binding = [System.Windows.Data.Binding]::new("Title")
$column = [System.Windows.Controls.DataGridTextColumn]::new()
$column.Header = "Object type"
$column.IsReadOnly = $true
$column.Binding = $binding
$global:dgObjectsToExport.Columns.Add($column)
$global:dgObjectsToExport.ItemsSource = $script:exportObjects
Add-XamlEvent $script:exportForm "btnClose" "add_click" ({
$script:exportForm = $null
@@ -739,10 +748,10 @@ function Show-GraphBulkExportForm
{
$folder = Get-GraphObjectFolder $item.ObjectType (Get-XamlProperty $script:exportForm "txtExportPath" "Text") (Get-XamlProperty $script:exportForm "chkAddObjectType" "IsChecked") (Get-XamlProperty $script:exportForm "chkAddCompanyName" "IsChecked")
$objects = @(Get-GraphObjects -Url $url -property $objectType.ViewProperties -objectType $objectType)
$objects = @(Get-GraphObjects -Url $url -property $item.ObjectType.ViewProperties -objectType $item.ObjectType)
foreach($obj in $objects)
{
Write-Status "Export $($item.Title): $((Get-GraphObjectName $obj))" -Force
Write-Status "Export $($item.Title): $((Get-GraphObjectName $obj.Object $obj.ObjectType))" -Force
Export-GraphObject $obj.Object $item.ObjectType $folder
}
Save-Setting "" "LastUsedFullPath" $folder
@@ -876,19 +885,36 @@ function Show-GraphBulkImportForm
Add-GraphImportExtensions $script:importForm 0
$script:lstObjectsToImport = $script:importForm.FindName("lstObjectsToImport")
if($script:lstObjectsToImport)
{
$script:lstObjectsToImport.ItemsSource = $script:importObjects
$column = Get-GridCheckboxColumn "Selected"
$global:dgObjectsToImport.Columns.Add($column)
Add-XamlEvent $script:importForm "chkCheckAll" "add_click" ({
foreach($item in $script:importObjects)
$column.Header.IsChecked = $true # All items are checked by default
$column.Header.add_Click({
foreach($item in $global:dgObjectsToImport.ItemsSource)
{
$item.Selected = $this.IsChecked
}
$script:lstObjectsToImport.Items.Refresh()
})
}
$global:dgObjectsToImport.Items.Refresh()
}
)
# Add Object type column
$binding = [System.Windows.Data.Binding]::new("Title")
$column = [System.Windows.Controls.DataGridTextColumn]::new()
$column.Header = "Object type"
$column.IsReadOnly = $true
$column.Binding = $binding
$global:dgObjectsToImport.Columns.Add($column)
# Add Order column
$binding = [System.Windows.Data.Binding]::new("ObjectType.ImportOrder")
$column = [System.Windows.Controls.DataGridTextColumn]::new()
$column.Header = "Import order"
$column.IsReadOnly = $true
$column.Binding = $binding
$global:dgObjectsToImport.Columns.Add($column)
$global:dgObjectsToImport.ItemsSource = $script:importObjects
Add-XamlEvent $script:importForm "btnClose" "add_click" ({
$script:importForm = $null
@@ -934,6 +960,11 @@ function Show-GraphBulkImportForm
{
[System.Windows.MessageBox]::Show("No objects were imported. Verify folder and exported files", "Error", "OK", "Error")
}
else
{
Show-GraphObjects
Write-Status ""
}
})
if((Get-XamlProperty $script:importForm "txtImportPath" "Text"))
@@ -994,6 +1025,113 @@ function Add-GraphImportExtensions
}
}
function Show-GraphBulkDeleteForm
{
$script:deleteForm = Get-XamlObject ($global:AppRootFolder + "\Xaml\BulkDeleteForm.xaml") -AddVariables
if(-not $script:deleteForm) { return }
$script:deleteObjects = @()
foreach($objType in $global:lstMenuItems.ItemsSource)
{
if(-not $objType.Title) { continue }
if($objType.ShowButtons -is [Object[]] -and $objType.ShowButtons -notcontains "Delete") { continue }
$script:deleteObjects += New-Object PSObject -Property @{
Title = $objType.Title
Selected = $false
ObjectType = $objType
}
}
$column = Get-GridCheckboxColumn "Selected"
$global:dgBulkDeleteObjects.Columns.Add($column)
$column.Header.IsChecked = $false # All items are NOT checked by default
$column.Header.add_Click({
foreach($item in $global:dgBulkDeleteObjects.ItemsSource)
{
$item.Selected = $this.IsChecked
}
$global:dgBulkDeleteObjects.Items.Refresh()
}
)
# Add title column
$binding = [System.Windows.Data.Binding]::new("Title")
$column = [System.Windows.Controls.DataGridTextColumn]::new()
$column.Header = "Title"
$column.IsReadOnly = $true
$column.Binding = $binding
$global:dgBulkDeleteObjects.Columns.Add($column)
$ocList = [System.Collections.ObjectModel.ObservableCollection[object]]::new(@($script:deleteObjects))
$global:dgBulkDeleteObjects.ItemsSource = [System.Windows.Data.CollectionViewSource]::GetDefaultView($ocList)
Add-XamlEvent $script:deleteForm "btnClose" "add_click" ({
$script:deleteForm = $null
Show-ModalObject
})
Add-XamlEvent $script:deleteForm "btnDelete" "add_click" ({
$selCount = (($global:dgBulkDeleteObjects.ItemsSource | Where Selected -eq $true) | measure).Count
if($selCount -eq 0)
{
[System.Windows.MessageBox]::Show("No object types selected`n`nSelect types you want to delete", "Error", "OK", "Error")
return
}
if(([System.Windows.MessageBox]::Show("Are you sure you want to delete all objects of the selected type(s)?`n`n$selCount type(s) selected", "Delete Objects?", "YesNo", "Warning")) -ne "Yes")
{
return
}
Write-Status "Delete objects" -Block
Write-Log "****************************************************************"
Write-Log "Start bulk delete"
Write-Log "****************************************************************"
foreach($item in ($global:dgBulkDeleteObjects.ItemsSource | Where Selected -eq $true))
{
Write-Log "----------------------------------------------------------------"
Write-Log "Delete $($item.ObjectType.Title) objects"
Write-Log "----------------------------------------------------------------"
$url = $item.ObjectType.API
if($item.ObjectType.QUERYLIST)
{
$url = "$($url.Trim())?$($item.ObjectType.QUERYLIST.Trim())"
}
try
{
Write-Status "Get $($item.Title) objects" -Force
$objects = @(Get-GraphObjects -Url $url -property $item.ObjectType.ViewProperties -objectType $item.ObjectType)
foreach($obj in $objects)
{
Write-Status "Delete $($item.Title): $((Get-GraphObjectName $obj.Object $obj.ObjectType))" -Force
Remove-GraphObject $obj.Object $obj.ObjectType $folder
}
}
catch
{
Write-LogError "Failed when deleting $($item.Title) objects" $_.Exception
}
}
Write-Log "****************************************************************"
Write-Log "Bulk delete finished"
Write-Log "****************************************************************"
Show-GraphObjects
Write-Status ""
})
Show-ModalForm "Bulk Delete" $script:deleteForm -HideButtons
}
function Get-GraphFileObjects
{
param($path, $Exclude = @("*_settings.json","*_assignments.json"), $SelectedStatus = $true, $ObjectType = $global:curObjectType)
@@ -1788,6 +1926,82 @@ function Import-GraphObject
$newObj
}
function Remove-GraphObjects
{
$objectsToDelete = @()
if(($global:dgObjects.ItemsSource | Where IsSelected -eq $true).Count -gt 0)
{
# Delete checked items
$objectsToDelete += ($global:dgObjects.ItemsSource | Where IsSelected -eq $true)
}
elseif($global:dgObjects.SelectedItem)
{
# Delete the selected item
$objectsToDelete += $global:dgObjects.SelectedItem
}
if($objectsToDelete.Count -eq 0)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect items you want to delete", "Error", "OK", "Error")
return
}
if(([System.Windows.MessageBox]::Show("Are you sure you want to delete $($objectsToDelete.Count) $($global:curObjectType.Title) object(s)?", "Delete Objects?", "YesNo", "Warning")) -ne "Yes")
{
return
}
foreach($tmpObj in $objectsToDelete)
{
Remove-GraphObject $tmpObj.Object $tmpObj.ObjectType
}
Show-GraphObjects
Write-Status ""
}
function Remove-GraphObject
{
param($objToRemove, $objectType)
$strAPI = $null
if($objectType.PreDeleteCommand)
{
$ret = & $objectType.PreDeleteCommand $objToRemove $objectType
if($ret -is [HashTable])
{
if($ret.ContainsKey("Delete") -and $ret["Delete"] -eq $false)
{
# Delete handled manually or aborted
return $false
}
if($ret.ContainsKey("API"))
{
$strAPI = $ret["API"]
}
}
}
if($strAPI)
{
$api = $strAPI
}
elseif($objectType.DELETEAPI)
{
$api = $objectType.DELETEAPI
}
else
{
$api = $objectType.API
}
Write-Status "Delete $((Get-GraphObjectName $objToRemove $objectType))"
$strAPI = ($api + "/$($objToRemove.Id)")
Write-Log "Delete $($objectType.Title) object $((Get-GraphObjectName $objToRemove $objectType))"
Invoke-GraphRequest -Url $strAPI -HttpMethod "DELETE" -ODataMetadata "none"
}
function Copy-GraphObject
{
if(-not $dgObjects.SelectedItem)
@@ -1940,14 +2154,25 @@ function Add-GraphBulkMenu
$menuItem = [System.Windows.Controls.MenuItem]::new()
$menuItem.Header = "_Bulk"
$menuItem.Name = "EMBulk"
$subItem = [System.Windows.Controls.MenuItem]::new()
$subItem.Header = "_Export"
$subItem.Add_Click({Show-GraphBulkExportForm})
$menuItem.AddChild($subItem) | Out-Null
$subItem = [System.Windows.Controls.MenuItem]::new()
$subItem.Header = "_Import"
$subItem.Add_Click({Show-GraphBulkImportForm})
$menuItem.AddChild($subItem) | Out-Null
$subItem = [System.Windows.Controls.MenuItem]::new()
$subItem.Header = "_Delete"
$subItem.Name = "mnuBulkDelete"
$allowBulkDelete = Get-SettingValue "EMAllowBulkDelete"
# Add it hidden even if not enabled, the save settings will enable it
$subItem.Visibility = (?: ($allowBulkDelete -eq $true) "Visible" "Collapsed")
$subItem.Add_Click({Show-GraphBulkDeleteForm})
$menuItem.AddChild($subItem) | Out-Null
$mnuMain.Items.Insert(1,$menuItem) | Out-Null
}
+38
View File
@@ -1,5 +1,43 @@
# Release Notes
## 3.1.2 - 2021-06-20
**New features**
- Delete and Bulk Delete - Delete selected items or delete ALL items of selected object types
**Note:** This must be enabled in the settings. They are not visible by default.
**WARNING:** Use this carefully! It will delete profiles and policies in Intune.
- Support for new object Health Scripts
- Object permissions is now handled by ViewObject and authentication provider. This is to support future view extensions.
**Fixes**
* Azure Role Read permission can be disabled in settings
* Minor UI changes e.g. List Boxes for bulk Import/Export changed to DataGrid
* Minor bulk export fixes
## 3.1.1 - 2021-06-16
**New features**
- Download script for Custom Attribute
- Documentation
- Added support for additional objects (Enrollment restrictions)
**Fixes**
- Failed to get user information during logon. Something was changed in Graph that caused calling ME with full ODATA to fail.
- Added RoleManagement.Read.Directory as a default required permission.
**NOTE:** This will most likely cause a consent prompt
- Some additional minor fixes
## 3.1.0 - 2021-06-08
**Breaking Changes**
+21
View File
@@ -0,0 +1,21 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5" Grid.IsSharedSizeScope='True'>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row='0' Margin="0,0,5,0" VerticalAlignment="Top">
<Label Content="Objects to delete" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="All objects of the seleted types will be deleted" Margin="0,2,0,0" />
</StackPanel>
<DataGrid Name="dgBulkDeleteObjects" Grid.Row='1' CanUserAddRows="False" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" Margin="0,0,0,5">
</DataGrid>
<StackPanel Name="spDeleteSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row='2' Grid.ColumnSpan='2' >
<Button Name="btnDelete" Content="Delete" Width='100' Margin="5,0,0,0" />
<Button Name="btnClose" Content="Close" Width='100' Margin="5,0,0,0" />
</StackPanel>
</Grid >
+4
View File
@@ -77,6 +77,9 @@
</StackPanel>
</Grid>
<DataGrid Name="dgObjectsToExport" Grid.Column='1' CanUserAddRows="False" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" Margin="0,0,0,5" />
<!--
<ListBox Name="lstObjectsToExport" Grid.Column='1'
SelectionMode="Single"
Grid.IsSharedSizeScope='True' >
@@ -96,6 +99,7 @@
</ListBox>
<CheckBox IsChecked="true" Margin="7,2,0,0" Grid.Column='1' Grid.Row='1' Name="chkCheckAll" ToolTip="Select/Deselect all" />
-->
</Grid >
<StackPanel Name="spExportSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row='2' Grid.ColumnSpan='2' >
+2 -22
View File
@@ -90,29 +90,9 @@
</StackPanel>
</Grid>
<ListBox Name="lstObjectsToImport" Grid.Column='1'
SelectionMode="Single"
Grid.IsSharedSizeScope='True' >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="SelectedColumn" />
<ColumnDefinition Width="Auto" SharedSizeGroup="FileNameColumn" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Title}" Grid.Column='1' Margin="5,0,0,0" />
<TextBlock Text="{Binding ObjectType.ImportOrder}" Grid.Column='2' Margin="5,0,0,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<DataGrid Name="dgObjectsToImport" Grid.Column='1' CanUserAddRows="False" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" Margin="0,0,0,5" />
<CheckBox IsChecked="true" Margin="7,2,0,0" Grid.Column='1' Grid.Row='1' Name="chkCheckAll" ToolTip="Select/Deselect all" />
</Grid >
</Grid>
<StackPanel Name="spImportSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row='2' Grid.ColumnSpan='2' >
<Button Name="btnImport" Content="Import" Width='100' Margin="5,0,0,0" />
+1
View File
@@ -90,6 +90,7 @@
<DataGrid.Columns>
<DataGridTextColumn Header="Property" Binding="{Binding PropertyName}" IsReadOnly="True" Width="Auto" />
<DataGridTextColumn Header="Category" Binding="{Binding Category}" IsReadOnly="True" Width="Auto" />
<DataGridTextColumn Header="SubCategory" Binding="{Binding SubCategory}" IsReadOnly="True" Width="Auto" />
<DataGridTextColumn Header="Intune Object" Binding="{Binding Object1Value}" IsReadOnly="True" Width="1*" />
<DataGridTextColumn Header="Backup Object" Binding="{Binding Object2Value}" IsReadOnly="True" Width="1*" />
</DataGrid.Columns>
+1
View File
@@ -42,6 +42,7 @@
<StackPanel Grid.Row="2" Name="spSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,0,0" >
<Button Name="btnView" Content="View" MinWidth="100" Margin="0,0,5,0" IsEnabled="False" ToolTip="Veiw the json data of an item" />
<Button Name="btnCopy" Content="Copy" MinWidth="100" Margin="0,0,5,0" IsEnabled="False" ToolTip="Clone the selected item"/>
<Button Name="btnDelete" Content="Delete" MinWidth="100" Margin="0,0,5,0" IsEnabled="False" ToolTip="Delete selected item(s)"/>
<Button Name="btnImport" Content="Import" MinWidth="100" Margin="0,0,5,0" IsEnabled="False" ToolTip="Import items" />
<Button Name="btnExport" Content="Export" MinWidth="100" IsEnabled="False" ToolTip="Export selected or all items" />
</StackPanel>
+7
View File
@@ -0,0 +1,7 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#3898C6" Data="M9.375 3.125h37.5V50h-37.5z" />
<Path Fill="#7B7B7B" Data="M3.125 6.25H12.5v3.125H3.125zm0 9.375H12.5v3.125H3.125zm0 9.375H12.5v3.125H3.125zm0 9.375H12.5V37.5H3.125zm0 9.375H12.5v3.125H3.125z" />
<Path Data="M18.75 15.625H37.5V25H18.75z" Fill="#ffffff" />
</Canvas>
</Viewbox>