diff --git a/Core.psm1 b/Core.psm1 index 23680b0..2f73e2a 100644 --- a/Core.psm1 +++ b/Core.psm1 @@ -1159,7 +1159,7 @@ function Add-ViewItem 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") ) + foreach($required in @("openid","profile","email","User.ReadWrite.All","Group.ReadWrite.All","RoleManagement.Read.Directory")) #,"https://management.azure.com/user_impersonation") ) { if($required -in $global:PermissionScope) { continue } $global:PermissionScope += $required diff --git a/Documentation/ObjectInfo/#microsoft.graph.deviceEnrollmentLimitConfiguration.json b/Documentation/ObjectInfo/#microsoft.graph.deviceEnrollmentLimitConfiguration.json new file mode 100644 index 0000000..7342869 --- /dev/null +++ b/Documentation/ObjectInfo/#microsoft.graph.deviceEnrollmentLimitConfiguration.json @@ -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" + } +] \ No newline at end of file diff --git a/Documentation/ObjectInfo/#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration.json b/Documentation/ObjectInfo/#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration.json new file mode 100644 index 0000000..a5bde25 --- /dev/null +++ b/Documentation/ObjectInfo/#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration.json @@ -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" + } + ] + } + } + ] + } +] \ No newline at end of file diff --git a/Documentation/Strings-en.json b/Documentation/Strings-en.json index a68d099..7ce0ae3 100644 Binary files a/Documentation/Strings-en.json and b/Documentation/Strings-en.json differ diff --git a/Documentation/Strings-sv.json b/Documentation/Strings-sv.json index d060524..cc56ef9 100644 Binary files a/Documentation/Strings-sv.json and b/Documentation/Strings-sv.json differ diff --git a/Extensions/Compare.psm1 b/Extensions/Compare.psm1 index f5170e1..5259171 100644 --- a/Extensions/Compare.psm1 +++ b/Extensions/Compare.psm1 @@ -168,19 +168,19 @@ 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") + } } function Add-CompareProperty @@ -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 - $val2 = $prop.$settingsValue - $prop2 = $docObj1.Settings | Where { $_.EntityKey -eq $prop.EntityKey } + $addedProperties += ($prop.EntityKey + $prop.Category + $prop.SubCategory) + $val2 = $prop.$settingsValue + $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 } } diff --git a/Extensions/Documentation.psm1 b/Extensions/Documentation.psm1 index 7665628..9ef21b2 100644 --- a/Extensions/Documentation.psm1 +++ b/Extensions/Documentation.psm1 @@ -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 @@ -1586,10 +1586,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 +1644,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 +1783,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,8 +2513,15 @@ 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 +2547,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) diff --git a/Extensions/EndpointManager.psm1 b/Extensions/EndpointManager.psm1 index 6609747..7ee804d 100644 --- a/Extensions/EndpointManager.psm1 +++ b/Extensions/EndpointManager.psm1 @@ -275,6 +275,7 @@ function Invoke-InitializeModule AssignmentsType = "deviceManagementScriptAssignments" Icon="CustomAttributes" GroupId = "CustomAttributes" # MacOS Settings + DetailExtension = { Add-ScriptExtensions @args } }) Add-ViewItem (New-Object PSObject -Property @{ @@ -1044,8 +1045,9 @@ function Invoke-DownloadScript $dlgSave.InitialDirectory = Get-SettingValue "IntuneRootFolder" $env:Temp $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))) } } } diff --git a/Extensions/MSALAuthentication.psm1 b/Extensions/MSALAuthentication.psm1 index c44d9d6..84fb743 100644 --- a/Extensions/MSALAuthentication.psm1 +++ b/Extensions/MSALAuthentication.psm1 @@ -103,7 +103,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 +114,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 { @@ -993,7 +993,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 +1340,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)") diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 6b8313e..596e814 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,23 @@ # Release Notes +## 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** diff --git a/Xaml/CompareForm.xaml b/Xaml/CompareForm.xaml index 7bb0f6c..e946dd8 100644 --- a/Xaml/CompareForm.xaml +++ b/Xaml/CompareForm.xaml @@ -90,6 +90,7 @@ +