Compare commits

...
5 Commits
Author SHA1 Message Date
Mikael Karlsson 46435b5717 3.4.0
New features and fixes
2022-03-01 17:54:14 +11:00
Mikael Karlsson 5534eb368e 3.3.3
Fixed displayName missing bug
2021-12-14 19:15:27 +11:00
Mikael Karlsson bc48d14176 3.3.2 2021-12-14 02:04:15 +11:00
Mikael Karlsson 2b9efd5c85 3.3.1 Beta 2021-10-28 21:30:21 +11:00
Mikael Karlsson 4add87884a 3.3.0
Beta release
2021-10-17 14:02:08 +11:00
85 changed files with 46484 additions and 5564 deletions
+17 -17
View File
@@ -14,11 +14,11 @@ Microsoft links:
The **ADMX Import** tool is used for configuring 3rd party applications e.g. Chrome, Google Update etc., These ADMX files are available from the software vendor. An ADMX can be loaded in the tool and all settings can be configured using a similar UI as GPMC. When the ADMX is loaded, the script will look for an ADML file that is either in the same directory or in the en-US subdirectory. An ADML file can also be loaded manually, if another language should be used in the UI.
![Screenshot](/ADMXExample.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/ADMXExample.png" height="50%" width="50%"/>
The image above shows the the tool after the chrome.admx file was loaded. The tool supports delivering ADMX settings to HKLM (Computer Settings) and HKCU (User Settings). Categories will be added based on the Class attribute for each ADMX policy setting. The *All settings* category will display all the settings for the base category (Computer or User)
![Screenshot](/ADMXSettingExample.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/ADMXSettingExample.png" height="50%" width="50%"/>
A policy setting can either be edited via double-clicking an item or right-clicking and select Edit.
@@ -26,13 +26,13 @@ The *Intune OMA-URI name* property specifies the name of the OMA-URI row in the
A policy must be set to Enabled before any changes can be made. The *Policy* tab will list all possible settings for the policy. This could be a dropdown box, text box, check box, numeric up-down box etc. The script creates the controls based on the presentation settings in the ADML file. An ADML is not mandatory but the controls and the UI could cause unpredictive results. Always use the associated ADML for correctly generated controls.
![Screenshot](/ADMXSettingExampleOMAURI.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/ADMXSettingExampleOMAURI.png" height="50%" width="50%"/>
The *OMA-URI Settings* tab contains the configured settings. This is the string that will be added to the enabled policy. This can be manually configure in case there is something that is not supported by the script. Do **NOT** add <enabled /> or <disabled /> to this text box. The script will add that automatically. If *Manual configuration* is checked, the script will upload the text as it is specified, including additional manual changes. If it is not checked, the script will generate the text when importing the profile. If manual configuration is added and then checkbox is cleared, those changes will be lost during the upload.
The *XML Definition* tab contains the XML node for the ADMX policy. This is used for reference in case manual configuration is required.
![Screenshot](/ADMXImportSetting.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/ADMXImportSetting.png" height="50%" width="50%"/>
The *Import* tab is used for creating the Custom Profile in Intune. The *Custom Profile Name* is mandatory and specifies the name of the profile.
@@ -50,7 +50,7 @@ The *Import* button will create the Custom Profile in Intune. There is no visual
The **Reg Values** tool can be used to create registry values in HKLM and HKCU. This uses the same functionality as the ADMX Import tool; ADMX ingestion. The difference is that the Reg Values tool builds the ADMX file in the background based on the added registry values. There are some benefits of using this over a PowerShell script e.g. Intune will state if the registry keys were applied successfully and if a conflict or an error occurred.
![Screenshot](/ADMXRegValuePolicy.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/ADMXRegValuePolicy.png" height="50%" width="50%"/>
The initial screen include the options of specifying the Custom Profile name and description. The *Policy type* can either be Policy or Preferences. See Known Issues and Limitations for more information about policy types.
@@ -82,39 +82,39 @@ The *Additional value settings* section has additional settings for a policy typ
Example of setting registry values for a device and a user:
![Screenshot](/RegPolicyHKCU.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegPolicyHKCU.png" height="50%" width="50%"/>
Example of adding HKCU settings
![Screenshot](/RegPolicyHKLM.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegPolicyHKLM.png" height="50%" width="50%"/>
Example of adding HKLM settings
![Screenshot](/RegADMXFileContent.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegADMXFileContent.png" height="50%" width="50%"/>
Example of generated ADMX file
![Screenshot](/RegValueIntuneProfile.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegValueIntuneProfile.png" height="50%" width="50%"/>
Example of the created Custom Profile created.
![Screenshot](/RegProfileADMXIngestion.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegProfileADMXIngestion.png" height="50%" width="50%"/>
Example of the OMA-URI row for ADMX ingestion for a custom registry value.
![Screenshot](/RegProfileOMAURISetting.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegProfileOMAURISetting.png" height="50%" width="50%"/>
Example of the OMA-URI row for specifying the registry values to set.
![Screenshot](/RegValuesHKCU.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegValuesHKCU.png" height="50%" width="50%"/>
Example of the implemented HKCU settings for a user
![Screenshot](/RegValuesHKLM.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegValuesHKLM.png" height="50%" width="50%"/>
Example of the implemented HKLM settings for a device
![Screenshot](/RegValuesHKLMList.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegValuesHKLMList.png" height="50%" width="50%"/>
Example of the List type implementation on a device
@@ -142,7 +142,7 @@ The Policy CSP will create multiple registry values under HKLM\Software\Microsof
The ADMXDefault part will contain each Category, with full path, specified in the ADMX file. This is why the AppID must be unique when using multiple versions of the same admx file since each of these files will have the same category IDs e.g. each Chrome version should be named based on the version like Chromev91.
![Screenshot](/RegADMXDefault.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegADMXDefault.png" height="50%" width="50%"/>
**Note:** If the same ADMX filename is used, the first file saved will win. It looks like Intune will not overwrite an existing ADMX file. That is why a unique name must be specified when different versions of the ADMX file is used.
@@ -170,11 +170,11 @@ The CategoryPath is the full path to the category where the setting is defined.
One registry key for each ADMX policy is created under the Provider path (PolicyManager\Provider\\<GUID>) . This includes the OME-URI settings configured in the Custom Profile.
![Screenshot](/RegADMXProvider.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegADMXProvider.png" height="50%" width="50%"/>
Applied settings are added to the Current registry key, Current\Device or Current\\<SID> depending if it is for the device or the user. There is one key for each policy category.
![Screenshot](/RegADMXCurrent.png?raw=true)
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/RegADMXCurrent.png" height="50%" width="50%"/>
**Troubleshooting**
Binary file not shown.
+55 -1
View File
@@ -69,7 +69,23 @@ function Initialize-CloudAPIManagement
[string]
$View = "",
[switch]
$ShowConsoleWindow
$ShowConsoleWindow,
[switch]
$JSonSettings,
[string]
$JSonFile,
[switch]
$Silent,
[string]
$SilentBatchFile,
[string]
$tenantId,
[string]
$appId,
[string]
$secret,
[string]
$certificate
)
$global:wpfNS = "xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'"
@@ -77,6 +93,12 @@ function Initialize-CloudAPIManagement
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
Add-Type -AssemblyName PresentationFramework
$global:hideUI = ($Silent -eq $true)
$global:SilentBatchFile = $SilentBatchFile
if($global:hideUI -ne $true)
{
# Run with UI
try
{
[xml]$xaml = Get-Content ([IO.Path]::GetDirectoryName($PSCommandPath) + "\Xaml\SplashScreen.xaml")
@@ -93,17 +115,49 @@ function Initialize-CloudAPIManagement
{
}
}
else
{
# Run silent
if(-not $tenantId)
{
# Core module not loaded yet so can't use log function
Write-Error "Tenant Id is missing. Use -TenantId <Tenant-guid> on the command line to run silent batch jobs"
return
}
$global:TenantId = $tenantId
$global:AzureAppId = $appId
$global:ClientSecret = $secret
$global:ClientCert = $certificate
}
if($ShowConsoleWindow -ne $true)
{
Hide-Console
}
if($JSonSettings -eq $true)
{
$global:UseJSonSettings = $true
$global:JSonSettingFile = $JSonFile
}
else
{
$global:UseJSonSettings = $false
}
if($global:hideUI -ne $true)
{
$global:txtSplashText.Text = "Unblock files"
}
[System.Windows.Forms.Application]::DoEvents()
Unblock-AllFiles $PSScriptRoot
if($global:hideUI -ne $true)
{
$global:txtSplashText.Text = "Load core module"
}
[System.Windows.Forms.Application]::DoEvents()
Import-Module ($PSScriptRoot + "\Core.psm1") -Force -Global
+759 -31
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -54,6 +54,8 @@ This is the first version of the documentation support.
* Some Endpoint Security/Settings Catalog items is not translated based on Graph API in the portal e.g. *Antivirus - Windows 10 and Windows Server (ConfigMgr)* policies. These will be documented based on Graph API information which might be different compared to the portal
* Markdown is currently in experimental state. The script can document to an MD file created in the Documents folder but this can be to large in environments with many objects. The script will create HTML tables to support code blocks and column span. The MD View must support HTML tables to display the document. The *Markdown Viewer* extension in Chrome was used during testing.
Please create an [Issue](https://github.com/Micke-K/IntuneManagement/issues) if properties are documented incorrectly or missing.
# Deep Dive
@@ -64,7 +66,7 @@ The documentation is based on a two step process
This will collection all the information about the object and add it to a PowerShell object in the code
* Send the information to the selected output type
* Send the information to the selected output provider
This will send all the information gathered about the object to the selected output provider
@@ -14,5 +14,66 @@
"dataType": 20,
"booleanActions": 0,
"category": "WindowsFeatureUpdateProfile.Details.deploymentSettingsTitle"
},
{
"nameResourceKey": "WindowsFeatureUpdateProfile.Details.RolloutOptions.label",
"descriptionResourceKey": "",
"entityKey": "featureUpdateRolloutOption",
"dataType": 16,
"booleanActions": 0,
"category": "WindowsFeatureUpdateProfile.Details.deploymentSettingsTitle",
"options": [
{
"nameResourceKey": "WindowsUpdateRolloutOptions.immediateStart",
"descriptionResourceKey": "",
"value": "immediateStart"
},
{
"nameResourceKey": "WindowsUpdateRolloutOptions.gradualRollout",
"descriptionResourceKey": "",
"value": "gradualRollout",
"ChildSettings": [
{
"nameResourceKey": "WindowsFeatureUpdateProfile.Details.GradualRolloutStartDate.label",
"descriptionResourceKey": "",
"dataType": 20,
"category": "WindowsFeatureUpdateProfile.Details.deploymentSettingsTitle",
"entityKey": "featureUpdateRolloutStartDate",
"booleanActions": 0
},
{
"nameResourceKey": "WindowsFeatureUpdateProfile.Details.GradualRolloutEndDate.label",
"descriptionResourceKey": "",
"dataType": 20,
"category": "WindowsFeatureUpdateProfile.Details.deploymentSettingsTitle",
"entityKey": "featureUpdateRolloutEndDate",
"booleanActions": 0
},
{
"nameResourceKey": "WindowsFeatureUpdateProfile.Details.GradualRolloutInterval.label",
"descriptionResourceKey": "",
"dataType": 20,
"category": "WindowsFeatureUpdateProfile.Details.deploymentSettingsTitle",
"entityKey": "featureUpdateRolloutInterval",
"booleanActions": 0
}
]
},
{
"nameResourceKey": "WindowsUpdateRolloutOptions.startDateOnly",
"descriptionResourceKey": "",
"value": "startDateOnly",
"ChildSettings": [
{
"nameResourceKey": "WindowsFeatureUpdateProfile.Details.GradualRolloutStartDate.label",
"descriptionResourceKey": "",
"dataType": 20,
"category": "WindowsFeatureUpdateProfile.Details.deploymentSettingsTitle",
"entityKey": "featureUpdateRolloutStartDate",
"booleanActions": 0
}
]
}
]
}
]
@@ -89,11 +89,24 @@
"category": 2,
"nameResourceKey": "publicPlayStoreEnabledName",
"descriptionResourceKey": "publicPlayStoreEnabledDescription",
"childSettings": [
{
"dataType": 10,
"category": 2,
"nameResourceKey": "publicPlayStoreEnabledWarning",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 2,
"enabled": true
}
],
"options": [
],
"entityKey": "publicPlayStoreEnabled",
"booleanActions": 0,
@@ -72,6 +72,23 @@
"defaultValue": false,
"policyType": 46,
"enabled": true
},
{
"dataType": 0,
"category": 7,
"nameResourceKey": "managedPasteboardRequiredName",
"descriptionResourceKey": "managedPasteboardRequiredDescription",
"childSettings": [
],
"options": [
],
"entityKey": "managedPasteboardRequired",
"booleanActions": 9,
"defaultValue": false,
"policyType": 46,
"enabled": true
}
],
"options": [
@@ -1883,23 +1900,6 @@
"defaultValue": false,
"policyType": 46,
"enabled": true
},
{
"dataType": 0,
"category": 7,
"nameResourceKey": "managedPasteboardRequiredName",
"descriptionResourceKey": "managedPasteboardRequiredDescription",
"childSettings": [
],
"options": [
],
"entityKey": "managedPasteboardRequired",
"booleanActions": 9,
"defaultValue": false,
"policyType": 46,
"enabled": true
}
],
"options": [
@@ -224,6 +224,23 @@
"defaultValue": false,
"policyType": 46,
"enabled": true
},
{
"dataType": 0,
"category": 18,
"nameResourceKey": "blockIosICloudPrivateRelayName",
"descriptionResourceKey": "blockIosICloudPrivateRelayDescription",
"childSettings": [
],
"options": [
],
"entityKey": "iCloudPrivateRelayBlocked",
"booleanActions": 9,
"defaultValue": false,
"policyType": 46,
"enabled": true
}
],
"options": [
@@ -1,5 +1,6 @@
{
"cloudandstorage_macgeneral": {
"cloudandstorage_macgeneral": [
{
"isSettingDescription": false,
"showAsSectionHeader": true,
"dataType": 8,
@@ -24,6 +25,23 @@
"policyType": 61,
"enabled": true
},
{
"dataType": 0,
"category": 18,
"nameResourceKey": "blockICloudDesktopAndDocumentsName",
"descriptionResourceKey": "blockICloudDesktopAndDocumentsDescription",
"childSettings": [
],
"options": [
],
"entityKey": "iCloudDesktopAndDocumentsBlocked",
"booleanActions": 9,
"defaultValue": false,
"policyType": 61,
"enabled": true
},
{
"dataType": 0,
"category": 18,
@@ -184,5 +202,39 @@
"booleanActions": 0,
"policyType": 61,
"enabled": true
},
{
"isSettingDescription": false,
"showAsSectionHeader": true,
"dataType": 8,
"category": 18,
"nameResourceKey": "userApprovedAndAutomatedDeviceEnrollmentHeaderNameMac",
"descriptionResourceKey": "userApprovedAndAutomatedDeviceEnrollmentHeaderDescriptionMac",
"childSettings": [
{
"dataType": 0,
"category": 18,
"nameResourceKey": "blockMacICloudPrivateRelayName",
"descriptionResourceKey": "blockMacICloudPrivateRelayDescription",
"childSettings": [
],
"options": [
],
"entityKey": "iCloudPrivateRelayBlocked",
"booleanActions": 9,
"defaultValue": false,
"policyType": 61,
"enabled": true
}
],
"options": [
],
"booleanActions": 0,
"policyType": 61,
"enabled": true
}
]
}
@@ -45,7 +45,7 @@
"enabled": true
},
{
"dataType": 14,
"dataType": 15,
"category": 22,
"nameResourceKey": "contentCachingMaxSizeBytesName",
"descriptionResourceKey": "contentCachingMaxSizeBytesDescription",
@@ -383,13 +383,13 @@
],
"options": [
{
"nameResourceKey": "localSecurityOptionsSmartCardRemovalBehaviorLockWorkstation",
"value": "lockWorkstation",
"nameResourceKey": "localSecurityOptionsSmartCardRemovalBehaviorNoAction",
"value": "noAction",
"enabled": true
},
{
"nameResourceKey": "localSecurityOptionsSmartCardRemovalBehaviorNoAction",
"value": "noAction",
"nameResourceKey": "localSecurityOptionsSmartCardRemovalBehaviorLockWorkstation",
"value": "lockWorkstation",
"enabled": true
},
{
@@ -405,8 +405,8 @@
],
"entityKey": "localSecurityOptionsSmartCardRemovalBehavior",
"booleanActions": 0,
"defaultValue": "lockWorkstation",
"unconfiguredValue": "lockWorkstation",
"defaultValue": "noAction",
"unconfiguredValue": "noAction",
"policyType": 77,
"enabled": true
},
@@ -219,6 +219,102 @@
"policyType": 108,
"enabled": true
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "frontCamerasName",
"descriptionResourceKey": "frontCamerasDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "frontCameras",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "rearCamerasName",
"descriptionResourceKey": "rearCamerasDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "rearCameras",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "infraredCamerasName",
"descriptionResourceKey": "infraredCamerasDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "infraredCameras",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
@@ -251,6 +347,38 @@
"policyType": 108,
"enabled": true
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "microphonesName",
"descriptionResourceKey": "microphonesDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "microphones",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
@@ -299,6 +427,134 @@
"policyType": 108,
"enabled": true
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "bluetoothName",
"descriptionResourceKey": "bluetoothDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "bluetooth",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "wwanName",
"descriptionResourceKey": "wwanDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "wwan",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "nfcName",
"descriptionResourceKey": "nfcDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "nfc",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "wifiName",
"descriptionResourceKey": "wifiDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "wifi",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"isSettingDescription": false,
"showAsSectionHeader": false,
@@ -378,6 +634,182 @@
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": true
},
{
"isSettingDescription": false,
"showAsSectionHeader": false,
"dataType": 8,
"category": 136,
"nameResourceKey": "portName",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "usbTypeAPortName",
"descriptionResourceKey": "usbTypeAPortDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "usbTypeAPort",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "usbTypeCPortName",
"descriptionResourceKey": "usbTypeCPortDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "usbTypeCPort",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "sdCardName",
"descriptionResourceKey": "sdCardDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "sdCard",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "wakeOnLANName",
"descriptionResourceKey": "wakeOnLANDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "wakeOnLAN",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
},
{
"dataType": 16,
"category": 136,
"nameResourceKey": "wakeOnPowerName",
"descriptionResourceKey": "wakeOnPowerDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "enabledOption",
"value": "enabled",
"enabled": true
},
{
"nameResourceKey": "disabledOption",
"value": "disabled",
"enabled": true
}
],
"entityKey": "wakeOnPower",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 108,
"enabled": false
}
]
}
@@ -113,23 +113,6 @@
"policyType": 2,
"enabled": true
},
{
"dataType": 0,
"category": 41,
"nameResourceKey": "safeBootDisabledName",
"descriptionResourceKey": "safeBootDisabledDescription",
"childSettings": [
],
"options": [
],
"entityKey": "safeBootBlocked",
"booleanActions": 3,
"defaultValue": false,
"policyType": 2,
"enabled": true
},
{
"dataType": 0,
"category": 41,
@@ -249,23 +232,6 @@
"policyType": 2,
"enabled": true
},
{
"dataType": 0,
"category": 41,
"nameResourceKey": "debuggingFeaturesAllowedName",
"descriptionResourceKey": "debuggingFeaturesAllowedDescription",
"childSettings": [
],
"options": [
],
"entityKey": "securityAllowDebuggingFeatures",
"booleanActions": 0,
"defaultValue": false,
"policyType": 2,
"enabled": true
},
{
"dataType": 0,
"category": 41,
@@ -895,6 +861,62 @@
"unconfiguredValue": "deviceDefault",
"policyType": 2,
"enabled": true
},
{
"columns": [
{
"metadata": {
"dataType": 20,
"category": 41,
"nameResourceKey": "systemUpdateFreezePeriodStartDateColumnName",
"descriptionResourceKey": "systemUpdateFreezePeriodStartDateColumnDescription",
"emptyValueResourceKey": "systemUpdateFreezePeriodStartDateEmptyValueKey",
"childSettings": [
],
"options": [
],
"entityKey": "startDate",
"booleanActions": 0,
"policyType": 2,
"enabled": true
}
},
{
"metadata": {
"dataType": 20,
"category": 41,
"nameResourceKey": "systemUpdateFreezePeriodEndDateColumnName",
"descriptionResourceKey": "systemUpdateFreezePeriodEndDateColumnDescription",
"emptyValueResourceKey": "systemUpdateFreezePeriodEndDateEmptyValueKey",
"childSettings": [
],
"options": [
],
"entityKey": "endDate",
"booleanActions": 0,
"policyType": 2,
"enabled": true
}
}
],
"dataType": 21,
"category": 41,
"nameResourceKey": "systemUpdateFreezePeriodsTableName",
"descriptionResourceKey": "systemUpdateFreezePeriodsTableDescription",
"childSettings": [
],
"options": [
],
"entityKey": "systemUpdateFreezePeriodsList",
"booleanActions": 0,
"policyType": 2,
"enabled": true
}
],
"options": [
@@ -1211,6 +1233,87 @@
"defaultValue": false,
"policyType": 2,
"enabled": true
},
{
"dataType": 19,
"category": 41,
"nameResourceKey": "showWorkContactsInPersonalProfileName",
"descriptionResourceKey": "showWorkContactsInPersonalProfileDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "blockOption",
"value": false,
"enabled": true
},
{
"nameResourceKey": "notConfigured",
"value": true,
"enabled": true
}
],
"entityKey": "crossProfilePoliciesShowWorkContactsInPersonalProfile",
"booleanActions": 0,
"defaultValue": true,
"unconfiguredValue": true,
"policyType": 2,
"enabled": true
},
{
"dataType": 0,
"category": 41,
"nameResourceKey": "copyPasteBetweenWorkAndPersonalProfilesName",
"descriptionResourceKey": "copyPasteBetweenWorkAndPersonalProfilesDescription",
"childSettings": [
],
"options": [
],
"entityKey": "crossProfilePoliciesAllowCopyPaste",
"booleanActions": 0,
"defaultValue": false,
"policyType": 2,
"enabled": true
},
{
"dataType": 16,
"category": 41,
"nameResourceKey": "dataSharingBetweenWorkAndPersonalProfilesName",
"descriptionResourceKey": "dataSharingBetweenWorkAndPersonalProfilesDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "DeviceDefaultDataSharingBetweenWorkAndPersonalProfilesOption",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "BlockAllDataSharingBetweenWorkAndPersonalProfilesOption",
"value": "crossProfileDataSharingBlocked",
"enabled": true
},
{
"nameResourceKey": "BlockWorkToPersonalDataSharingBetweenWorkAndPersonalProfilesOption",
"value": "dataSharingFromWorkToPersonalBlocked",
"enabled": true
},
{
"nameResourceKey": "NoRestrictionsDataSharingBetweenWorkAndPersonalProfilesOption",
"value": "crossProfileDataSharingAllowed",
"enabled": true
}
],
"entityKey": "crossProfilePoliciesAllowDataSharing",
"booleanActions": 0,
"defaultValue": "notConfigured",
"unconfiguredValue": "notConfigured",
"policyType": 2,
"enabled": true
}
],
"options": [
@@ -258,6 +258,43 @@
"policyType": 9,
"enabled": true
},
{
"columns": [
{
"metadata": {
"dataType": 20,
"category": 41,
"nameResourceKey": "empty",
"descriptionResourceKey": "empty",
"emptyValueResourceKey": "trustedServerCertificateNameExample",
"childSettings": [
],
"options": [
],
"entityKey": "trustedServerCertificateNamesName",
"booleanActions": 0,
"policyType": 9,
"enabled": true
}
}
],
"dataType": 21,
"category": 41,
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
"options": [
],
"entityKey": "trustedServerCertificateNames",
"booleanActions": 0,
"policyType": 9,
"enabled": true
},
{
"complexOptions": [
{
@@ -491,6 +528,43 @@
"policyType": 9,
"enabled": true
},
{
"columns": [
{
"metadata": {
"dataType": 20,
"category": 41,
"nameResourceKey": "empty",
"descriptionResourceKey": "empty",
"emptyValueResourceKey": "trustedServerCertificateNameExample",
"childSettings": [
],
"options": [
],
"entityKey": "trustedServerCertificateNamesName",
"booleanActions": 0,
"policyType": 9,
"enabled": true
}
}
],
"dataType": 21,
"category": 41,
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
"options": [
],
"entityKey": "trustedServerCertificateNames",
"booleanActions": 0,
"policyType": 9,
"enabled": true
},
{
"complexOptions": [
{
@@ -782,6 +856,43 @@
"policyType": 9,
"enabled": true
},
{
"columns": [
{
"metadata": {
"dataType": 20,
"category": 41,
"nameResourceKey": "empty",
"descriptionResourceKey": "empty",
"emptyValueResourceKey": "trustedServerCertificateNameExample",
"childSettings": [
],
"options": [
],
"entityKey": "trustedServerCertificateNamesName",
"booleanActions": 0,
"policyType": 9,
"enabled": true
}
}
],
"dataType": 21,
"category": 41,
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
"options": [
],
"entityKey": "trustedServerCertificateNames",
"booleanActions": 0,
"policyType": 9,
"enabled": true
},
{
"complexOptions": [
{
@@ -85,23 +85,6 @@
"policyType": 28,
"enabled": true
},
{
"dataType": 0,
"category": 41,
"nameResourceKey": "blockBackupServiceName",
"descriptionResourceKey": "blockBackupServiceDescription",
"childSettings": [
],
"options": [
],
"entityKey": "backupBlocked",
"booleanActions": 9,
"defaultValue": false,
"policyType": 28,
"enabled": false
},
{
"dataType": 0,
"category": 41,
@@ -153,23 +136,6 @@
"policyType": 28,
"enabled": true
},
{
"dataType": 0,
"category": 41,
"nameResourceKey": "blockCellularWiFiTetheringName",
"descriptionResourceKey": "blockCellularWiFiTetheringDescription",
"childSettings": [
],
"options": [
],
"entityKey": "cellularBlockWiFiTethering",
"booleanActions": 9,
"defaultValue": false,
"policyType": 28,
"enabled": false
},
{
"dataType": 0,
"category": 41,
@@ -186,6 +152,23 @@
"defaultValue": false,
"policyType": 28,
"enabled": true
},
{
"dataType": 0,
"category": 41,
"nameResourceKey": "blockAppsInstallFromUnknownSourcesName",
"descriptionResourceKey": "blockAppsInstallFromUnknownSourcesDescription",
"childSettings": [
],
"options": [
],
"entityKey": "appsBlockInstallFromUnknownSources",
"booleanActions": 9,
"defaultValue": false,
"policyType": 28,
"enabled": true
}
]
}
@@ -505,6 +505,7 @@
"category": 41,
"nameResourceKey": "enforcedSoftwareUpdateDelayName",
"descriptionResourceKey": "enforcedSoftwareUpdateDelayDescription",
"emptyValueResourceKey": "EnforcedSoftwareUpdateDelayNamePlaceholder",
"childSettings": [
],
@@ -513,7 +514,6 @@
],
"entityKey": "softwareUpdatesEnforcedDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 46,
"enabled": true
}
@@ -113,6 +113,7 @@
"category": 41,
"nameResourceKey": "enforcedSoftwareUpdateDelayName",
"descriptionResourceKey": "enforcedSoftwareUpdateDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -121,7 +122,6 @@
],
"entityKey": "softwareUpdatesEnforcedDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -130,6 +130,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateMajorOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateMajorOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -138,7 +139,6 @@
],
"entityKey": "softwareUpdateMajorOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
}
@@ -154,6 +154,7 @@
"category": 41,
"nameResourceKey": "enforcedSoftwareUpdateDelayName",
"descriptionResourceKey": "enforcedSoftwareUpdateDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -162,7 +163,6 @@
],
"entityKey": "softwareUpdatesEnforcedDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -171,6 +171,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateMinorOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateMinorOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -179,7 +180,6 @@
],
"entityKey": "softwareUpdateMinorOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
}
@@ -195,6 +195,7 @@
"category": 41,
"nameResourceKey": "enforcedSoftwareUpdateDelayName",
"descriptionResourceKey": "enforcedSoftwareUpdateDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -203,7 +204,6 @@
],
"entityKey": "softwareUpdatesEnforcedDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -212,6 +212,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateNonOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateNonOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -220,7 +221,6 @@
],
"entityKey": "softwareUpdateNonOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
}
@@ -229,13 +229,14 @@
},
{
"nameResourceKey": "delayMajorAndMinorOSUpdateVisibilityOption",
"value": "delayMajorOsUpdateVisibility,delayOSUpdateVisibility",
"value": "delayOSUpdateVisibility,delayMajorOsUpdateVisibility",
"children": [
{
"dataType": 14,
"category": 41,
"nameResourceKey": "enforcedSoftwareUpdateDelayName",
"descriptionResourceKey": "enforcedSoftwareUpdateDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -244,7 +245,6 @@
],
"entityKey": "softwareUpdatesEnforcedDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -253,6 +253,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateMajorOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateMajorOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -261,7 +262,6 @@
],
"entityKey": "softwareUpdateMajorOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -270,6 +270,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateMinorOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateMinorOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -278,7 +279,6 @@
],
"entityKey": "softwareUpdateMinorOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
}
@@ -287,13 +287,14 @@
},
{
"nameResourceKey": "delayMajorAndNonOsUpdateVisibilityOption",
"value": "delayMajorOsUpdateVisibility,delayAppUpdateVisibility",
"value": "delayAppUpdateVisibility,delayMajorOsUpdateVisibility",
"children": [
{
"dataType": 14,
"category": 41,
"nameResourceKey": "enforcedSoftwareUpdateDelayName",
"descriptionResourceKey": "enforcedSoftwareUpdateDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -302,7 +303,6 @@
],
"entityKey": "softwareUpdatesEnforcedDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -311,6 +311,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateMajorOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateMajorOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -319,7 +320,6 @@
],
"entityKey": "softwareUpdateMajorOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -328,6 +328,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateNonOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateNonOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -336,7 +337,6 @@
],
"entityKey": "softwareUpdateNonOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
}
@@ -352,6 +352,7 @@
"category": 41,
"nameResourceKey": "enforcedSoftwareUpdateDelayName",
"descriptionResourceKey": "enforcedSoftwareUpdateDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -360,7 +361,6 @@
],
"entityKey": "softwareUpdatesEnforcedDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -369,6 +369,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateMinorOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateMinorOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -377,7 +378,6 @@
],
"entityKey": "softwareUpdateMinorOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -386,6 +386,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateNonOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateNonOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -394,7 +395,6 @@
],
"entityKey": "softwareUpdateNonOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
}
@@ -403,13 +403,14 @@
},
{
"nameResourceKey": "delayAllUpdateVisibilityOption",
"value": "delayMajorOsUpdateVisibility,delayOSUpdateVisibility,delayAppUpdateVisibility",
"value": "delayOSUpdateVisibility,delayAppUpdateVisibility,delayMajorOsUpdateVisibility",
"children": [
{
"dataType": 14,
"category": 41,
"nameResourceKey": "enforcedSoftwareUpdateDelayName",
"descriptionResourceKey": "enforcedSoftwareUpdateDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -418,7 +419,6 @@
],
"entityKey": "softwareUpdatesEnforcedDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -427,6 +427,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateMajorOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateMajorOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -435,7 +436,6 @@
],
"entityKey": "softwareUpdateMajorOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -444,6 +444,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateMinorOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateMinorOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -452,7 +453,6 @@
],
"entityKey": "softwareUpdateMinorOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
},
@@ -461,6 +461,7 @@
"category": 41,
"nameResourceKey": "softwareUpdateNonOSDeferredInstallDelayName",
"descriptionResourceKey": "softwareUpdateNonOSDeferredInstallDelayDescription",
"emptyValueResourceKey": "enforcedSoftwareUpdateDelayEmptyValue",
"childSettings": [
],
@@ -469,7 +470,6 @@
],
"entityKey": "softwareUpdateNonOSDeferredInstallDelayInDays",
"booleanActions": 0,
"defaultValue": 30,
"policyType": 61,
"enabled": true
}
@@ -672,6 +672,23 @@
"policyType": 42,
"enabled": true
},
{
"dataType": 0,
"category": 56,
"nameResourceKey": "singleSignOnExtensionManagedAppsInBundleIdACLIncludedName",
"descriptionResourceKey": "singleSignOnExtensionManagedAppsInBundleIdACLIncludedDescription",
"childSettings": [
],
"options": [
],
"entityKey": "managedAppsInBundleIdACLIncluded",
"booleanActions": 9,
"defaultValue": false,
"policyType": 42,
"enabled": true
},
{
"dataType": 20,
"category": 56,
@@ -722,6 +739,22 @@
"policyType": 42,
"enabled": true
},
{
"dataType": 20,
"category": 56,
"nameResourceKey": "singleSignOnExtensionSignInHelpTextName",
"descriptionResourceKey": "singleSignOnExtensionSignInHelpTextDescription",
"childSettings": [
],
"options": [
],
"entityKey": "signInHelpText",
"booleanActions": 0,
"policyType": 42,
"enabled": true
},
{
"columns": [
{
@@ -640,6 +640,23 @@
"policyType": 58,
"enabled": true
},
{
"dataType": 0,
"category": 56,
"nameResourceKey": "singleSignOnExtensionManagedAppsInBundleIdACLIncludedName",
"descriptionResourceKey": "singleSignOnExtensionManagedAppsInBundleIdACLIncludedDescription",
"childSettings": [
],
"options": [
],
"entityKey": "managedAppsInBundleIdACLIncluded",
"booleanActions": 9,
"defaultValue": false,
"policyType": 58,
"enabled": true
},
{
"dataType": 0,
"category": 56,
@@ -674,6 +691,74 @@
"policyType": 58,
"enabled": true
},
{
"dataType": 0,
"category": 56,
"nameResourceKey": "singleSignOnExtensionUserSetupDelayedName",
"descriptionResourceKey": "singleSignOnExtensionUserSetupDelayedDescription",
"childSettings": [
],
"options": [
],
"entityKey": "userSetupDelayed",
"booleanActions": 9,
"defaultValue": false,
"policyType": 58,
"enabled": true
},
{
"dataType": 0,
"category": 56,
"nameResourceKey": "singleSignOnExtensionKerberosAppsInBundleIdACLIncludedName",
"descriptionResourceKey": "singleSignOnExtensionKerberosAppsInBundleIdACLIncludedDescription",
"childSettings": [
],
"options": [
],
"entityKey": "kerberosAppsInBundleIdACLIncluded",
"booleanActions": 9,
"defaultValue": false,
"policyType": 58,
"enabled": true
},
{
"dataType": 0,
"category": 56,
"nameResourceKey": "singleSignOnExtensionCredentialsCacheMonitoredName",
"descriptionResourceKey": "singleSignOnExtensionCredentialsCacheMonitoredDescription",
"childSettings": [
],
"options": [
],
"entityKey": "credentialsCacheMonitored",
"booleanActions": 9,
"defaultValue": false,
"policyType": 58,
"enabled": true
},
{
"dataType": 0,
"category": 56,
"nameResourceKey": "singleSignOnExtensionTLSForLDAPRequiredName",
"descriptionResourceKey": "singleSignOnExtensionTLSForLDAPRequiredDescription",
"childSettings": [
],
"options": [
],
"entityKey": "tlsForLDAPRequired",
"booleanActions": 9,
"defaultValue": false,
"policyType": 58,
"enabled": true
},
{
"dataType": 0,
"category": 56,
@@ -788,6 +873,54 @@
"policyType": 58,
"enabled": true
},
{
"dataType": 20,
"category": 56,
"nameResourceKey": "singleSignOnExtensionUsernameLabelCustomName",
"descriptionResourceKey": "singleSignOnExtensionUsernameLabelCustomDescription",
"emptyValueResourceKey": "singleSignOnExtensionUsernameLabelCustomEmptyValue",
"childSettings": [
],
"options": [
],
"entityKey": "usernameLabelCustom",
"booleanActions": 0,
"policyType": 58,
"enabled": true
},
{
"dataType": 16,
"category": 56,
"nameResourceKey": "singleSignOnExtensionModeCredentialUsedName",
"descriptionResourceKey": "singleSignOnExtensionModeCredentialUsedDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "singleSignOnExtensionModeCredentialUsedAlwaysName",
"value": "always",
"enabled": true
},
{
"nameResourceKey": "singleSignOnExtensionModeCredentialUsedWhenNotSpecifiedName",
"value": "whenNotSpecified",
"enabled": true
},
{
"nameResourceKey": "singleSignOnExtensionModeCredentialUsedKerberosDefaultName",
"value": "kerberosDefault",
"enabled": true
}
],
"entityKey": "modeCredentialUsed",
"booleanActions": 0,
"defaultValue": "kerberosDefault",
"policyType": 58,
"enabled": true
},
{
"dataType": 20,
"category": 56,
@@ -838,6 +971,22 @@
"policyType": 58,
"enabled": true
},
{
"dataType": 20,
"category": 56,
"nameResourceKey": "singleSignOnExtensionSignInHelpTextName",
"descriptionResourceKey": "singleSignOnExtensionSignInHelpTextDescription",
"childSettings": [
],
"options": [
],
"entityKey": "signInHelpText",
"booleanActions": 0,
"policyType": 58,
"enabled": true
},
{
"dataType": 20,
"category": 56,
@@ -960,6 +1109,42 @@
"booleanActions": 0,
"policyType": 58,
"enabled": true
},
{
"columns": [
{
"metadata": {
"dataType": 20,
"category": 56,
"nameResourceKey": "singleSignOnExtensionPreferredKDCsColumnName",
"emptyValueResourceKey": "singleSignOnExtensionPreferredKDCsColumnEmptyValue",
"childSettings": [
],
"options": [
],
"entityKey": "preferredKDCsColumn",
"booleanActions": 0,
"policyType": 58,
"enabled": true
}
}
],
"dataType": 21,
"category": 56,
"nameResourceKey": "singleSignOnExtensionPreferredKDCsName",
"descriptionResourceKey": "singleSignOnExtensionPreferredKDCsDescription",
"childSettings": [
],
"options": [
],
"entityKey": "preferredKDCs",
"booleanActions": 0,
"policyType": 58,
"enabled": true
}
],
"enabled": true
@@ -344,6 +344,24 @@
"policyType": 61,
"enabled": true
},
{
"dataType": 14,
"category": 85,
"nameResourceKey": "macTouchIdTimeoutInHoursName",
"descriptionResourceKey": "macTouchIdTimeoutInHoursDescription",
"emptyValueResourceKey": "macTouchIdTimeoutInHoursEmptyValueKey",
"childSettings": [
],
"options": [
],
"entityKey": "touchIdTimeoutInHours",
"booleanActions": 0,
"defaultValue": 48,
"policyType": 61,
"enabled": true
},
{
"dataType": 0,
"category": 85,
@@ -57,6 +57,67 @@
"defaultValue": false,
"policyType": 2,
"enabled": true
},
{
"dataType": 16,
"category": 87,
"nameResourceKey": "personalProfilePersonalApplicationsListTypeName",
"descriptionResourceKey": "personalProfilePersonalApplicationsListTypeDescription",
"childSettings": [
],
"options": [
{
"nameResourceKey": "notConfigured",
"value": "notConfigured",
"enabled": true
},
{
"nameResourceKey": "blockedList",
"value": "blockedApps",
"children": [
{
"dataType": 25,
"category": 87,
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 2,
"enabled": true
}
],
"enabled": true
},
{
"nameResourceKey": "allowedList",
"value": "allowedApps",
"children": [
{
"dataType": 25,
"category": 87,
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 2,
"enabled": true
}
],
"enabled": true
}
],
"entityKey": "personalProfilePlayStoreMode",
"booleanActions": 0,
"defaultValue": "notConfigured",
"policyType": 2,
"enabled": true
}
],
"options": [
@@ -747,6 +747,8 @@
],
"entityKey": "passwordRequiredType",
"booleanActions": 0,
"defaultValue": "deviceDefault",
"unconfiguredValue": "deviceDefault",
"policyType": 29,
"enabled": true
}
@@ -364,6 +364,8 @@
],
"entityKey": "passwordRequiredType",
"booleanActions": 0,
"defaultValue": "deviceDefault",
"unconfiguredValue": "deviceDefault",
"policyType": 30,
"enabled": true
}
@@ -35,6 +35,7 @@
"category": 106,
"nameResourceKey": "complianceMinimumPasswordLengthName",
"descriptionResourceKey": "complianceMinimumPasswordLengthDescription",
"emptyValueResourceKey": "ComplianceMinimumPasswordLengthPlaceholder",
"childSettings": [
],
@@ -43,7 +44,6 @@
],
"entityKey": "passwordMinimumLength",
"booleanActions": 0,
"defaultValue": 4,
"policyType": 34,
"enabled": true
},
@@ -172,7 +172,7 @@
"category": 106,
"nameResourceKey": "compliancePasswordExpirationName",
"descriptionResourceKey": "compliancePasswordExpirationDescription",
"emptyValueResourceKey": "IOSMacPasswordExpirationInDaysEmptyValueKey",
"emptyValueResourceKey": "CompliancePasswordExpirationPlaceholder",
"childSettings": [
],
@@ -181,7 +181,6 @@
],
"entityKey": "passwordExpirationDays",
"booleanActions": 0,
"defaultValue": 41,
"policyType": 34,
"enabled": true
},
@@ -190,6 +189,7 @@
"category": 106,
"nameResourceKey": "complianceNumberOfPreviousPasswordsToBlockName",
"descriptionResourceKey": "complianceNumberOfPreviousPasswordsToBlockDescription",
"emptyValueResourceKey": "ComplianceNumberOfPreviousPasswordsToBlockPlaceholder",
"childSettings": [
],
@@ -198,7 +198,6 @@
],
"entityKey": "passwordPreviousPasswordBlockCount",
"booleanActions": 0,
"defaultValue": 5,
"policyType": 34,
"enabled": true
}
@@ -100,6 +100,7 @@
"category": 106,
"nameResourceKey": "complianceMinimumPasswordLengthName",
"descriptionResourceKey": "complianceMinimumPasswordLengthDescription",
"emptyValueResourceKey": "ComplianceMinimumPasswordLengthPlaceholder",
"childSettings": [
],
@@ -108,7 +109,6 @@
],
"entityKey": "passwordMinimumLength",
"booleanActions": 0,
"defaultValue": 4,
"policyType": 35,
"enabled": true
},
@@ -166,7 +166,7 @@
"category": 106,
"nameResourceKey": "compliancePasswordExpirationName",
"descriptionResourceKey": "compliancePasswordExpirationDescription",
"emptyValueResourceKey": "passwordExpirationInDaysEmptyValueTwoYearsKey",
"emptyValueResourceKey": "CompliancePasswordExpirationPlaceholder",
"childSettings": [
],
@@ -175,7 +175,6 @@
],
"entityKey": "passwordExpirationDays",
"booleanActions": 0,
"defaultValue": 41,
"policyType": 35,
"enabled": true
},
@@ -184,6 +183,7 @@
"category": 106,
"nameResourceKey": "complianceNumberOfPreviousPasswordsToBlockName",
"descriptionResourceKey": "complianceNumberOfPreviousPasswordsToBlockDescription",
"emptyValueResourceKey": "ComplianceNumberOfPreviousPasswordsToBlockPlaceholder",
"childSettings": [
],
@@ -192,7 +192,6 @@
],
"entityKey": "passwordPreviousPasswordBlockCount",
"booleanActions": 0,
"defaultValue": 5,
"policyType": 35,
"enabled": true
},
@@ -35,6 +35,7 @@
"category": 106,
"nameResourceKey": "complianceMinimumPasswordLengthName",
"descriptionResourceKey": "complianceMinimumPasswordLengthDescription",
"emptyValueResourceKey": "ComplianceMinimumPasswordLengthPlaceholder",
"childSettings": [
],
@@ -43,7 +44,6 @@
],
"entityKey": "passwordMinimumLength",
"booleanActions": 0,
"defaultValue": 4,
"policyType": 37,
"enabled": true
},
@@ -176,7 +176,7 @@
"category": 106,
"nameResourceKey": "compliancePasswordExpirationName",
"descriptionResourceKey": "compliancePasswordExpirationDescription",
"emptyValueResourceKey": "IOSMacPasswordExpirationInDaysEmptyValueKey",
"emptyValueResourceKey": "CompliancePasswordExpirationPlaceholder",
"childSettings": [
],
@@ -185,7 +185,6 @@
],
"entityKey": "passwordExpirationDays",
"booleanActions": 0,
"defaultValue": 41,
"policyType": 37,
"enabled": true
},
@@ -194,6 +193,7 @@
"category": 106,
"nameResourceKey": "complianceNumberOfPreviousPasswordsToBlockName",
"descriptionResourceKey": "complianceNumberOfPreviousPasswordsToBlockDescription",
"emptyValueResourceKey": "ComplianceNumberOfPreviousPasswordsToBlockPlaceholder",
"childSettings": [
],
@@ -202,7 +202,6 @@
],
"entityKey": "passwordPreviousPasswordBlockCount",
"booleanActions": 0,
"defaultValue": 5,
"policyType": 37,
"enabled": true
}
@@ -35,6 +35,7 @@
"category": 106,
"nameResourceKey": "complianceMinimumPasswordLengthName",
"descriptionResourceKey": "complianceMinimumPasswordLengthDescription",
"emptyValueResourceKey": "ComplianceMinimumPasswordLengthPlaceholder",
"childSettings": [
],
@@ -43,7 +44,6 @@
],
"entityKey": "passwordMinimumLength",
"booleanActions": 0,
"defaultValue": 4,
"policyType": 38,
"enabled": true
},
@@ -176,7 +176,7 @@
"category": 106,
"nameResourceKey": "compliancePasswordExpirationName",
"descriptionResourceKey": "compliancePasswordExpirationDescription",
"emptyValueResourceKey": "IOSMacPasswordExpirationInDaysEmptyValueKey",
"emptyValueResourceKey": "CompliancePasswordExpirationPlaceholder",
"childSettings": [
],
@@ -185,7 +185,6 @@
],
"entityKey": "passwordExpirationDays",
"booleanActions": 0,
"defaultValue": 41,
"policyType": 38,
"enabled": true
},
@@ -194,6 +193,7 @@
"category": 106,
"nameResourceKey": "complianceNumberOfPreviousPasswordsToBlockName",
"descriptionResourceKey": "complianceNumberOfPreviousPasswordsToBlockDescription",
"emptyValueResourceKey": "ComplianceNumberOfPreviousPasswordsToBlockPlaceholder",
"childSettings": [
],
@@ -202,7 +202,6 @@
],
"entityKey": "passwordPreviousPasswordBlockCount",
"booleanActions": 0,
"defaultValue": 5,
"policyType": 38,
"enabled": true
}
@@ -178,6 +178,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"enabled": false
}
],
@@ -383,6 +426,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"enabled": false
}
],
@@ -588,6 +674,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"enabled": false
}
],
@@ -793,6 +922,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"enabled": false
}
],
@@ -998,6 +1170,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 8,
"enabled": true
}
],
"enabled": false
}
],
@@ -178,6 +178,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"enabled": false
}
],
@@ -399,6 +442,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"enabled": false
}
],
@@ -604,6 +690,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"enabled": false
}
],
@@ -809,6 +938,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"enabled": false
}
],
@@ -1014,6 +1186,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"enabled": false
}
],
@@ -1219,6 +1434,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 12,
"enabled": true
}
],
"enabled": false
}
],
@@ -160,6 +160,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 25,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 25,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 25,
"enabled": true
}
],
"enabled": false
}
],
File diff suppressed because it is too large Load Diff
@@ -95,6 +95,49 @@
{
"nameResourceKey": "derivedCredentialsOption",
"value": "derivedCredential",
"children": [
{
"dataType": 9,
"category": 120,
"childSettings": [
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsSearchingForTenantLevel",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 105,
"enabled": true
},
{
"dataType": 10,
"category": 120,
"nameResourceKey": "derivedCredentialsTenantLevelNotConfigured",
"childSettings": [
],
"options": [
],
"booleanActions": 0,
"policyType": 105,
"enabled": true
}
],
"options": [
],
"entityKey": "derivedCredentialSettings@odata.bind",
"booleanActions": 0,
"policyType": 105,
"enabled": true
}
],
"enabled": false
}
],
@@ -3304,8 +3304,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
@@ -3515,8 +3515,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
@@ -3795,8 +3795,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
@@ -4187,8 +4187,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
@@ -4398,8 +4398,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
@@ -4678,8 +4678,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
@@ -167,8 +167,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
@@ -378,8 +378,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
@@ -663,8 +663,8 @@
],
"dataType": 21,
"category": 112,
"nameResourceKey": "trustedServerCertificateNamesName",
"descriptionResourceKey": "trustedServerCertificateNamesDescription",
"nameResourceKey": "androidTrustedServerCertificateNamesName",
"descriptionResourceKey": "androidTrustedServerCertificateNamesDescription",
"childSettings": [
],
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+266 -13
View File
@@ -11,7 +11,7 @@ Objects can be compared based on Properties or Documentatation info.
function Get-ModuleVersion
{
'1.0.7'
'1.0.9'
}
function Invoke-InitializeModule
@@ -50,16 +50,16 @@ function Add-CompareProvider
if($global:compareProviders.Count -eq 0)
{
$global:compareProviders += [PSCustomObject]@{
Name = "Exported File"
Name = "Intune Objects with Exported Files"
Value = "export"
ObjectCompare = { Compare-ObjectsBasedonProperty @args }
BulkCompare = { Start-BulkCompareExportObjects @args }
ProviderOptions = "CompareExportOptions"
Activate = { Invoke-ActivateCompareExportObjects @args }
Activate = { Invoke-ActivateCompareWithExportObjects @args }
}
$global:compareProviders += [PSCustomObject]@{
Name = "Named Objects"
Name = "Named Objects in Intune"
Value = "name"
BulkCompare = { Start-BulkCompareNamedObjects @args }
ProviderOptions = "CompareNamedOptions"
@@ -67,6 +67,15 @@ function Add-CompareProvider
RemoveProperties = @("Id")
}
$global:compareProviders += [PSCustomObject]@{
Name = "Files in Exported Folders"
Value = "exportedFolders"
ObjectCompare = { Compare-ObjectsBasedonProperty @args }
BulkCompare = { Start-BulkCompareExportFolders @args }
ProviderOptions = "CompareExportedFilesOptions"
Activate = { Invoke-ActivateCompareExportedObjects @args }
}
$global:compareProviders += [PSCustomObject]@{
Name = "Existing objects"
Value = "existing"
@@ -118,9 +127,6 @@ function Invoke-ShowMainWindow
$button.Margin = "0,0,5,0"
$button.IsEnabled = $false
$button.ToolTip = "Compare object with exported file"
$global:dgObjects.add_selectionChanged({
Set-XamlProperty $global:dgObjects.Parent "btnCompare" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null) $false $true)
})
$button.Add_Click({
Show-CompareForm $global:dgObjects.SelectedItem
@@ -131,6 +137,12 @@ function Invoke-ShowMainWindow
$global:spSubMenu.Children.Insert(0, $button)
}
function Invoke-EMSelectedItemsChanged
{
$hasSelectedItems = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true) -or ($null -ne $global:dgObjects.SelectedItem)
Set-XamlProperty $global:dgObjects.Parent "btnCompare" "IsEnabled" $hasSelectedItems
}
function Invoke-ViewActivated
{
if($global:currentViewObject.ViewInfo.ID -ne "IntuneGraphAPI") { return }
@@ -269,7 +281,9 @@ function Set-CompareProviderOptions
}
}
function Invoke-ActivateCompareExportObjects
# Compare Intune object with exported folder
function Invoke-ActivateCompareWithExportObjects
{
param($providerOptions, $firstTime)
@@ -292,6 +306,39 @@ function Invoke-ActivateCompareExportObjects
}
}
# Compare two exported folders
function Invoke-ActivateCompareExportedObjects
{
param($providerOptions, $firstTime)
if($firstTime)
{
$path = Get-Setting "" "LastUsedFullPath"
if($path)
{
$path = [IO.Directory]::GetParent($path).FullName
}
Set-XamlProperty $providerOptions "txtExportPathSource" "Text" (?? $path (Get-SettingValue "RootFolder"))
Set-XamlProperty $providerOptions "txtExportPathCompare" "Text" (Get-SettingValue "ExportPathCompare")
Add-XamlEvent $providerOptions "browseExportPathSource" "add_click" ({
$folder = Get-Folder (Get-XamlProperty $this.Parent "txtExportPathSource" "Text") "Select root folder for source"
if($folder)
{
Set-XamlProperty $this.Parent "txtExportPathSource" "Text" $folder
}
})
Add-XamlEvent $providerOptions "browseExportPathCompare" "add_click" ({
$folder = Get-Folder (Get-XamlProperty $this.Parent "txtExportPathCompare" "Text") "Select folder to compare the source with"
if($folder)
{
Set-XamlProperty $this.Parent "txtExportPathCompare" "Text" $folder
}
})
}
}
function Invoke-ActivateCompareNamesObjects
{
param($providerOptions, $firstTime)
@@ -468,6 +515,8 @@ function Start-BulkCompareExportObjects
Write-Log "Start bulk Exported Objects compare"
Write-Log "****************************************************************"
$compareObjectsResult = @()
$txtNameFilter = (Get-XamlProperty $global:ccContentProviderOptions.Content "txtCompareNameFilter" "Text").Trim()
$rootFolder = (Get-XamlProperty $global:ccContentProviderOptions.Content "txtExportPath" "Text")
$compareProps = $script:defaultCompareProps
@@ -521,12 +570,20 @@ function Start-BulkCompareExportObjects
Write-Log "Object from file '$($fileObj.FullName)' has no Id property. Compare not supported" 2
continue
}
$objName = Get-GraphObjectName $fileObj.Object $fileObj.ObjectType
if($txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
{
continue
}
$curObject = $graphObjects | Where { $_.Object.Id -eq $fileObj.Object.Id }
if(-not $curObject)
{
# Add objects that are exported but deleted
Write-Log "Object '$((Get-GraphObjectName $fileObj.Object $fileObj.ObjectType))' with id $($fileObj.Object.Id) not found in Intune. Deleted?" 2
Write-Log "Object '$($objName)' with id $($fileObj.Object.Id) not found in Intune. Deleted?" 2
$compareProperties = @([PSCustomObject]@{
Object1Value = $null
Object2Value = (Get-GraphObjectName $fileObj.Object $item.ObjectType)
@@ -554,13 +611,19 @@ function Start-BulkCompareExportObjects
# Add objects that are not exported
if(($compareObjectsResult | Where { $_.Id -eq $graphObj.Id})) { continue }
$objName = Get-GraphObjectName $graphObj.Object $item.ObjectType
if($txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
{
continue
}
$compareObjectsResult += [PSCustomObject]@{
Object1 = $curObject.Object
Object2 = $null
ObjectType = $item.ObjectType
Id = $graphObj.Id
Result = @([PSCustomObject]@{
Object1Value = (Get-GraphObjectName $graphObj.Object $item.ObjectType)
Object1Value = $objName
Object2Value = $null
Match = $false
})
@@ -594,18 +657,18 @@ function Start-BulkCompareExportObjects
if($outputType -eq "objectType")
{
Save-BulkCompareResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
Save-BulkCompareResults $compResultValues (Join-Path $folder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
}
}
else
{
Write-Log "Folder $folder not found. Skipping import" 2
Write-Log "Folder $folder not found. Skipping compare" 2
}
}
if($outputType -eq "all" -and $compResultValues.Count -gt 0)
{
Save-BulkCompareResults $compResultValues (Join-Path $folder "Compare_$(((Get-Date).ToString("yyyyMMDD-HHmm"))).csv") $compareProps
Save-BulkCompareResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMDD-HHmm"))).csv") $compareProps
}
Write-Log "****************************************************************"
@@ -618,6 +681,185 @@ function Start-BulkCompareExportObjects
}
}
function Start-BulkCompareExportFolders
{
Write-Log "****************************************************************"
Write-Log "Start bulk Exported Folders compare"
Write-Log "****************************************************************"
$compareObjectsResult = @()
$txtNameFilter = (Get-XamlProperty $global:ccContentProviderOptions.Content "txtCompareNameFilter" "Text").Trim()
$rootFolderSource = (Get-XamlProperty $global:ccContentProviderOptions.Content "txtExportPathSource" "Text")
$rootFolderCompare = (Get-XamlProperty $global:ccContentProviderOptions.Content "txtExportPathCompare" "Text")
$compareProps = $script:defaultCompareProps
foreach($removeProp in $global:cbCompareProvider.SelectedItem.RemoveProperties)
{
$compareProps.Remove($removeProp) | Out-Null
}
foreach($removeProp in $global:cbCompareType.SelectedItem.RemoveProperties)
{
$compareProps.Remove($removeProp) | Out-Null
}
if(-not $rootFolderSource -or -not $rootFolderCompare)
{
[System.Windows.MessageBox]::Show("Both folders must be specified", "Error", "OK", "Error")
return
}
if([IO.Directory]::Exists($rootFolderSource) -eq $false)
{
[System.Windows.MessageBox]::Show("Root folder $rootFolderSource does not exist", "Error", "OK", "Error")
return
}
if([IO.Directory]::Exists($rootFolderCompare) -eq $false)
{
[System.Windows.MessageBox]::Show("Root folder $rootFolderCompare does not exist", "Error", "OK", "Error")
return
}
$outputType = $global:cbCompareSave.SelectedValue
Save-Setting "Compare" "SaveType" $outputType
$compResultValues = @()
foreach($item in ($global:dgObjectsToCompare.ItemsSource | where Selected -eq $true))
{
Write-Status "Compare $($item.ObjectType.Title) objects" -Force -SkipLog
Write-Log "----------------------------------------------------------------"
Write-Log "Compare $($item.ObjectType.Title) objects"
Write-Log "----------------------------------------------------------------"
$folderSource = Join-Path $rootFolderSource $item.ObjectType.Id
$folderCompare = Join-Path $rootFolderCompare $item.ObjectType.Id
if([IO.Directory]::Exists($folderSource))
{
Save-Setting "" "LastUsedFullPath" $folderSource
$fileCompareObjs = @(Get-GraphFileObjects $folderCompare -ObjectType $item.ObjectType)
foreach ($fileSourceObj in @(Get-GraphFileObjects $folderSource -ObjectType $item.ObjectType))
{
$objName = Get-GraphObjectName $fileSourceObj.Object $item.ObjectType
if($txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
{
continue
}
if(-not $fileSourceObj.Object.Id)
{
Write-Log "Object from file '$($fileSourceObj.FullName)' has no Id property. Compare not supported" 2
continue
}
$compareObject = $fileCompareObjs | Where { $_.Object.Id -eq $fileSourceObj.Object.Id }
if(-not $compareObject)
{
# Add objects that are exported but deleted
Write-Log "Object '$($objName)' with id $($fileSourceObj.Object.Id) not found in Intune. Deleted?" 2
$compareProperties = @([PSCustomObject]@{
Object1Value = $null
Object2Value = (Get-GraphObjectName $fileSourceObj.Object $fileSourceObj.ObjectType)
Match = $false
})
}
else
{
$fileSourceObj.Object | Add-Member Noteproperty -Name "@ObjectFromFile" -Value $true -Force
$compareObject.Object | Add-Member Noteproperty -Name "@ObjectFromFile" -Value $true -Force
$compareProperties = Compare-Objects $compareObject.Object $fileSourceObj.Object $item.ObjectType
}
$compareObjectsResult += [PSCustomObject]@{
Object1 = $compareObject.Object
Object2 = $fileSourceObj.Object
ObjectType = $item.ObjectType
Id = $fileSourceObj.Object.Id
Result = $compareProperties
}
}
foreach($fileCompareObj in $fileCompareObjs)
{
# Add objects that were not exported in source folder
if(($compareObjectsResult | Where { $_.Id -eq $fileCompareObj.Object.Id})) { continue }
$objName = Get-GraphObjectName $fileCompareObj.Object $item.ObjectType
if($txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
{
continue
}
$compareObjectsResult += [PSCustomObject]@{
Object1 = $fileCompareObj.Object
Object2 = $null
ObjectType = $item.ObjectType
Id = $fileCompareObj.Object.Id
Result = @([PSCustomObject]@{
Object1Value = (Get-GraphObjectName $fileCompareObj.Object $item.ObjectType)
Object2Value = $null
Match = $false
})
}
}
if($outputType -eq "objectType")
{
$compResultValues = @()
}
foreach($compObj in @($compareObjectsResult | Where { $_.ObjectType.Id -eq $item.ObjectType.Id }))
{
$objName = Get-GraphObjectName (?? $compObj.Object1 $compObj.Object2) $item.ObjectType
foreach($compValue in $compObj.Result)
{
$compResultValues += [PSCustomObject]@{
ObjectName = $objName
Id = $compObj.Id
Type = $compObj.ObjectType.Title
ODataType = $compObj.Object1.'@OData.Type'
Property = $compValue.PropertyName
Value1 = $compValue.Object1Value
Value2 = $compValue.Object2Value
Category = $compValue.Category
SubCategory = $compValue.SubCategory
Match = $compValue.Match
}
}
}
if($outputType -eq "objectType")
{
Save-BulkCompareResults $compResultValues (Join-Path $folderSource "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
}
}
else
{
Write-Log "Folder $folderSource not found. Skipping compare" 2
}
}
if($outputType -eq "all" -and $compResultValues.Count -gt 0)
{
Save-BulkCompareResults $compResultValues (Join-Path $rootFolderSource "Compare_$(((Get-Date).ToString("yyyyMMDD-HHmm"))).csv") $compareProps
}
Write-Log "****************************************************************"
Write-Log "Bulk compare Exported Folders finished"
Write-Log "****************************************************************"
Write-Status ""
if($compareObjectsResult.Count -eq 0)
{
[System.Windows.MessageBox]::Show("No objects were comparced. Verify folder and exported files", "Error", "OK", "Error")
}
}
function Save-BulkCompareResults
{
param($compResultValues, $file, $props)
@@ -1064,6 +1306,11 @@ function Compare-ObjectsBasedonDocumentation
$val1 = $prop.$settingsValue
$prop2 = $docObj2.Settings | Where { $_.EntityKey -eq $prop.EntityKey -and $_.Category -eq $prop.Category -and $_.SubCategory -eq $prop.SubCategory -and $_.Enabled -eq $prop.Enabled }
$val2 = $prop2.$settingsValue
if($val1 -isnot [array] -and $val2 -is [array] -and $val2.Count -gt 1)
{
Write-Log "Multiple compare results returend for $($prop.Name). Using first result" 2
$val2 = $val2[0]
}
Add-CompareProperty $prop.Name $val1 $val2 $prop.Category $prop.SubCategory
}
@@ -1076,6 +1323,12 @@ function Compare-ObjectsBasedonDocumentation
$val2 = $prop.$settingsValue
$prop2 = $docObj1.Settings | Where { $_.EntityKey -eq $prop.EntityKey -and $_.Category -eq $prop.Category -and $_.SubCategory -eq $prop.SubCategory -and $_.Enabled -eq $prop.Enabled }
$val1 = $prop2.$settingsValue
if($val2 -isnot [array] -and $val1 -is [array] -and $val1.Count -gt 1)
{
Write-Log "Multiple compare results returend for $($prop.Name). Using first result" 2
$val1 = $val1[0]
}
Add-CompareProperty $prop.Name $val1 $val2 $prop.Category $prop.SubCategory
}
}
+212 -34
View File
@@ -20,13 +20,38 @@ $global:documentationProviders = @()
function Get-ModuleVersion
{
'1.0.7'
'1.1.0'
}
function Invoke-InitializeModule
{
# Make sure we add the default Output types
Add-OutputType
$script:columnHeaders = @{
Name="Inputs.displayNameLabel"
Value="TableHeaders.value"
Description="TableHeaders.description"
GroupMode="SettingDetails.modeTableHeader" #assignmentTypeSelectionLabel?
Group="TableHeaders.assignedGroups"
Groups="TableHeaders.groups"
useDeviceContext="SettingDetails.installContextLabel"
uninstallOnDeviceRemoval="SettingDetails.UninstallOnRemoval"
isRemovable="SettingDetails.installAsRemovable"
vpnConfigurationId="PolicyType.vpn"
Action="SettingDetails.actionColumnName"
Schedule="ScheduledAction.List.schedule"
MessageTemplate="ScheduledAction.Notification.messageTemplate"
EmailCC="ScheduledAction.Notification.additionalRecipients"
Filter="AssignmentFilters.assignmentFilterColumnHeader"
Rule="ApplicabilityRules.GridLabel.Rule"
ValueWithLabel="TableHeaders.value"
Status="TableHeaders.status"
CombinedValueWithLabel="TableHeaders.value"
CombinedValue="TableHeaders.value"
useDeviceLicensing="TableHeaders.licenseType"
#filterMode="Filter mode" # Not in any string file yet
}
}
function Invoke-ShowMainWindow
@@ -38,12 +63,6 @@ function Invoke-ShowMainWindow
$button.Margin = "0,0,5,0"
$button.IsEnabled = $false
$button.ToolTip = "Document selected objects"
$global:dgObjects.add_selectionChanged({
##Set-XamlProperty $global:dgObjects.Parent "btnDocument" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null) $false $true)
#$itemSelected = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true).Count -ge 0 -or $global:dgObjects.SelectedItem
Set-XamlProperty $global:dgObjects.Parent "btnDocument" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null) $false $true)
})
$button.Add_Click({
@@ -57,6 +76,12 @@ function Invoke-ShowMainWindow
$global:spSubMenu.Children.Insert(0, $button)
}
function Invoke-EMSelectedItemsChanged
{
$hasSelectedItems = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true) -or ($null -ne $global:dgObjects.SelectedItem)
Set-XamlProperty $global:dgObjects.Parent "btnDocument" "IsEnabled" $hasSelectedItems
}
function Invoke-GraphObjectsChanged
{
$btnDocument = $global:spSubMenu.Children | Where-Object { $_.Name -eq "btnDocument" }
@@ -87,6 +112,35 @@ function Invoke-ViewActivated
}
}
function Set-DocColumnHeaderLanguageId
{
param($columnName, $lngId)
if(-not $script:columnHeaders -or -not $lngId) { return }
if($script:columnHeaders.ContainsKey($columnName))
{
$script:columnHeaders[$columnName] = $lngId
}
else
{
$script:columnHeaders.Add($columnName, $lngId)
}
}
function Invoke-DocTranslateColumnHeader
{
param($columnName)
$lngText = ""
if($script:columnHeaders.ContainsKey($columnName))
{
$lngText = Get-LanguageString $script:columnHeaders[$columnName]
}
(?? $lngText $columnName)
}
function Add-OutputType
{
param($outputInfo)
@@ -575,11 +629,20 @@ function Add-ScopeTagStrings
{
foreach($scopeTagId in $obj.roleScopeTagIds)
{
$scopeTagObj = $script:scopeTags | Where Id -eq $scopeTagId
if($scopeTagObj)
$scopeTagName = $scopeTagId
if($scopeTagId -eq "0")
{
$objScopeTags += $scopeTagObj.displayName
$scopeTagName = (Get-LanguageString "SettingDetails.default")
}
elseif($script:scopeTags)
{
$scopeTagObj = $script:scopeTags | Where Id -eq $scopeTagId
if($scopeTagObj.displayName)
{
$scopeTagName = $scopeTagObj.displayName
}
}
$objScopeTags += $scopeTagName
}
}
if($objScopeTags.Count -gt 0)
@@ -588,27 +651,6 @@ function Add-ScopeTagStrings
}
}
function Get-AllEntityTypes
{
param($entityType, $xml, $hashTable)
if(-not $hashTable.ContainsKey($entityType))
{
$hashTable.Add($entityType, $xml.SelectSingleNode("//*[name()='EntityType' and @Name='$entityType']"))
}
$nodes = $xml.SelectNodes("//*[@BaseType='graph.$entityType']")
foreach($node in $nodes)
{
if($node.Abstract -ne "true")
{
$hashTable.Add($node.Name, $node)
}
Get-AllEntityTypes $node.Name $xml $hashTable
}
}
function Get-ObjectPlatformFromType
{
param($obj)
@@ -1761,6 +1803,10 @@ function Invoke-TranslateSection
{
$propValue = $prop.defaultValue
}
elseif($rawValue -eq $null -and ![String]::IsNullOrEmpty($prop.emptyValueResourceKey) -and $global:chkSetDefaultValue.IsChecked)
{
$propValue = Get-LanguageString $prop.emptyValueResourceKey
}
else
{
$propValue = $rawValue
@@ -1801,6 +1847,11 @@ function Invoke-TranslateSection
}
$rawValue = $value
}
elseif($script:currentObject.'@ObjectFromFile' -eq $true)
{
$value = "##TBD - Linked Certificate"
$rawValue = $value
}
}
elseif($prop.dataType -eq 200) # Multi option based on boolean value
{
@@ -2031,6 +2082,8 @@ function Add-PropertyInfo
}
$script:objectSettingsData += Get-PropertyInfo $prop $value $originalValue $jsonValue
Invoke-CustomPostAddValue $prop
}
function Add-PropertyInfoObject
@@ -2077,6 +2130,15 @@ function Get-PropertyInfo
$jsonValue = $rawValue | ConvertTo-Json -Depth 10 -Compress
}
if($prop.emptyValueResourceKey)
{
$defValue = Get-LanguageString $prop.emptyValueResourceKey
}
else
{
$defValue = $prop.defaultValue
}
return New-Object PSObject -Property @{
Name=$name
Description=$description
@@ -2088,7 +2150,7 @@ function Get-PropertyInfo
DataType=$prop.dataType
RawValue=$originalValue
RawJsonValue=$jsonValue
DefaultValue=$prop.defaultValue
DefaultValue=$defValue
UnconfiguredValue=$prop.unconfiguredValue
Enabled=$prop.Enabled
EntityKey=$prop.EntityKey
@@ -2123,6 +2185,23 @@ function Get-CustomProfileValue
}
}
function Invoke-CustomPostAddValue
{
param($prop)
foreach($docProvider in ($global:documentationProviders | Sort -Property Priority))
{
if($docProvider.PostAddValue)
{
$retObj = & $docProvider.PostAddValue $script:currentObject $prop $script:propertySeparator $script:objectSeparator
if($retObj -ne $null)
{
return $retObj
}
}
}
}
function Get-CustomPropertyObject
{
param($obj, $prop)
@@ -2819,6 +2898,8 @@ function Invoke-TranslateAssignments
}
}
$groupInfo = $null
if($groupIds.Count -gt 0)
{
$ht = @{}
@@ -2829,6 +2910,12 @@ function Invoke-TranslateAssignments
$groupInfo = (Invoke-GraphRequest -Url "/directoryObjects/getByIds?`$select=displayName,id" -Content $body -Method "Post").Value
}
if(($null -eq $groupInfo -or ($groupInfo | measure).Count -eq 0) -and $obj."@ObjectFromFile" -eq $true -and $script:migTable)
{
### Get group info from mig table when documenting from file if there's no access to the environment
$groupInfo = $script:migTable.Objects | Where Type -eq "Group"
}
if($filterIds.Count -gt 0)
{
$batchInfo = @{}
@@ -3119,7 +3206,10 @@ function Show-DocumentationForm
$objectTypes,
[Switch]
[Parameter(Mandatory=$false,ParameterSetName = "Objects")]
$SelectedDocuments)
$SelectedDocuments,
[Switch]
$ShowFolderSource
)
$objectList = @()
@@ -3193,6 +3283,22 @@ function Show-DocumentationForm
$global:btnAddToDocumentationList.Visibility = "Collapsed"
}
if($ShowFolderSource -ne $true)
{
$global:grdDocumentFromFolder.Visibility = "Collapsed"
$global:spDocumentFromFolder.Visibility = "Collapsed"
}
else
{
Add-XamlEvent $script:docForm "browseDocumentFromFolder" "add_click" {
$folder = Get-Folder (Get-XamlProperty $script:docForm "txtDocumentFromFolder" "Text") "Select root folder for export files"
if($folder)
{
Set-XamlProperty $script:docForm "txtDocumentFromFolder" "Text" $folder
}
}
}
$column = Get-GridCheckboxColumn "IsSelected"
$global:grdDocumentObjects.Columns.Add($column)
@@ -3283,6 +3389,11 @@ function Show-DocumentationForm
$txtDocumentationRawData.Text = ""
$loadExportedInfo = $true
$script:migTable = $null
$script:scopeTags = $null
$diSource = $nul
$global:intentCategories = $null
$global:catRecommendedSettings = $null
$global:intentCategoryDefs = $null
@@ -3341,6 +3452,19 @@ function Show-DocumentationForm
}
elseif($global:grdDocumentObjects.Tag -eq "ObjectTypes")
{
$fromExportFolder = $false
if($global:txtDocumentFromFolder.Text)
{
$diSource = [IO.DirectoryInfo]$global:txtDocumentFromFolder.Text
if($diSource.Exists -eq $false)
{
[System.Windows.MessageBox]::Show("Source folder not found:`n`n$($diSource.FullName)", "Documentation", "OK", "Error")
Write-Status ""
return
}
$fromExportFolder = $true
}
$sourceList = @()
foreach($objGroup in ($global:grdDocumentObjects.ItemsSource | Where IsSelected -eq $true))
{
@@ -3349,12 +3473,26 @@ function Show-DocumentationForm
{
Write-Status "Get $($objectType.Title) objects"
if($fromExportFolder -eq $false)
{
$graphObjects = @(Get-GraphObjects -property $objectType.ViewProperties -objectType $objectType)
if($objectType.PostListCommand)
{
$graphObjects = & $objectType.PostListCommand $graphObjects $objectType
}
}
else
{
$objectPath = [IO.Path]::Combine($diSource.FullName,$objectType.ID)
if([IO.Directory]::Exists($objectPath) -eq $false)
{
Write-Log "Object path for $($objectType.Title) ($($objectType.ID)) not found. Skipping object type" 2
continue
}
$graphObjects = Get-GraphFileObjects $objectPath -ObjectType $objectType
$graphObjects | ForEach-Object { $_.Object | Add-Member Noteproperty -Name "@ObjectFromFile" -Value $true -Force }
}
$groupSourceList += $graphObjects
}
@@ -3379,6 +3517,39 @@ function Show-DocumentationForm
return
}
if($fromExportFolder -eq $true -and $diSource -and $loadExportedInfo -eq $true)
{
$loadExportedInfo = $false
$migFileName = [IO.Path]::Combine($diSource.FullName,"MigrationTable.json")
if([IO.File]::Exists($migFileName) -eq $false)
{
Write-Log "MigrationTable not found. Groups will be documented with GroupId" 2
}
else
{
Write-Log "Load Migration table from $migFileName"
$script:migTable = ConvertFrom-Json (Get-Content $migFileName -Raw)
}
$scopeTagObjectType = $global:currentViewObject.ViewItems | Where Id -eq "ScopeTags"
if($scopeTagObjectType)
{
$scopePath = [IO.Path]::Combine($diSource.FullName,$scopeTagObjectType.Id)
if([IO.Directory]::Exists($scopePath) -eq $false)
{
Write-Log "Object path for Scope (Tags) ($($scopePath)) not found" 2
}
else
{
$scopeTagObjects = Get-GraphFileObjects $scopePath -ObjectType $scopeTagObjectType
$script:scopeTags = @(($scopeTagObjects | Select Object))
}
}
}
if($global:cbDocumentationType.SelectedItem.PreProcess)
{
Write-Status "Run PreProcess for $($global:cbDocumentationType.SelectedItem.Name)"
@@ -3403,7 +3574,14 @@ function Show-DocumentationForm
}
}
if($tmpObj.Object."@ObjectFromFile" -eq $true)
{
$obj = $tmpObj
}
else
{
$obj = Get-GraphObject $tmpObj.Object $tmpObj.ObjectType
}
if($obj)
{
@@ -3636,7 +3814,7 @@ function Set-OutputOptionsTabStatus
function Invoke-DocumentObjectTypes
{
Show-DocumentationForm -objectTypes $global:currentViewObject.ViewItems
Show-DocumentationForm -objectTypes $global:currentViewObject.ViewItems -ShowFolderSource
}
function Invoke-DocumentSelectedObjects
+166 -1
View File
@@ -10,7 +10,7 @@ This module will also document some objects based on PowerShell functions
function Get-ModuleVersion
{
'1.0.5'
'1.1.0'
}
function Invoke-InitializeModule
@@ -23,6 +23,7 @@ function Invoke-InitializeModule
GetCustomChildObject = { Get-CDDocumentCustomChildObjet @args }
GetCustomPropertyObject = { Get-CDDocumentCustomPropertyObject @args }
AddCustomProfileProperty = { Add-CDDocumentCustomProfileProperty @args }
PostAddValue = { Invoke-CDDocumentCustomPostAdd @args }
})
}
@@ -93,6 +94,13 @@ function Invoke-CDDocumentObject
Properties = @("Name","Value","Category","SubCategory")
}
}
elseif($type -eq '#microsoft.graph.deviceAndAppManagementAssignmentFilter')
{
Invoke-CDDocumentAssignmentFilter $documentationObj
return [PSCustomObject]@{
Properties = @("Name","Value")
}
}
}
function Get-CDAllManagedApps
@@ -169,6 +177,73 @@ Property separator character
Object separator character
#>
function Invoke-CDDocumentCustomPostAdd
{
param($obj, $prop, $propSeparator, $objSeparator)
if($obj.'@OData.Type' -eq "#microsoft.graph.windowsUpdateForBusinessConfiguration")
{
if($prop.EntityKey -eq "featureUpdatesDeferralPeriodInDays")
{
# Inject Windows 11 update setting. Not included in the file
$tmpProp = [PSCustomObject]@{
nameResourceKey = "allowWindows11UpgradeName"
descriptionResourceKey = "allowWindows11UpgradeDescription"
entityKey = "allowWindows11Upgrade"
dataType = 0
booleanActions = 109
category = $prop.Category
}
$propValue = Invoke-TranslateBoolean $obj $tmpProp
$script:UpdateCategory = $prop.Category
Add-PropertyInfo $tmpProp $propValue -originalValue $obj.allowWindows11Upgrade
}
if($prop.EntityKey -eq "featureUpdatesRollbackWindowInDays")
{
if($obj.businessReadyUpdatesOnly -eq "businessReadyOnly")
{
$propValue = Get-LanguageString "BooleanActions.notConfigured"
}
else
{
$propValue = Get-LanguageString "BooleanActions.enable"
}
# Inject Pre-release setting. Not included in the file
$tmpProp = [PSCustomObject]@{
nameResourceKey = "preReleaseBuilds"
descriptionResourceKey = "preReleaseBuildsDescription"
entityKey = "preReleaseEnabled" # Not a class property!
dataType = 0
booleanActions = 2
category = $prop.Category
}
Add-PropertyInfo $tmpProp $propValue -originalValue $obj.businessReadyUpdatesOnly
if($obj.businessReadyUpdatesOnly -ne "businessReadyOnly")
{
# Pre-release channel selected. Inject info
$propValue = Get-LanguageString "SettingDetails.$($obj.businessReadyUpdatesOnly)Option"
$tmpProp = [PSCustomObject]@{
nameResourceKey = "preReleaseChannel"
descriptionResourceKey = "preReleaseBuildsDescription"
entityKey = "businessReadyUpdatesOnly"
dataType = 0
booleanActions = 2
category = $prop.Category
}
Add-PropertyInfo $tmpProp $propValue -originalValue $obj.businessReadyUpdatesOnly
}
}
}
}
function Add-CDDocumentCustomProfileValue
{
param($obj, $prop, $topObj, $propSeparator, $objSeparator)
@@ -320,6 +395,18 @@ function Add-CDDocumentCustomProfileValue
return $false
}
}
elseif($obj.'@OData.Type' -eq "#microsoft.graph.windowsUpdateForBusinessConfiguration")
{
if($prop.EntityKey -eq "businessReadyUpdatesOnly" -or
$prop.EntityKey -eq "autoRestartNotificationDismissal" -or
$prop.EntityKey -eq "scheduleRestartWarningInHours" -or
$prop.EntityKey -eq "scheduleImminentRestartWarningInMinutes" -or
$prop.EntityKey -eq "deliveryOptimizationMode")
{
# Not used anymore
return $false
}
}
}
<#
@@ -695,6 +782,11 @@ function Add-CDDocumentCustomProfileProperty
}
$obj | Add-Member Noteproperty -Name "syntheticWipOrApps" -Value $syntheticWipOrApps -Force
if($null -eq $obj.profileTarget)
{
$obj.profileTarget = "user"
}
$retValue = $true
}
elseif($obj.'@OData.Type' -like "#microsoft.graph.iosDeviceFeaturesConfiguration")
@@ -872,6 +964,29 @@ function Add-CDDocumentCustomProfileProperty
$obj | Add-Member Noteproperty -Name "featureUpdateDisplayName" -Value $verInfoTxt
if($obj.rolloutSettings.offerStartDateTimeInUTC -and
$obj.rolloutSettings.offerEndDateTimeInUTC)
{
$featureUpdateRolloutOption = "gradualRollout"
$obj | Add-Member Noteproperty -Name "featureUpdateRolloutStartDate" -Value ((Get-Date $obj.rolloutSettings.offerStartDateTimeInUTC).ToLongDateString())
$obj | Add-Member Noteproperty -Name "featureUpdateRolloutEndDate" -Value ((Get-Date $obj.rolloutSettings.offerEndDateTimeInUTC).ToLongDateString())
if($null -ne $obj.rolloutSettings.offerIntervalInDays)
{
$obj | Add-Member Noteproperty -Name "featureUpdateRolloutInterval" -Value ($obj.rolloutSettings.offerIntervalInDays)
}
}
elseif($obj.rolloutSettings.offerStartDateTimeInUTC)
{
$featureUpdateRolloutOption = "startDateOnly"
$obj | Add-Member Noteproperty -Name "featureUpdateRolloutStartDate" -Value ((Get-Date $obj.rolloutSettings.offerStartDateTimeInUTC).ToLongDateString())
}
else
{
$featureUpdateRolloutOption = "immediateStart"
}
$obj | Add-Member Noteproperty -Name "featureUpdateRolloutOption" -Value $featureUpdateRolloutOption
$retValue = $true
}
elseif($obj.'@OData.Type' -eq "#microsoft.graph.iosUpdateConfiguration")
@@ -1061,6 +1176,16 @@ function Add-CDDocumentCustomProfileProperty
$obj | Add-Member Noteproperty -Name "detectionScriptAdded" -Value (-not [String]::IsNullOrEmpty($obj.detectionScriptContent))
$obj | Add-Member Noteproperty -Name "remediationScriptAdded" -Value (-not [String]::IsNullOrEmpty($obj.remediationScriptContent))
$obj | Add-Member Noteproperty -Name "useLoggedOnCredentials" -Value ($obj.runAsAccount -ne "system")
if($obj.detectionScriptContent)
{
$obj | Add-Member Noteproperty -Name "detectionScriptContentString" -Value ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(($obj.detectionScriptContent))))
}
if($obj.remediationScriptContent)
{
$obj | Add-Member Noteproperty -Name "remediationScriptContentString" -Value ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String(($obj.remediationScriptContent))))
}
}
if(($obj.PSObject.Properties | where Name -eq "securityRequireSafetyNetAttestationBasicIntegrity") -and
@@ -2491,3 +2616,43 @@ function Invoke-CDDocumentNotification
}
}
#endregion
#region
function Invoke-CDDocumentAssignmentFilter
{
param($documentationObj)
$obj = $documentationObj.Object
$objectType = $documentationObj.ObjectType
$script:objectSeparator = ?? $global:cbDocumentationObjectSeparator.SelectedValue ([System.Environment]::NewLine)
$script:propertySeparator = ?? $global:cbDocumentationPropertySeparator.SelectedValue ","
###################################################
# Basic info
###################################################
Add-BasicDefaultValues $obj $objectType
# "Filters" is not in the translation file
Add-BasicPropertyValue (Get-LanguageString "TableHeaders.configurationType") "Filters"
Add-BasicPropertyValue (Get-LanguageString "Inputs.platformLabel") (Get-LanguageString "Platform.$($obj.platform)")
###################################################
# Settings
###################################################
$label = Get-LanguageString "ApplicabilityRules.GridLabel.rule"
# "Rules" is not in the translation file
$category = "Rules"
Add-CustomSettingObject ([PSCustomObject]@{
Name = $label
Value = $obj.rule
EntityKey = "rule"
Category = $category
SubCategory = $null
})
}
#endregion
+482
View File
@@ -0,0 +1,482 @@
function Get-ModuleVersion
{
'1.0.0'
}
function Invoke-InitializeModule
{
Add-OutputType ([PSCustomObject]@{
Name="Markdown (Experimental)"
Value="md"
#OutputOptions = (Add-MDOptionsControl)
#Activate = { Invoke-MDActivate @args }
PreProcess = { Invoke-MDPreProcessItems @args }
NewObjectGroup = { Invoke-MDNewObjectGroup @args }
Process = { Invoke-MDProcessItem @args }
PostProcess = { Invoke-MDPostProcessItems @args }
ProcessAllObjects = { Invoke-MDProcessAllObjects @args }
})
}
function Invoke-MDPreProcessItems
{
$script:mdStrings = [System.Text.StringBuilder]::new()
$script:sectionAnchors = @()
$script:totAnchors = @()
}
function Invoke-MDPostProcessItems
{
$userName = $global:me.displayName
if($global:me.givenName -and $global:me.surname)
{
$userName = ($global:me.givenName + " " + $global:me.surname)
}
$script:mdContent = [System.Text.StringBuilder]::new()
$script:mdContent.AppendLine("# $((?? $global:txtMDTitleProperty.Text "Intune documentation"))")
$script:mdContent.AppendLine("")
$script:mdContent.AppendLine("")
$mail = ""
if($global:me.mail)
{
$mail = " ($($global:me.mail))"
}
$script:mdContent.AppendLine("*Organization:* $($global:Organization.displayName)`n")
$script:mdContent.AppendLine("*Generated by:* $userName$mail`n")
$script:mdContent.AppendLine("*Generated:* $((Get-Date).ToShortDateString()) $((Get-Date).ToLongTimeString())`n")
if($script:sectionAnchors.Count -gt 0)
{
$script:mdContent.AppendLine("")
$script:mdContent.AppendLine("## Table of Contents")
}
foreach($header in $script:sectionAnchors)
{
$script:mdContent.AppendLine("[$($header.Name)](#$($header.Anchor))`n")
}
$script:mdContent.AppendLine("")
$mdText = $script:mdContent.ToString()
$mdText += $script:mdStrings.ToString()
$fileName = Expand-FileName "%MyDocuments%\%Organization%-%Date%.md"
try
{
$mdText | Out-File -FilePath $fileName -Force -Encoding utf8 -ErrorAction Stop
Write-Log "Markdown document $fileName saved successfully"
}
catch
{
Write-LogError "Failed to save Markdown file" $_.Exception
}
}
function Invoke-MDNewObjectGroup
{
param($obj, $documentedObj)
$objectTypeString = Get-ObjectTypeString $obj.Object $obj.ObjectType
Add-MDHeader "$((?? $objectTypeString $obj.ObjectType.Title))" -Level 1 -USEHtml
}
function Invoke-MDProcessItem
{
param($obj, $objectType, $documentedObj)
if(!$documentedObj -or !$obj -or !$objectType) { return }
$objName = Get-GraphObjectName $obj $objectType
Add-MDHeader $objName -Level 2 -USEHtml
$script:mdStrings.AppendLine("")
try
{
foreach($tableType in @("BasicInfo","FilteredSettings"))
{
if($tableType -eq "BasicInfo")
{
$properties = @("Name","Value")
}
elseif($global:cbMDDocumentationProperties.SelectedValue -eq 'extended' -and $documentedObj.DisplayProperties)
{
$properties = @("Name","Value","Description")
}
elseif($global:cbMDDocumentationProperties.SelectedValue -eq 'custom' -and $global:txtMDCustomProperties.Text)
{
$properties = @()
foreach($prop in $global:txtMDCustomProperties.Text.Split(","))
{
# This will add language support for custom columens (or replacing existing header)
$propInfo = $prop.Split('=')
if(($propInfo | measure).Count -gt 1)
{
$properties += $propInfo[0]
Set-DocColumnHeaderLanguageId $propInfo[0] $propInfo[1]
}
else
{
$properties += $prop
}
}
}
else
{
$properties = (?? $documentedObj.DefaultDocumentationProperties (@("Name","Value")))
}
$lngId = ?: ($tableType -eq "BasicInfo") "SettingDetails.basics" "TableHeaders.settings" -AddCategories
Add-MDTableItems $obj $objectType ($documentedObj.$tableType) $properties $lngId -AddCategories -AddSubcategories
#Add-MDTableItems $obj $objectType ($documentedObj.$tableType) $properties $lngId `
# -AddCategories:($global:chkMDAddCategories.IsChecked -eq $true) `
# -AddSubcategories:($global:chkMDAddSubCategories.IsChecked -eq $true)
}
if(($documentedObj.ComplianceActions | measure).Count -gt 0)
{
$properties = @("Action","Schedule","MessageTemplate","EmailCC")
Add-MDTableItems $obj $objectType $documentedObj.ComplianceActions $properties "Category.complianceActionsLabel"
}
if(($documentedObj.ApplicabilityRules | measure).Count -gt 0)
{
$properties = @("Rule","Property","Value")
Add-MDTableItems $obj $objectType $documentedObj.ApplicabilityRules $properties "SettingDetails.applicabilityRules"
}
Add-MDObjectSettings $obj $objectType $documentedObj
if(($documentedObj.Assignments | measure).Count -gt 0)
{
$params = @{}
if($documentedObj.Assignments[0].RawIntent)
{
$properties = @("GroupMode","Group","Filter","FilterMode")
$settingsObj = $documentedObj.Assignments | Where { $_.Settings -ne $null } | Select -First 1
if($settingsObj)
{
foreach($objProp in $settingsObj.Settings.Keys)
{
if($objProp -in $properties) { continue }
if($objProp -in @("Category","RawIntent")) { continue }
$properties += ("Settings." + $objProp)
}
}
}
else
{
$isFilterAssignment = $false
foreach($assignment in $documentedObj.Assignments)
{
if(($assignment.target.PSObject.Properties | Where Name -eq "deviceAndAppManagementAssignmentFilterType"))
{
$isFilterAssignment = $true
break
}
}
$properties = @("Group")
if($isFilterAssignment)
{
$properties += @("Filter","FilterMode")
}
$params.Add("AddCategories", $true)
}
Add-MDTableItems $obj $objectType $documentedObj.Assignments $properties "TableHeaders.assignments" @params
}
}
catch
{
Write-LogError "Failed to process object $objName" $_.Exception
}
}
function Add-MDTableItems
{
param($obj, $objectType, $items, $properties, $lngId, [switch]$AddCategories, [switch]$AddSubcategories, $captionOverride)
if($captionOverride)
{
$caption = $captionOverride
}
elseif($lngId)
{
$caption = "$((Get-LanguageString $lngId)) - $((Get-GraphObjectName $obj $objectType))"
}
else
{
$caption = "$((Get-GraphObjectName $obj $objectType)) ($($objectType.Title))"
}
$tableText = [System.Text.StringBuilder]::new()
$tableText.AppendLine("<table>")
$tableText.AppendLine("<tr>")
$columnHeaders = "|"
$columnChars = "|"
$columnCount = 0
foreach($prop in $properties)
{
$tableText.AppendLine("<td> $($prop.Split(".")[-1]) </td>")
$columnCount++
$columnHeaders += ((Invoke-DocTranslateColumnHeader ($prop.Split(".")[-1])) + "|")
$columnChars += "----|"
}
$tableText.AppendLine("</tr>")
#Add-MDText $columnHeaders
#Add-MDText $columnChars
$curCategory = ""
$curSubCategory = ""
$columnCategory = $null
$columnSubCategory = $null
foreach($itemObj in $items)
{
if($itemObj.Category -and $curCategory -ne $itemObj.Category -and $AddCategories -eq $true)
{
$tableText.AppendLine("<tr>")
$tableText.AppendLine("<td colspan=`"$($columnCount)`">`n`n**$((Set-MDText $itemObj.Category))**`n`n</td>")
$tableText.AppendLine("</tr>")
#$columnCategory = "|**" + (Set-MDText $itemObj.Category) + "**|"
#Add-MDText $columnCategory
$curCategory = $itemObj.Category
$curSubCategory = ""
}
if($itemObj.SubCategory -and $curSubCategory -ne $itemObj.SubCategory -and $AddSubcategories -eq $true)
{
$tableText.AppendLine("<tr>")
$tableText.AppendLine("<td colspan=`"$($columnCount)`">`n`n***$((Set-MDText $itemObj.SubCategory))***`n`n</td>")
$tableText.AppendLine("</tr>")
#$columnSubCategory = "|***" + (Set-MDText $itemObj.SubCategory) + "***|"
#Add-MDText $columnSubCategory
$curSubCategory = $itemObj.SubCategory
}
#$columnData = "|"
try
{
$tableText.AppendLine("<tr>")
foreach($prop in $properties)
{
try
{
# This adds support for properties like Settings.PropName
$propArr = $prop.Split('.')
$tmpObj = $itemObj
$propName = $propArr[-1]
for($x = 0; $x -lt ($propArr.Count - 1);$x++)
{
$tmpObj = $tmpObj."$($propArr[$x])"
}
$tableText.AppendLine("<td>$((Set-MDText "$($tmpObj.$propName)" -CodeBlock))</td>")
#$columnData += "$((Set-MDText "$($tmpObj.$propName)"))|"
}
catch
{
#$columnData += "|"
Write-LogError "Failed to add property value for $prop" $_.Exception
}
}
}
catch
{
Write-Log "Failed to process property" 2
}
finally
{
$tableText.AppendLine("</tr>")
}
#Add-MDText $columnData
}
$tableText.AppendLine("</table>")
Add-MDText $tableText.ToString()
Add-MDHeader $caption -Level 6 -TOT -AddParagraph
}
function Add-MDText
{
param($text, [switch]$AddParagraph)
$script:mdStrings.AppendLine($text)
if($AddParagraph -eq $true)
{
# Add new paragraph by default
$script:mdStrings.AppendLine("")
}
}
function Set-MDText
{
param($text, [switch]$CodeBlock)
if($CodeBlock -eq $true)
{
$trimText = $text.Trim()
if($trimText.StartsWith("<") -and $trimText.EndsWith(">"))
{
return ([Environment]::NewLine + [Environment]::NewLine + "``````xml" + [Environment]::NewLine + $text + [Environment]::NewLine + "``````" + [Environment]::NewLine + [Environment]::NewLine)
}
}
$text = $text.Replace("|", '`|')
$text = $text.Replace("*", '`*')
$text = $text.Replace("$", '`$')
$text = $text.Replace("`r`n", "<br />")
$text = $text.Replace("`n", "<br />")
$text
}
function Add-MDHeader
{
param($text, [int]$level = 1, [switch]$AddParagraph, [switch]$UseHTML, [switch]$ToT, [switch]$SkipTOC)
$prefix = ""
if($ToT -eq $true)
{
$prefix = "Table $(($script:totAnchors.Count + 1)). "
}
if($UseHTML -eq $true)
{
if($ToT -eq $true)
{
$sectionAnchor = "table-$(($script:totAnchors.Count + 1))"
}
else
{
$sectionAnchor = "section-$(($script:sectionAnchors.Count + 1))"
}
$script:mdStrings.AppendLine("<h$level id=`"$prefix$($sectionAnchor)`">$text</h$level>")
}
else
{
# Warnig: Not complete! Use HTML if not working...
$text = "$prefix$text"
$sectionAnchor = $text.ToLower().Replace(" ","-").Replace("[","").Replace("]","")
$mdHeader = [String]::new('#',$level)
$script:mdStrings.AppendLine("$mdHeader $text")
}
if($ToT -eq $true)
{
$script:totAnchors += [PSCustomObject]@{
Name = $text
Anchor = $sectionAnchor
}
}
elseif($SkipTOC -ne $true)
{
$script:sectionAnchors += [PSCustomObject]@{
Name = $text
Anchor = $sectionAnchor
}
}
if($AddParagraph -eq $true)
{
# Add new paragraph by default
$script:mdStrings.AppendLine("`n")
}
}
function Add-MDObjectSettings
{
param($obj, $objectType, $documentedObj)
if($obj."@OData.Type" -eq "#microsoft.graph.deviceManagementScript")
{
if($obj.ScriptContent)
{
$script:mdStrings.AppendLine("~~~powershell")
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.ScriptContent))
$script:mdStrings.AppendLine("~~~")
$caption = "{1} - {0}" -f $obj.fileName,(Get-LanguageString "WindowsManagement.powerShellScriptObjectName")
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
}
}
if($obj."@OData.Type" -eq "#microsoft.graph.deviceShellScript")
{
if($obj.ScriptContent)
{
$script:mdStrings.AppendLine("~~~shell")
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.ScriptContent))
$script:mdStrings.AppendLine("~~~")
$caption = "{1} - {0}" -f $obj.fileName,(Get-LanguageString "WindowsManagement.shellScriptObjectName")
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
}
}
elseif($obj."@OData.Type" -eq "#microsoft.graph.deviceHealthScript")
{
if($obj.detectionScriptContent)
{
$script:mdStrings.AppendLine("~~~powershell")
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.detectionScriptContent))
$script:mdStrings.AppendLine("~~~")
$caption = Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label"
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
}
if($obj.remediationScriptContent)
{
$script:mdStrings.AppendLine("~~~powershell")
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.remediationScriptContent))
$script:mdStrings.AppendLine("~~~")
$caption = Get-LanguageString "ProactiveRemediations.Create.Settings.RemediationScriptMultiLineTextBox.label"
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
}
}
elseif($obj."@OData.Type" -eq "#microsoft.graph.win32LobApp")
{
foreach($rule in ($obj.requirementRules | Where { $_.'@OData.Type' -eq "#microsoft.graph.win32LobAppPowerShellScriptRequirement" } ))
{
$script:mdStrings.AppendLine("~~~powershell")
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.scriptContent))
$script:mdStrings.AppendLine("~~~")
$caption = "{0} - {1}" -f @($obj.displayName, "Requirement script")
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
}
foreach($rule in ($obj.detectionRules | Where { $_.'@OData.Type' -eq "#microsoft.graph.win32LobAppPowerShellScriptDetection" } ))
{
$script:mdStrings.AppendLine("~~~powershell")
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.scriptContent))
$script:mdStrings.AppendLine("~~~")
$caption = "{0} - {1}" -f @($obj.displayName,(Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label"))
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
}
}
}
+287 -6
View File
@@ -3,7 +3,7 @@
#https://docs.microsoft.com/en-us/office/vba/api/overview/word
function Get-ModuleVersion
{
'1.0.4'
'1.1.0'
}
function Invoke-InitializeModule
@@ -70,6 +70,14 @@ function Add-WordOptionsControl
$global:spWordCustomProperties.Visibility = (?: ($global:cbWordDocumentationProperties.SelectedValue -ne "custom") "Collapsed" "Visible")
$global:txtWordCustomProperties.Visibility = (?: ($global:cbWordDocumentationProperties.SelectedValue -ne "custom") "Collapsed" "Visible")
$global:cbWordDocumentationLevel.ItemsSource = ("[ { Name: `"Full`",Value: `"full`" }, { Name: `"Limited`",Value: `"limited`" }, { Name: `"Basic`",Value: `"basic`" }]" | ConvertFrom-Json)
$global:cbWordDocumentationLevel.SelectedValue = (Get-Setting "Documentation" "WordDocumentationLevel" "full")
$global:gdWordDocumentationLimitOptions.Visibility = (?: ($global:cbWordDocumentationLevel.SelectedValue -ne "limited") "Collapsed" "Visible")
$global:txtWordDocumentationLimitMaxLength.Text = Get-Setting "Documentation" "WordDocumentationLimitMaxLength" ""
$global:txtWordDocumentationLimitTruncateLength.Text = Get-Setting "Documentation" "WordDocumentationLimitTruncateLength" ""
$global:chkWordDocumentationLimitAttatch.IsChecked = ((Get-Setting "Documentation" "WordDocumentationLimitAttatch" "true") -ne "false")
$global:txtWordDocumentTemplate.Text = Get-Setting "Documentation" "WordDocumentTemplate" ""
$global:txtWordDocumentName.Text = (Get-Setting "Documentation" "WordDocumentName" "%MyDocuments%\%Organization%-%Date%.docx")
@@ -86,6 +94,12 @@ function Add-WordOptionsControl
$global:txtWordTitleProperty.Text = Get-Setting "Documentation" "WordTitleProperty" "Intune documentation"
$global:txtWordSubjectProperty.Text = Get-Setting "Documentation" "WordSubjectProperty" "Intune documentation"
$global:chkWordIncludeScripts.IsChecked = ((Get-Setting "Documentation" "WordIncludeScripts" "true") -ne "false")
$global:chkWordExcludeScriptSignature.IsChecked = ((Get-Setting "Documentation" "WordExcludeScriptSignature" "false") -ne "false")
$global:chkWordAttatchJsonFile.IsChecked = ((Get-Setting "Documentation" "WordAttatchJsonFile" "false") -ne "false")
$global:txtWordScriptTableStyle.Text = Get-Setting "Documentation" "WordScriptTableStyle" ""
$global:txtWordScriptStyle.Text = Get-Setting "Documentation" "WordScriptStyle"
$global:chkWordOpenDocument.IsChecked = ((Get-Setting "Documentation" "WordOpenDocument" "true") -ne "false")
@@ -105,6 +119,10 @@ function Add-WordOptionsControl
$global:txtWordCustomProperties.Visibility = (?: ($this.SelectedValue -ne "custom") "Collapsed" "Visible")
}
Add-XamlEvent $script:wordForm "cbWordDocumentationLevel" "add_selectionChanged" {
$global:gdWordDocumentationLimitOptions.Visibility = (?: ($this.SelectedValue -ne "limited") "Collapsed" "Visible")
}
$script:wordForm
}
function Invoke-WordActivate
@@ -117,6 +135,12 @@ function Invoke-WordPreProcessItems
Save-Setting "Documentation" "WordExportProperties" $global:cbWordDocumentationProperties.SelectedValue
Save-Setting "Documentation" "WordCustomDisplayProperties" $global:txtWordCustomProperties.Text
Save-Setting "Documentation" "WordDocumentTemplate" $global:txtWordDocumentTemplate.Text
Save-Setting "Documentation" "WordDocumentName" $global:txtWordDocumentName.Text
Save-Setting "Documentation" "WordDocumentationLevel" $global:cbWordDocumentationLevel.SelectedValue
Save-Setting "Documentation" "WordDocumentationLimitMaxLength" $global:txtWordDocumentationLimitMaxLength.Text
Save-Setting "Documentation" "WordDocumentationLimitTruncateLength" $global:txtWordDocumentationLimitTruncateLength.Text
Save-Setting "Documentation" "WordDocumentationLimitAttatch" $global:chkWordDocumentationLimitAttatch.IsChecked
Save-Setting "Documentation" "WordAddCategories" $global:chkWordAddCategories.IsChecked
Save-Setting "Documentation" "WordAddSubCategories" $global:chkWordAddSubCategories.IsChecked
@@ -132,6 +156,60 @@ function Invoke-WordPreProcessItems
Save-Setting "Documentation" "WordTitleProperty" $global:txtWordTitleProperty.Text
Save-Setting "Documentation" "WordSubjectProperty" $global:txtWordSubjectProperty.Text
Save-Setting "Documentation" "WordIncludeScripts" $global:chkWordIncludeScripts.IsChecked
Save-Setting "Documentation" "WordExcludeScriptSignature" $global:chkWordExcludeScriptSignature.IsChecked
Save-Setting "Documentation" "WordAttatchJsonFile" $global:chkWordAttatchJsonFile.IsChecked
Save-Setting "Documentation" "WordScriptTableStyle" $global:txtWordScriptTableStyle.Text
Save-Setting "Documentation" "WordScriptStyle" $global:txtWordScriptStyle.Text
$script:limitMaxValue = 100
$script:truncateValueLength = $script:limitMaxValue
if($global:cbWordDocumentationLevel.SelectedValue -eq "limited")
{
if($global:txtWordDocumentationLimitMaxLength.Text)
{
try
{
$script:limitMaxValue = [int]::Parse($global:txtWordDocumentationLimitMaxLength.Text)
}
catch
{
Write-LogError "Failed to parse $($global:txtWordDocumentationLimitMaxLength.Text) to int. Max value length will be set to 100." $_.Exception
}
}
if($global:txtWordDocumentationLimitTruncateLength.Text)
{
try
{
$script:truncateValueLength = [int]::Parse($global:txtWordDocumentationLimitTruncateLength.Text)
}
catch
{
Write-LogError "Failed to parse $($global:txtWordDocumentationLimitTruncateLength.Text) to int. Truncat length will be set to $script:limitMaxValue." $_.Exception
}
}
if($script:limitMaxValue -lt 20)
{
Write-Log "Max value length must be 20 or more. Changed to 20" 2
$script:limitMaxValue = 0
}
if($script:truncateValueLength -lt 0)
{
Write-Log "Truncate length must be 0 or more. Changed to 0" 2
$script:truncateValueLength = 0
}
elseif($script:truncateValueLength -gt $script:limitMaxValue)
{
Write-Log "Truncate length cannot be larger than Max value length. Canged to: $($script:limitMaxValue)" 2
$script:truncateValueLength = $script:limitMaxValue
}
}
try
{
$script:wordApp = New-Object -ComObject Word.Application
@@ -153,7 +231,7 @@ function Invoke-WordPreProcessItems
}
catch
{
Write-LogError "Failed to create document based on tmeplate: $($global:txtWordDocumentTemplate.Text)" $_.Exception
Write-LogError "Failed to create document based on template: $($global:txtWordDocumentTemplate.Text)" $_.Exception
}
}
else
@@ -274,6 +352,17 @@ function Invoke-WordPreProcessItems
}
}
}
else
{
if(($script:doc.TablesOfContents | measure).Count -eq 0)
{
# Where should it be added?
# $script:doc.TablesOfContents.Add($script:wordApp.Selection.Range) | out-null
}
Invoke-DocGoToEnd
$script:wordApp.Selection.InsertNewPage()
}
}
function Invoke-WordPostProcessItems
@@ -432,7 +521,7 @@ function Invoke-WordProcessItem
foreach($prop in $global:txtWordCustomProperties.Text.Split(","))
{
# This will add language support for custom colument (or replacing existing header)
# This will add language support for custom columens (or replacing existing header)
$propInfo = $prop.Split('=')
if(($propInfo | measure).Count -gt 1)
{
@@ -450,13 +539,21 @@ function Invoke-WordProcessItem
$properties = (?? $documentedObj.DefaultDocumentationProperties (@("Name","Value")))
}
if($global:cbWordDocumentationLevel.SelectedValue -eq "basic" -and $tableType -ne "BasicInfo")
{
continue
}
$lngId = ?: ($tableType -eq "BasicInfo") "SettingDetails.basics" "TableHeaders.settings" -AddCategories
Add-DocTableItems $obj $objectType ($documentedObj.$tableType) $properties $lngId `
-AddCategories:($global:chkWordAddCategories.IsChecked -eq $true) `
-AddSubcategories:($global:chkWordAddSubCategories.IsChecked -eq $true)
-AddSubcategories:($global:chkWordAddSubCategories.IsChecked -eq $true) `
-ForceFullValue:($tableType -eq "BasicInfo")
}
if($global:cbWordDocumentationLevel.SelectedValue -ne "basic")
{
if(($documentedObj.ComplianceActions | measure).Count -gt 0)
{
$properties = @("Action","Schedule","MessageTemplate","EmailCC")
@@ -471,6 +568,9 @@ function Invoke-WordProcessItem
Add-DocTableItems $obj $objectType $documentedObj.ApplicabilityRules $properties "SettingDetails.applicabilityRules"
}
Add-DocObjectSettings $obj $objectType $documentedObj
}
if(($documentedObj.Assignments | measure).Count -gt 0)
{
$params = @{}
@@ -511,6 +611,20 @@ function Invoke-WordProcessItem
Add-DocTableItems $obj $objectType $documentedObj.Assignments $properties "TableHeaders.assignments" @params
}
if($global:chkWordAttatchJsonFile.IsChecked -eq $true)
{
$fileName = Export-GraphObject $obj $objectType ([IO.Path]::GetTempPath()) -IsFullObject -PassThru -SkipAddID
if($fileName)
{
$fi = [IO.FileInfo]$fileName
if($fi.Exists)
{
$script:doc.Application.Selection.InlineShapes.AddOLEObject("",$fi.FullName,$false,$true,"$($env:WinDir)\System32\Notepad.exe",0,$fi.Name)
try { $fi.Delete() } catch {} # Cleanup
}
}
}
}
catch
{
@@ -594,7 +708,7 @@ function Set-WordColumnHeaderLanguageId
function Add-DocTableItems
{
param($obj, $objectType, $items, $properties, $lngId, [switch]$AddCategories, [switch]$AddSubcategories, $captionOverride)
param($obj, $objectType, $items, $properties, $lngId, [switch]$AddCategories, [switch]$AddSubcategories, $captionOverride, [switch]$forceFullValue)
$tblHeaderStyle = $global:txtWordTableHeaderStyle.Text
$tblCategoryStyle = $global:txtWordCategoryHeaderStyle.Text
@@ -653,7 +767,48 @@ function Add-DocTableItems
{
$tmpObj = $tmpObj."$($propArr[$x])"
}
$script:docTable.Cell($row, $i).Range.Text = "$($tmpObj.$propName)"
$propValue = "$($tmpObj.$propName)"
$propValueFull = $null
if($forceFullValue -ne $true -and $global:cbWordDocumentationLevel.SelectedValue -eq "limited" -and $propValue.Length -gt $script:limitMaxValue)
{
$propValueFull = $propValue
if($script:truncateValueLength -gt 0)
{
$propValue = ($propValue.Substring(0, $script:truncateValueLength) + "...")
if($global:chkWordDocumentationLimitAttatch.IsChecked -eq $true)
{
$propValue = ("`r`n" + $propValue)
}
}
else
{
$propValue = $null
}
}
if($null -ne $propValue)
{
$script:docTable.Cell($row, $i).Range.Text = $propValue
}
if($propValueFull -and $global:chkWordDocumentationLimitAttatch.IsChecked -eq $true)
{
if($null -ne $propValue)
{
#$script:doc.Application.Selection.TypeParagraph()
}
$tmpName = "$((Get-GraphObjectName $obj $objectType))-$propName"
$tmpFile = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "$($tmpName).txt")
$tmpFile = Remove-InvalidFileNameChars $tmpFile
$propValueFull | Out-File -LiteralPath $tmpFile -Force
$fi = [IO.FileInfo]$tmpFile
[void]$script:docTable.Cell($row, $i).Range.InlineShapes.AddOLEObject("",$fi.FullName,$false,$true,"$($env:WinDir)\System32\Notepad.exe",0,"Full value")
#$script:doc.Application.Selection.InlineShapes.AddOLEObject("",$fi.FullName,$false,$true,"$($env:WinDir)\System32\Notepad.exe",0,"Full value", $script:docTable.Cell($row, $i).Range)
try { $fi.Delete() } catch {}
}
}
catch
{
@@ -711,6 +866,49 @@ function Add-DocTableItems
#$script:doc.Application.Selection.TypeParagraph()
}
function Add-DocTableScript
{
param($caption, $header, $script)
if(-not $script) { return }
$tblScriptStyle = (?? $global:txtWordScriptTableStyle.Text $global:txtWordTableStyle.Text)
$range = $script:doc.application.selection.range
$scriptTable = $script:doc.Tables.Add($range, 2, 1, [Microsoft.Office.Interop.Word.WdDefaultTableBehavior]::wdWord9TableBehavior, [Microsoft.Office.Interop.Word.WdAutoFitBehavior]::wdAutoFitWindow)
$scriptTable.ApplyStyleHeadingRows = $true
Set-DocObjectStyle $scriptTable $tblScriptStyle | Out-Null
if($header)
{
$scriptTable.Cell(1, 1).Range.Text = $header
}
$scriptTable.Cell(2,1).Range.Font.Bold = $false
$scriptTable.Cell(2, 1).Range.Text = $script
if($global:txtWordScriptStyle.Text)
{
Set-DocObjectStyle $scriptTable.Rows(2).Range $global:txtWordScriptStyle.Text | Out-Null
}
else
{
$tmp = $script:wordStyles | Where Name -like "HTML Code"
if($tmp)
{
$scriptTable.Cell(2,1).Range.Font = $tmp.Style.Font
}
$scriptTable.Cell(2,1).Range.Font.Bold = $false
}
$scriptTable.Cell(2,1).Range.NoProofing = $true
# -2 = Table, 1 = Below
$scriptTable.Application.Selection.InsertCaption(-2, ". $caption", $null, 1)
# Add new row after the table
$script:doc.Application.Selection.TypeParagraph()
}
function Get-DocStyle
{
param($styleName)
@@ -787,3 +985,86 @@ function Set-DocObjectStyle
}
$styleSet
}
function Add-DocObjectSettings
{
param($obj, $objectType, $documentedObj)
if($obj."@OData.Type" -eq "#microsoft.graph.deviceManagementScript")
{
if($obj.ScriptContent -and $global:chkWordIncludeScripts.IsChecked -eq $true)
{
$caption = "{1} - {0}" -f $obj.displayName,(Get-LanguageString "WindowsManagement.powerShellScriptObjectName")
Add-DocTableScript $caption $obj.FileName (Get-DocScriptContent $obj.ScriptContent)
}
}
if($obj."@OData.Type" -eq "#microsoft.graph.deviceShellScript")
{
if($obj.ScriptContent -and $global:chkWordIncludeScripts.IsChecked -eq $true)
{
$caption = "{1} - {0}" -f $obj.displayName,(Get-LanguageString "WindowsManagement.shellScriptObjectName")
Add-DocTableScript $caption $obj.FileName (Get-DocScriptContent $obj.ScriptContent)
}
}
elseif($obj."@OData.Type" -eq "#microsoft.graph.deviceHealthScript")
{
if($obj.detectionScriptContent)
{
$caption = Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label"
$header = "{1} - {0}" -f $obj.displayName,$caption
Add-DocTableScript $header $caption (Get-DocScriptContent $obj.detectionScriptContent)
}
if($obj.remediationScriptContent)
{
$caption = Get-LanguageString "ProactiveRemediations.Create.Settings.RemediationScriptMultiLineTextBox.label"
$header = "{1} - {0}" -f $obj.displayName,$caption
Add-DocTableScript $header $caption (Get-DocScriptContent $obj.remediationScriptContent)
}
}
elseif($obj."@OData.Type" -eq "#microsoft.graph.win32LobApp")
{
foreach($rule in ($obj.requirementRules | Where { $_.'@OData.Type' -eq "#microsoft.graph.win32LobAppPowerShellScriptRequirement" } ))
{
$caption = "{0} - {1}" -f @($obj.displayName, "Requirement script")
Add-DocTableScript $caption $rule.displayName (Get-DocScriptContent $rule.scriptContent)
}
foreach($rule in ($obj.detectionRules | Where { $_.'@OData.Type' -eq "#microsoft.graph.win32LobAppPowerShellScriptDetection" } ))
{
$caption = "{0} - {1}" -f @($obj.displayName,(Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label"))
Add-DocTableScript $caption (Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label") (Get-DocScriptContent $rule.scriptContent)
}
}
}
function Get-DocScriptContent
{
param($encodeContent)
if(-not $encodeContent) { return }
try
{
$scriptContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($encodeContent))
if($global:chkWordExcludeScriptSignature.IsChecked -eq $true)
{
$x = $scriptContent.IndexOf("# SIG # Begin signature block")
if($x -gt 0)
{
$scriptContent = $scriptContent.SubString(0,$x)
$scriptContent = $scriptContent + "# SIG # Begin signature block`nSignature data excluded..."
}
}
$scriptContent
}
catch
{
}
}
+218 -35
View File
@@ -11,7 +11,7 @@ This module is for the Endpoint Manager/Intune View. It manages Export/Import/Co
#>
function Get-ModuleVersion
{
'3.1.12'
'3.4.0'
}
function Invoke-InitializeModule
@@ -74,6 +74,7 @@ function Invoke-InitializeModule
SubPath = "EndpointManager"
}) "EndpointManager"
$viewPanel = Get-XamlObject ($global:AppRootFolder + "\Xaml\EndpointManagerPanel.xaml") -AddVariables
Set-EMViewPanel $viewPanel
@@ -84,12 +85,13 @@ function Invoke-InitializeModule
Description = "Manages Intune environments. This view can be used for copying objects in an Intune environment. It can also be used for backing up an entire Intune environment and cloning the Intune environment into another tenant."
ID="IntuneGraphAPI"
ViewPanel = $viewPanel
AuthenticationID = "MSAL"
ItemChanged = { Show-GraphObjects; Invoke-ModuleFunction "Invoke-GraphObjectsChanged"; Write-Status ""}
Deactivating = { Invoke-EMDeactivateView }
Activating = { Invoke-EMActivatingView }
Authentication = (Get-MSALAuthenticationObject)
Authenticate = { Invoke-EMAuthenticateToMSAL }
AppInfo = (Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547")
AppInfo = (Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" "EM")
SaveSettings = { Invoke-EMSaveSettings }
Permissions = @()
@@ -223,6 +225,7 @@ function Invoke-InitializeModule
Icon = "Branding"
SkipRemoveProperties = @('Id')
GroupId = "Azure"
SkipAddIDOnExport = $true
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -236,8 +239,9 @@ function Invoke-InitializeModule
PreReplaceCommand = { Start-PreReplaceEnrollmentRestrictions @args } # Note: Uses same PreReplaceCommand as restrictions
PostReplaceCommand = { Start-PostReplaceEnrollmentRestrictions @args } # Note: Uses same PostReplaceCommand as restrictions
PreFilesImportCommand = { Start-PreFilesImportEnrollmentRestrictions @args } # Note: Uses same PreFilesImportCommand as restrictions
PostListCommand = { Start-PostListESP @args }
#PreUpdateCommand = { Start-PreUpdateEnrollmentRestrictions @args } # Note: Uses same PreUpdateCommand as restrictions
QUERYLIST = "`$filter=endsWith(id,'Windows10EnrollmentCompletionPageConfiguration')"
#QUERYLIST = "`$filter=endsWith(id,'Windows10EnrollmentCompletionPageConfiguration')"
Permissons=@("DeviceManagementServiceConfig.ReadWrite.All")
SkipRemoveProperties = @('Id')
AssignmentsType = "enrollmentConfigurationAssignments"
@@ -250,19 +254,21 @@ function Invoke-InitializeModule
Id = "EnrollmentRestrictions"
API = "/deviceManagement/deviceEnrollmentConfigurations"
ViewID = "IntuneGraphAPI"
QUERYLIST = "`$filter=not endsWith(id,'Windows10EnrollmentCompletionPageConfiguration')"
#QUERYLIST = "`$filter=not endsWith(id,'Windows10EnrollmentCompletionPageConfiguration')"
PostExportCommand = { Start-PostExportEnrollmentRestrictions @args }
PreImportCommand = { Start-PreImportEnrollmentRestrictions @args }
PreDeleteCommand = { Start-PreDeleteEnrollmentRestrictions @args }
PreReplaceCommand = { Start-PreReplaceEnrollmentRestrictions @args }
PostReplaceCommand = { Start-PostReplaceEnrollmentRestrictions @args }
PreFilesImportCommand = { Start-PreFilesImportEnrollmentRestrictions @args }
PostListCommand = { Start-PostListEnrollmentRestrictions @args }
#PreUpdateCommand = { Start-PreUpdateEnrollmentRestrictions @args }
PropertiesToRemoveForUpdate = @('priority')
Permissons=@("DeviceManagementServiceConfig.ReadWrite.All")
SkipRemoveProperties = @('Id')
AssignmentsType = "enrollmentConfigurationAssignments"
GroupId = "EnrollmentRestrictions"
ViewProperties = @("displayName","platformType","description","Id")
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -402,8 +408,10 @@ function Invoke-InitializeModule
Expand="categories,assignments" # ODataMetadata is set to minimal so assignments can't be autodetected
ODataMetadata="minimal" # categories property not supported with ODataMetadata full
PostFileImportCommand = { Start-PostFileImportApplications @args }
PostCopyCommand = { Start-PostCopyApplications @args }
PreUpdateCommand = { Start-PreUpdateApplication @args }
PreImportCommand = { Start-PreImportCommandApplication @args }
DetailExtension = { Add-DetailExtensionApplications @args }
GroupId = "Apps"
})
@@ -606,7 +614,7 @@ function Invoke-InitializeModule
function Invoke-EMAuthenticateToMSAL
{
$global:EMViewObject.AppInfo = Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
$global:EMViewObject.AppInfo = Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" "EM"
Set-MSALCurrentApp $global:EMViewObject.AppInfo
& $global:msalAuthenticator.Login -Account (?? $global:MSALToken.Account.UserName (Get-Setting "" "LastLoggedOnUser"))
}
@@ -622,7 +630,7 @@ function Invoke-EMActivatingView
Show-MSALError
# Refresh values in case they have changed
$global:EMViewObject.AppInfo = (Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547")
$global:EMViewObject.AppInfo = (Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" "EM")
if(-not $global:EMViewObject.Authentication)
{
$global:EMViewObject.Authentication = Get-MSALAuthenticationObject
@@ -647,6 +655,16 @@ function Invoke-EMSaveSettings
Write-Status ""
}
Set-EMUIStatus
}
function Invoke-GraphAuthenticationUpdated
{
Set-EMUIStatus
}
function Set-EMUIStatus
{
# Hide/Show Delete button
$allowDelete = Get-SettingValue "EMAllowDelete"
$global:btnDelete.Visibility = (?: ($allowDelete -eq $true) "Visible" "Collapsed")
@@ -710,9 +728,7 @@ function Set-EMViewPanel
Set-XamlProperty $panel "btnDelete" "Visibility" (?: ($allowDelete -eq $true) "Visible" "Collapsed")
$global:dgObjects.add_selectionChanged({
Set-XamlProperty $this.Parent "btnView" "IsEnabled" (?: ($null -eq $global:dgObjects.SelectedItem) $false $true)
Set-XamlProperty $this.Parent "btnCopy" "IsEnabled" (?: ($null -eq $global:dgObjects.SelectedItem) $false $true)
Set-XamlProperty $this.Parent "btnDelete" "IsEnabled" (?: ($null -eq $global:dgObjects.SelectedItem -and $global:curObjectType.AllowDelete -ne $false) $false $true)
Invoke-ModuleFunction "Invoke-EMSelectedItemsChanged"
})
# ToDo: Move this to the view object
@@ -749,11 +765,39 @@ function Set-EMViewPanel
Write-Status ""
})
}
$global:btnLoadAllPages.add_click({
Write-Status "Loading $($global:curObjectType.Title) objects"
$graphObjects = @(Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -AllPages)
$graphObjects | ForEach-Object { $global:dgObjects.ItemsSource.AddNewItem($_) | Out-Null }
$global:dgObjects.ItemsSource.CommitNew()
Set-GraphPagesButtonStatus
Invoke-FilterBoxChanged $global:txtFilter -ForceUpdate
Write-Status ""
})
$global:btnLoadNextPage.add_click({
Write-Status "Loading $($global:curObjectType.Title) objects"
$graphObjects = @(Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -SinglePage)
$graphObjects | ForEach-Object { $global:dgObjects.ItemsSource.AddNewItem($_) | Out-Null }
$global:dgObjects.ItemsSource.CommitNew()
Set-GraphPagesButtonStatus
Invoke-FilterBoxChanged $global:txtFilter -ForceUpdate
Write-Status ""
})
}
function Invoke-EMSelectedItemsChanged
{
$hasSelectedItems = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true) -or ($null -ne $global:dgObjects.SelectedItem)
Set-XamlProperty $global:dgObjects.Parent "btnView" "IsEnabled" $hasSelectedItems #(?: ($null -eq ($global:dgObjects.SelectedItem)) $false $true)
Set-XamlProperty $global:dgObjects.Parent "btnCopy" "IsEnabled" $hasSelectedItems #(?: ($null -eq $global:dgObjects.SelectedItem) $false $true)
Set-XamlProperty $global:dgObjects.Parent "btnDelete" "IsEnabled" $hasSelectedItems #(?: ($null -eq $global:dgObjects.SelectedItem -and $global:curObjectType.AllowDelete -ne $false) $false $true)
}
function Invoke-FilterBoxChanged
{
param($txtBox)
param($txtBox,[switch]$ForceUpdate)
$filter = $null
@@ -763,10 +807,17 @@ function Invoke-FilterBoxChanged
$txtBox.Tag = 1
$txtBox.Text = "Filter"
$txtBox.Foreground="Lightgray"
}
elseif($ForceUpdate -eq $true)
{
$dgObjects.ItemsSource.Filter = $dgObjects.ItemsSource.Filter
}
elseif($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false)
{
}
else
{
if($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false) { return }
$txtBox.FontStyle = "Normal"
$txtBox.Tag = $null
$txtBox.Foreground="Black"
@@ -788,11 +839,9 @@ function Invoke-FilterBoxChanged
}
}
if($dgObjects.ItemsSource -is [System.Windows.Data.ListCollectionView])
if($dgObjects.ItemsSource -is [System.Windows.Data.ListCollectionView] -and $txtBox.IsFocused -eq $true)
{
# This causes odd behaviour with focus e.g. and item has to be clicked twice to be selected
$dgObjects.ItemsSource.Filter = $filter
$dgObjects.ItemsSource.Refresh()
}
$allObjectsCount = 0
@@ -857,9 +906,15 @@ function Start-PostExportEndpointSecurity
{
param($obj, $objectType, $path)
$fileName = (Get-GraphObjectName $obj $objectType)
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
{
$fileName = ($fileName + "_" + $obj.Id)
}
$settings = Invoke-GraphRequest -Url "$($objectType.API)/$($obj.id)/settings"
$settingsJson = "{ `"settings`": $((ConvertTo-Json $settings.value -Depth 20 ))`n}"
$fileName = "$path\$((Remove-InvalidFileNameChars (Get-GraphObjectName $obj $objectType)))_Settings.json"
$fileName = "$path\$((Remove-InvalidFileNameChars $fileName))_Settings.json"
$settingsJson | Out-File -LiteralPath $fileName -Force
}
@@ -1130,8 +1185,8 @@ function Start-PostGetIntuneBranding
foreach($imgType in @("themeColorLogo","lightBackgroundLogo","landingPageCustomizedImage"))
{
Write-LogDebug "Get $imgType for $($obj.profileName)"
$imgJson = Invoke-GraphRequest -Url "$($objectType.API)/$($obj.Id)/$imgType"
Write-LogDebug "Get $imgType for $($obj.Object.profileName)"
$imgJson = Invoke-GraphRequest -Url "$($objectType.API)/$($obj.Object.Id)/$imgType"
if($imgJson.Value)
{
$obj.Object.$imgType = $imgJson
@@ -1272,10 +1327,13 @@ function Add-ScriptExportExtensions
{
param($form, $buttonPanel, $index = 0)
$ctrl = $form.FindName("chkExportScript")
if(-not $ctrl)
{
$xaml = @"
<StackPanel $($global:wpfNS) Orientation="Horizontal" Margin="0,0,5,0">
<Label Content="Export script" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Export the powershell script to a ps1 file" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Export the script associated with PowerShell or Shell profiles" />
</StackPanel>
"@
$label = [Windows.Markup.XamlReader]::Parse($xaml)
@@ -1283,9 +1341,11 @@ function Add-ScriptExportExtensions
$global:chkExportScript = [System.Windows.Controls.CheckBox]::new()
$global:chkExportScript.IsChecked = $true
$global:chkExportScript.VerticalAlignment = "Center"
$global:chkExportScript.Name = "chkExportScript"
@($label, $global:chkExportScript)
}
}
function Start-PostExportScripts
{
@@ -1622,14 +1682,38 @@ function Start-PreImportAssignmentsAppConfiguration
#endregon
#region Applications
function Start-PostCopyApplications
{
param($objCopyFrom, $objNew, $objectType)
Start-ImportApp $objNew
Write-Status ""
}
function Start-PostFileImportApplications
{
param($obj, $objectType, $file)
$tmpObj = Get-Content -LiteralPath $file | ConvertFrom-Json
if(-not $tmpObj.'@odata.type') { return }
if(-not ($obj.PSObject.Properties | Where Name -eq '@odata.type'))
{
# Add @odata.type property if it is missing. Required by app package import
$obj | Add-Member -MemberType NoteProperty -Name '@odata.type' -Value $objectType.'@odata.type'
}
Start-ImportApp $obj
}
function local:Start-ImportApp
{
param($obj, $packageFile = $null)
if(-not $obj.'@odata.type') { return }
if($null -eq $packageFile)
{
$pkgPath = Get-SettingValue "EMIntuneAppPackages"
if(-not $pkgPath -or [IO.Directory]::Exists($pkgPath) -eq $false)
@@ -1639,23 +1723,19 @@ function Start-PostFileImportApplications
}
$packageFile = "$($pkgPath)\$($obj.fileName)"
}
$fi = [IO.FileInfo]$packageFile
if([IO.File]::Exists($packageFile) -eq $false)
if($fi.Exists -eq $false)
{
Write-LogDebug "Package source file $packageFile not found" 2
Write-LogDebug "Package source file $($fi.FullName) not found" 2
return
}
Write-Status "Import appliction package file $($obj.fileName)"
Write-Log "Import application file '$($packageFile)' for $($obj.displayName)"
Write-Status "Import appliction package file $($fi.FullName)"
Write-Log "Import application file '$($($fi.FullName))' for $($obj.displayName)"
if(-not ($obj.PSObject.Properties | Where Name -eq '@odata.type'))
{
# Add @odata.type property if it is missing. Required by app package import
$obj | Add-Member -MemberType NoteProperty -Name '@odata.type' -Value $tmpObj.'@odata.type'
}
$appType = $tmpObj.'@odata.type'.Trim('#')
$appType = $obj.'@odata.type'.Trim('#')
if($appType -eq "microsoft.graph.win32LobApp")
{
@@ -1710,6 +1790,55 @@ function Start-PreImportCommandApplication
}
}
function Add-DetailExtensionApplications
{
param($form, $buttonPanel, $index = 0)
$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($global:dgObjects.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$($global:dgObjects.SelectedItem.Object.displayName)", "Update app file?", "YesNo", "Warning")) -ne "Yes")
{
return
}
}
$pkgPath = Get-SettingValue "EMIntuneAppPackages"
$of = [System.Windows.Forms.OpenFileDialog]::new()
$of.FileName = $global:dgObjects.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 $($global:dgObjects.SelectedItem.Object.displayName) file"
Start-ImportApp $global:dgObjects.SelectedItem.Object $of.FileName
Write-Status ""
}
})
$tmp = $form.FindName($buttonPanel)
if($tmp)
{
$tmp.Children.Insert($index, $btnUpload)
}
}
#endregion
#region Group Policy/Administrative Templates functions
@@ -1781,9 +1910,23 @@ function Start-PostExportAdministrativeTemplate
{
param($obj, $objectType, $path)
$fileName = (Get-GraphObjectName $obj $objectType)
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
{
$fileName = ($fileName + "_" + $obj.Id)
}
# Collect and save all the settings of the Administrative Templates profile
if($obj.definitionValues)
{
$settings = $obj.definitionValues
}
else
{
$settings = Get-GPOObjectSettings $obj
$fileName = "$path\$((Remove-InvalidFileNameChars (Get-GraphObjectName $obj $objectType)))_Settings.json"
}
$fileName = "$path\$((Remove-InvalidFileNameChars $fileName))_Settings.json"
ConvertTo-Json $settings -Depth 20 | Out-File -LiteralPath $fileName -Force
}
@@ -1846,7 +1989,7 @@ function Start-PostGetAdministrativeTemplate
$obj.Object | Add-Member Noteproperty -Name "definitionValues" -Value $definitionValues -Force
}
<#
# Leave for now. This only loads the configured defenition values and not the values specified.
# Leave for now. This only loads the configured definition values and not the values specified.
# That would require enumerating each definition value which takes time.
$definitionValues = (Invoke-GraphRequest "deviceManagement/groupPolicyConfigurations('$($obj.Id)')/definitionValues?`$expand=definition(`$select=id,classType,displayName,policyType,groupPolicyCategoryId)" -ODataMetadata "minimal").value
@@ -2013,8 +2156,21 @@ function Start-PostExportRoleDefinitions
{
param($obj, $objectType, $path)
$fileName = "$path\$((Remove-InvalidFileNameChars (Get-GraphObjectName $obj $objectType))).json"
$fileName = (Get-GraphObjectName $obj $objectType)
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
{
$fileName = ($fileName + "_" + $obj.Id)
}
$tmpObj = $null
$fileName = "$path\$((Remove-InvalidFileNameChars $fileName)).json"
if([IO.File]::Exists($fileName))
{
$tmpObj = Get-Content -LiteralPath $fileName | ConvertFrom-Json
}
else
{
Write-Log "File not found: $fileName. Could not get role assignments" 3
}
if(($tmpObj.RoleAssignments | measure).Count -gt 0)
{
@@ -2164,6 +2320,14 @@ function Start-PostExportESP
Save-EMDefaultPolicy $obj $objectType $path
}
}
function Start-PostListESP
{
param($objList, $objectType)
# endswith not working so filter them out
$objList | Where { $_.Object.'@OData.Type' -eq '#microsoft.graph.windows10EnrollmentCompletionPageConfiguration' }
}
#endregion
#region Enrollment Restriction functions
@@ -2249,6 +2413,19 @@ function Start-PreUpdateEnrollmentRestrictions
Remove-Property $obj "priority"
}
function Start-PostListEnrollmentRestrictions
{
param($objList, $objectType)
# endswith not working so filter them out
$objList | Where {
($_.Object.'@OData.Type' -eq '#microsoft.graph.deviceEnrollmentPlatformRestrictionConfiguration' -or
$_.Object.'@OData.Type' -eq '#microsoft.graph.deviceEnrollmentLimitConfiguration' -or
$_.Object.'@OData.Type' -eq '#microsoft.graph.deviceEnrollmentPlatformRestrictionsConfiguration') -and
$_.Object.id -notlike "*_PlatformRestrictions" -and $_.Object.platformType -ne "WindowsPhone" -and $_.Object.platformType -ne "AndroidAosp"
}
}
#endregion
#region ScopeTags
@@ -2385,10 +2562,15 @@ function Add-EMAssignmentsToExportFile
{
param($obj, $objectType, $path, $Url = "")
$fileName = "$path\$((Remove-InvalidFileNameChars (Get-GraphObjectName $obj $objectType))).json"
$fileName = (Get-GraphObjectName $obj $objectType)
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
{
$fileName = ($fileName + "_" + $obj.Id)
}
$fileName = "$path\$((Remove-InvalidFileNameChars $fileName)).json"
if([IO.File]::Exists($fileName) -eq $false)
{
Write-Log "File not found: $fileName. Could not add assignments" 3
Write-Log "File not found: $fileName. Could not add assignments to file" 3
return
}
$tmpObj = Get-Content -LiteralPath $fileName | ConvertFrom-Json
@@ -2514,6 +2696,7 @@ function Add-ConditionalAccessImportExtensions
$global:cbImportCAState.Margin="0,5,0,0"
$global:cbImportCAState.HorizontalAlignment="Left"
$global:cbImportCAState.Width=250
$global:cbImportCAState.Name = "cbImportCAState"
@($label, $global:cbImportCAState)
}
+4 -3
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.3'
'3.1.4'
}
function Invoke-InitializeModule
@@ -21,11 +21,12 @@ function Invoke-InitializeModule
Description = "Displays read-only information in Intune."
ID = "EMInfoGraphAPI"
ViewPanel = $viewPanel
AuthenticationID = "MSAL"
ItemChanged = { Show-GraphObjects; Invoke-ModuleFunction "Invoke-GraphObjectsChanged"; Write-Status ""}
Activating = { Invoke-EMInfoActivatingView }
Authentication = (Get-MSALAuthenticationObject)
Authenticate = { Invoke-EMInfoAuthenticateToMSAL }
AppInfo = (Get-GraphAppInfo "EM" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547")
AppInfo = (Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" "EM")
SaveSettings = { Invoke-EMSaveSettings }
Permissions = @()
})
@@ -95,7 +96,7 @@ function Invoke-EMInfoActivatingView
function Invoke-EMInfoAuthenticateToMSAL
{
$global:EMInfoViewObject.AppInfo = Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
$global:EMInfoViewObject.AppInfo = Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" "EM"
Set-MSALCurrentApp $global:EMInfoViewObject.AppInfo
$usr = (?? $global:MSALToken.Account.UserName (Get-Setting "" "LastLoggedOnUser"))
if($usr)
+14 -4
View File
@@ -10,7 +10,7 @@ This module manages Application objects in Intune e.g. uploading application fil
#>
function Get-ModuleVersion
{
'3.1.1'
'3.4.0'
}
#########################################################################################
@@ -42,6 +42,12 @@ function Get-MSIFileInformation
$values = @{}
if(-not $MSIFile) { return }
$fi = [IO.FileInfo]$MSIFile
if($fi.Extension -ne ".msi") { return }
try
{
$wiObj = New-Object -ComObject WindowsInstaller.Installer
@@ -203,6 +209,8 @@ function Copy-Win32LOBPackage
Remove-Item -Path $tmpFile
$fi = [IO.FileInfo]$intunewinFile
# Get encryption info from detection.xml and build encryptionInfo object
$encryptionInfo = @{}
@@ -216,7 +224,7 @@ function Copy-Win32LOBPackage
$tmpIntunewinPath = ([IO.Path]::GetTempPath() + [Guid]::NewGuid().ToString("n"))
mkdir $tmpIntunewinPath | Out-Null
$tmpIntunewinFile = $tmpIntunewinPath + "\" + $DetectionXML.ApplicationInfo.FileName
$tmpIntunewinFile = $tmpIntunewinPath + "\" + $fi.Name
# Extract the encrypted file from the intunewin file
Export-IntunewinFileObject $intunewinFile $DetectionXML.ApplicationInfo.FileName $tmpIntunewinFile
@@ -244,8 +252,8 @@ function Add-FileToIntuneApp
{
param($appId, $appType, $appFile, $fileBody)
$contentVersion = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions"
$contentVersionId = $contentVersion.value[0].id
$contentVersion = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions" -HttpMethod POST -Content "{}"
$contentVersionId = $contentVersion.id
$fileObj = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files" -HttpMethod POST -Content (ConvertTo-Json $fileBody -Depth 5)
if(-not $fileObj)
@@ -268,10 +276,12 @@ function Add-FileToIntuneApp
Wait-IntuneFileState "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files/$($fileObj.Id)" "CommitFile"
$fiUpload = [IO.FileInfo]$appFile
# Commit the content version
$commitAppBody = @{
"@odata.type" = "#$appType"
committedContentVersion = $contentVersionId
fileName = $fiUpload.Name
}
$reponse = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId" -HttpMethod PATCH -Content (ConvertTo-Json $commitAppBody -Depth 5)
+8 -4
View File
@@ -9,7 +9,7 @@ Module for listing Intune assignments
#>
function Get-ModuleVersion
{
'1.0.1'
'1.0.3'
}
function Invoke-InitializeModule
@@ -170,6 +170,7 @@ function Get-EMIntuneAssignments
}
else
{
$assignmentObj = $assignment.target.groupId
Write-Warning "Could not find a group with ID $($assignment.target.groupId)"
}
$included = $assignment.target.'@odata.type' -eq "#microsoft.graph.groupAssignmentTarget"
@@ -230,10 +231,13 @@ function Invoke-IntueAssignmentFilterBoxChanged
$txtBox.Tag = 1
$txtBox.Text = "Filter"
$txtBox.Foreground="Lightgray"
}
elseif($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false)
{
}
else
{
if($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false) { return }
$txtBox.FontStyle = "Normal"
$txtBox.Tag = $null
$txtBox.Foreground="Black"
@@ -249,10 +253,10 @@ function Invoke-IntueAssignmentFilterBoxChanged
}
}
if($dgObject.ItemsSource -is [System.Windows.Data.ListCollectionView])
if($dgObject.ItemsSource -is [System.Windows.Data.ListCollectionView] -and $txtBox.IsFocused -eq $true)
{
# This causes odd behaviour with focus e.g. and item has to be clicked twice to be selected
$dgObject.ItemsSource.Filter = $filter
$dgObject.ItemsSource.Refresh()
#$dgObject.ItemsSource.Refresh()
}
}
+8 -4
View File
@@ -22,7 +22,7 @@ $global:EMToolsViewObject = $null
function Get-ModuleVersion
{
'1.0.1'
'1.0.3'
}
function Invoke-InitializeModule
@@ -76,6 +76,7 @@ function Add-EMToolsViewItem
Title = "Intune Tools"
Description = "Additional tools for managing Intune"
ID = "EMTools"
AuthenticationID = "MSAL"
ViewPanel = $viewPanel
ItemChanged = { Show-EMTool }
Activating = { Invoke-EMToolsActivatingView }
@@ -889,10 +890,13 @@ function Invoke-ADMXFilterPolicies
$txtBox.Tag = 1
$txtBox.Text = "Filter"
$txtBox.Foreground="Lightgray"
}
elseif($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false)
{
}
else
{
if($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false) { return }
$txtBox.FontStyle = "Normal"
$txtBox.Tag = $null
$txtBox.Foreground="Black"
@@ -907,11 +911,11 @@ function Invoke-ADMXFilterPolicies
}
}
if($global:dgADMXSettings.ItemsSource -is [System.Windows.Data.ListCollectionView])
if($global:dgADMXSettings.ItemsSource -is [System.Windows.Data.ListCollectionView] -and $txtBox.IsFocused -eq $true)
{
# This causes odd behaviour with focus e.g. and item has to be clicked twice to be selected
$global:dgADMXSettings.ItemsSource.Filter = $filter
$global:dgADMXSettings.ItemsSource.Refresh()
#$global:dgADMXSettings.ItemsSource.Refresh()
}
}
+387 -68
View File
@@ -10,7 +10,7 @@ This module manages Authentication for the application with MSAL. It is also res
#>
function Get-ModuleVersion
{
'3.0.5'
'3.4.0'
}
$global:msalAuthenticator = $null
@@ -18,10 +18,47 @@ function Invoke-InitializeModule
{
$script:MSALAllApps = @()
$global:MSALToken = $null
$global:MSALAuthority = $null
$global:MSALTenantId = $null
$script:AccessableTenants = $null
$global:SkipTokenCacheHelperEx = $null
$script:lstAADEnvironments = @(
[PSCustomObject]@{
Name = "Azure AD Public"
Value = "public"
URL = "login.microsoftonline.com"
},
[PSCustomObject]@{
Name = "Azure AD US Government"
Value = "usGov"
URL = "login.microsoftonline.us"
},
[PSCustomObject]@{
Name = "Azure AD China"
Value = "china"
URL = "login.partner.microsoftonline.cn"
GraphURL = "https://microsoftgraph.chinacloudapi.cn"
}
)
$script:lstGCCEnvironments = @(
[PSCustomObject]@{
Name = "GCC"
Value = "gcc"
URL = "graph.microsoft.com"
},
[PSCustomObject]@{
Name = "GCC High"
Value = "gcgHigh"
URL = "graph.microsoft.us"
},
[PSCustomObject]@{
Name = "GCC DoD"
Value = "gccDoD"
URL = "dod-graph.microsoft.us"
}
)
$global:appSettingSections += (New-Object PSObject -Property @{
Title = "MSAL"
Id = "MSAL"
@@ -56,7 +93,7 @@ function Invoke-InitializeModule
Title = "Use Default Permissions"
Key = "UseDefaultPermissions"
Type = "Boolean"
DefaultValue = $false
DefaultValue = $true
Description = "Default permissions of the selected app will be used when logging on. Some objects might not be accessable"
}) "MSAL"
@@ -68,6 +105,30 @@ function Invoke-InitializeModule
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-SettingsObject (New-Object PSObject -Property @{
Title = "Azure Login"
Key = "AzureLogin"
Type = "List"
ItemsSource = $script:lstAADEnvironments
DefaultValue = "public"
}) "MSAL"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "GCC Environment"
Key = "GCCEnvironment"
Type = "List"
ItemsSource = $script:lstGCCEnvironments
DefaultValue = "gcc"
}) "MSAL"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Sort Account List"
Key = "SortAccountList"
Type = "Boolean"
DefaultValue = $false
Description = "Sort the list of cached accounts based on user name. Updated at restart or account change"
}) "MSAL"
Add-MSALPrereq
#$script:MSALDLLMissing = $true #!!!!
@@ -79,6 +140,7 @@ function Get-MSALAuthenticationObject
{
$global:msalAuthenticator = New-Object PSObject -Property @{
Title = "MSAL"
ID = "MSAL"
SilentLogin = { Connect-MSALUser -Silent @args; }
Login = { Connect-MSALUser @args }
Logout = { Disconnect-MSALUser }
@@ -91,9 +153,20 @@ function Get-MSALAuthenticationObject
$global:msalAuthenticator
}
function Invoke-SettingsUpdated
{
Initialize-MSALSettings
}
function Initialize-MSALSettings
{
}
function Clear-MSALCurentUserVaiables
{
$global:MSALAuthority = $null
$global:MSALTenantId = $null
$global:MSALGraphEnvironment = $null
}
function Get-MSALCurrentApp
@@ -108,13 +181,60 @@ function Set-MSALCurrentApp
$global:appObj = $appInfoObj
}
function Set-MSALGraphEnvironment
{
param($user, $tenantId)
if($global:MSALGraphEnvironment)
{
return
}
$graphEnv = "graph.microsoft.com"
if($user)
{
$curAADEnv = $script:lstAADEnvironments | Where URL -eq $user.Environment
}
else
{
$loginValue = Get-SettingValue "AzureLogin" "public" -TenantID (?? $tenantId $loginHint.user.TenantId)
$curAADEnv = $script:lstAADEnvironments | Where value -eq $loginValue
}
if($curAADEnv.Value -eq "usGov")
{
$gccEnv = Get-SettingValue "GCCEnvironment" "gcc" -TenantID (?? $tenantId $loginHint.user.TenantId)
if($gccEnv)
{
$GCCEnvObj = $script:lstGCCEnvironments | Where Value -eq $gccEnv
if($GCCEnvObj.URL)
{
$graphEnv = $GCCEnvObj.URL
}
else
{
Write-Log "Could not find GCC environment based on $gccEnv. Default will be used" 2
}
}
}
elseif($cuAADEnv.GraphURL)
{
$graphEnv = $cuAADEnv.GraphURL
}
Write-Log "Use Graph environment: $graphEnv"
$global:MSALGraphEnvironment = $graphEnv
}
function Get-MSALUserInfo
{
if($global:MSALToken)
{
Write-Log "Get current user"
$tmpMe = MSGraph\Invoke-GraphRequest -Url "ME" -SkipAuthentication -ODataMetadata "Skip"
if($tmpMe.creationType -ne "Invitation")
if($null -ne $tmpMe -and $tmpMe.creationType -ne "Invitation")
{
### Only get user info from home tenant
$global:Me = $tmpMe
@@ -125,6 +245,11 @@ function Get-MSALUserInfo
Write-Log "Get organization info"
$global:Organization = (MSGraph\Invoke-GraphRequest -Url "Organization" -SkipAuthentication -ODataMetadata "Skip").Value
if($global:Organization)
{
if($global:Organization -is [array]) { $global:Organization = $global:Organization[0]}
Save-Setting $global:Organization.Id "_Name" $global:Organization.displayName
}
}
else
{
@@ -217,6 +342,12 @@ function Install-MSALDependencyModule
{
param($moduleToInstall, $button)
if($global:hideUI -eq $true)
{
Write-Log "Cannot install MSAL module in Silent mode"
return
}
$forceUserInstallation = $false
if($global:chkCurrentUser.IsChecked -eq $false -and (Get-IsAdmin) -eq $false)
@@ -416,6 +547,38 @@ function Add-MSALPrereq
}
}
function Connect-MSALClientApp
{
param($clientId, $tenantId, $secret, $Certificate)
$scopes = [String[]]".default"
if(-not $script:MSALApp)
{
$authority = "https://login.microsoftonline.com/$tenantId"
#$redirectUri = "http://localhost"
if($secret)
{
$ClientApplicationBuilder = [Microsoft.Identity.Client.ConfidentialClientApplicationBuilder]::Create($clientId).WithClientSecret($ClientSecret).WithAuthority([URI]::new($authority)) #.WithRedirectUri($redirectUri)
}
elseif($Certificate)
{
$ClientApplicationBuilder = [Microsoft.Identity.Client.ConfidentialClientApplicationBuilder]::Create($clientId).WithCertificate($ClientSecret).WithAuthority([URI]::new($authority)) #.WithRedirectUri($redirectUri)
}
else
{
return
}
$script:MSALApp = $ClientApplicationBuilder.Build()
}
if($script:MSALApp)
{
$accessTokenRequest = $script:MSALApp.AcquireTokenForClient($scopes)
$global:MSALToken = Get-MsalAuthenticationToken $accessTokenRequest
}
}
function Get-MsalAuthenticationToken
{
param($aquireTokenObj)
@@ -485,19 +648,42 @@ function Get-MsalAuthenticationToken
$authResult
}
function Get-MSALLoginEnvironment
{
$loginValue = Get-SettingValue "AzureLogin" "public"
$loginEnv = $script:lstAADEnvironments | Where value -eq $loginValue
return (?? $loginEnv.Environment "login.microsoftonline.com")
}
function Get-MSALApp
{
param($appInfo)
param($appInfo, $loginHint)
$msalApp = $script:MSALAllApps | Where { $_.ClientId -eq $appInfo.ClientID -and (-not $appInfo.RedirectUri -or $_.AppConfig.RedirectUri -eq $appInfo.RedirectUri)}
if(-not $msalApp)
$tenant = ?? $appInfo.TenantId "organizations"
if($loginHint.Environment)
{
Write-Log "Add MSAL App $($appInfo.ClientID) $((?? $appInfo.TenantId $appInfo.Authority))"
$authority = "https://$($loginHint.Environment)/$tenant/"
}
elseif($appInfo.Authority)
{
$authority = $appInfo.Authority
}
else
{
$authority = "https://$((Get-MSALLoginEnvironment))/$tenant/"
}
if(-not $msalApp -or $msalApp.Authority -ne $authority)
{
Write-Log "Add MSAL App $($appInfo.ClientID) $authority"
$appBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($appInfo.ClientID)
if($appInfo.TenantId) { [void]$appBuilder.WithAuthority("https://login.microsoftonline.com/$($appInfo.TenantId)/") }
elseif ($appInfo.Authority) { [void]$appBuilder.WithAuthority($appInfo.Authority) }
[void]$appBuilder.WithAuthority($authority)
#if($appInfo.TenantId) { [void]$appBuilder.WithAuthority("https://$((?? $loginHint.Environment (Get-MSALLoginEnvironment)))/$($appInfo.TenantId)/") }
#elseif ($appInfo.Authority) { [void]$appBuilder.WithAuthority($appInfo.Authority) }
if($appInfo.RedirectUri) { [void]$appBuilder.WithRedirectUri($appInfo.RedirectUri) }
[void] $appBuilder.WithClientName("CloudAPIPowerShellManagement")
@@ -514,6 +700,18 @@ function Get-MSALApp
return $msalApp
}
function Get-MSALAppAuthority
{
try
{
([uri]$global:MSALApp.Authority).Authority
}
catch
{
Get-MSALLoginEnvironment
}
}
function Connect-MSALUser
{
param(
@@ -529,12 +727,35 @@ function Connect-MSALUser
[switch]
$Interactive,
$Account
[switch]
$ClientApp,
$Account,
$Tenant
)
# No login during first time the app is started
if($global:FirstTimeRunning -and $global:MainAppStarted -eq $false) { return }
if($global:hideUI -eq $true)
{
if($global:AzureAppId -and $global:ClientSecret -and $global:TenantId)
{
Connect-MSALClientApp $global:AzureAppId $global:TenantId -secret $global:ClientSecret
}
elseif($global:AzureAppId -and $global:ClientCert -and $global:TenantId)
{
Connect-MSALClientApp $global:AzureAppId $global:TenantId -certificate $global:ClientCert
}
else
{
Write-Log "Azure AppId, Tenant Id and Sercret/Cert must be specified for batch login" 3
}
return
}
Write-LogDebug "Authenticate"
if(-not $global:appObj.ClientId)
@@ -543,11 +764,10 @@ function Connect-MSALUser
return
}
if(-not $global:appObj.TenantId -and -not $global:appObj.Authority)
{
Write-Log "Tenant id/Authority is missing. Cannot authenticate" 3
return
}
#if(-not $global:appObj.TenantId -and -not $global:appObj.Authority)
#{
# Write-Log "Tenant id/Authority is missing. Cannot authenticate" 3
#}
if ($global:SkipTokenCacheHelperEx -ne $true -and -not ("TokenCacheHelperEx" -as [type]))
{
@@ -570,49 +790,23 @@ function Connect-MSALUser
$global:MSALToken = $null
}
if((Get-SettingValue "UseDefaultPermissions") -eq $true -or ($global:currentViewObject.ViewInfo.Permissions | measure).Count -eq 0)
{
[string[]] $Scopes = "https://graph.microsoft.com/.default"
$useDefaultPermissions = $true
}
else
{
#$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"
}
$script:curViewPermissions = $global:currentViewObject.ViewInfo.Permissions
foreach($tmpScope in $script:curViewPermissions)
{
if($reqScopes -notcontains $tmpScope) { $reqScopes += $tmpScope }
}
$Scopes = [String[]]$reqScopes
}
$global:MSALApp = Get-MSALApp $global:appObj
$global:MSALApp = Get-MSALApp $global:appObj $Account
$loginHint = ""
$global:MSALAccounts = $global:MSALApp.GetAccountsAsync().GetAwaiter().GetResult()
if($Account)
{
$loginHint = $global:MSALAccounts | Where UserName -eq $Account
if($global:MSALToken -and $global:MSALToken.Account.UserName -ne $Account)
$userName = ?? $Account.UserName $Account
$loginHint = $global:MSALAccounts | Where UserName -eq $userName
if($global:MSALToken -and $global:MSALToken.Account.UserName -ne $userName)
{
# We're logging in with someone else...
Clear-MSALCurentUserVaiables
$global:MSALToken = $null
}
}
# If we force interactive login the skip setting loginHint to force the user select account
# If we force interactive login then skip setting loginHint to force the user to select account
if(-not $loginHint -and $Interactive -ne $true)
{
if($global:MSALAccounts)
@@ -638,10 +832,47 @@ function Connect-MSALUser
}
}
if($ForceRefresh -eq $true)
{
$global:MSALGraphEnvironment = $null
}
$tenantId = ?? $global:MSALTenantId $global:appObj.TenantId
Set-MSALGraphEnvironment $loginHint $tenantId
$useDefaultPermissions = (Get-SettingValue "UseDefaultPermissions" -TenantID (?? $tenantId $loginHint.HomeAccountId.TenantId))
if($useDefaultPermissions -eq $true -or ($global:currentViewObject.ViewInfo.Permissions | measure).Count -eq 0)
{
[string[]] $Scopes = "https://$($global:MSALGraphEnvironment)/.default"
$useDefaultPermissions = $true
}
else
{
#$Scopes = [string[]]$global:PermissionScope
$reqScopes = [string[]]$global:msalAuthenticator.Permissions
$useDefaultPermissions = $false
$resolveRoles = ((Get-SettingValue "AzureADRoleRead" $false -TenantID (?? $tenantId $loginHint.HomeAccountId.TenantId)) -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"
}
$script:curViewPermissions = $global:currentViewObject.ViewInfo.Permissions
foreach($tmpScope in $script:curViewPermissions)
{
if($reqScopes -notcontains $tmpScope) { $reqScopes += $tmpScope }
}
$Scopes = [String[]]$reqScopes
}
$prompConsent = $false
$authResult = $null
$tenantId = $global:appObj.TenantId
$authority = ?? $global:MSALAuthority $global:appObj.Authority
try
{
@@ -652,8 +883,8 @@ function Connect-MSALUser
{
$aquireTokenObj = $global:MSALApp.AcquireTokenSilent($Scopes, $loginHint)
if($ForceRefresh) { [void]$aquireTokenObj.WithForceRefresh($ForceRefresh) }
if ($tenantId) { [void] $aquireTokenObj.WithAuthority("https://login.microsoftonline.com/$($TenantId)/") }
if ($authority) { [void]$aquireTokenObj.WithAuthority($authority) }
if ($tenantId) { [void]$aquireTokenObj.WithAuthority("https://$((Get-MSALAppAuthority))/$($tenantId)/") }
else { [void]$aquireTokenObj.WithAuthority($global:MSALApp.Authority) }
$authResult = Get-MsalAuthenticationToken $aquireTokenObj
@@ -709,7 +940,10 @@ function Connect-MSALUser
}
}
}
catch {}
catch
{
Write-LogError "Failed to perform silent login" $_.Exception
}
# Interactive login is only allowed once the app has started. Skip if silent login failed during startup
if($global:MainAppStarted -and ((-not $authResult -and $Silent -ne $true) -or $prompConsent))
@@ -726,12 +960,12 @@ function Connect-MSALUser
if ($tenantId)
{
Write-Log "Tenant id: $tenantId"
[void] $aquireTokenObj.WithAuthority("https://login.microsoftonline.com/$tenantId)/")
[void]$aquireTokenObj.WithAuthority("https://$((Get-MSALAppAuthority))/$tenantId/")
}
elseif ($authority)
else
{
Write-Log "Authority: $authority"
[void]$aquireTokenObj.WithAuthority($authority)
Write-Log "Authority: $($global:MSALApp.Authority)"
[void]$aquireTokenObj.WithAuthority($global:MSALApp.Authority)
}
if($loginHintName)
@@ -775,7 +1009,7 @@ function Connect-MSALUser
if($currentLoggedInUserId -ne $authResult.Account.HomeAccountId.Identifier)
{
$script:AccessableTenants = $null
if($authResult -and (Get-Setting "" "GetTenantList" $false) -eq $true)
if($authResult -and (Get-SettingValue "GetTenantList" -TenantID $authResult.Account.HomeAccountId.TenantId) -eq $true)
{
#########################################################################################################
### Get tenant list
@@ -786,8 +1020,8 @@ function Connect-MSALUser
# Can we reuse the app used for login?
$appBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($global:appObj.ClientID)
if($tenantId) { [void]$appBuilder.WithAuthority("https://login.microsoftonline.com/$($tenantId)") }
elseif ($authority) { [void]$appBuilder.WithAuthority($authority) }
if($tenantId) { [void]$appBuilder.WithAuthority("https://$((Get-MSALAppAuthority))/$($tenantId)") }
else { [void]$appBuilder.WithAuthority($global:MSALApp.Authority) }
if($global:appObj.RedirectUri) { [void]$appBuilder.WithRedirectUri($global:appObj.RedirectUri) }
$app = $appBuilder.Build()
@@ -840,10 +1074,79 @@ function Connect-MSALUser
Write-LogDebug "User, tenant or app has changed"
Get-MSALUserInfo
Invoke-MSALCheckObjectViewAccess
Invoke-ModuleFunction "Invoke-GraphAuthenticationUpdated"
}
}
function Invoke-MSALCheckObjectViewAccess
{
foreach($viewObjInfo in ($global:viewObjects | Where { $_.ViewInfo.AuthenticationID -eq "MSAL" }))
{
$viewObjInfo = $global:viewObjects | Where { $_.ViewInfo.Id -eq $global:EMViewObject.Id }
if($viewObjInfo)
{
$accessToken = Get-JWTtoken $global:MSALToken.AccessToken
if($accessToken.Payload.scp)
{
$curPermissions = $accessToken.Payload.scp.Split(" ")
foreach($viewItem in $viewObjInfo.ViewItems)
{
$full = 0
$partial = 0
foreach($permission in $viewItem.Permissons)
{
if($curPermissions -contains $permission)
{
$full++
continue
}
# Check read access
$arrTemp = $permission.Split('.')
if($arrTemp[1] -eq "ReadWrite")
{
$arrTemp[1] = "Read"
$arrTemp -join "."
}
if($curPermissions -contains $permission)
{
$partial++
}
}
$hasAccess = $false
if($viewItem.Permissons.Count -eq $full)
{
$accessType = "Full"
$hasAccess = $true
}
elseif($partial -gt 0)
{
$accessType = "Limited"
}
else
{
$accessType = "None"
}
if(-not ($viewItem.PSObject.Properties | Where Name -eq "@HasPermissions"))
{
$viewItem | Add-Member -NotePropertyName "@HasPermissions" -NotePropertyValue $hasAccess
$viewItem | Add-Member -NotePropertyName "@AccessType" -NotePropertyValue $accessType
}
else
{
$viewItem."@HasPermissions" = $hasAccess
$viewItem."@AccessType" = $accessType
}
}
}
}
}
Show-ViewMenu
}
function Disconnect-MSALUser
{
param($user, [switch]$force, [switch]$PassThru)
@@ -963,7 +1266,9 @@ function Get-MSALProfileEllipse
$icon.Margin = "0,0,5,0"
$grdAccount.Children.Add($icon) | Out-Null
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS>$($account.UserName)<LineBreak/>$($account.HomeAccountId.TenantId)</TextBlock>")
$tenantName = Get-Setting $account.HomeAccountId.TenantId "_Name" $account.HomeAccountId.TenantId
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS>$($account.UserName)<LineBreak/>$($tenantName)</TextBlock>")
$lbObj.SetValue([System.Windows.Controls.Grid]::ColumnProperty,1)
$grdAccount.Children.Add($lbObj) | Out-Null
@@ -977,7 +1282,7 @@ function Get-MSALProfileEllipse
Write-Status "Logging in with $($this.Tag.UserName)"
Hide-Popup
Clear-MSALCurentUserVaiables
Connect-MSALUser -Account $this.Tag.UserName
Connect-MSALUser -Account $this.Tag #!!!.UserName
if($global:curObjectType)
{
@@ -1151,13 +1456,21 @@ function Get-MSALProfileEllipse
[System.Windows.Controls.Canvas]::SetTop($obj,($point.Y + $obj.Tag.ActualHeight))
})
$otherLogins = $global:grdProfileInfo.FindName("grdAccountsAndTenants")
$otherLogins = $global:grdProfileInfo.FindName("grdCachedAccounts")
#########################################################################################################
### Add cached users
#########################################################################################################
if((Get-SettingValue "SortAccountList") -eq $true)
{
$accounts = $global:MSALAccounts | Sort -Property Username
}
else
{
$accounts = $global:MSALAccounts
}
foreach($account in $global:MSALAccounts)
foreach($account in $accounts)
{
# Skip current logged on user
if($global:MSALToken.Account.Username -eq $Account.Username) { continue }
@@ -1186,7 +1499,9 @@ function Get-MSALProfileEllipse
$icon.Margin = "0,0,5,0"
$grdLogin.Children.Add($icon) | Out-Null
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS>$($account.UserName)<LineBreak/>$($account.HomeAccountId.TenantId)</TextBlock>")
$tenantName = Get-Setting $account.HomeAccountId.TenantId "_Name" $account.HomeAccountId.TenantId
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS>$($account.UserName)<LineBreak/>$($tenantName)</TextBlock>")
$lbObj.SetValue([System.Windows.Controls.Grid]::ColumnProperty,1)
$grdLogin.Children.Add($lbObj) | Out-Null
@@ -1200,7 +1515,7 @@ function Get-MSALProfileEllipse
Write-Status "Logging in with $($this.Tag.UserName)"
Hide-Popup
Clear-MSALCurentUserVaiables
Connect-MSALUser -Account $this.Tag.UserName
Connect-MSALUser -Account $this.Tag #!!!.UserName
if($global:curObjectType)
{
@@ -1280,8 +1595,12 @@ function Get-MSALProfileEllipse
Write-Status ""
})
$otherLogins = $global:grdProfileInfo.FindName("grdLoginAccount")
Add-GridObject $otherLogins $lnkButton
$otherLogins = $global:grdProfileInfo.FindName("grdTenantAccounts")
if(($script:AccessableTenants | measure).Count -gt 1)
{
#########################################################################################################
@@ -1311,9 +1630,9 @@ function Get-MSALProfileEllipse
$lnkButton.add_Click({
Write-Status "Logging in to $($this.Tag.DisplayName)"
# Set authority to selected tenant
$global:MSALAuthority = "https://login.microsoftonline.com/$($this.Tag.tenantId)/"
$global:MSALTenantId = $this.Tag.tenantId
Hide-Popup
Connect-MSALUser -Account $global:MSALToken.Account.Username
Connect-MSALUser -Account ($global:MSALAccounts | Where UserName -eq $global:MSALToken.Account.Username)
if($global:curObjectType)
{
+1126 -83
View File
File diff suppressed because it is too large Load Diff
+81 -10
View File
@@ -1,12 +1,20 @@
# IntuneManagement with PowerShell and WPF UI
These PowerShell scripts are using Microsoft Authentication Library (MSAL), Microsoft Graph APIs and Azure Management APIs to manage objects in Intune and Azure. The scripts has a simple WPF UI and it supports operations like Export, Import, Copy and Download.
<p align="center">
<a href="https://twitter.com/Micke_K_72">
<img src="https://img.shields.io/twitter/follow/Micke_K_72.svg?style=social" target="_blank" />
</a>
</p>
These PowerShell scripts are using Microsoft Authentication Library (MSAL), Microsoft Graph APIs and Azure Management APIs to manage objects in Intune and Azure. The scripts has a simple WPF UI and it supports operations like Export, Import, Copy, Download, Compare etc.
This makes it easy to backup or clone a complete Intune environment. The scripts can export and import objects including assignments and support import/export between tenants. The scripts will create a migration table during export and use that for importing assignments in other environments. It will create missing groups in the target environment during import. Group information like name, description and type will be imported based on the exported group e.g. dynamic groups are supported. There will be one json file for each group in the export folder.
The script also support dependencies e.g. an App Protection is depending on an App, Policy Sets are depending on Compliance Policies, objects has Scope Tags etc. Dependency support requires exported json files and that the dependency objects are imported in the environment. The script uses the exported json files to get the Id and name's of the exported object and uses that information and updates Id's before import an object from a json file. The Bulk Import form shows the import order of the objects. The objects with the lowest order number will be imported first.
![Screenshot](/IntuneManagement.PNG?raw=true)
<p align="center">
<img src="https://raw.githubusercontent.com/Micke-K/IntuneManagement/master/IntuneManagement.PNG" height="80%" width="80%"/>
</p>
This PowerShell application is based on the foundation modules CloudAPIPowerShellManagement and Core. These modules manages UI, settings, logging etc. The functionality for the application is located in the extension modules. This makes it easy to add/remove features, views etc. Additional features will be added...
@@ -21,11 +29,47 @@ Before starting the app:
Before logging on:
* The app will use the Intune PowerShell Azure Enterprise Application by default but request all permissions required by the script. The will most likely cause a consent prompt since it uses more permission than the Intune module. Enable **Use Default Permissions** in Settings to only request the current permissions granted to the Enterprise App.
**Note:** Using default permission might reduce functionality e.g. permissions for one or more object types might be missing
* Enable **Get Tenant List** in Settings if accessing multiple environments with the same account. This might cause a Consent prompt
* The app will use the Intune PowerShell Azure Enterprise Application by default and only use the permissions granted to that appliction. Disable **Use Default Permissions** in Settings to request additional permissions. The will cause a consent prompt if one or more permissions are missing for the app.
**Note:** If the app has not been approved for the organization, a consent prompt will be disablyed.
* Enable **Get Tenant List** in Settings if accessing multiple environments with the same account e.g. a guest account in other tenants. This might cause a Consent prompt
Start the script by running **Start.cmd**, **Start-WithConsole.cmd** or **Start-IntuneManagement.ps1**. **Start-WithConsole.cmd** will leave the command prompt window open so you can see the log while running the app.
Start the script by running **Start.cmd**, **Start-WithJson.cmd**, **Start-WithConsole.cmd** or **Start-IntuneManagement.ps1**. **Start-WithConsole.cmd** will leave the command prompt window open so you can see the log while running the app.
## Silent Batch Job (Beta)
The script can be executed without UI. This is to support DevOps environment.
Silent batch job is supported by the following features:
* Export
* Import
The Silent Batch Job feature requires an Azure App to be configured with a secret or a certificate. The app must also be delegated with the required permissions to Graph objects used by the tool.
The silent feature uses an exported json file with settings for the specified operation. This file can be generated in the Bulk Export/Import forms. Required settings for the silent job is configured in the form and then exported to a file. The path to the file is then passed on the command line. The file can be used for multiple environments if the **Add company name to the path** option is selected. Note that this requires that the appmust have at least read permission on the Organizations API.
The following variables can be used in the path and filename:
* %Date% - This will be translated to yyyy-MM-dd format (eg 2020-02-27)
* %DateTime% - This will be translated to yyyyMMdd-HHmm format (eg 20200227-1750)
* %Organization% - Name of the tenant
* Any environment variable
The tool will by default generate the files; `BulkExport.json` and `BulkImport.json`. These files can be merged into one file but that must be done manually. These files can also be edited manually. Each setting represents a control in the UI form. When the script is triggered silently, it will create the form in the background, populate it with the values from the file and then trigger the bulk function.
**Note** The Silent Batch feature use settings configured in the UI. If this is triggered in a DevOps envionment, it is recommended to generate a settings JSON file with the desired settings and then use that in the DevOps environment
The app authentication can either be passed on the command line or stored in the settings. Tennant Settings is required for multiple environments.
**Command line example:**
Start-IntuneManagement.ps1 -Silent -TenantId "<*TenantID*>" -SilentBatchFile <*PathToFile*> [-AppId <*AppId*>] [-Secret <*Secret*> | -Certificate <*CertThumb*>]
Start-IntuneManagement.ps1 -Silent -SilentBatchFile "C:\Temp\BatchImport.json" -TenantId "00000000-0000-0000-0000-000000000000" -AppId "00000000-0000-0000-0000-000000000001" -Secret "KJ76P~B9###9-.8I####-_MySecret"
**Setting example:**
Start-IntuneManagement.ps1 -Silent -SilentBatchFile "C:\Temp\BatchImport.json" -TenantId "00000000-0000-0000-0000-000000000000"
## Documentation
@@ -79,13 +123,17 @@ The documentation method is a bit slower but will show the values as they are st
Bulk compare is supported. This can be performed in two ways:
* **Export File** - This will read each exported file and compare it with the existing object
* **Intune Objects with Exported Files** - This will read each exported file and compare it with the existing object
The result file will be stored in the exported folder structure. Either in the Object Type folder or the parent folder depending on the Save as setting.
**Note:** This cannot be used with files exported from a different environment since it used the Id as identifier
* **Named Objects** - Compare file based on patterns
* **Named Objects in Intune** - Compare Intune objects based on patterns
This can be used in where a pattern is used separate objects between different environments e.g. [Test] Policy 1 vs [Prod] Policy 1.
* **Files in Exported Folders** - Compare two exported folders
This can be used in where a pattern is used separate objects between different environments e.g. [Test] Policy 1 vs [Prod] Policy 1.
@@ -171,6 +219,28 @@ See [Change Log](ReleaseNotes.md) for more information
## Authentication
See [MSAL Info](MSALInfo.md) for more information about authentication
## Settings
Settings for the script is default stored in the registry. However, the script supports settings to be stored in a json file so it can be copied between computers. Registry settings can be exported in the Settings dialog.
To use settings based on a json file:
```
Start-IntuneManagement.ps1 -JSonSettings [-JSonFile <PathToFile>]
```
If only -JSonSettings is used the script will use the default json setting file:
```
%LOCALAPPDATA%\CloudAPIPowerShellManagement\Settings.json
```
Use -JSonFile for custom location of the file
Start-WithJson.cmd is included as an example on how to start the script with json settings.
**Note:** If the file can't be created, the script will revert back registry. Make sure that the script can write to the file. It is not recommended to store the file in a folder that requires UAC to get write permissions.
## Supported Intune objects
* App Configurations (App and Device)
* App Protection
@@ -235,13 +305,14 @@ Android Store Apps are **not** imported. The Create API is documented in Microso
Using multiple tenants support causes multiple logins/consent prompts the first time if 'Microsoft Graph PowerShell' is used. Querying the API for tenant list uses a different scope that is not included by default in the 'Microsoft Graph PowerShell' app.
~~Using multiple tenants support *might* cause and endless loop in the login screen and cause duplicate accounts in token cache. Actual cause is not found yet but it happens on rare occasions and it looks like it happens when a guest account is used. Workaround: Cancel the login, restart the script, logout and restart the script again.~~ - Not seen this in a long time. Please create issue if this happens
~~Using multiple tenants support *might* cause and endless loop in the login screen and cause duplicate accounts in token cache. Actual cause is not found yet but it happens on rare occasions and it looks like it happens when a guest account is used. Workaround: Cancel the login, restart the script, logout and restart the script again.~~ - Not seen this in a long time. Please create an issue if this happens
When multi tenant settings is Enabled/Disabled, the Profile Info is not updated until the account is changed or app is restarted. Profile Info popup is built after logon.
The *List Applications* API might not list an imported app immediately after the import. Click *Refresh* to reload the application objects.
When using the filter box to search for items, the checkbox must be clicked twice to select an item.
~~When using the filter box to search for items, the checkbox must be clicked twice to select an item.~~<br />
Issue fixed in 3.3.2
Logout will only clear the token from cache and not from the browser e.g. if login is triggered after a logout, the user will still be listed in the 'Select user' dialog.
+212
View File
@@ -1,5 +1,217 @@
# Release Notes
## 3.4.0 - 2022-03-01
**New features**
- **Silent batch job**
Export/Import can now be executed without UI<br />
See documentation for full requirements
**Note** Please report any issues to [Issue 39](https://github.com/Micke-K/IntuneManagement/issues/39)
This is based on [Issue 39](https://github.com/Micke-K/IntuneManagement/issues/39)
- **Documentation**
- Support for documenting an environment based on exported files<br />
Select the **Source files** folder in the Documentation Types (Bulk menu) dialog.
Note: Some values will NOT be included. These are referenced values and not a property on the object eg Certificate on a VPN profile, Root certificate on a SCEP profile etc. These values will be documented with ##TBD...<br />
This is based on [Issue 37](https://github.com/Micke-K/IntuneManagement/issues/37)
- Support for attaching the json file for the object in the word document
- Support for documentation output level (Word)<br />
Documenting the full environment can create a document with 1000+ pages depending on the amount of profiles and policies. The documentation output level can now be used to reduce the document size. The output level options are:
- Full - Document every single value
- Limited - Set max value and truncate size for documentation and as option, attach the original value as a text document to the value cell e.g. truncate all values over 500 characters to 10 characters and attach the full value as a text file in the document. This will reduce documentation size for profiles with large XML strings like ADMX ingestion
- Basic - Only include the Basic and Assignments tables in the documentation
- Added support for documenting Filters
- Added UI for configuring custom columns<br />
This can now be done in the Detail View<br />
This is based on [Issue 30](https://github.com/Micke-K/IntuneManagement/issues/30)<br />
- Added support for updating Name and Descriptions of the object in Detail View<br />
This is As-Is functionality. Not all object types have been tested.<br />
It is recommended to use the portal for this.<br />
This is based on a private request<br />
- Added support for copying an app
**Note** This requires that the **App packages folder** is specified in Settings and that the file for the app is available in that folder. If the app file is missing it can be uploaded manually in the Details view
This is based on [Issue 42](https://github.com/Micke-K/IntuneManagement/issues/42)
- Added support for manually upload an app file via the Details view
**Fixes**
- **Documentation**<br />
- Updated documentation files with support for new properties and removed unused values (Windows Updates, Windows Feature Updates etc.)
- Fixed an issue where VPN profiles in some cases was missing the Base VPN settings
- Fixed an issue when using a template<br />
A table of content will no longer be created. That should be included in the template
- **Application import**
- Minor change in the app Win32 upload functionality to align to portal APIs
- The File Name is now updated to be based on the actual uploaded file
**Important** Please create an issue if there are any problems
- Fixed an issue where ESP and Enrolment Restriction objects were not listed
The original filters stopped working
**Note** The Enrolment restrictions has changed in Graph. There is now one object for each OS type. So there will be multiple restriction objects exported. platformType column was added to identify each object
This is based on [Issue 41](https://github.com/Micke-K/IntuneManagement/issues/41)
- Minor fixes in Import/Export extensions - Required for silent batch job support
- Fixed an issue where PostListCommand was not triggered
- Additional Endpoint Security columns were not listed
- Azure Branding objects was missing the language column <br />
<br />
- Fixed issue where the Document button was not enabled when **Select All** was clicked (without selecting an object first)
This is based on [Issue 36](https://github.com/Micke-K/IntuneManagement/issues/36)
- Other minor bug fixes to support the new features
## 3.3.3 - 2021-12-15
**Fixes**
- Fixed issue where displayName was missing in object list<br />
Thank you Jason!
## 3.3.2 - 2021-12-14
**New features**
- Markdown support for documentation (Experimental)
This will create a MD document in the Documents folder.
**Note:** This is not working 100% at the moment. The script will create a MD document but it might be too large if all objects in the environment are documented.
Also note that HTML tables are used so that code can be documented as code blocks. This must be supported by the MD Viewer. The *Markdown Viewer* extension in Chrome was used during testing.
Please report any suggestions to the issue.<br />
This is based on [Issue 35](https://github.com/Micke-K/IntuneManagement/issues/35)
- Added support for batched export
This will use batch API to request full info for up to 20 objects per batch to reduce export time
This can be enabled in setting
- Added support for scrolling cached users and guest accounts in the profile info<br />
This can be enabled in settings
- Added support for sorting cached users<br />
This can be enabled in settings
**Fixes**
- Paged return of objects<br />
Only first page of objects will be loaded by default.
Additional pages can be loaded with **Load More** or all available objects can be loaded with **Load All**.<br />
This is based on [Issue 28](https://github.com/Micke-K/IntuneManagement/issues/28)
- Fixed an issue where a checkbox had to be clicked twice to be checked when the list was filtered <br />
This is based on a known issue
- Fixed an issue where buttons were not enabled when **Select All** was checked<br />
This is based on [Issue 36](https://github.com/Micke-K/IntuneManagement/issues/36)
- Fixed an issue when adding object ID to the file name during export
The separate settings file was not exported with the ID in the name which could cause issues during import
## 3.3.1 (Beta) - 2021-10-28
This is a **BETA** release. It contains core changes for Authentication and Settings management. Please report any issues [here](https://github.com/Micke-K/IntuneManagement/issues).
**New features**
- Added support for selecting GCC when using US Government Cloud
- Tenant Specific Setting
The script now supports tenant specific settings. This can be used in scenarios like: only allow delete on you test environments, tenant specific Intune app folders etc.
Login settings like Cloud and GCC is only used if logging on with a cached token. It will otherwise use the current tenant settings.
**Test feedback request:** If there are any users accessing multiple cloud environments like US Government with different GCC levels, please report any issues, working or not. Please report it to [Issue 26](https://github.com/Micke-K/IntuneManagement/issues/26)
Note: Not all settings have be tested and verified and only Setting Values are supported e.g. last Bulk Compare strings are global. Cached settings might not be updated when connecting to another tenant.
- Log View
View the log of the current session in the app
- Added support for documenting scripts for Word
This is based on [Issue 34](https://github.com/Micke-K/IntuneManagement/issues/34)
- New Script options in the Output option tab e.g. enable/disable script documentation, remove PowerShell signature block and documentation styles
- Supports PowerShell/Shell scripts, Proactive Remediations and Win32 Apps (Requirement/Detection scripts)
- Scripts will be documented in a separate table with style *HTLM Code* by default. Spell check is disabled for the script text.
- Permission detection if **Use Default Permissions** is enabled
Default permissions will only use the permission consented to the selected Azure App. The script will check the required permissions with the Access Token. If permissions are missing for one or more objects, they will be marked as red in the menu or they can be excluded from the menu by enable **Hide No-access items** in Settings
**Default Settings Value Changes**
* **Use Default Permissions** is now set to Enabled by default. With the Tenant Specific Settings feature, this can now be enabled globally or per tenant. Consultants accessing multiple environments might not have permissions to grant consent requests so this could be enabled on a global level and then disabled for tenants where the permissions can be added.
**Fixes**
* Fixed an issue when using Json settings where it could not add child settings
## 3.3.0 (Beta) - 2021-10-17
This is a **BETA** release. It contains core changes for Authentication and Settings management. Please report any issues [here](https://github.com/Micke-K/IntuneManagement/issues).
**New features**
- Support for Settings in Json files
Settings can now be stored in json files and copied between devices.
See [Readme](README.md#Settings) on how to use this feature
This is based on [Issue 33](https://github.com/Micke-K/IntuneManagement/issues/33)
- Bulk Compare for exported folders
The tool can now compare two exported folders
This is based on [Issue 32](https://github.com/Micke-K/IntuneManagement/issues/32)
- Support for Azure AD US Government cloud and Azure AD China cloud. Default is Azure AD Public cloud.
Change cloud in Settings
**Note:** This is a major change to the authentication. This may have an impact if a custom configured Azure app is used.
This is based on [Issue 26](https://github.com/Micke-K/IntuneManagement/issues/26). Please report any problem, progress or testing with US Government/China cloud or if there are any issues when a custom configured Azure app is used.
- Export can now add Id to the name of the backup file
This can be used if there are multiple objects with the same name.
This can be enabled in Settings. Backup file name will be <Name>_<Id>.json.
- Export/Import/Compare/Delete now supports name filter
Objects are filtered based on escaped RegEx -nomatch expression so wildcards are not supported.
- IntuneAssignments report will now include the id of deleted groups
**Fixes**
* Fixed an issue in Export. Groups were not exported if exporting multiple times and multiple folders during the same session.
* Fixed an issue in Compare where the csv file was not stored in the correct folder
* Fixed an issue in Compare where the comparing object may return System[]. This can happen if the generated files has multiple documentation items for a property. First result will be used.
## 3.2.3 - 2021-10-07
**New features**
+19 -2
View File
@@ -1,7 +1,24 @@
[CmdletBinding(SupportsShouldProcess=$True)]
param(
[switch]
$ShowConsoleWindow
$ShowConsoleWindow,
[switch]
$JSonSettings,
[string]
$JSonFile,
[switch]
$Silent,
[string]
$SilentBatchFile = "",
[string]
$TenantId,
[string]
$AppId,
[string]
$Secret,
[string]
$Certificate
)
Import-Module ($PSScriptRoot + "\CloudAPIPowerShellManagement.psd1") -Force
Initialize-CloudAPIManagement -View "IntuneGraphAPI" -ShowConsoleWindow:($ShowConsoleWindow)
$param = $PSBoundParameters
Initialize-CloudAPIManagement -View "IntuneGraphAPI" @param
+1
View File
@@ -0,0 +1 @@
cmd /c powershell -ex bypass -File "%~DP0Start-IntuneManagement.ps1" -JSonSettings
+60
View File
@@ -29,6 +29,65 @@
</Style.Triggers>
</Style>
<Style x:Key='ErrorControl' TargetType='ContentControl'>
<Setter Property='Template'>
<Setter.Value>
<ControlTemplate TargetType='ContentControl'>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle Width="16" Height="16" ToolTip="{Binding ToolTip}" Name="errorIcon" Visibility="Collapsed">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1M8,16C3.589,16 0,12.411 0,8 0,3.589 3.589,0 8,0 12.411,0 16,3.589 16,8 16,12.411 12.411,16 8,16" />
<GeometryDrawing Brush="#FFE41400" Geometry="F1M9,10L7,10 7,3 9,3z M9,13L7,13 7,11 9,11z M8,1C4.134,1 1,4.134 1,8 1,11.865 4.134,15 8,15 11.865,15 15,11.865 15,8 15,4.134 11.865,1 8,1" />
<GeometryDrawing Brush="#FFEFEFF0" Geometry="F1M9,11L7,11 7,13 9,13z M9,10L7,10 7,3 9,3z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter Grid.Column="1" Name="errorControl" />
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self},Path=Tag}" Value="True">
<Setter TargetName="errorIcon" Property="Visibility" Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers>
<ControlTemplate.Resources>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Tag, RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}}" Value="True">
<Setter Property="Border.BorderBrush" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ControlTemplate.Resources>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ErrorBorder" TargetType="Control">
<Style.Triggers>
<DataTrigger Binding="{Binding HasErrors}" Value="True">
<Setter Property="Border.BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="HoverUnderlineStyleWithBackground" TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
@@ -131,4 +190,5 @@
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
+15 -3
View File
@@ -1,19 +1,31 @@
<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="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row='0' Margin="0,0,5,0" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" Grid.Row='0' Margin="0,0,5,0" >
<Label Content="Name filter" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify name filter for the objects to delete" />
</StackPanel>
<TextBox Text="" Name="txtDeleteNameFilter" Grid.Column='1' Grid.Row='0' Margin="0,5,0,0" />
<StackPanel Orientation="Horizontal" Grid.Row='1' Margin="5,0,5,0" VerticalAlignment="Top" Grid.ColumnSpan="2">
<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 Name="dgBulkDeleteObjects" Grid.Row='2' Grid.ColumnSpan="2" 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' >
<StackPanel Name="spDeleteSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row='3' 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>
+23 -7
View File
@@ -37,24 +37,30 @@
<Button Grid.Column="2" Name="browseExportPath" Padding="5,0,5,0" Width="50" ToolTip="Browse for folder">...</Button>
</Grid>
<!-- Force object type in name by setting it to true and disable the checkbox. Leave it on for information -->
<StackPanel Orientation="Horizontal" Grid.Row='1' Margin="0,0,5,0" >
<Label Content="Name filter" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify name filter for the objects to export" />
</StackPanel>
<TextBox Text="" Name="txtExportNameFilter" Grid.Column='1' Grid.Row='1' Margin="0,5,0,0" />
<!-- Force object type in name by setting it to true and disable the checkbox. Leave it on for information -->
<StackPanel Orientation="Horizontal" Grid.Row='2' Margin="0,0,5,0">
<Label Content="Add object name to path" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This will export all objects to a sub-directory of the export path with name based on object type" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='1' Name='chkAddObjectType' VerticalAlignment="Center" IsEnabled="false" IsChecked="true" />
<CheckBox Grid.Column='1' Grid.Row='2' Name='chkAddObjectType' VerticalAlignment="Center" IsEnabled="false" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='2' Margin="0,0,5,0">
<StackPanel Orientation="Horizontal" Grid.Row='3' Margin="0,0,5,0">
<Label Content="Export Assignments" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Export object assignments" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='2' Name='chkExportAssignments' VerticalAlignment="Center" IsChecked="true" />
<CheckBox Grid.Column='1' Grid.Row='3' Name='chkExportAssignments' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='3' Margin="0,0,5,0">
<StackPanel Orientation="Horizontal" Grid.Row='4' Margin="0,0,5,0">
<Label Content="Add company name to path" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This will add the company name in Azure to the export path" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='3' Name='chkAddCompanyName' VerticalAlignment="Center" IsChecked="true" />
<CheckBox Grid.Column='1' Grid.Row='4' Name='chkAddCompanyName' VerticalAlignment="Center" IsChecked="true" />
</Grid>
<Grid Grid.Row='1' VerticalAlignment="Stretch">
@@ -102,9 +108,19 @@
-->
</Grid >
<StackPanel Name="spExportSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row='2' Grid.ColumnSpan='2' >
<Grid Grid.Row='2' Grid.ColumnSpan='2' >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" >
<Button Name="btnExportSettingsForSilentExport" Content="Save" Width='100' Margin="5,0,0,0" ToolTip="Save settings for batch job" />
</StackPanel>
<StackPanel Name="spExportSubMenu" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right" >
<Button Name="btnExport" Content="Export" Width='100' Margin="5,0,0,0" />
<Button Name="btnClose" Content="Close" Width='100' Margin="5,0,0,0" />
</StackPanel>
</Grid >
</Grid >
+30 -13
View File
@@ -15,6 +15,7 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
@@ -38,38 +39,44 @@
<Button Grid.Column="2" Name="browseImportPath" Padding="5,0,5,0" Width="50" ToolTip="Browse for folder">...</Button>
</Grid>
<StackPanel Orientation="Horizontal" Grid.Row='1' Margin="0,0,5,0" Name="spMigrationTableInfo">
<StackPanel Orientation="Horizontal" Grid.Row='1' Margin="0,0,5,0" >
<Label Content="Name filter" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify name filter for the objects to import" />
</StackPanel>
<TextBox Text="" Name="txtImportNameFilter" Grid.Column='1' Grid.Row='1' Margin="0,5,0,0" />
<StackPanel Orientation="Horizontal" Grid.Row='2' Margin="0,0,5,0" Name="spMigrationTableInfo">
<Label Content="Migration Table" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This contains information about the exported environment e.g. Groups, ScopeTags etc. Note: This is only used when import object from a different tenant" />
</StackPanel>
<Label Grid.Column='1' Grid.Row='1' Name="lblMigrationTableInfo" />
<Label Grid.Column='1' Grid.Row='2' Name="lblMigrationTableInfo" />
<!-- Force object type in name by setting it to true and disable the checkbox. Leave it on for information -->
<StackPanel Orientation="Horizontal" Grid.Row='2' Margin="0,0,5,0">
<StackPanel Orientation="Horizontal" Grid.Row='3' Margin="0,0,5,0">
<Label Content="Add object name to path" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This will import objects from a sub-directory of the import path with name based on object type" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='2' Name='chkAddObjectType' VerticalAlignment="Center" IsEnabled="false" IsChecked="true" />
<CheckBox Grid.Column='1' Grid.Row='3' Name='chkAddObjectType' VerticalAlignment="Center" IsEnabled="false" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='3' Margin="0,0,5,0">
<StackPanel Orientation="Horizontal" Grid.Row='4' Margin="0,0,5,0">
<Label Content="Import Scope (Tags)" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This will import ScopeTags. The ScopeTags must exist in the target environment before thay can be assigned during import of an object" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='3' Name='chkImportScopes' VerticalAlignment="Center" IsChecked="true" />
<CheckBox Grid.Column='1' Grid.Row='4' Name='chkImportScopes' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='4' Margin="0,0,5,0">
<StackPanel Orientation="Horizontal" Grid.Row='5' Margin="0,0,5,0">
<Label Content="Import Assignments" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Import object assignments. Note: This will create groups that don't exist in the target environment" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='4' Name='chkImportAssignments' VerticalAlignment="Center" IsChecked="true" />
<CheckBox Grid.Column='1' Grid.Row='5' Name='chkImportAssignments' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='5' Margin="0,0,5,0">
<StackPanel Orientation="Horizontal" Grid.Row='6' Margin="0,0,5,0">
<Label Content="Replace Dependecy IDs" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Replaces IDs of dependency objects e.g. App Config references Applications. Increases import time but makes sure objects are imported correctly. Note: References objects must exist!" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='5' Name='chkReplaceDependencyIDs' VerticalAlignment="Center" IsChecked="true" />
<CheckBox Grid.Column='1' Grid.Row='6' Name='chkReplaceDependencyIDs' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='6' Margin="0,0,5,0" Name="lblImportType" Visibility="Collapsed">
<StackPanel Orientation="Horizontal" Grid.Row='7' Margin="0,0,5,0" Name="lblImportType" Visibility="Collapsed">
<Label Content="Import Type" />
<Rectangle Style="{DynamicResource InfoIcon}">
<Rectangle.ToolTip>
@@ -83,7 +90,7 @@
</Rectangle.ToolTip>
</Rectangle>
</StackPanel>
<ComboBox Name="cbImportType" Margin="0,5,0,0" MinWidth="250" Grid.Row='6' Grid.Column="1" HorizontalAlignment="Left"
<ComboBox Name="cbImportType" Margin="0,5,0,0" MinWidth="250" Grid.Row='7' Grid.Column="1" HorizontalAlignment="Left"
DisplayMemberPath="Name" SelectedValuePath="Value" Visibility="Collapsed" />
</Grid>
@@ -111,9 +118,19 @@
</Grid>
<StackPanel Name="spImportSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row='2' Grid.ColumnSpan='2' >
<Grid Grid.Row='2' Grid.ColumnSpan='2' >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" >
<Button Name="btnExportSettingsForSilentImport" Content="Save" Width='100' Margin="5,0,0,0" ToolTip="Save settings for batch job" />
</StackPanel>
<StackPanel Name="spImportSubMenu" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right" >
<Button Name="btnImport" Content="Import" Width='100' Margin="5,0,0,0" />
<Button Name="btnClose" Content="Close" Width='100' Margin="5,0,0,0" />
</StackPanel>
</Grid>
</Grid >
+8 -2
View File
@@ -8,11 +8,17 @@
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,0,5,0" >
<StackPanel Orientation="Horizontal" Grid.Row='0' Margin="0,0,5,0" >
<Label Content="Name filter" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify name filter for the objects to compare" />
</StackPanel>
<TextBox Text="" Name="txtCompareNameFilter" Grid.Column='1' Grid.Row='0' Margin="0,5,5,0" />
<StackPanel Orientation="Horizontal" Grid.Row='1' Margin="0,0,5,0" >
<Label Content="Export root" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="The root folder where exported files are stored. This sould be the Company Name folder if it was included in the export." />
</StackPanel>
<Grid Grid.Column='1' Grid.Row='0' Margin="0,5,5,0">
<Grid Grid.Column='1' Grid.Row='1' Margin="0,5,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
+51
View File
@@ -0,0 +1,51 @@
<Grid Name="grdImportProperties" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row='0' Margin="0,0,5,0" >
<Label Content="Name filter" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify name filter for the objects to compare" />
</StackPanel>
<TextBox Text="" Name="txtCompareNameFilter" Grid.Column='1' Grid.Row='0' Margin="0,5,5,0" />
<StackPanel Orientation="Horizontal" Grid.Row='1' Margin="0,0,5,0" >
<Label Content="Source root" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="The root folder where exported files are stored. This sould be the Company Name folder if it was included in the export." />
</StackPanel>
<Grid Grid.Column='1' Grid.Row='1' Margin="0,5,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="" Name="txtExportPathSource" />
<Button Grid.Column="2" Name="browseExportPathSource" Padding="5,2,5,2" Width="50" ToolTip="Browse for folder">...</Button>
</Grid>
<StackPanel Orientation="Horizontal" Grid.Row='2' Margin="0,0,5,0" >
<Label Content="Compare root" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="The folder with exported object that should be compared with the source" />
</StackPanel>
<Grid Grid.Column='1' Grid.Row='2' Margin="0,5,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="" Name="txtExportPathCompare" />
<Button Grid.Column="2" Name="browseExportPathCompare" Padding="5,2,5,2" Width="50" ToolTip="Browse for folder">...</Button>
</Grid>
</Grid>
+20
View File
@@ -17,6 +17,8 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
@@ -65,6 +67,24 @@
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='5' Name='chkSetDefaultValue' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="6" Grid.ColumnSpan="2" Name="spDocumentFromFolder">
<Label Content="Source files" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Create documentation from exported files" />
</StackPanel>
<Grid Grid.Row='7' Margin="5,0,0,0" Grid.ColumnSpan="2" Name="grdDocumentFromFolder">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="" Name="txtDocumentFromFolder" />
<Button Grid.Column="2" Name="browseDocumentFromFolder" Padding="5,0,5,0" Width="50" ToolTip="Browse for export folder">...</Button>
</Grid>
<Label Content="Objects to document" Grid.Row="0" Grid.Column="4" />
<DataGrid Name="grdDocumentObjects" Grid.Row="1" Grid.RowSpan="99" Grid.Column="4" CanUserAddRows="False" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" Margin="0,0,5,0">
+99
View File
@@ -18,6 +18,12 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
@@ -25,6 +31,17 @@
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="0">
<Label Content="Output Properties" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify the output type. Simple will only add Value and Name for Settings. Extended will output the same as Raw Output. Use Custom to select custom properties" />
@@ -38,6 +55,58 @@
</StackPanel>
<TextBox Text="" Name="txtWordCustomProperties" Margin="0,5,5,5" Grid.Row="1" Grid.Column="1"/>
</Grid>
<Grid Grid.Row="1" Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="0">
<Label Content="Output Level" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify the output level. Full will document full value of each setting, Limited will truncate the value if more than 100 characters and Basic will only include the basic information and assignments but no settings" />
</StackPanel>
<ComboBox Name="cbWordDocumentationLevel" Margin="0,5,0,0" MinWidth="250" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"
DisplayMemberPath="Name" SelectedValuePath="Value" />
<Grid Grid.Row="1" Grid.ColumnSpan="2" Name="gdWordDocumentationLimitOptions">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" >
<Label Content="Attach full value" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Attach value as a text file if exceeds the Max value length" />
</StackPanel>
<CheckBox Grid.Column='1' Name='chkWordDocumentationLimitAttatch' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="1">
<Label Content="Max value length" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify the max sting length of the value. Value over this size will be truncated. Default is 100" />
</StackPanel>
<TextBox Text="" Name="txtWordDocumentationLimitMaxLength" Margin="0,5,5,5" Width="100" Grid.Row="1" HorizontalAlignment="Left" Grid.Column="1"/>
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="2">
<Label Content="Truncated value length" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify the length for the truncate size. Default is same size as Max value length. Specify 0 to skip tuncated text and only include the attached value (must be enabled)" />
</StackPanel>
<TextBox Text="" Name="txtWordDocumentationLimitTruncateLength" Margin="0,5,5,5" Width="100" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="1"/>
</Grid>
</Grid>
<StackPanel Orientation="Horizontal" Margin="0,0,5,0" Grid.Row="2">
<Label Content="Word document template" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="The document template (*.dotx) file to use for the documentation. Normal.dotx will be used if this is empty" />
@@ -150,4 +219,34 @@
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='17' Name='chkWordOpenDocument' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='18' Margin="0,0,5,0">
<Label Content="Document scripts" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Include scripts in the documentation" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='18' Name='chkWordIncludeScripts' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='19' Margin="0,0,5,0">
<Label Content="Remove script signature" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Remove signature block from PowerShell scripts to reduce script documentation size" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='19' Name='chkWordExcludeScriptSignature' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='20' Margin="0,0,5,0">
<Label Content="Attatch Json file" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Attatch the Json file to the documentation" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='20' Name='chkWordAttatchJsonFile' VerticalAlignment="Center" IsChecked="false" />
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="21">
<Label Content="Script table style" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify the table style to use for scripts. Ducument table style will be use as default" />
</StackPanel>
<TextBox Grid.Column='1' Grid.Row='21' Name='txtWordScriptTableStyle' Margin="0,5,5,5"/>
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="22">
<Label Content="Script font style" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Specify the font style to use for documenting scripts. HTML Code is used as default" />
</StackPanel>
<TextBox Grid.Column='1' Grid.Row='22' Name='txtWordScriptStyle' Margin="0,5,5,5"/>
</Grid>
+13 -3
View File
@@ -14,7 +14,13 @@
SelectionUnit="FullRow"
CanUserAddRows="False"
Grid.Column="1"
Grid.Row="1" />
Grid.Row="1">
<DataGrid.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="NoWrap"/>
</Style>
</DataGrid.Resources>
</DataGrid>
<Grid Name="grdTitle" Visibility="Collapsed" >
<Grid.ColumnDefinitions>
@@ -22,13 +28,17 @@
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Background="{DynamicResource TitleBackgroundColor}" Margin="0,0,0,5" >
<ContentControl Name="ccIcon" Width="24" Height="24" Margin="5,0,0,0" />
</Border>
<TextBlock Name="txtFormTitle" Text="" Grid.Column="1" Grid.ColumnSpan="3" FontWeight="Bold" Padding="5" Margin="0,0,0,5" Background="{DynamicResource TitleBackgroundColor}" />
<TextBox Name="txtFilter" Grid.Column="2" MinWidth="200" MaxHeight="20" Margin="0,0,5,3" />
<TextBlock Name="txtFormTitle" Text="" Grid.Column="1" Grid.ColumnSpan="5" FontWeight="Bold" Padding="5" Margin="0,0,0,5" Background="{DynamicResource TitleBackgroundColor}" />
<Button Name="btnLoadAllPages" Grid.Column="2" Content="Load All" Width='100' Margin="0,5,5,7" Visibility="Collapsed" />
<Button Name="btnLoadNextPage" Grid.Column="3" Content="Load More" Width='100' Margin="0,5,5,7" Visibility="Collapsed" />
<TextBox Name="txtFilter" Grid.Column="4" MinWidth="200" MaxHeight="20" Margin="0,0,5,3" />
<!--
<Grid Grid.Column="2" MinWidth="200" MaxHeight="20">
<TextBlock Text="Filter" Background="White" />
+59
View File
@@ -0,0 +1,59 @@
<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.RowDefinitions>
<RowDefinition Height="4*" MinHeight="300" />
<RowDefinition Height="3" />
<RowDefinition Height="1*" MinHeight="100" />
</Grid.RowDefinitions>
<DataGrid Name="dgLogInfo"
AutoGenerateColumns="False"
SelectionMode="Single"
SelectionUnit="FullRow"
CanUserAddRows="False">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Type}" Value="3">
<Setter Property="Foreground" Value="Red"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Type}" Value="2">
<Setter Property="Foreground" Value="Orange"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Date" Binding="{Binding DateTime, StringFormat={}{0:d}}" IsReadOnly="True" Width="Auto" />
<DataGridTextColumn Header="Time" Binding="{Binding DateTime, StringFormat={}{0:HH:mm.ss.fff}}" IsReadOnly="True" Width="Auto" />
<DataGridTextColumn Header="Type" Binding="{Binding TypeText}" IsReadOnly="True" Width="Auto" />
<DataGridTemplateColumn Header="Text">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Text}" TextWrapping="NoWrap" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Grid Grid.Row="3">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Date\Time" Grid.Row="0" Grid.Column="0" />
<TextBlock Text="{Binding Path=DateTime, StringFormat={}{0:yyyy-MM-dd HH:mm.ss.fff}}" Grid.Row="0" Grid.Column="2" />
<TextBox Grid.Row="1" Grid.ColumnSpan="99" Text="{Binding Path=Text}" HorizontalAlignment="Stretch" Name="txtLogInfo" IsReadOnly="True" AcceptsReturn="true" />
</Grid>
</Grid>
+16 -1
View File
@@ -34,8 +34,11 @@
<Menu Name="mnuMain" Padding="0,5,0,5" Grid.ColumnSpan="2" >
<MenuItem Header="_File" >
<MenuItem Header="_Settings" Name="mnuSettings" />
<MenuItem Header="_Tenant Settings" Name="mnuTenantSettings" />
<Separator />
<MenuItem Header="_Release Notes" Name="mnuUpdates" />
<MenuItem Header="_About" Name="mnuAbout" />
<Separator />
<MenuItem Header="_Exit" Name="mnuExit" />
</MenuItem>
<MenuItem Name="mnuViews" Header="_Views" >
@@ -45,7 +48,7 @@
<Grid Name="grdViewPanel" Grid.Column="1" Grid.RowSpan="2" Grid.Row="1" Margin="0,5,5,5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Grid Grid.Row="1" Margin="5" VerticalAlignment="Stretch">
<Grid Grid.Row="1" Margin="5" VerticalAlignment="Stretch" Name="grdViewItemMenu">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
@@ -64,6 +67,18 @@
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding @AccessType}" Value="None">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding @AccessType}" Value="Limited">
<Setter Property="Foreground" Value="Orange" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
</Grid>
+127 -1
View File
@@ -1,4 +1,6 @@
<Grid Margin="0,5,0,5" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TabControl SelectedIndex="0" Margin="0,5,0,5" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TabItem Header="Json">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
@@ -22,3 +24,127 @@
<Button Name="btnCopy" MinWidth="100" Margin="0,0,0,0" ToolTip="Copy text to clipboard">Copy</Button>
</WrapPanel>
</Grid>
</TabItem>
<TabItem Header="Settings">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="0" HorizontalAlignment="Left">
<Label Content="Name" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Name of the object" />
</StackPanel>
<TextBox Name="txtObjectName" Margin="0,5,5,0" Grid.Row="0" Grid.Column="1" />
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="1" HorizontalAlignment="Left">
<Label Content="Description" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Name of the object" />
</StackPanel>
<TextBox Name="txtObjectDescription" Margin="0,5,5,0" Grid.Row="1" Grid.Column="1" AcceptsReturn="True" Height="100" />
<StackPanel Orientation="Horizontal" Grid.Column="1" Margin="5,5,5,0" Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Right">
<Button Name="btnObjectSettingsSave" Content="Save" Margin="0,0,0,0" Width="100" />
</StackPanel>
</Grid>
</TabItem>
<TabItem Header="Columns">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,0,5,0" >
<Label Content="Properties" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Properties of the current object" />
</StackPanel>
<ListBox Name="lstObjectProperties" SelectionMode="Single" Grid.Row="1" Grid.RowSpan="99" MinWidth="100" DisplayMemberPath="Name">
</ListBox>
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5,0,5,0">
<Button Content=">" Name="btnObjectColumnsAdd" Width="50" ToolTip="Add property" />
</StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Row="1" Grid.Column="2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox Name="lstObjectColumns" SelectionMode="Single" Grid.Row="0" MinWidth="150" DisplayMemberPath="Property" Height="200">
</ListBox>
<StackPanel Grid.Column="1" Margin="5,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center">
<Button Content="Up" Name="btnObjectColumnsMoveUp" Width="50" ToolTip="Move the selected column up" />
<Button Content="Down" Name="btnObjectColumnsMoveDown" Width="50" ToolTip="Move the selected column down" Margin="0,5,0,0"/>
<Button Content="Delete" Name="btnObjectColumnsDelete" Width="50" ToolTip="Delete the selected column" Margin="0,5,0,0"/>
<Button Content="Clear" Name="btnObjectColumnsClear" Width="50" ToolTip="Delete all custom columns" Margin="0,5,0,0"/>
</StackPanel>
<CheckBox Grid.Row='1' Name='chkObjectColumnOverride' Grid.ColumnSpan="2" Content="Override default columns" VerticalAlignment="Center" ToolTip="Do not add default columns first. If this is checked then only the properties in the list will be displayed" />
<Grid Grid.Row="3" Grid.ColumnSpan="2" Name="grdObjectColumns">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="0" HorizontalAlignment="Left">
<Label Content="Property" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Property to display. Sub properties and array values are supported eg files[0].displayName" />
</StackPanel>
<TextBox Name="txtObjectColumnsProperty" Text="{Binding Property}" Margin="0,5,5,0" Grid.Row="0" Grid.Column="1" />
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="1">
<Label Content="Header" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Header for the property. Name of property will be used if not specified" />
</StackPanel>
<TextBox Name="txtObjectColumnsHeader" Text="{Binding Header}" Margin="0,5,5,0" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" />
<StackPanel Orientation="Horizontal" Margin="0,5,5,0" Grid.Row="2" HorizontalAlignment="Left">
<Label Content="Current settings:" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Current property settings. Only updated when saved" />
</StackPanel>
<Label Name="lblObjectColumnsConfig" Content="" Margin="0,0,5,0" Grid.Row="3" />
<StackPanel Orientation="Horizontal" Grid.Column="1" Margin="5,5,5,0" Grid.Row="4" Grid.ColumnSpan="2" HorizontalAlignment="Right">
<Button Name="btnObjectColumnsReset" Content="Reset" Margin="0,0,5,0" Width="100" ToolTip="Revert all changes" />
<Button Name="btnObjectColumnsSave" Content="Save" Margin="0,0,0,0" Width="100" />
</StackPanel>
</Grid>
</Grid>
</ScrollViewer>
</Grid>
</TabItem>
</TabControl>
+31 -1
View File
@@ -11,6 +11,17 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
@@ -19,6 +30,8 @@
<TextBlock Margin="5" Name="txtOrganization" FontWeight="Bold" />
<Button Margin="5" Name="lnkLogout" Content="Sign out" Grid.Column="2" Style="{DynamicResource LinkButton}" HorizontalAlignment="Right"/>
</Grid>
<TextBlock Margin="5" Name="txtUsername" Grid.Row="1" Grid.Column="2" FontWeight="Bold" FontSize="24" />
<TextBlock Margin="5" Name="txtLogonName" Grid.Row="2" Grid.Column="2" />
@@ -35,10 +48,27 @@
<Button Margin="5" Name="lnkForceRefresh" ToolTip="Force a refresh of the token e.g. after being added to a new role" Content="Refresh" Cursor="Hand" Style="{DynamicResource LinkButton}" />
</StackPanel>
<Grid Grid.Row="8" Name="grdAccountsAndTenants" Grid.ColumnSpan="2" Margin="5,0,5,0" HorizontalAlignment="Stretch">
<ScrollViewer Grid.Row="8" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" MaxHeight="200">
<Grid Name="grdCachedAccounts" Margin="5,0,5,2" HorizontalAlignment="Stretch" VerticalAlignment="Top" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</ScrollViewer>
<Grid Name="grdLoginAccount" Grid.Row="9" Grid.ColumnSpan="2" Margin="5,0,5,0" HorizontalAlignment="Stretch" VerticalAlignment="Top" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<ScrollViewer Grid.Row="10" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" MaxHeight="200">
<Grid Name="grdTenantAccounts" Margin="5,0,5,2" HorizontalAlignment="Stretch" VerticalAlignment="Top" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</ScrollViewer>
</Grid>
</Border>
+3 -8
View File
@@ -6,18 +6,12 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--
<StackPanel Name="spSettings" Grid.Column="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Grid.IsSharedSizeScope='True' Margin="0">
</StackPanel>
-->
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Padding="0,0,5,0">
<Grid Name="spSettings" Grid.Column="1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Grid.IsSharedSizeScope='True' Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
@@ -25,7 +19,8 @@
</ScrollViewer>
<StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal" Margin="0,5,0,5">
<Button Name="btnSave" Width="100">Save</Button>
<Button Name="btnExport" Width="100">Export</Button>
<Button Name="btnSave" Width="100" Margin="15,0,0,0">Save</Button>
<Button Name="btnClose" Width="100" Margin="15,0,0,0">Close</Button>
</StackPanel>
</Grid>