Version 3 Beta 1 - Complete re-write

This commit is contained in:
Micke
2021-04-13 17:57:12 +10:00
parent 2dfaf1bfba
commit c7f8cbe760
90 changed files with 28774 additions and 7724 deletions

57
CS/TokenCacheHelperEx.cs Normal file
View File

@@ -0,0 +1,57 @@
// Updated original code from
// Added support for custom file location
// https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-net-token-cache-serialization#simple-token-cache-serialization-msal-only
using System;
using System.IO;
using System.Security.Cryptography;
using Microsoft.Identity.Client;
public static class TokenCacheHelperEx
{
public static void EnableSerialization(ITokenCache tokenCache, String fileName = @"%LOCALAPPDATA%\GraphPowerShellManager\MSALToken.bin")
{
tokenCache.SetBeforeAccess(BeforeAccessNotification);
tokenCache.SetAfterAccess(AfterAccessNotification);
CacheFilePath = Environment.ExpandEnvironmentVariables(fileName);
}
/// <summary>
/// Path to the token cache
/// </summary>
public static string CacheFilePath { get; private set;}
private static readonly object FileLock = new object();
private static void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
lock (FileLock)
{
args.TokenCache.DeserializeMsalV3(File.Exists(CacheFilePath)
? ProtectedData.Unprotect(File.ReadAllBytes(CacheFilePath),
null,
DataProtectionScope.CurrentUser)
: null);
}
}
private static void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if the access operation resulted in a cache update
if (args.HasStateChanged)
{
lock (FileLock)
{
Directory.CreateDirectory(Path.GetDirectoryName(CacheFilePath));
// reflect changes in the persistent store
File.WriteAllBytes(CacheFilePath,
ProtectedData.Protect(args.TokenCache.SerializeMsalV3(),
null,
DataProtectionScope.CurrentUser)
);
}
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,108 @@
#region Console functions
# https://stackoverflow.com/questions/40617800/opening-powershell-script-and-hide-command-prompt-but-not-the-gui
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetConsoleIcon(IntPtr hIcon);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint wMsg, uint wParam, IntPtr lParam);
'
function Show-Console
{
$consolePtr = [Console.Window]::GetConsoleWindow()
# Hide = 0,
# ShowNormal = 1,
# ShowMinimized = 2,
# ShowMaximized = 3,
# Maximize = 3,
# ShowNormalNoActivate = 4,
# Show = 5,
# Minimize = 6,
# ShowMinNoActivate = 7,
# ShowNoActivate = 8,
# Restore = 9,
# ShowDefault = 10,
# ForceMinimized = 11
[Console.Window]::ShowWindow($consolePtr, 4)
}
function Hide-Console
{
$consolePtr = [Console.Window]::GetConsoleWindow()
#0 hide
[Console.Window]::ShowWindow($consolePtr, 0) | Out-Null
}
#endregion
# Unblock all files
# Not 100% OK but avoid issues with loading blocked files
function Unblock-AllFiles
{
param($folder)
(Get-ChildItem $folder -force | Where-Object {! $_.PSIsContainer}) | Unblock-File
foreach($subFolder in (Get-ChildItem $folder -force | Where-Object {$_.PSIsContainer}))
{
Unblock-AllFiles $subFolder.FullName
}
}
function Initialize-CloudAPIManagement
{
[CmdletBinding(SupportsShouldProcess=$True)]
param(
[string]
$View = "",
[switch]
$ShowConsoleWindow
)
$global:wpfNS = "xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'"
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
Add-Type -AssemblyName PresentationFramework
try
{
[xml]$xaml = Get-Content ([IO.Path]::GetDirectoryName($PSCommandPath) + "\Xaml\SplashScreen.xaml")
$global:SplashScreen = ([Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml)))
$global:txtSplashTitle = $global:SplashScreen.FindName("txtSplashTitle")
$global:txtSplashText = $global:SplashScreen.FindName("txtSplashText")
$global:txtSplashTitle.Text = ("Initializing Cloud API PowerShell Management")
$global:SplashScreen.Show() | Out-Null
[System.Windows.Forms.Application]::DoEvents()
}
catch
{
}
if($ShowConsoleWindow -ne $true)
{
Hide-Console
}
$global:txtSplashText.Text = "Unblock files"
[System.Windows.Forms.Application]::DoEvents()
Unblock-AllFiles $PSScriptRoot
$global:txtSplashText.Text = "Load core module"
[System.Windows.Forms.Application]::DoEvents()
Import-Module ($PSScriptRoot + "\Core.psm1") -Force -Global
Start-CoreApp $View
}

1435
Core.psm1 Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,332 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-AppProtectionName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-AppProtections}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-AppProtectionName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all app protection/configuration policies"
Import-AllAppProtectionObjects (Join-Path $rootFolder (Get-AppProtectionFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-AppProtectionName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all app protection/configuration policies"
Get-AppProtectionObjects | ForEach-Object { Export-SingleAppProtection $PSItem.Object (Join-Path $rootFolder (Get-AppProtectionFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-AppProtectionFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-AppProtectionName
{
return "App Protection/Configuration"
}
function Get-AppProtectionFolderName
{
return "AppProtection"
}
function Get-AppProtections
{
Write-Status "Loading app protections and configurations"
$dgObjects.ItemsSource = @(Get-AppProtectionObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllAppProtections $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedAppProtection $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllAppProtectionObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-AppProtectionObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-AppProtection}) -ViewFullObject ([scriptblock]{Get-AppProtectionObject $global:dgObjects.SelectedItem.Object}) -ForceFullObject
}
function Get-AppProtectionObjects
{
Get-GraphObjects -Url "/deviceAppManagement/managedAppPolicies"
}
function Get-AppProtectionObject
{
param($object, $additional = "")
if(-not $object.id) { return }
$objType = Get-AppProtectionObjectType $object."@odata.type"
$expand = ""
if($objType -eq "targetedManagedAppConfigurations")
{
$expand = "?`$expand=Apps"
}
if($objType)
{
Invoke-GraphRequest -Url "/deviceAppManagement/$objType/$($object.id)$($expand)"
}
}
function Export-AllAppProtections
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleAppProtection $objTmp.Object $path
}
}
}
function Export-SelectedAppProtection
{
param($path = "$env:Temp")
Export-SingleAppProtection $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleAppProtection
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-AppProtectionFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = Get-AppProtectionObjectForExport $psObj
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
Add-MigrationInfo $obj.assignments
}
$global:exportedObjects++
}
}
function Get-AppProtectionObjectType
{
param($odataType)
if($odataType -like "*targetedManagedAppConfiguration*")
{
"targetedManagedAppConfigurations"
}
elseif($odataType -like "*iosManagedAppProtection*")
{
"iosManagedAppProtections"
}
elseif($odataType -like "*androidManagedAppProtection*")
{
"androidManagedAppProtections"
}
elseif($odataType -like "*mdmWindowsInformationProtectionPolicy*")
{
# Win 10 - With enrollment e.g. Intune enrolled Win 10 devices
"mdmWindowsInformationProtectionPolicies"
}
elseif($odataType -like "*windowsInformationProtectionPolicy*")
{
# Win 10 - Without enrollment e.g. MAM polices for Win 10
"WindowsInformationProtectionPolicies"
}
}
function Get-AppProtectionObjectForExport
{
param($obj)
$objType = Get-AppProtectionObjectType $obj."@odata.type"
$expand = "?`$expand=assignments"
if($objType -eq "targetedManagedAppConfigurations")
{
$expand += ",Apps"
}
if($objType)
{
Invoke-GraphRequest -Url "/deviceAppManagement/$objType/$($obj.id)$($expand)"
}
}
function Copy-AppProtection
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect app protection/configuration item you want to copy", "Error", "OK", "Error")
return
}
$ret = Show-InputDialog "Copy app protection/configuration" "Select name for the new policy" "$($dgObjects.SelectedItem.displayName) - Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
$obj = Get-AppProtectionObjectForExport $dgObjects.SelectedItem.Object
if($obj)
{
# Remove assignment properties
Remove-ObjectProperty $obj "assignments"
Remove-ObjectProperty $obj "assignments@odata.context"
# Import new profile
$obj.displayName = $ret
Import-AppProtection $obj | Out-Null
$dgObjects.ItemsSource = @(Get-AppProtectionObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-AppProtection
{
param($obj)
if(($obj | GM -MemberType NoteProperty -Name "Apps"))
{
$apps = $obj.Apps
}
Start-PreImport $obj -RemoveProperties @("apps","apps@odata.context")
Write-Status "Import $($obj.displayName)"
$objType = Get-AppProtectionObjectType $obj."@odata.context"
if($objType)
{
#Import the app configuration policy
$response = Invoke-GraphRequest -Url "/deviceAppManagement/$objType" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
if($response -and $apps)
{
# Import targeted apps
$response2 = Invoke-GraphRequest -Url "/deviceAppManagement/$objType/$($response.Id)/targetApps" -Content "{ apps: $(ConvertTo-Json $apps -Depth 5)}" -HttpMethod POST
}
$response
}
}
function Import-AllAppProtectionObjects
{
param($path = "$env:Temp")
Import-AppProtectionObjects (Get-JsonFileObjects $path)
}
function Import-AppProtectionObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import app protection/configuration policies"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import App Protection/Configuration: $($obj.Object.displayName)"
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
$response = Import-AppProtection $obj.Object
if($response)
{
$global:importedObjects++
$dataType = Get-AppProtectionObjectType $response."@odata.context"
if($dataType)
{
Import-GraphAssignments $assignments "assignments" "/deviceAppManagement/$dataType/$($response.Id)/assign"
}
}
}
$dgObjects.ItemsSource = @(Get-AppProtectionObjects)
Write-Status ""
}

View File

@@ -1,249 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-AutoPilotName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-AutoPilots}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-AutoPilotName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all AutoPilot policies"
Import-AllAutoPilotObjects (Join-Path $rootFolder (Get-AutoPilotFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-AutoPilotName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all AutoPilot policies"
Get-AutoPilotObjects | ForEach-Object { Export-SingleAutoPilotObject $PSItem.Object (Join-Path $rootFolder (Get-AutoPilotFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-AutoPilotFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-AutoPilotName
{
(Get-AutoPilotFolderName)
}
function Get-AutoPilotFolderName
{
"AutoPilot"
}
function Get-AutoPilots
{
Write-Status "Loading AutoPilot profiles"
$dgObjects.ItemsSource = @(Get-AutoPilotObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllAutoPilots $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedAutoPilotObject $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllAutoPilotObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-AutoPilotObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-AutoPilot}) -ViewFullObject ([scriptblock]{Get-AutoPilotObject $global:dgObjects.SelectedItem.Object})
}
function Get-AutoPilotObjects
{
Get-GraphObjects -Url "/deviceManagement/windowsAutopilotDeploymentProfiles"
}
function Get-AutoPilotObject
{
param($object, $additional = "")
if(-not $Object.id) { return }
Invoke-GraphRequest -Url "/deviceManagement/windowsAutopilotDeploymentProfiles/$($Object.id)$additional"
}
function Export-AllAutoPilots
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleAutoPilotObject $objTmp.Object $path
}
}
}
function Export-SelectedAutoPilotObject
{
param($path = "$env:Temp")
Export-SingleAutoPilotObject $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleAutoPilotObject
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-AutoPilotFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = Invoke-GraphRequest -Url "/deviceManagement/windowsAutopilotDeploymentProfiles/$($psObj.id)?`$expand=assignments"
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
Add-MigrationInfo $obj.assignments
}
$global:exportedObjects++
}
}
function Copy-AutoPilot
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect AutoPilot item you want to copy", "Error", "OK", "Error")
return
}
$ret = Show-InputDialog "Copy AutoPilot" "Select name for the new object" "$($dgObjects.SelectedItem.displayName) Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
# Convert to Json and back to clone the object
$obj = ConvertTo-Json $dgObjects.SelectedItem.Object -Depth 5 | ConvertFrom-Json
if($obj)
{
# Import new profile
$obj.displayName = Remove-InvalidFileNameChars $ret
Import-AutoPilot $obj | Out-Null
$dgObjects.ItemsSource = @(Get-AutoPilotObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-AutoPilot
{
param($obj)
Write-Status "Import $($obj.displayName)"
Start-PreImport $obj
Invoke-GraphRequest -Url "/deviceManagement/windowsAutopilotDeploymentProfiles" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
}
function Import-AllAutoPilotObjects
{
param(
$path = "$env:Temp"
)
Import-AutoPilotObjects (Get-JsonFileObjects $path)
}
function Import-AutoPilotObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import AutoPilot profiles"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import AutoPilot profile: $($obj.Object.displayName)"
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
$response = Import-AutoPilot $obj.Object
if($response)
{
$global:importedObjects++
Import-GraphAssignments2 $assignments "/deviceManagement/windowsAutopilotDeploymentProfiles/$($response.Id)/assignments"
}
}
$dgObjects.ItemsSource = @(Get-AutoPilotObjects)
Write-Status ""
}

View File

@@ -1,319 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-AZBrandingName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-AZBrandings}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-AZBrandingName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all Azure branding"
Import-AllAZBrandingObjects (Join-Path $rootFolder (Get-AZBrandingFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-AZBrandingName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all Azure branding"
Get-AZBrandingObjects | ForEach-Object { Export-SingleAZBranding $PSItem.Object (Join-Path $rootFolder (Get-AZBrandingFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-AZBrandingFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-AZBrandingName
{
return "Azure Branding"
}
function Get-AZBrandingFolderName
{
return "AZBranding"
}
function Get-AZBrandings
{
Write-Status "Loading Azure brandings"
$dgObjects.ItemsSource = @(Get-AZBrandingObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllAZBrandings $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedAZBranding $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("DisplayColumn", "localeDisplayName")
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllAZBrandingObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-AZBrandingObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -ViewFullObject ([scriptblock]{Get-AZBrandingObject $global:dgObjects.SelectedItem.Object})
}
function Get-AZBrandingObjects
{
$response = Get-AzureNativeObjects "LoginTenantBrandings" -property @('locale', 'localeDisplayName')
if($response)
{
$response | Where { $_.Object.isConfigured -eq $true }
}
}
function Get-AZBrandingObject
{
param($object, $additional = "")
if(-not $Object.locale) { return }
Invoke-AzureNativeRequest "LoginTenantBrandings/$($Object.locale)$additional"
}
function Export-AllAZBrandings
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleAZBranding $objTmp.Object $path
}
}
}
function Export-SelectedAZBranding
{
param($path = "$env:Temp")
Export-SingleAZBranding $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleAZBranding
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-AZBrandingFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.localeDisplayName)"
$obj = Invoke-AzureNativeRequest "LoginTenantBrandings/$($psObj.locale)"
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.localeDisplayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
Save-AzureBrandingFile $obj "tileLogoUrl" $path
Save-AzureBrandingFile $obj "bannerLogoUrl" $path
Save-AzureBrandingFile $obj "illustrationUrl" $path
Save-AzureBrandingFile $obj "squareLogoDarkUrl" $path
$global:exportedObjects++
}
Set-ObjectPath $global:txtExportPath.Text
}
}
function Save-AzureBrandingFile
{
param($obj, $prop, $path)
if(-not $obj.$prop) { return }
$arr=$obj.$prop.Split('.')
if($arr.Length -ne 1)
{
return
}
$fileType = "jpg" # Assume...not OK. $arr[0] contains information about what kind of file it is
$fileName = "$path\$((Remove-InvalidFileNameChars "$($obj.localeDisplayName).$prop.$fileType"))"
try
{
if(Test-Path $fileName)
{
Remove-Item -Path $fileName -Force
}
[IO.File]::WriteAllBytes($fileName, [System.Convert]::FromBase64String($arr[1]))
}
catch {}
}
function Import-AZBranding
{
param($obj)
if($global:runningBulkImport -eq $true)
{
# Update Default and create the rest...
$createNew = $obj.locale -ne 0
}
else
{
$curObj = $global:lstFiles.ItemsSource | Where { $_.Object.locale -eq $obj.locale }
if($curObj -and $obj.locale -ne 0)
{
return # Do not update existing object except default
}
elseif(-not $curObj)
{
$createNew = $true
}
else
{
$createNew = $false
}
}
$json = "{"
if($createNew) { $json += "`"locale`":`"$($obj.locale)`"," }
if($obj.signInUserIdLabel) { $json += "`"userIdLabel`": `"$($obj.signInUserIdLabel)`"," }
if($obj.signInPageText) { $json += "`"boilerPlateText`": `"$($obj.signInPageText)`"," }
if($obj.signInBackColor) { $json += "`"backgroundColor`": `"$($obj.signInBackColor)`"," }
if($obj.tileLogoUrl) { $json += "`"tileLogoUrl`": `"$($obj.tileLogoUrl)`"," }
if($obj.bannerLogoUrl) { $json += "`"bannerLogoUrl`": `"$($obj.bannerLogoUrl)`"," }
if($obj.illustrationUrl) { $json += "`"illustrationUrl`": `"$($obj.illustrationUrl)`"," }
if($obj.squareLogoDarkUrl) { $json += "`"squareLogoDarkUrl`": `"$($obj.squareLogoDarkUrl)`"," }
if($obj.hideKeepMeSignedIn -and $obj.locale -eq 0) { $json += "`"keepMeSignedInDisabled`": $($obj.hideKeepMeSignedIn.ToString().ToLower())," }
if($createNew)
{
if($curObj.bannerLogoUrl -ne $curObj.bannerLogoUrl)
{
$json += "`"isTileLogoUpdated`":true,"
}
if($curObj.illustrationUrl -ne $curObj.illustrationUrl)
{
$json += "`"isIllustrationImageUpdated`":true,"
}
if($curObj.squareLogoDarkUrl -ne $curObj.squareLogoDarkUrl)
{
$json += "`"isSquareDarkLogoUpdated`":true,"
}
if($curObj.bannerLogoUrl -ne $curObj.bannerLogoUrl)
{
$json += "`"isBannerLogoUpdated`":true,"
}
}
$json = $json.TrimEnd(',')
$json += "}"
Write-Status "Import $($obj.localeDisplayName)"
if($createNew)
{
Invoke-AzureNativeRequest "LoginTenantBrandings" -Method POST -Body $json | Out-Null
}
else
{
Invoke-AzureNativeRequest "LoginTenantBrandings/$($obj.locale)" -Method PATCH -Body $json | Out-Null
}
}
function Import-AllAZBrandingObjects
{
param($path = "$env:Temp")
Import-AZBrandingObjects (Get-JsonFileObjects $path)
}
function Import-AZBrandingObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import Azure brandings"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import Azure branding"
$response = Import-AZBranding $obj.Object
if($response)
{
$global:importedObjects++
}
}
$dgObjects.ItemsSource = @(Get-AZBrandingObjects)
Write-Status ""
}

View File

@@ -1,221 +0,0 @@
#Requires -module Az.Accounts
function Invoke-InitializeModule
{
if(-not $global:AzToken)
{
# Only allow re-logging if it failed the first time
$global:AuthenticatedToAzure = $false
}
#!!! - Used for testing login
#Disconnect-AzAccount -Username admin@delematelab2.onmicrosoft.com
}
function Connect-AzureNative
{
<#
.SYNOPSIS
Tries to connect to Azure with existing token
Uses Connect-AZAccount if no token found in cache
#>
param($user)
Write-Log "Authenticate to Azure (Az module). Try from cache with user $user"
$Context = (Get-AzContext -ListAvailable | Where { $_.Account.Id -eq $user } | select -first 1)
if (-not $Context)
{
$user | Clip # Copy login id to clipboard
# Run Connect-AZAccount in a separate runspace or it will hang
$Runspace = [runspacefactory]::CreateRunspace()
$PowerShell = [powershell]::Create()
$PowerShell.Runspace = $Runspace
$Runspace.Open()
$PowerShell.AddScript({Connect-AZAccount})
$PowerShell.Invoke()
[System.Windows.Forms.Application]::DoEvents()
$Context = (Get-AzContext -ListAvailable | Where { $_.Account.Id -eq $user } | select -first 1)
}
$global:AzToken = ""
try
{
$Resource = '74658136-14ec-4630-ad9b-26e160ff0fc6'
$global:AzToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id, $null, "Never", $null, $Resource)
}
catch
{
Write-LogError "Failed to authenticate with Instance.AuthenticationFactory.Authenticate" $_.Exception
}
if(-not $global:AzToken)
{
Write-Log "Failed to authenticate" 3
}
else
{
Write-Log "Authenticated as $($global:AzToken.UserId)"
}
$global:AuthenticatedToAzure = $true
Set-MainTitle
}
# Invoke-AzureNativeRequest is based on the following project
# https://github.com/JustinGrote/Az.PortalAPI/tree/master/Az.PortalAPI
#
# Some small changes:
# - Get-AzContext is based on the same user as Intune user
# - Renamed Invoke-Request to Invoke-AzureNativeRequest
# - Added support for HTTP Method PATCH
# - Added support for paging with nextLink (Lazy solution...not fully tested but looks like it is working)
# - Removed Token parameter. Created the Connect-AzureNative to get token
# - Removed Context parameter
function Invoke-AzureNativeRequest {
<#
.SYNOPSIS
Runs a command against the Azure Portal API
#>
[CmdletBinding(SupportsShouldProcess)]
param (
#The target of your request. This is appended to the Portal API URI. Example: Permissions
[Parameter(Mandatory)]$Target,
#The command you wish to execute. Example: GetUserSystemRoleTemplateIds
[Parameter()]$Action,
#The body of your request. This is usually in JSON format
$Body,
#Specify the HTTP Method you wish to use. Defaults to GET
[ValidateSet("GET","POST","OPTIONS","DELETE","PATCH")]
$Method = "GET",
#The base URI for the Portal API. Typically you don't need to change this
[Uri]$baseURI = 'https://main.iam.ad.ext.azure.com/api/',
[URI]$requestOrigin = 'https://iam.hosting.portal.azure.net',
#The request ID for the session. You can generate one with [guid]::NewGuid().guid.
#Typically you only specify this if you're trying to retry an operation and don't want to duplicate the request, such as for a POST operation
$requestID = [guid]::NewGuid().guid,
[switch]$allowPaging
)
if(-not $global:AzToken -and $global:AuthenticatedToAzure -eq $false)
{
Connect-AzureNative $global:me.userPrincipalName
}
if(-not $global:AzToken)
{
return
}
#Combine the BaseURI and Target
[String]$ApiAction = $Target.TrimStart('/')
if ($Action) {
$ApiAction = $ApiAction + '/' + $Action
}
$uriStr = "$baseURI$ApiAction"
if($allowPaging)
{
$uri = [Uri]::New("$uriStr&nextLink=null")
}
else
{
$uri = [Uri]::New($baseURI,$ApiAction)
}
if(-not $global:AzToken.AccessToken.tostring())
{
Write-Log "No access token available" 3
return
}
$InvokeRestMethodParams = @{
Uri = $uri
Method = $Method
Header = [ordered]@{
Authorization = 'Bearer ' + $global:AzToken.AccessToken.tostring()
'Content-Type' = 'application/json'
'x-ms-client-request-id' = $requestID
'Host' = $baseURI.Host
'Origin' = 'https://iam.hosting.portal.azure.net'
}
Body = $Body
}
$max = 100
$cur = 0
$retObj = Invoke-RestMethod @InvokeRestMethodParams
if(($retObj | GM -MemberType NoteProperty -Name "nextLink"))
{
while($retObj.nextLink)
{
# Get more objects
$InvokeRestMethodParams["Uri"] = [Uri]::New($uriStr + "&nextLink=" + $retObj.nextLink)
$retObj = Invoke-RestMethod @InvokeRestMethodParams
if($cur -ge $max) { break }
$cur++ # Loop gets stuck if nextLink=null is added to the command line so make sure it doesn't hang forever
}
}
$retObj
}
function Get-AzureNativeObjects
{
param(
[Array]
$Target,
[Array]
$property,
[Array]
$exclude,
$SortProperty = "",
[switch]$allowPaging)
$objects = @()
$nativeObjects = Invoke-AzureNativeRequest $Target -allowPaging:($allowPaging -eq $true)
if(($nativeObjects | GM -Name "items"))
{
$objectList = $nativeObjects.Items
}
else
{
$objectList = $nativeObjects
}
foreach($nativeObject in $objectList)
{
$params = @{}
if($property) { $params.Add("Property", $property) }
if($exclude) { $params.Add("ExcludeProperty", $exclude) }
foreach($objTmp in ($nativeObject | select @params))
{
$objTmp | Add-Member -NotePropertyName "Object" -NotePropertyValue $nativeObject
$objects += $objTmp
}
}
if($objects.Count -gt 0 -and $SortProperty -and ($objects[0] | GM -MemberType NoteProperty -Name $SortProperty))
{
$objects = $objects | sort -Property $SortProperty
}
$objects
}

View File

@@ -1,306 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-BaselineTemplatesName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-BaselineTemplates}
})
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-BaselineName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-BaselineProfiles}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-AppProtectionName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all baseline policies"
Import-AllBaselineProfileObjects (Join-Path $rootFolder (Get-BaselineFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-AppProtectionName)
Folder = (Get-BaselineFolderName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all baseline policies"
Get-BaselineProfileObjects | ForEach-Object { Export-SingleBaselineProfile $PSItem.Object (Join-Path $rootFolder (Get-BaselineFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-BaselineFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-BaselineTemplatesName
{
return "Baseline Templates"
}
function Get-BaselineName
{
return "Baseline Profiles"
}
function Get-BaselineFolderName
{
return "Baseline"
}
function Get-BaselineTemplates
{
Write-Status "Loading baseline templates" -SkipLog
$dgObjects.ItemsSource = @(Get-BaselineTemplateObjects)
}
function Get-BaselineTemplateObjects
{
Get-GraphObjects -Url "/deviceManagement/templates"
}
function Get-BaselineProfiles
{
Write-Status "Loading banding profiles" -SkipLog
$dgObjects.ItemsSource = @(Get-BaselineProfileObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllBaselineProfiles $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedBaselineProfile $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllBaselineProfileObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-BaselineProfileObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude @("*_Settings.json","*_assignments.json"))
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-BaselineProfile}) -ViewFullObject ([scriptblock]{Get-BaselineProfileObject $global:dgObjects.SelectedItem.Object})
}
function Get-BaselineProfileObjects
{
Get-GraphObjects -Url "/deviceManagement/intents"
}
function Get-BaselineProfileObject
{
param($object, $additional = "")
if(-not $Object.id) { return }
$profile = Invoke-GraphRequest -Url "/deviceManagement/intents/$($Object.id)"
$settings = Invoke-GraphRequest -Url "/deviceManagement/intents/$($Object.id)/Settings"
@($profile, $settings)
}
function Export-AllBaselineProfiles
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleBaselineProfile $objTmp.Object $path
}
}
}
function Export-SelectedBaselineProfile
{
param($path = "$env:Temp")
Export-SingleBaselineProfile $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleBaselineProfile
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-BaselineFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = $psObj
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
$settings = Invoke-GraphRequest -Url "/deviceManagement/intents/$($obj.id)/settings"
ConvertTo-Json $settings.value -Depth 5 | Out-File "$path\$($obj.displayName)_Settings.json" -Force
}
$assignments = Invoke-GraphRequest -Url "/deviceManagement/intents/$($obj.id)/assignments"
if(($assignments.Value | measure).Count -gt 0)
{
ConvertTo-Json $assignments.value -Depth 5| Out-File "$path\$($obj.displayName)_assignments.json" -Force
}
$global:exportedObjects++
}
}
function Copy-BaselineProfile
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect baseline profile you want to copy", "Error", "OK", "Error")
return
}
$ret = Show-InputDialog "Copy baseline profiles" "Select name for the new object" "$($dgObjects.SelectedItem.displayName) - Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
# Convert to Json and back to clone the object
$obj = ConvertTo-Json $dgObjects.SelectedItem.Object -Depth 5 | ConvertFrom-Json
$settings = Invoke-GraphRequest -Url "/deviceManagement/intents/$($obj.id)/settings"
$intentSettings = ConvertTo-Json $settings.value -Depth 5
if($obj)
{
# Import new profile
$obj.displayName = $ret
Import-BaselineProfile $obj $intentSettings | Out-null
$dgObjects.ItemsSource = @(Get-BaselineProfileObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-BaselineProfile
{
param($obj, $intentSettings, $templateId)
$json = @"
{
"displayName": "$($obj.displayName)",
"description": "$($obj.description)",
"settingsDelta":
$($intentSettings)
}
"@
if($templateId)
{
$tempId = $templateId
}
else
{
$tempId = $obj.templateId
}
Write-Status "Import $($obj.displayName)"
return Invoke-GraphRequest -Url "/deviceManagement/templates/$($tempId)/createInstance" -Content $json -HttpMethod POST
}
function Import-AllBaselineProfileObjects
{
param(
$path = "$env:Temp"
)
Import-BaselineProfileObjects (Get-JsonFileObjects $path)
}
function Import-BaselineProfileObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import terms and conditions"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import security baseline: $($obj.Object.displayName)"
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
$settingsFile = $obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_settings.json"
if(-not (Test-Path $settingsFile)) { continue }
$intentSettings = Get-Content $settingsFile -Raw
$response = Import-BaselineProfile $obj.Object $intentSettings
if($response)
{
$global:importedObjects++
Import-GraphAssignments $assignments "assignments" "/deviceManagement/intents/$($response.Id)/assign"
}
}
$dgObjects.ItemsSource = @(Get-BaselineProfileObjects)
Write-Status ""
}

View File

@@ -1,236 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-IntuneBrandingName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-IntuneBrandings}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-IntuneBrandingName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all Intune branding objects"
Import-AllIntuneBrandingObjects (Join-Path $rootFolder (Get-IntuneBrandingFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-IntuneBrandingName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all Intune branding objects"
Get-IntuneBrandingObjects | ForEach-Object { Export-SingleIntuneBranding $PSItem.Object (Join-Path $rootFolder (Get-IntuneBrandingFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-IntuneBrandingFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-IntuneBrandingName
{
return "Intune Branding"
}
function Get-IntuneBrandingFolderName
{
return "IntuneBranding"
}
function Get-IntuneBrandings
{
Write-Status "Loading banding profiles"
$dgObjects.ItemsSource = @(Get-IntuneBrandingObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllIntuneBrandings $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
# Same as ExportAllScript since only one object is supported
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-AllIntuneBrandings $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllIntuneBrandingObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-IntuneBrandingObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles})
}
function Get-IntuneBrandingObjects
{
Get-GraphObjects -Url "/deviceManagement/intuneBrand" -property @("displayName")
}
function Export-AllIntuneBrandings
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleIntuneBranding $objTmp.Object $path
}
}
}
function Export-SingleIntuneBranding
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-IntuneBrandingFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = $psObj
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
Save-IntuneBrandingFile $obj "lightBackgroundLogo" $path
Save-IntuneBrandingFile $obj "darkBackgroundLogo" $path
Save-IntuneBrandingFile $obj "landingPageCustomizedImage" $path
}
$global:exportedObjects++
}
}
function Save-IntuneBrandingFile
{
param($obj, $prop, $path)
if(-not $obj.$prop.type) { return }
$arr=$obj.$prop.type.Split('/')
if($arr.Length -gt 1)
{
$fileType = $arr[1]
}
else
{
$fileType = ".jpg" # assume...
}
$fileName = "$path\$((Remove-InvalidFileNameChars "$($obj.displayName).$prop.$fileType"))"
try
{
if(Test-Path $fileName)
{
Remove-Item -Path $fileName -Force
}
[IO.File]::WriteAllBytes($fileName, [System.Convert]::FromBase64String($obj.$prop.value))
}
catch {}
}
function Import-IntuneBranding
{
param($obj)
Start-PreImport $obj -RemoveProperties @("@odata.context")
$newObject = @"
{
"intuneBrand":$((ConvertTo-Json $obj -Depth 5))
}
"@
Write-Status "Import $($obj.displayName)"
# Note: Branding is imported to deviceManagement with JSON parent object intuneBrand
Invoke-GraphRequest -Url "$URL/deviceManagement" -Content $newObject -HttpMethod PATCH
}
function Import-AllIntuneBrandingObjects
{
param($path = "$env:Temp")
Import-IntuneBrandingObjects (Get-JsonFileObjects $path)
}
function Import-IntuneBrandingObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import Intune branding"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import Intune branding"
$response = Import-IntuneBranding $obj.Object
# Note: No assignments for branding. This is default branding for everyone
}
$dgObjects.ItemsSource = @(Get-IntuneBrandingObjects)
Write-Status ""
}

View File

@@ -1,255 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-CompliancePolicyName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-CompliancePolicies}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-CompliancePolicyName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all Intune compliance policies"
Import-AllCompliancePolicyObjects (Join-Path $rootFolder (Get-CompliancePolicyFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-CompliancePolicyName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all compliance policies"
Get-CompliancePolicyObjects | ForEach-Object { Export-SingleCompliancePolicy $PSItem.Object (Join-Path $rootFolder (Get-CompliancePolicyFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-CompliancePolicyFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-CompliancePolicyName
{
return "Compliance Policies"
}
function Get-CompliancePolicyFolderName
{
return "CompliancePolicies"
}
function Get-CompliancePolicies
{
Write-Status "Loading compliance policies"
$dgObjects.ItemsSource = @(Get-CompliancePolicyObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllCompliancePolicies $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedCompliancePolicy $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllCompliancePolicyObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-CompliancePolicyObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-CompliancePolicy}) -ViewFullObject ([scriptblock]{Get-CompliancePolicyObject $global:dgObjects.SelectedItem.Object})
}
function Get-CompliancePolicyObjects
{
Get-GraphObjects -Url "/deviceManagement/deviceCompliancePolicies"
}
function Get-CompliancePolicyObject
{
param($object, $additional = "")
if(-not $Object.id) { return }
Invoke-GraphRequest -Url "/deviceManagement/deviceCompliancePolicies/$($Object.id)$additional"
}
function Export-AllCompliancePolicies
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleCompliancePolicy $objTmp.Object $path
}
}
}
function Export-SelectedCompliancePolicy
{
param($path = "$env:Temp")
Export-SingleCompliancePolicy $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleCompliancePolicy
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-CompliancePolicyFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = Invoke-GraphRequest -Url "/deviceManagement/deviceCompliancePolicies/$($psObj.id)?`$expand=assignments"
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
Add-MigrationInfo $obj.assignments
}
$global:exportedObjects++
}
}
function Copy-CompliancePolicy
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect compliance policy item you want to copy", "Error", "OK", "Error")
return
}
$ret = Show-InputDialog "Copy compliance policy" "Select name for the new object" "$($dgObjects.SelectedItem.displayName) - Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
# Convert to Json and back to clone the object
$obj = ConvertTo-Json $dgObjects.SelectedItem.Object -Depth 5 | ConvertFrom-Json
if($obj)
{
# Import new profile
$obj.displayName = $ret
Import-CompliancePolicy $obj | Out-null
$dgObjects.ItemsSource = @(Get-CompliancePolicyObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-CompliancePolicy
{
param($obj)
Start-PreImport $obj
$json = ConvertTo-Json $obj -Depth 5
$json = $json.Trim().TrimEnd('}').Trim()
$json += @"
,
"scheduledActionsForRule":[{"ruleName":"PasswordRequired","scheduledActionConfigurations":[{"actionType":"block","gracePeriodHours":0,"notificationTemplateId":"","notificationMessageCCList":[]}]}]
}
"@
Write-Status "Import $($obj.displayName)"
Invoke-GraphRequest -Url "/deviceManagement/deviceCompliancePolicies" -Content $json -HttpMethod POST
}
function Import-AllCompliancePolicyObjects
{
param($path = "$env:Temp")
Import-CompliancePolicyObjects (Get-JsonFileObjects $path)
}
function Import-CompliancePolicyObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import compliance policies"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import Compliance Policy: $($obj.Object.displayName)"
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
$response = Import-CompliancePolicy $obj.Object
if($response)
{
$global:importedObjects++
Import-GraphAssignments $assignments "assignments" "/deviceManagement/deviceCompliancePolicies/$($response.Id)/assign"
}
}
$dgObjects.ItemsSource = @(Get-CompliancePolicyObjects)
Write-Status ""
}

View File

@@ -1,291 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-ConditionalAccessName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-ConditionalAccess}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-ConditionalAccessName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all conditional access policies"
Import-AllConditionalAccessObjects (Join-Path $rootFolder (Get-ConditionalAccessFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-ConditionalAccessName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all conditional access policies"
Get-ConditionalAccessObjects | ForEach-Object { Export-SingleConditionalAccess $PSItem.Object (Join-Path $rootFolder (Get-ConditionalAccessFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-ConditionalAccessFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-ConditionalAccessName
{
return "Conditional Access"
}
function Get-ConditionalAccessFolderName
{
return "ConditionalAccess"
}
function Get-ConditionalAccess
{
Write-Status "Loading conditional access objects"
$dgObjects.ItemsSource = @(Get-ConditionalAccessObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllConditionalAccess $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedConditionalAccess $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllConditionalAccessObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-ConditionalAccessObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -ViewFullObject ([scriptblock]{Get-ConditionalAccessObject $global:dgObjects.SelectedItem.Object})
}
function Get-ConditionalAccessObjects
{
#https://main.iam.ad.ext.azure.com/api/Policies/Policies?top=10&nextLink=null&appId=&includeBaseline=true
Get-AzureNativeObjects "Policies/Policies?top=10&appId=&includeBaseline=true" -property @('policyName') -allowPaging
}
function Get-ConditionalAccessObject
{
param($object, $additional = "")
if(-not $Object.policyId) { return }
if($Object.baselineType -eq 0)
{
Invoke-AzureNativeRequest "Policies/$($Object.policyId)$additional"
}
else
{
Invoke-AzureNativeRequest "BaselinePolicies/$($Object.policyId)$additional"
}
}
function Export-AllConditionalAccess
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleConditionalAccess $objTmp.Object $path
}
}
}
function Export-SelectedConditionalAccess
{
param($path = "$env:Temp")
Export-SingleConditionalAccess $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleConditionalAccess
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-ConditionalAccessFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.policyName)"
if($psObj.baselineType -eq 0)
{
$obj = Invoke-AzureNativeRequest "Policies/$($psObj.policyId)"
}
else
{
$obj = Invoke-AzureNativeRequest "BaselinePolicies/$($psObj.policyId)"
}
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $psObj.policyName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
}
if($jsonObj.usersV2.included.groupIds)
{
$jsonObj.usersV2.included.groupIds | ForEach-Object { Add-GroupMigrationObject $PSItem }
}
if($jsonObj.usersV2.excluded.groupIds)
{
$jsonObj.usersV2.excluded.groupIds | ForEach-Object { Add-GroupMigrationObject $PSItem }
}
if($jsonObj.usersV2.included.userIds -or $jsonObj.usersV2.excluded.userIds)
{
Write-Log "Users are specified in $($psObj.policyName). User are not supported in this version. This conditional access policy might not be imported" 2
}
if($jsonObj.usersV2.included.roleIds -or $jsonObj.usersV2.excluded.roleIds)
{
Write-Log "Roles are specified in $($psObj.policyName). Roles are not supported in this version. This conditional access policy might not be imported" 2
}
if($jsonObj.conditions.namedNetworks.includedNetworkIds -or $jsonObj.conditions.namedNetworks.excludedNetworkIds)
{
Write-Log "Networks are specified in $($psObj.policyName). Named networks are not supported in this version. This conditional access policy might not be imported" 2
}
# There might be a lot more to check here...
$global:exportedObjects++
}
}
function Import-ConditionalAccess
{
param($obj)
Start-PreImport $obj
$json = Update-JsonForEnvironment $json
if($obj.baselineType -eq 0)
{
$obj.policyId = ""
$obj.isAllProtocolsEnabled = $true
$json = ConvertTo-Json $obj -Depth 10
$json = Update-JsonForEnvironment $json
if((Invoke-AzureNativeRequest "Policies/Validate" -Method POST -Body $json) -eq 11)
{
Invoke-AzureNativeRequest "Policies" -Method POST -Body $json | Out-Null
}
else
{
Write-Log "Policy validation of json data failed" 3
}
}
else
{
Write-Log "Conditional Access Baseline Policies does not support import"
#Invoke-AzureNativeRequest "BaselinePolicies/$($obj.id)" -Method PUT -Body (ConvertTo-Json $obj -Depth 5) | Out-Null
}
}
function Import-AllConditionalAccessObjects
{
param($path = "$env:Temp")
Import-ConditionalAccessObjects (Get-JsonFileObjects $path)
}
function Import-ConditionalAccessObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import conditional access policies"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import Conditional Access: $($obj.Object.policyName)"
$response = Import-ConditionalAccess $obj.Object
if($response)
{
$global:importedObjects++
}
# No additionl assignments on conditional access policies
}
$dgObjects.ItemsSource = @(Get-ConditionalAccessObjects)
Write-Status ""
}
<#
# Get all networks
Get-AzureNativeObjects "NamedNetworksV2"
# Network example
#{"networkName":"Australia","cidrIpRanges":[],"categories":[],"applyToUnknownCountry":false,"countryIsoCodes":["AU"],"isTrustedLocation":false,"namedLocationsType":2}
Get-AzureNativeObjects "NamedNetworksV2" -Method POST -Body $json | Out-Nul
# Get all contry codes
NamedNetworksV2/CountryCodes
#>

View File

@@ -1,251 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-DeviceConfigurationName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-DeviceConfigurations}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-DeviceConfigurationName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all device configuration objects"
Import-AllDeviceConfigurationObjects (Join-Path $rootFolder (Get-DeviceConfigurationFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-DeviceConfigurationName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all device configuration objects"
Get-DeviceConfigurationObjects | ForEach-Object { Export-SingleDeviceConfiguration $PSItem.Object (Join-Path $rootFolder (Get-DeviceConfigurationFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-DeviceConfigurationFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-DeviceConfigurationName
{
return "Device Configurations"
}
function Get-DeviceConfigurationFolderName
{
return "DeviceConfigurations"
}
function Get-DeviceConfigurations
{
Write-Status "Loading device configurations"
$dgObjects.ItemsSource = @(Get-DeviceConfigurationObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllDeviceConfigurations $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedDeviceConfiguration $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllDeviceConfigurationObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-DeviceConfigurationObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-DeviceConfiguration}) -ViewFullObject ([scriptblock]{Get-DeviceConfigurationObject $global:dgObjects.SelectedItem.Object})
}
function Get-DeviceConfigurationObjects
{
Get-GraphObjects -Url "/deviceManagement/deviceConfigurations"#,"/deviceManagement/groupPolicyConfigurations"
}
function Get-DeviceConfigurationObject
{
param($object, $additional = "")
if(-not $Object.id) { return }
Invoke-GraphRequest -Url "/deviceManagement/deviceConfigurations/$($Object.id)$additional"
}
function Export-AllDeviceConfigurations
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleDeviceConfiguration $objTmp.Object $path
}
}
}
function Export-SelectedDeviceConfiguration
{
param($path = "$env:Temp")
Export-SingleDeviceConfiguration $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleDeviceConfiguration
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-DeviceConfigurationFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = Invoke-GraphRequest -Url "/deviceManagement/deviceConfigurations/$($psObj.id)?`$expand=assignments"
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
if($script:chkExportScript.IsChecked)
{
$fileName = "$path\$($obj.FileName)"
[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($obj.scriptContent)) | Out-File $fileName -Force
}
Add-MigrationInfo $obj.assignments
$global:exportedObjects++
}
}
}
function Copy-DeviceConfiguration
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect device configuration item you want to copy", "Error", "OK", "Error")
return
}
$ret = Show-InputDialog "Copy device configuration" "Select name for the new object" "$($dgObjects.SelectedItem.displayName) - Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
# Convert to Json and back to clone the object
$obj = ConvertTo-Json $dgObjects.SelectedItem.Object -Depth 5 | ConvertFrom-Json
if($obj)
{
# Import new profile
$obj.displayName = $ret
Import-DeviceConfiguration $obj | Out-Null
$dgObjects.ItemsSource = @(Get-DeviceConfigurationObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-DeviceConfiguration
{
param($obj)
Write-Status "Import $($obj.displayName)"
Start-PreImport $obj
Invoke-GraphRequest -Url "/deviceManagement/deviceConfigurations" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
}
function Import-AllDeviceConfigurationObjects
{
param($path = "$env:Temp")
Import-DeviceConfigurationObjects (Get-JsonFileObjects $path)
}
function Import-DeviceConfigurationObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import device configuration profiles"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import device configuration policy: $($obj.Object.displayName)"
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
$response = Import-DeviceConfiguration $obj.Object
if($response)
{
$global:importedObjects++
Import-GraphAssignments $assignments "assignments" "/deviceManagement/deviceConfigurations/$($response.Id)/assign"
}
}
$dgObjects.ItemsSource = @(Get-DeviceConfigurationObjects)
Write-Status ""
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
<#
.SYNOPSIS
Module for read-only Intune objects
.DESCRIPTION
This module is for the Endpoint Info View. It shows read-only objects in Intune
.NOTES
Author: Mikael Karlsson
#>
function Get-ModuleVersion
{
'3.0.0'
}
function Invoke-InitializeModule
{
#Add menu group and items
$global:EMInfoViewObject = (New-Object PSObject -Property @{
Title = "Intune Info"
Description = "Displays read-only information in Intune."
ID = "EMInfoGraphAPI"
ViewPanel = $viewPanel
ItemChanged = { Show-GraphObjects; Write-Status ""}
Activating = { Invoke-EMInfoActivatingView }
Authentication = (Get-MSALAuthenticationObject)
Authenticate = { Invoke-EMInfoAuthenticateToMSAL }
AppInfo = (Get-GraphAppInfo "EM" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547")
SaveSettings = { Invoke-EMSaveSettings }
})
Add-ViewObject $global:EMInfoViewObject
Add-ViewItem (New-Object PSObject -Property @{
Title = "Baseline Templates"
Id = "BaselineTemplates"
ViewID = "EMInfoGraphAPI"
API = "/deviceManagement/templates"
ShowButtons = @("View")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
Icon="EndpointSecurity"
})
Add-ViewItem (New-Object PSObject -Property @{
Title = "Android Google Play"
Id = "AndroidGooglePlay"
ViewID = "EMInfoGraphAPI"
ViewProperties = @("bindStatus", "lastAppSyncDateTime", "ownerUserPrincipalName")
API = "/deviceManagement/androidManagedStoreAccountEnterpriseSettings"
ShowButtons = @("View")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
})
Add-ViewItem (New-Object PSObject -Property @{
Title = "Android Enrolment Profiles"
Id = "AndroidEnrolmentProfiles"
ViewID = "EMInfoGraphAPI"
API = "deviceManagement/androidDeviceOwnerEnrollmentProfiles"
ShowButtons = @("View")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
Icon = "AndroidCOWP"
})
Add-ViewItem (New-Object PSObject -Property @{
Title = "Apple VPP Tokens"
Id = "AppleVPPTokens"
ViewID = "EMInfoGraphAPI"
ViewProperties = @("appleId", "state", "appleId", "id")
API = "/deviceAppManagement/vppTokens"
ShowButtons = @("View")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
})
Add-ViewItem (New-Object PSObject -Property @{
Title = "Apple Enrollment Tokens"
Id = "AppleEnrollmentTokens"
ViewID = "EMInfoGraphAPI"
ViewProperties = @("tokenName", "appleIdentifier", "tokenExpirationDateTime", "id")
API = "/deviceManagement/depOnboardingSettings/?`$top=100"
ShowButtons = @("View")
Permissons=@("DeviceManagementServiceConfig.ReadWrite.All")
})
}
function Invoke-EMInfoActivatingView
{
if(-not $global:EMInfoViewObject.ViewPanel)
{
# Use the same view panel as Intune Manager
$global:EMInfoViewObject.ViewPanel = $global:EMViewObject.ViewPanel
}
}
function Invoke-EMInfoAuthenticateToMSAL
{
$global:EMInfoViewObject.AppInfo = Get-GraphAppInfo "EMAzureApp" "d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
Set-MSALCurrentApp $global:EMInfoViewObject.AppInfo
$usr = (?? $global:MSALToken.Account.UserName (Get-Setting "" "LastLoggedOnUser"))
if($usr)
{
& $global:msalAuthenticator.Login -Account $usr
}
}

View File

@@ -1,288 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-ESPName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-ESPs}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-ESPName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all enrollment status page settings"
Import-AllESPObjects (Join-Path $rootFolder (Get-ESPFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-ESPName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all enrollment status page settings"
Get-ESPObjects | ForEach-Object { Export-SingleESP $PSItem.Object (Join-Path $rootFolder (Get-ESPFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-ESPFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-ESPName
{
return "Enrollment Status Page"
}
function Get-ESPFolderName
{
return "EnrollmentStatusPage"
}
function Get-ESPs
{
Write-Status "Loading enrollment status page objects"
$dgObjects.ItemsSource = @(Get-ESPObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllESPs $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedESP $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllESPObjects $global:txtExportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-ESPObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-ESP}) -ViewFullObject ([scriptblock]{Get-ESPObject $global:dgObjects.SelectedItem.Object})
}
function Get-ESPObjects
{
Get-GraphObjects -Url "/deviceManagement/deviceEnrollmentConfigurations"
}
function Get-ESPObject
{
param($object, $additional = "")
if(-not $Object.id) { return }
Invoke-GraphRequest -Url "/deviceManagement/deviceEnrollmentConfigurations/$($Object.id)$additional"
}
function Export-AllESPs
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleESP $objTmp.Object $path
}
}
}
function Export-SelectedESP
{
param($path = "$env:Temp")
Export-SingleESP $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleESP
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-ESPFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = Invoke-GraphRequest -Url "/deviceManagement/deviceEnrollmentConfigurations/$($psObj.id)" #?`$expand=assignments"
if($obj)
{
if($obj.id -like "*_default*")
{
$idx = $obj.id.ToLower().IndexOf("_default")
$baseName = "Default_" + $obj.id.SubString($idx + "_default".Length)
}
else
{
# ?`$expand=assignments is not working so get assignments
$assignments = Invoke-GraphRequest -Url "/deviceManagement/deviceEnrollmentConfigurations/$($obj.id)/assignments"
if($assignments.value)
{
$obj | Add-Member -NotePropertyName "assignments" -NotePropertyValue $assignments.value
}
$baseName = Remove-InvalidFileNameChars $obj.displayName
}
$fileName = "$path\$baseName.json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
Add-MigrationInfo $obj.assignments
}
$global:exportedObjects++
}
}
function Copy-ESP
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect enrollment status page item you want to copy", "Error", "OK", "Error") | Out-Null
return
}
if($dgObjects.SelectedItem.Object.id -like "*_default*")
{
[System.Windows.MessageBox]::Show("You cannot copy default items`n`nSelect custom entrollment status page item", "Error", "OK", "Error") | Out-Null
return
}
$ret = Show-InputDialog "Copy enrollment status page" "Select name for the new object" "$($dgObjects.SelectedItem.displayName) - Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
# Convert to Json and back to clone the object
$obj = ConvertTo-Json $dgObjects.SelectedItem.Object -Depth 5 | ConvertFrom-Json
if($obj)
{
# Import new profile
$obj.displayName = $ret
Import-ESP $obj | Out-Null
$dgObjects.ItemsSource = @(Get-ESPObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-ESP
{
param($obj)
Start-PreImport $obj
if($obj.id -like "*_default*")
{
Write-Status "Update $($obj.displayName)"
Invoke-GraphRequest -Url "/deviceManagement/deviceEnrollmentConfigurations/$($obj.id)" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod PATCH
}
else
{
Write-Status "Import $($obj.displayName)"
Invoke-GraphRequest -Url "/deviceManagement/deviceEnrollmentConfigurations" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
}
}
function Import-AllESPObjects
{
param($path = "$env:Temp")
Import-ESPObjects (Get-JsonFileObjects $path)
}
function Import-ESPObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import enrollment status page"
foreach($obj in $Objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
if($obj.Object.id -like "*_default*")
{
$idx = $obj.Object.id.ToLower().IndexOf("_default")
$extInfo = " ($($obj.Object.id.SubString($idx + "_default".Length)))"
}
else
{
$extInfo = ""
}
Write-Log "Import Enrollment Status Page: $($obj.Object.displayName)$extInfo"
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
$response = Import-ESP $obj.Object
if($response)
{
$global:importedObjects++
Import-GraphAssignments $assignments "enrollmentConfigurationAssignments" "/deviceManagement/deviceEnrollmentConfigurations/$($response.Id)/assign"
}
}
$dgObjects.ItemsSource = @(Get-ESPObjects)
Write-Status ""
}

View File

@@ -1,335 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-GPOSettingName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-GPOSettings}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-GPOSettingName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all administrative templates"
Import-AllGPOSettingObjects (Join-Path $rootFolder (Get-GPOSettingFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-GPOSettingName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all administrative templates"
Get-GPOSettingObjects | ForEach-Object { Export-SingleGPOSetting $PSItem.Object (Join-Path $rootFolder (Get-GPOSettingFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-GPOSettingFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-GPOSettingName
{
return "Administrative Templates"
}
function Get-GPOSettingFolderName
{
return "AdministrativeTemplates"
}
function Get-GPOSettings
{
Write-Status "Loading administrative templates"
$dgObjects.ItemsSource = @(Get-GPOSettingObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllGPOSettings $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedGPOSetting $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllGPOSettingObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-GPOSettingObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-GPOSetting}) -ViewFullObject ([scriptblock]{Get-GPOSettingObject $global:dgObjects.SelectedItem.Object})
}
function Get-GPOSettingObjects
{
Get-GraphObjects -Url "/deviceManagement/groupPolicyConfigurations"
}
function Get-GPOSettingObject
{
param($object, $additional = "")
if(-not $Object.id) { return }
@((Invoke-GraphRequest -Url "/deviceManagement/groupPolicyConfigurations/$($Object.id)$additional"),(Get-GPOObjectSettings $Object))
}
function Export-AllGPOSettings
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleGPOSetting $objTmp.Object $path
}
}
}
function Export-SelectedGPOSetting
{
param($path = "$env:Temp")
Export-SingleGPOSetting $global:dgObjects.SelectedItem.Object $path
}
function Get-GPOObjectSettings
{
param($GPOObj)
$gpoSettings = @()
# Get all configured policies in the Administrative Templates profile
$GPODefinitionValues = Invoke-GraphRequest -Url "/deviceManagement/groupPolicyConfigurations/$($GPOObj.id)/definitionValues?`$expand=definition"
foreach($definitionValue in $GPODefinitionValues.value)
{
# Get presentation values for the current settings (with presentation object included)
$presentationValues = Invoke-GraphRequest -Url "/deviceManagement/groupPolicyConfigurations/$($GPOObj.id)/definitionValues/$($definitionValue.id)/presentationValues?`$expand=presentation"
# Set base policy settings
$obj = @{
"enabled" = $definitionValue.enabled
"definition@odata.bind" = "$($global:graphURL)/deviceManagement/groupPolicyDefinitions('$($definitionValue.definition.id)')"
}
if($presentationValues.value)
{
# Policy presentation values set e.g. a drop down list, check box, text box etc.
$obj.presentationValues = @()
$presentations = $null
foreach ($presentationValue in $presentationValues.value)
{
# Add presentation@odata.bind property that links the value to the presentation object
$presentationValue | Add-Member -MemberType NoteProperty -Name "presentation@odata.bind" -Value "$($global:graphURL)/deviceManagement/groupPolicyDefinitions('$($definitionValue.definition.id)')/presentations('$($presentationValue.presentation.id)')"
#Remove presentation object so it is not included in the export
Remove-ObjectProperty $presentationValue "presentation"
#Optional removes. Import will igonre them
Remove-ObjectProperty $presentationValue "id"
Remove-ObjectProperty $presentationValue "lastModifiedDateTime"
Remove-ObjectProperty $presentationValue "createdDateTime"
# Add presentation value to the list
$obj.presentationValues += $presentationValue
}
}
$gpoSettings += $obj
}
$gpoSettings
}
function Export-SingleGPOSetting
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-GPOSettingFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = Invoke-GraphRequest -Url "deviceManagement/groupPolicyConfigurations/$($psObj.Id)?`$expand=assignments"
if($obj)
{
# Save Administrative Templates profile
ConvertTo-Json $obj -Depth 5 | Out-File "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json" -Force
# Collect and save all the settings of the Administrative Templates profile
$gpoSettings = Get-GPOObjectSettings $obj
ConvertTo-Json $gpoSettings -Depth 5 | Out-File "$path\$($obj.displayName)_Settings.json" -Force
# Export assignment info
Add-MigrationInfo $obj.assignments
}
$global:exportedObjects++
}
}
function Copy-GPOSetting
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect administrative templates profile you want to copy", "Error", "OK", "Error")
return
}
$ret = Show-InputDialog "Copy administrative template" "Select name for the new profile" "$($dgObjects.SelectedItem.displayName) - Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
# Convert to Json and back to clone the object
$obj = ConvertTo-Json $dgObjects.SelectedItem.Object -Depth 5 | ConvertFrom-Json
if($obj)
{
# Get the settings of the profile
$gpoSettings = Get-GPOObjectSettings $obj
# Import the new profile
$obj.displayName = $ret
Import-GPOSetting $obj $gpoSettings | Out-Null
#Reload objects
$dgObjects.ItemsSource = @(Get-GPOSettingObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-GPOSetting
{
param($obj, $settings)
Write-Status "Import $($obj.displayName)"
Start-PreImport $obj
# Import Administrative Template profile
$response = Invoke-GraphRequest -Url "/deviceManagement/groupPolicyConfigurations" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
if($response)
{
foreach($setting in $settings)
{
Start-PreImport $setting
# Import each setting for the Administrative Template profile
$response2 = Invoke-GraphRequest -Url "/deviceManagement/groupPolicyConfigurations/$($response.id)/definitionValues" -Content (ConvertTo-Json $setting -Depth 5) -HttpMethod POST
}
}
$response
}
function Import-AllGPOSettingObjects
{
param($path = "$env:Temp")
# Read json files and import all objects
# Note: Each json file must match the object type being imported
Import-GPOSettingObjects (Get-JsonFileObjects $path)
}
function Import-GPOSettingObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import administrative template profile"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import Administrative Template: $($obj.Object.displayName)"
$gpoSettings = $null
# Load settings from the <AdminTeplateName>_settings.json file
$settingsFile = ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_settings.json")
if(Test-Path $settingsFile)
{
$gpoSettings = (ConvertFrom-Json (Get-Content $settingsFile -Raw))
}
# Get assignment settings
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
# Import Administrative Template object
$response = Import-GPOSetting $obj.Object $gpoSettings
if($response)
{
$global:importedObjects++
# Import assignments
Import-GraphAssignments $assignments "assignments" "/deviceManagement/groupPolicyConfigurations/$($response.Id)/assign"
}
}
#Reload list of objects
$dgObjects.ItemsSource = @(Get-GPOSettingObjects)
Write-Status ""
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,224 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-MDMMAMName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-MDMMAM}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-MDMMAMName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all MDM/MAM setting"
Import-AllMDMMAMObjects (Join-Path $rootFolder (Get-MDMMAMFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-MDMMAMName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all MDM/MAM settings"
Get-MDMMAMObjects | ForEach-Object { Export-SingleMDMMAM $PSItem.Object (Join-Path $rootFolder (Get-MDMMAMFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-MDMMAMFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-MDMMAMName
{
return "MDM/MAM"
}
function Get-MDMMAMFolderName
{
return "MDMMAM"
}
function Get-MDMMAM
{
Write-Status "Loading MDM/MAM object"
$dgObjects.ItemsSource = @(Get-MDMMAMObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllMDMMAM $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedMDMMAM $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllMDMMAMObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-MDMMAMObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -ViewFullObject ([scriptblock]{Get-MDMMAMObject $global:dgObjects.SelectedItem.Object})
}
function Get-MDMMAMObjects
{
Get-AzureNativeObjects "MdmApplications" -property @('appDisplayName')
}
function Get-MDMMAMObject
{
param($object, $additional = "")
if(-not $Object.objectId) { return }
Invoke-AzureNativeRequest "/MdmApplications/$($Object.objectId)$additional"
}
function Export-AllMDMMAM
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleMDMMAM $objTmp.Object $path
}
}
}
function Export-SelectedMDMMAM
{
param($path = "$env:Temp")
Export-SingleMDMMAM $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleMDMMAM
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-MDMMAMFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.appDisplayName)"
$obj = Invoke-AzureNativeRequest "MdmApplications/$($psObj.objectId)"
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.appDisplayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
}
if($obj.mdmAppliesToGroups)
{
$obj.mdmAppliesToGroups | ForEach-Object { Add-GroupMigrationObject $PSItem.objectId }
}
if($obj.mamAppliesToGroups)
{
$obj.mamAppliesToGroups | ForEach-Object { Add-GroupMigrationObject $PSItem.objectId }
}
$global:exportedObjects++
}
}
function Import-MDMMAM
{
param($obj)
$argStr = "?"
if($obj.enrollmentUrl) { $argStr += "mdmAppliesToChanged=true" }
else{ $argStr += "mdmAppliesToChanged=false" }
if($obj.mamEnrollmentUrl) { $argStr += "&mamAppliesToChanged=true" }
else{ $argStr += "&mamAppliesToChanged=false" }
$response = Invoke-AzureNativeRequest "MdmApplications/$($obj.objectId)$argStr" -Method PUT -Body (Update-JsonForEnvironment (ConvertTo-Json $obj -Depth 5))
}
function Import-AllMDMMAMObjects
{
param($path = "$env:Temp")
Import-MDMMAMObjects (Get-JsonFileObjects $path)
}
function Import-MDMMAMObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import MDM/MAM settings"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import MDM/MAM app settings: $($obj.Object.appDisplayName)"
Import-MDMMAM $obj.Object
# No assignments for MDM/MAM
}
$dgObjects.ItemsSource = @(Get-MDMMAMObjects)
Write-Status ""
}

File diff suppressed because it is too large Load Diff

1952
Extensions/MSGraph.psm1 Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,314 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-PowerShellScriptName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-PowerShellScripts}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-PowerShellScriptName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all powershell scripts"
Import-AllPowerShellScriptObjects (Join-Path $rootFolder (Get-PowerShellScriptFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-PowerShellScriptName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all powershell scripts"
Get-PowerShellScriptObjects | ForEach-Object { Export-SinglePowerShellScript $PSItem.Object (Join-Path $rootFolder (Get-PowerShellScriptFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-PowerShellScriptFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-PowerShellScriptName
{
return "PowerShell Script"
}
function Get-PowerShellScriptFolderName
{
return "PowerShell"
}
function Get-PowerShellScripts
{
Write-Status "Loading PowerShell objects"
$dgObjects.ItemsSource = @(Get-PowerShellScriptObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllPowerShellScripts $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedPowerShellScript $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllPowerShellScriptObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-PowerShellScriptObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
$exportExtension = (New-Object PSObject -Property @{
Xaml = @"
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Margin="0,0,5,0">
<Label Content="Export script" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Export the powershell script to a ps1 file" />
</StackPanel>
<CheckBox Grid.Column='1' Name='chkExportScript' VerticalAlignment="Center" IsChecked="true" />
</Grid>
"@
Script = [ScriptBlock]{
param($form)
$script:chkExportScript = $form.FindName("chkExportScript")
}
})
$script:exportParams.Add("Extension", $exportExtension)
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-PowerShellScript}) -ViewFullObject ([scriptblock]{Get-PowerShellScriptObject $global:dgObjects.SelectedItem.Object})
#Add download button
$btnDownload = New-Object System.Windows.Controls.Button
$btnDownload.Content = 'Download'
$btnDownload.Name = 'btnDownload'
$btnDownload.Margin = "5,0,0,0"
$btnDownload.Width = "100"
$spSubMenu.Children.Insert(0, $btnDownload)
$btnDownload.Add_Click({
Invoke-DownloadScript
})
}
function Get-PowerShellScriptObjects
{
Get-GraphObjects -Url "/deviceManagement/deviceManagementScripts"
}
function Get-PowerShellScriptObject
{
param($object, $additional = "")
if(-not $Object.id) { return }
Invoke-GraphRequest -Url "/deviceManagement/deviceManagementScripts/$($object.id)$additional"
}
function Export-AllPowerShellScripts
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SinglePowerShellScript $objTmp.Object $path
}
}
}
function Export-SelectedPowerShellScript
{
param($path = "$env:Temp")
Export-SinglePowerShellScript $global:dgObjects.SelectedItem.Object $path
}
function Export-SinglePowerShellScript
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-PowerShellScriptFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = Get-PowerShellScriptObject -object $psObj -additional "?`$expand=assignments"
#$obj = Invoke-GraphRequest -Url "/deviceManagement/deviceManagementScripts/$($psObj.id)?`$expand=assignments"
if($obj)
{
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
if($script:chkExportScript.IsChecked)
{
$fileName = "$path\$($obj.FileName)"
[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($obj.scriptContent)) | Out-File $fileName -Force
}
Add-MigrationInfo $obj.assignments
$global:exportedObjects++
}
}
}
function Copy-PowerShellScript
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect PowerShell script you want to copy", "Error", "OK", "Error")
return
}
$ret = Show-InputDialog "Copy PowerShell script" "Select name for the new object" "$($global:dgObjects.SelectedItem.displayName) - Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
$obj = Get-PowerShellScriptObject -object $dgObjects.SelectedItem.Object
#$obj = Invoke-GraphRequest -Url "/deviceManagement/deviceManagementScripts/$($dgObjects.SelectedItem.id)"
if($obj)
{
# Import new profile
$obj.displayName = $ret
Import-PowerShellScript $obj | Out-null
$dgObjects.ItemsSource = @(Get-PowerShellScriptObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-PowerShellScript
{
param($obj)
Start-PreImport $obj -RemoveProperties @("id","assignments@odata.context","assignments")
Write-Status "Import $($obj.displayName)"
Invoke-GraphRequest -Url "/deviceManagement/deviceManagementScripts" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
}
function Import-AllPowerShellScriptObjects
{
param(
$path = "$env:Temp"
)
Import-PowerShellScriptObjects (Get-JsonFileObjects $path)
}
function Import-PowerShellScriptObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import PowerShell scripts"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import PowerShell script: $($obj.Object.displayName)"
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
$response = Import-PowerShellScript $obj.Object
if($response)
{
$global:importedObjects++
Import-GraphAssignments $assignments "deviceManagementScriptAssignments" "/deviceManagement/deviceManagementScripts/$($response.Id)/assign"
}
}
$dgObjects.ItemsSource = @(Get-PowerShellScriptObjects)
Write-Status ""
}
function Invoke-DownloadScript
{
if(-not $global:dgObjects.SelectedItem.Object.id) { return }
$obj = Get-PowerShellScriptObject -object $dgObjects.SelectedItem.Object
#$obj = Invoke-GraphRequest -Url "/deviceManagement/deviceManagementScripts/$($global:dgObjects.SelectedItem.Object.id)"
if($obj.scriptContent)
{
Write-Log "Download PowerShell script '$($obj.FileName)' from $($obj.displayName)"
$fileName = "$path\$($obj.FileName)"
$dlgSave = New-Object -Typename System.Windows.Forms.SaveFileDialog
$dlgSave.InitialDirectory = Get-SettingValue "IntuneRootFolder" $env:Temp
$dlgSave.FileName = $obj.FileName
if($dlgSave.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK -and $dlgSave.Filename)
{
[System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($obj.scriptContent)) | Out-File $dlgSave.Filename -Force
}
}
}

View File

@@ -1,253 +0,0 @@
########################################################
#
# Common module functions
#
########################################################
function Add-ModuleMenuItems
{
Add-MenuItem (New-Object PSObject -Property @{
Title = (Get-TermsAndConditionName)
MenuID = "IntuneGraphAPI"
Script = [ScriptBlock]{Get-TermsAndConditions}
})
}
function Get-SupportedImportObjects
{
$global:importObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-TermsAndConditionName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Import all terms and conditions"
Import-AllTermsAndConditionObjects (Join-Path $rootFolder (Get-TermsAndConditionFolderName))
}
})
}
function Get-SupportedExportObjects
{
$global:exportObjects += (New-Object PSObject -Property @{
Selected = $true
Title = (Get-TermsAndConditionName)
Script = [ScriptBlock]{
param($rootFolder)
Write-Status "Export all Intune terms and conditions"
Get-TermsAndConditionObjects | ForEach-Object { Export-SingleTermsAndCondition $PSItem.Object (Join-Path $rootFolder (Get-TermsAndConditionFolderName)) }
}
})
}
function Export-AllObjects
{
param($addObjectSubfolder)
$subFolder = ""
if($addObjectSubfolder) { $subFolder = Get-TermsAndConditionFolderName }
}
########################################################
#
# Object specific functions
#
########################################################
function Get-TermsAndConditionName
{
return "Terms and Conditions"
}
function Get-TermsAndConditionFolderName
{
return "TermsAndConditions"
}
function Get-TermsAndConditions
{
Write-Status "Loading terms and conditions"
$dgObjects.ItemsSource = @(Get-TermsAndConditionObjects)
#Scriptblocks that will perform the export tasks. empty by default
$script:exportParams = @{}
$script:exportParams.Add("ExportAllScript", [ScriptBlock]{
Export-AllTermsAndConditions $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
$script:exportParams.Add("ExportSelectedScript", [ScriptBlock]{
Export-SelectedTermsAndCondition $global:txtExportPath.Text
Set-ObjectGrid
Write-Status ""
})
#Scriptblock that will perform the import all files
$script:importAll = [ScriptBlock]{
Import-AllTermsAndConditionObjects $global:txtImportPath.Text
Set-ObjectGrid
}
#Scriptblock that will perform the import of selected files
$script:importSelected = [ScriptBlock]{
Import-TermsAndConditionObjects $global:lstFiles.ItemsSource -Selected
Set-ObjectGrid
}
#Scriptblock that will read json files
$script:getImportFiles = [ScriptBlock]{
Show-FileListBox
$global:lstFiles.ItemsSource = @(Get-JsonFileObjects $global:txtImportPath.Text -Exclude "*_Settings.json")
}
Add-DefaultObjectButtons -export ([scriptblock]{Show-DefaultExportGrid @script:exportParams}) -import ([scriptblock]{Show-DefaultImportGrid -ImportAll $script:importAll -ImportSelected $script:importSelected -GetFiles $script:getImportFiles}) -copy ([scriptblock]{Copy-TermsAndCondition}) -ViewFullObject ([scriptblock]{Get-TermsAndConditionObject $global:dgObjects.SelectedItem.Object})
}
function Get-TermsAndConditionObjects
{
Get-GraphObjects -Url "/deviceManagement/termsAndConditions"
}
function Get-TermsAndConditionObject
{
param($object, $additional = "")
if(-not $Object.id) { return }
Invoke-GraphRequest -Url "/deviceManagement/termsAndConditions/$($Object.id)$additional"
}
function Export-AllTermsAndConditions
{
param($path = "$env:Temp")
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
foreach($objTmp in ($global:dgObjects.ItemsSource))
{
Export-SingleTermsAndCondition $objTmp.Object $path
}
}
}
function Export-SelectedTermsAndCondition
{
param($path = "$env:Temp")
Export-SingleTermsAndCondition $global:dgObjects.SelectedItem.Object $path
}
function Export-SingleTermsAndCondition
{
param($psObj, $path = "$env:Temp")
if(-not $psObj) { return }
if($global:runningBulkExport -ne $true)
{
if($global:chkAddCompanyName.IsChecked) { $path = Join-Path $path $global:organization.displayName }
if($global:chkAddObjectType.IsChecked) { $path = Join-Path $path (Get-TermsAndConditionFolderName) }
}
if(-not (Test-Path $path)) { mkdir -Path $path -Force -ErrorAction SilentlyContinue | Out-Null }
if(Test-Path $path)
{
Write-Status "Export $($psObj.displayName)"
$obj = Invoke-GraphRequest -Url "/deviceManagement/termsAndConditions/$($psObj.id)" #?`$expand=assignments"
if($obj)
{
# ?`$expand=assignments is not working so get assignments
$assignments = Invoke-GraphRequest -Url "/deviceManagement/termsAndConditions/$($obj.id)/assignments"
if($assignments.value)
{
$obj | Add-Member -NotePropertyName "assignments" -NotePropertyValue $assignments.value
}
$fileName = "$path\$((Remove-InvalidFileNameChars $obj.displayName)).json"
ConvertTo-Json $obj -Depth 5 | Out-File $fileName -Force
Add-MigrationInfo $obj.assignments
}
$global:exportedObjects++
}
}
function Copy-TermsAndCondition
{
if(-not $dgObjects.SelectedItem)
{
[System.Windows.MessageBox]::Show("No object selected`n`nSelect terms and conditions item you want to copy", "Error", "OK", "Error")
return
}
$ret = Show-InputDialog "Copy terms and conditions" "Select name for the new object" "$($dgObjects.SelectedItem.displayName) - Copy"
if($ret)
{
# Export profile
Write-Status "Export $($dgObjects.SelectedItem.displayName)"
# Get full object for export
$obj = Invoke-GraphRequest -Url "/deviceManagement/termsAndConditions/$($dgObjects.SelectedItem.Object.id)"
if($obj)
{
# Import new profile
$obj.displayName = $ret
Import-TermsAndCondition $obj | Out-Null
$dgObjects.ItemsSource = @(Get-TermsAndConditionObjects)
}
Write-Status ""
}
$dgObjects.Focus()
}
function Import-TermsAndCondition
{
param($obj)
Write-Status "Import $($obj.displayName)"
Start-PreImport $obj
Invoke-GraphRequest -Url "/deviceManagement/termsAndConditions" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
}
function Import-AllTermsAndConditionObjects
{
param($path = "$env:Temp")
Import-TermsAndConditionObjects (Get-JsonFileObjects $path)
}
function Import-TermsAndConditionObjects
{
param(
$Objects,
[switch]
$Selected
)
Write-Status "Import terms and conditions"
foreach($obj in $objects)
{
if($Selected -and $obj.Selected -ne $true) { continue }
Write-Log "Import Terms and Conditions: $($obj.Object.displayName)"
$assignments = Get-GraphAssignmentsObject $obj.Object ($obj.FileInfo.DirectoryName + "\" + $obj.FileInfo.BaseName + "_assignments.json")
$response = Import-TermsAndCondition $obj.Object
if($response)
{
$global:importedObjects++
Import-GraphAssignments2 $assignments "/deviceManagement/termsAndConditions/$($response.Id)/assignments"
}
}
$dgObjects.ItemsSource = @(Get-TermsAndConditionObjects)
Write-Status ""
}

BIN
Intune.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 256 KiB

49
MSALInfo.md Normal file
View File

@@ -0,0 +1,49 @@
# Microsoft Authentication Library (MSAL)
Microsoft Authentication Library (MSAL) is used for authenticating to Microsoft Graph and other APIs used by the script. Microsoft.Identity.Client.dll** is the library file that contains the authentication functions. This script is depending on the file to be able to authenticate to Microsoft Graph.
See the GitHub repository [MSAL.PS](https://github.com/AzureAD/MSAL.PS) for more information on using MSAL with PowerShell. This script does not use the module directly for various reasons but the MSAL.PS repository is a great source of information and the best place to start for using MSAL with PowerShell.
See GitHub repository [MSAL for .Net](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet) for additional information and source code. Latest version of MSAL can be downloaded [here](https://www.nuget.org/packages/Microsoft.Identity.Client/).
## Applications
MSAL uses OAuth2 to authenticate to an Application in Azure. This script has two applications pre-defined in Settings:
- Microsoft Intune PowerShell (d1ddf0e4-d672-4dae-b554-9d5bdfd93547)
- Microsoft Graph PowerShell (14d82eec-204b-4c2f-b7e8-296a70dab67e)
Microsoft Intune PowerShell is the same application as the Intune PowerShell module uses and this is the default application for the script.
The script will detect if the selected app is missing permissions and prompt for Consent if additional permissions are required. The script will also prompt for Consent if the application is not approved in the Tenant.
**Note:** Permissions in an app is just a filter and decides what can be done via the app. If a user only has Read permission but the app has ReadWrite, the user will not be able to update anything.
A Custom application can be specified in Settings. This could theoretically be a custom created app in Azure. However, if an App is registered in Azure, it will be single tenant only. This can be used to backup an existing environment but the Azure App cannot be used to import data in another tenant. Use Enterprise Apps and Common/Organizations authority to allow access to multiple tenants.
## Token
The MSAL authentication will create a token that is used when calling APIs in Microsoft Graph. This token is cached in an encrypted **msalcahce.bin3** file in the **%LOCALAPPDATA%\CloudAPIPowerShellManagement** folder. The file can only be decrypted by the same user. Caching the token can be disabled in Settings.
**Note:** Only the token is cached. Credentials are never stored.
The token expire after 1 hour. The script will do a "login" every time it calls an API. MSAL will manage the refresh of the token and only refresh it when it is about to expire or after it has expired. If the token needs to be refreshed e.g. the user was added to a new role, a forced refresh can be triggered in the Profile Info popup.
The Token info will show information like role memberships, expiry time, scope etc. There are three toke information available:
* MSAL Token - Token created when authenticating with MSAL. Contains the Access and ID tokes
* Access token - Token contains permissions information and used when calling Microsoft Graph APIs
* ID Token - Token contains user information and used when logging in
Access and ID Tokens are encoded (**NOT** encrypted) Java Web Token (JWT) tokens. JWT tokens are based on three Base64Url strings separated with a dot (.) e.g. Header.Payload.VerifySignature.
See [JWT.IO](https://jwt.io/) for more information about JWT tokens.
## Multi Tenant Support
Support for switching to other tenants can be enabled in Settings. This can be used if the user has a guest account in one or more tenants. This is disabled by default for the following reasons:
* Reduce login time - Getting the list of accessible tenants takes a few seconds extra
* Reduce prompts - There is no API in Microsoft Graph that returns a list of tenants the current user has access to. Instead, a Azure management API is used. This will require permissions to Azure management which might cause an additional prompt for Consent when logging in.
**Note:** This is only used when a user has access to multiple tenants. Users from other tenants can always be used without enabling the 'Get Tenant List' setting.

Binary file not shown.

19770
Microsoft.Identity.Client.xml Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

106
README.md
View File

@@ -1,78 +1,96 @@
# IntuneManagement with PowerShell and WPF UI
This PowerShell scripts are using Intune PowerShell module, Microsoft Graph APIs and AzureRM PowerShell module to manage objects in Intune and Azure. The scripts has a simple WPF UI and it supports operations like Export, Import, Copy and Download.
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.
This makes it easy to backup or clone a complete Intune environment. The scripts will export and import assignments and support import/export between environments. The scripts will create a migration table during export and use that for importing in other environments. It will create groups if they are missing in the environment for import.
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)
**Note:** The base PowerShell script is only a host for extensions. It is only used as a framework for basic UI, logging etc. The functionality is located in the extension modules which makes it easy to add/remove features.
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...
**Security note:** Since the scripts are not signed, a warning might be display when running it and files might be blocked. The script will unblock all files. This is to avoid issues that it fails to load the MSAL library etc. If there are any security concerns, the PowerShell code can be reviewed. The DLL files are downloaded from Microsoft repositories, see links below. These files can be downloaded and replaced. The DLL files *CAN* be removed but MSAL is a pre-requisite for login. The script will try to find the DLL in the Az or MSAL.PS module if not found in the script root directory. DLL files are included to reduce dependencies.
## Change log
**Version 2**
See [Change Log](ReleaseNotes.md) for more information
**Breaking changes**
* Removed support for AzureRM
## Authentication
See [MSAL Info](MSALInfo.md) for more information about authentication
**New features**
* Support for Az module for Azure objects (Conditional access, Company Branding and MDM/MAM settings)
* Reload - Reloads all modules
**Fixes**
* Allow more than 9 Conditional Access policies. Issue [#5](https://github.com/Micke-K/IntuneManagement/issues/5)
* Include WIP policies. Issue [#7](https://github.com/Micke-K/IntuneManagement/issues/7)
* Import is not working. Issue [#6](https://github.com/Micke-K/IntuneManagement/issues/6) and [#4](https://github.com/Micke-K/IntuneManagement/issues/4)
* Intune module can now be install with scope user. Issue [#8](https://github.com/Micke-K/IntuneManagement/issues/8)
## Intune objects
* Administrative Templates
* App Protection/Configuration policies
## Supported Intune objects
* App Configurations
* App Protection
* Applications
* Apple Enrolment Types - NOT fully tested
* Autopilot profiles
* Baseline Security profiles
* Compliance policies
* Configuration Items
* Enrollment Status Page profiles
* Intune Branding (Company Portal)
* PowerShell scripts (Supports download of PowerShell script)
* Terms and Conditions
**Note:** The Intune PowerShell module are using the BETA version of the Graph API which might change at any time.
## Azure objects
* Conditional Access
* Company Branding
* MDM/MAM app settings
* Device Configuration (Administrative Templates, Configuration Policies, Android OEM Config, Settings Catalog)
* Endpoint Security (Account Protection, Disk Encryption, Firewall, Security Baselines etc.)
* Enrollment Restrictions
* Enrollment Status Page profiles
* Feature Updates
* Intune Branding (Company Portal)
* Locations
* Named Locations
* Policy Sets
* Role Definitions
* Scope Tags
* Scripts (Supports download of PowerShell script)
* Terms and Conditions
* Update Policies
**Note:** Azure objects are not using the Microsoft Graph API. They are using undocumented APIs which might not be supported and change at any time.
## Prerequisites
**Note:** The scripts are using the BETA version of the Graph API which might change at any time.
## Azure Management APIs
* Tenants for the current user
**Note:** Azure Management APIs are undocumented APIs which might not be supported and they might change at any time.
## Pre-requisites
* .Net 4.7
* Intune PowerShell Module
* Install by running 'Install-Module -Name Microsoft.Graph.Intune'
* Az PowerShell Module
* Install by running 'Install-Module -Name Az -AllowClobber'
* Permissions in Azure to manage objects in Intune and Azure
* PowerShell 5.1
* MSAL
* Microsoft.Identity.Client.dll version 4.29.0.0 is included in this version
* License and permissions in Azure to manage objects in Intune and Azure
## References
* [Microsoft Graph API](https://docs.microsoft.com/en-us/graph/api/overview?toc=./ref/toc.json&view=graph-rest-beta)
* [Microsoft Intune PowerShell Module](https://github.com/microsoft/Intune-PowerShell-SDK)
* [Microsoft.Identity.Client](https://www.nuget.org/packages/Microsoft.Identity.Client/) (MSAL download)
* [MSAL.PS Module](https://github.com/AzureAD/MSAL.PS)
* [Az PowerShellModule](https://docs.microsoft.com/en-us/powershell/azure/new-azureps-module-az)
* [Microsoft Intune PowerShell Module](https://github.com/microsoft/Intune-PowerShell-SDK)
* [Microsoft.WindowsAPICodePack](https://www.nuget.org/packages/Microsoft-WindowsAPICodePack-Core) and [Microsoft.WindowsAPICodePack.Shell](https://www.nuget.org/packages/Microsoft-WindowsAPICodePack-Shell) for Browse Folder dialogs
## Acknowledgments
The app enryption and upload is based on [PowerShell Intune Examples](https://github.com/microsoftgraph/powershell-intune-samples)
The app encryption and upload is based on [Graph PowerShell Intune Examples](https://github.com/microsoftgraph/powershell-intune-samples)
Some MSAL functionalities are based on [MSAL.PS Module](https://github.com/AzureAD/MSAL.PS)
## Known Issues
The scripts are using two separate PowerShell modules for accessing Intune and Azure. This can cause multiple logins since they are authenticating to two different apps in azure and the authentication token for Intune PowerShell module have no permissions on the Azure objects.
The support for import/export between environments is limited. Only groups in assignments are supported in this version. Additional objects like users, locations, notifications etc. will not be migrated and might cause the import to fail.
Device Configuration and App Configuration objects are split up in different object types. They are using different Graph APIs and each object type in the menu uses one API. This is also why all Endpoint Security objects are of the same object type. They use the same API but are separated based on the Baseline Template Id they us.
The script will create a group if it is missing in the destination environment. It will create a security group with manual assigned members. This might not always be the desired case e.g. original group was synched from AD or it was a dynamic group.
Android Store Apps are **not** imported. The create method is documented in Microsoft Graph but it's not working. Looks like these apps must be synched from Google Play.
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.
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.
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.
## TIP
Download [Microsoft.WindowsAPICodePack](https://www.nuget.org/packages/WindowsAPICodePack-Core) and [Microsoft.WindowsAPICodePack.Shell](https://www.nuget.org/packages/WindowsAPICodePack-Shell) and copy the DLLs into the script folder to get a nicer folder dialog.
Check the log file for errors. The UI might not show errors why login failed etc. The log uses the Endpoint Configuration Manager (SCCM) format and it is best viewed with CMTrace. An old version can be downloaded [here](https://www.microsoft.com/en-us/download/confirmation.aspx?id=50012).
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

57
ReleaseNotes.md Normal file
View File

@@ -0,0 +1,57 @@
# Release Notes
## 3.0.0 Beta 1 - 2021-04-01
**Breaking changes**
- Dropped support for Azure Branding and MAM/MDM settings...for now
- Import might not work for items exported with previous versions. Some folders are renamed, import is depending on additional information.
**New features**
- Authentication managed by Microsoft Authentication Library (MSAL)
- Support for switching user
- Support for switching tenant. Multi tenant support must be enabled in Settings
- Token info, Profile picture info support etc.
- See [MSAL info](MSALInfo.md) for more information
- Support for multiple Views - Intune Management and Intune Info for now...
- Intune Management - Export/Import/Copy objects in Intune
- Intune Info - Show information about some objects in Intune
- Improved UI experience
- Support for resizing the Window
- Support for searching for objects
- Refresh objects in the list
- Scaled popup dialogs
- API management redeveloped from scratch to simplify support for new object types in the future
- Support for new object types (Settings Catalog, Named Locations, Scope Tags, Policy Sets etc.)
- Better support for migrating objects between environments
- Group migrations e.g. support for Dynamic Groups, different group types etc.
- Support for dependency objects e.g. Policy Sets reference other objects like Compliance Settings etc. The import of an object uses exported json files to identify dependent items and map old Id to the new Id in the target environment
- Support for migrating Scope Tags (Uses the dependency functionallity so Scope Tags must be Exported/Imported)
- Better support for migrating Assignments
**Dependencies**
- MSAL - **Microsoft.Identity.Client.dll**. This is included in Az / MSAL.PS modules or it can be installed separately. This release was developed and tested with MSAL version 4.21.0.0.
## 2.0.0 - 2021-02-01
**Breaking changes**
- Removed support for AzureRM
**New features**
- Support for Az module
**Fixes**
- Allow more than 9 Conditional Access policies. Issue [#5](https://github.com/Micke-K/IntuneManagement/issues/5)
- Include WIP policies. Issue [#7](https://github.com/Micke-K/IntuneManagement/issues/7)
- Import is not working. Issue #6 and [#4](https://github.com/Micke-K/IntuneManagement/issues/4)
- Intune module can now be install with scope user. Issue [#8](https://github.com/Micke-K/IntuneManagement/issues/8)
## 1.0.0
- Intune Management with PowerShell
- Dependencies: Intune and AzureRM PowerShell modules

View File

@@ -0,0 +1,7 @@
[CmdletBinding(SupportsShouldProcess=$True)]
param(
[switch]
$ShowConsoleWindow
)
Import-Module ($PSScriptRoot + "\CloudAPIPowerShellManagement.psd1") -Force
Initialize-CloudAPIManagement -View "IntuneGraphAPI" -ShowConsoleWindow:($ShowConsoleWindow)

2
Start-WithConsole.cmd Normal file
View File

@@ -0,0 +1,2 @@
cmd /c powershell -ex bypass -file "%~DP0Start-IntuneManagement.ps1" -ShowConsoleWindow
pause

View File

@@ -1 +1 @@
cmd /c powershell -ex bypass "%~DP0PSExtensionsHost.ps1"
cmd /c powershell -ex bypass -File "%~DP0Start-IntuneManagement.ps1"

View File

@@ -1,7 +1,19 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="TitleBackgroundColor" Color="#cccccc"/>
<SolidColorBrush x:Key="TitleBackgroundColor" Color="#ffC0C0C0"/>
<SolidColorBrush x:Key="TitleForegroundColor" Color="Black"/>
<SolidColorBrush x:Key="TextColor" Color="#FF000000"/>
<SolidColorBrush x:Key="SelectedRowBackgroundColor" Color="#FFCDCDCD" />
<SolidColorBrush x:Key="PersonPictureForegroundThemeBrush" Color="#cccccc"/>
<SolidColorBrush x:Key="PersonPictureEllipseBadgeForegroundThemeBrush" Color="#cccccc"/>
<SolidColorBrush x:Key="PersonPictureEllipseBadgeFillThemeBrush" Color="#cccccc"/>
<SolidColorBrush x:Key="PersonPictureEllipseBadgeStrokeThemeBrush" Color="#cccccc"/>
<SolidColorBrush x:Key="PersonPictureEllipseFillThemeBrush" Color="#cccccc"/>
<x:Double x:Key="PersonPictureEllipseBadgeStrokeOpacity">0.8</x:Double>
<x:Double x:Key="PersonPictureEllipseBadgeImageSourceStrokeOpacity">1.0</x:Double>
<x:Double x:Key="PersonPictureEllipseStrokeThickness">0</x:Double>
<x:Double x:Key="PersonPictureEllipseBadgeStrokeThickness">2</x:Double>
</ResourceDictionary>

View File

@@ -21,4 +21,114 @@
</Setter>
</Style>
<Style x:Key="HoverUnderlineStyle" TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextBlock.TextDecorations" Value="Underline" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="HoverUnderlineStyleWithBackground" TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextBlock.TextDecorations" Value="Underline" />
<Setter Property="TextBlock.Background" Value="LightGray" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="LinkButton" TargetType="Button">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<TextBlock Style="{DynamicResource HoverUnderlineStyle}" HorizontalAlignment="Left"> <!--TextDecorations="Underline" -->
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{DynamicResource SelectedRowBackgroundColor}" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="ContentButton" TargetType="Button">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{DynamicResource SelectedRowBackgroundColor}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SelectedRowBackgroundColor}"/>
</Trigger>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter Property="Panel.Background" TargetName="Border"
Value="{DynamicResource SelectedRowBackgroundColor}"/>
<Setter Property="Border.BorderBrush" TargetName="Border"
Value="{DynamicResource SelectedRowBackgroundColor}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type DataGridRow}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="{DynamicResource SelectedRowBackgroundColor}" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{DynamicResource SelectedRowBackgroundColor}" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<!--<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Yellow" /> -->
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource SelectedRowBackgroundColor}" />
<Setter Property="Foreground" Value="{DynamicResource TextColor}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource SelectedRowBackgroundColor}" />
<Setter Property="Foreground" Value="{DynamicResource TextColor}" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="Test" TargetType="{x:Type MenuItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Grid Background="{TemplateBinding Background}">
<TextBlock Title="{TemplateBinding Header}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

52
Xaml/AboutDialog.xaml Normal file
View File

@@ -0,0 +1,52 @@
<!-- <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="About" SizeToContent="Height" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" Width="300"> -->
<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Name="grdAbout">
<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="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Height="20" Name="txtTitle" FontWeight="Bold" Margin="0,5,0,0" />
<TextBlock Grid.Row="1" Text="(c) 2021 Mikael Karlsson - MIT License" Margin="0,5,0,0" />
<TextBlock Grid.Row="2">
See
<Hyperlink Name="linkSource" NavigateUri="https://github.com/Micke-K/IntuneManagement">
GitHub
</Hyperlink> for more information
</TextBlock>
<TextBlock Height="20" Name="txtViewTitle" Grid.Column="1" Margin="10,5,0,0" />
<TextBlock Name="txtViewDescription" Grid.Row="1" Grid.Column="1" Grid.RowSpan="3" VerticalAlignment="Top" Margin="10,5,0,0" TextWrapping="Wrap" />
<TextBlock Grid.Row="3" Text="Loaded modules:" Margin="0,5,0,0" />
<ListBox Name="lstModules" SelectionMode="Single" Grid.Row="4" Grid.ColumnSpan="2" Grid.IsSharedSizeScope='True'>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="NameColumn" />
<ColumnDefinition Width="Auto" SharedSizeGroup="VersionColumn" />
<ColumnDefinition Width="Auto" SharedSizeGroup="TypeColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Grid.Column='0' Margin="0,0,0,0" />
<TextBlock Text="{Binding Version}" Grid.Column='1' Margin="10,0,0,0" />
<TextBlock Text="{Binding Type}" Grid.Column='2' Margin="10,0,0,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Border>

106
Xaml/BulkExportForm.xaml Normal file
View File

@@ -0,0 +1,106 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5" Grid.IsSharedSizeScope='True'>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Name="grdExportProperties">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<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,0,5,0" >
<Label Content="Export root" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This root folder where exported files will be stored" />
</StackPanel>
<Grid Grid.Column='1' Grid.Row='0'>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="" Name="txtExportPath" />
<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="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" />
<StackPanel Orientation="Horizontal" Grid.Row='2' Margin="0,0,5,0">
<Label Content="ExportAssignments" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Export object assignments" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='2' Name='chkExportAssignments' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='3' 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" />
</Grid>
<Grid Grid.Row='1' VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Margin="0,0,5,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Label Content="Objects to export" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Select the object types that should be exported" />
</StackPanel>
</Grid>
<ListBox Name="lstObjectsToExport" Grid.Column='1'
SelectionMode="Single"
Grid.IsSharedSizeScope='True' >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="SelectedColumn" />
<ColumnDefinition Width="Auto" SharedSizeGroup="FileNameColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Title}" Grid.Column='1' Margin="5,0,0,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<CheckBox IsChecked="true" Margin="7,2,0,0" Grid.Column='1' Grid.Row='1' Name="chkCheckAll" ToolTip="Select/Deselect all" />
</Grid >
<StackPanel Name="spExportSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row='2' Grid.ColumnSpan='2' >
<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 >

122
Xaml/BulkImportForm.xaml Normal file
View File

@@ -0,0 +1,122 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5" Grid.IsSharedSizeScope='True'>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Name="grdImportProperties">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<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,0,5,0" >
<Label Content="Import root" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This root folder where exported files are stored" />
</StackPanel>
<Grid Grid.Column='1' Grid.Row='0'>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="" Name="txtImportPath" />
<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">
<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" />
<!-- 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 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" />
<StackPanel Orientation="Horizontal" Grid.Row='3' 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" />
<StackPanel Orientation="Horizontal" Grid.Row='4' 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" />
<StackPanel Orientation="Horizontal" Grid.Row='5' 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" />
</Grid>
<Grid Grid.Row='1' VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Margin="0,0,5,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Label Content="Objects to import" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Select the object types that should be imported" />
</StackPanel>
</Grid>
<ListBox Name="lstObjectsToImport" Grid.Column='1'
SelectionMode="Single"
Grid.IsSharedSizeScope='True' >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="SelectedColumn" />
<ColumnDefinition Width="Auto" SharedSizeGroup="FileNameColumn" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Title}" Grid.Column='1' Margin="5,0,0,0" />
<TextBlock Text="{Binding ObjectType.ImportOrder}" Grid.Column='2' Margin="5,0,0,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<CheckBox IsChecked="true" Margin="7,2,0,0" Grid.Column='1' Grid.Row='1' Name="chkCheckAll" ToolTip="Select/Deselect all" />
</Grid >
<StackPanel Name="spImportSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row='2' Grid.ColumnSpan='2' >
<Button Name="btnImport" Content="Import" Width='100' Margin="5,0,0,0" />
<Button Name="btnClose" Content="Close" Width='100' Margin="5,0,0,0" />
</StackPanel>
</Grid >

View File

@@ -0,0 +1,61 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Name="grdData">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DataGrid Name="dgObjects"
SelectionMode="Single"
SelectionUnit="FullRow"
CanUserAddRows="False"
Grid.Column="1"
Grid.Row="1" />
<Grid Name="grdTitle" Visibility="Collapsed" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<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" />
<!--
<Grid Grid.Column="2" MinWidth="200" MaxHeight="20">
<TextBlock Text="Filter" Background="White" />
<TextBox Name="txtFilter" Grid.Column="2" MinWidth="200" MaxHeight="20" Margin="0,0,5,3" Background="Transparent" />
</Grid>
-->
</Grid>
<Grid Name="grdObject" Grid.Row="1" Grid.RowSpan="2" Visibility="Collapsed" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" Margin="0,0,0,0" />
<CheckBox Grid.Row="2" Name="chkSelectAll" HorizontalAlignment="Left" Margin="7,2,0,0" ToolTip="Select/Unselect all" IsEnabled="False" />
<StackPanel Grid.Row="2" Name="spSubMenu" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,0,0" >
<Button Name="btnView" Content="View" MinWidth="100" Margin="0,0,5,0" IsEnabled="False" ToolTip="Veiw the json data of an item" />
<Button Name="btnCopy" Content="Copy" MinWidth="100" Margin="0,0,5,0" IsEnabled="False" ToolTip="Clone the selected item"/>
<Button Name="btnImport" Content="Import" MinWidth="100" Margin="0,0,5,0" IsEnabled="False" ToolTip="Import items" />
<Button Name="btnExport" Content="Export" MinWidth="100" IsEnabled="False" ToolTip="Export selected or all items" />
</StackPanel>
</Grid>
<Grid Name="grdNotLoggedIn" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Name="txtNotLoggedIn" Content="Not logged in. Please login to view objects" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Grid>

64
Xaml/ExportForm.xaml Normal file
View File

@@ -0,0 +1,64 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5" Grid.IsSharedSizeScope='True'>
<Grid Name="grdExportProperties">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<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,0,5,0" >
<Label Content="Export root" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This root folder where exported files should be stored" />
</StackPanel>
<Grid Grid.Column='1' Grid.Row='0'>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="" Name="txtExportPath" />
<Button Grid.Column="2" Name="browseExportPath" Padding="5,0,5,0" Width="50" ToolTip="Browse for folder">...</Button>
</Grid>
<StackPanel Orientation="Horizontal" Grid.Row='1' 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" IsChecked="" />
<StackPanel Orientation="Horizontal" Grid.Row='2' 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='2' Name='chkAddCompanyName' VerticalAlignment="Center" IsChecked="" />
<StackPanel Orientation="Horizontal" Grid.Row='3' Margin="0,0,5,0">
<Label Content="Export Assignments" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This will export assignments and add information to a migration table so they can be imported into other environments" />
</StackPanel>
<CheckBox Grid.Column='1' Grid.Row='3' Name='chkExportAssignments' VerticalAlignment="Center" IsChecked="true" />
</Grid>
</StackPanel>
<StackPanel Name="spExportSubMenu" Grid.Row='1' Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,0,5">
<Label Name="lblSelectedObject" Margin="5,0,0,0" />
<Button Name="btnExportSelected" Content="Export Selected" Width='100' Margin="5,0,0,0" VerticalAlignment="Center" />
<Button Name="btnExportAll" Content="Export All" Width='100' Margin="5,0,0,0" VerticalAlignment="Center" />
<Button Name="btnCancel" Content="Cancel" Width='100' Margin="5,0,0,0" VerticalAlignment="Center" />
</StackPanel>
</Grid>

View File

@@ -0,0 +1,13 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="29" Width="33">
<Path Fill="#3E3E3E" Data="M23.1 21.5c0 1.4-1.1 2.5-2.5 2.5h-11c-1.4 0-2.5-1.1-2.5-2.5v-19C7.1 1.1 8.2 0 9.6 0h11c1.4 0 2.5 1.1 2.5 2.5v19z" />
<Path Fill="#5AB3D9" Data="M21.1 4h-12v17h12V4z" />
<Path Fill="#FFFFFF" Data="M7.1 2.5v16.3L21 0H9.6C8.2 0 7.1 1.1 7.1 2.5z" Opacity="0.15" />
<Path Fill="#FFFFFF" Data="M25.9 27.6V9.8h-8.5c-.7 0-1.3.6-1.3 1.3v16.4h9.8v.1z" Opacity="0.4" />
<Path Fill="#0072c6" Data="M29 11.6c-.2-.3-.6-.3-.6-.3H18.1s-.4 0-.5.3v20.1c0 .5.6.5.6.5h10.3s.6 0 .6-.5V11.8c-.1-.1-.1-.2-.1-.2z" />
<Path Fill="#FFFFFF" Data="M20.6 12.5h-1.8v3.6h1.8v-3.6zm3.5 0h-1.8v3.6h1.8v-3.6zm3.6 0h-1.8v3.6h1.8v-3.6zm-7.1 5.3h-1.8v3.6h1.8v-3.6zm3.5 0h-1.8v3.6h1.8v-3.6zm3.6 0h-1.8v3.6h1.8v-3.6zm-7.1 5.3h-1.8v3.6h1.8v-3.6zm3.5 0h-1.8v3.6h1.8v-3.6zm0 5.3h-1.8V32h1.8v-3.6zm3.6-5.3h-1.8v3.6h1.8v-3.6z" />
<Path Fill="#FFFFFF" Data="M9.6 22.2l-.1-.2c1.2-.8 2.1-2.2 2.1-3.7 0-2.1-1.4-3.8-3.4-4.3H8c-.2 0-.5-.1-.7-.1-2.4 0-4.4 2-4.4 4.4 0 .3 0 .6.1.9v.1c.3 1.2 1 2.1 1.9 2.7v.2H0V32h14.3v-9.8H9.6z" Opacity="0.4" />
<Path Fill="#804998" Data="M10.7 18.2c0 2-1.6 3.6-3.6 3.6s-3.6-1.6-3.6-3.6 1.6-3.6 3.6-3.6c2.1 0 3.6 1.7 3.6 3.6zM9.8 23l-2.6 3.7L4.6 23H.8v9h12.7v-9H9.8z" />
<Path Fill="#FFFFFF" Data="M3.6 18.2c0 2 1.5 3.5 3.5 3.6l.9-7c-.2-.1-.5-.1-.8-.1-2-.1-3.6 1.6-3.6 3.5zm1 4.8H.8v9h5l.8-6.1-2-2.9z" Opacity="0.15" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,9 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#1D1D1D" Data="M43.75 43.75H6.25A6.25 6.25 0 010 37.5v-25a6.25 6.25 0 016.25-6.25h37.5A6.25 6.25 0 0150 12.5v25a6.25 6.25 0 01-6.25 6.25z" />
<Path Fill="#B7D333" Data="M6.25 12.5h37.5v25H6.25z" />
<Path Fill="#7FBA42" Data="M43.75 37.5H6.25v-6.25l37.5-12.5z" />
<Path Fill="#FFFFFF" Data="M40.625 15.625v18.75H9.375v-18.75h31.25M43.75 12.5H6.25v25h37.5v-25z" Opacity="0.4" />
<Path Fill="#9E9FA0" Data="M18.75 37.5h12.5v3.125h-12.5z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,6 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#2072B8" Data="M0 0h12.5v12.5H0V0zm0 15.625h12.5v12.5H0v-12.5zM0 31.25h12.5v12.5H0v-12.5zM15.625 0h12.5v12.5h-12.5V0zM31.25 0h12.5v12.5h-12.5V0zM16.788 38.29l3.822-3.422.008-1.332-2.637-2.286h-2.356v12.5h3.378zm2.276-13.546l5.126.288.946-.935-.362-5.086 3.351-1.364v-2.022h-12.5v12.5h2.012zm14.609-4.134l1.332.009 3.345-3.856 5.4 2.283v-3.421h-12.5v2.277z" />
<Path Fill="#7B7B7B" Data="M48.464 42.171l1.431-3.386-.414-.361-3.126-2.71.019-2.744 3.52-3.15-1.385-3.405-.543.038-4.13.292-1.926-1.955.262-4.714-3.386-1.431-.359.414-2.714 3.128-2.744-.019-3.15-3.522-3.405 1.385.04.543.29 4.13-1.951 1.928-4.718-.266-1.431 3.389.414.357 3.126 2.714-.017 2.744-3.519 3.15 1.382 3.405.547-.038 4.126-.292 1.928 1.951-.262 4.718 3.388 1.427.357-.41 2.714-3.128 2.742.023 3.15 3.519 3.405-1.385-.038-.546-.292-4.126 1.955-1.928 4.714.261zm-17.119-.968a7.522 7.522 0 01-4.006-9.857 7.522 7.522 0 019.857-4.008 7.522 7.522 0 014.007 9.857 7.524 7.524 0 01-9.858 4.008" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,7 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#2072B8" Data="M0 0h12.5v12.5H0V0zm0 15.625h12.5v12.5H0v-12.5zM0 31.25h12.5v12.5H0v-12.5zM15.625 0h12.5v12.5h-12.5V0zM31.25 0h12.5v12.5h-12.5V0zm-7.812 37.846V31.25h-7.813v12.5h11.161c-1.926-2.052-3.348-4.172-3.348-5.904zm0-18.989l1.492-.067a29.146 29.146 0 003.195-.344v-2.82h-12.5v12.5h7.813v-9.269zm11.853-3.232H31.25v2.081c1.477-.465 2.911-1.128 4.041-2.081zm8.459 2.08v-2.08h-4.035c1.133.952 2.563 1.614 4.035 2.08z" />
<Path Fill="#7FBA42" Data="M37.509 50C35.851 49.674 25 41.763 25 37.846V20.351c2.313-.103 9.37-.746 12.502-4.726 3.15 3.983 10.189 4.623 12.498 4.726v17.494C50 43.382 38.92 49.791 37.509 50z" />
<Path Data="M27.944 42.749C26.039 40.738 25 39.014 25 37.846V20.351c2.313-.103 9.369-.746 12.501-4.725 1.285 1.631 3.345 2.868 6.148 3.694L27.944 42.749z" Fill="#FFFFFF" Opacity="0.17"/>
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,26 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#FFFFFF" Data="M40.5 11h4v1h-4z" />
<Path Fill="#E5E5E5" Data="M20.5 49c-1.103 0-2-.897-2-2V7c0-1.103.897-2 2-2h24c1.103 0 2 .897 2 2v40c0 1.103-.897 2-2 2h-24z" />
<Path Fill="#7A7A7A" Data="M44.5 6c.551 0 1 .449 1 1v40c0 .551-.449 1-1 1h-24c-.551 0-1-.449-1-1V7c0-.551.449-1 1-1h24m0-2h-24a3 3 0 00-3 3v40a3 3 0 003 3h24a3 3 0 003-3V7a3 3 0 00-3-3z" />
<Path Fill="#FFFFFF" Data="M20.5 49c-1.103 0-2-.897-2-2V7c0-1.103.897-2 2-2h24c1.103 0 2 .897 2 2v40c0 1.103-.897 2-2 2h-24z" />
<Path Fill="#7A7A7A" Data="M44.5 6c.551 0 1 .449 1 1v40c0 .551-.449 1-1 1h-24c-.551 0-1-.449-1-1V7c0-.551.449-1 1-1h24m0-2h-24a3 3 0 00-3 3v40a3 3 0 003 3h24a3 3 0 003-3V7a3 3 0 00-3-3z" />
<Path Fill="#7A7A7A" Data="M19.5 6h26v6h-26z" />
<Path Fill="#FFFFFF" Data="M29.5 7h6v1h-6z" />
<Ellipse Fill="#57a300" Canvas.Left="23.5" Canvas.Top="14" Width="18" Height="18" />
<Path Fill="#0072c0" Data="M30.833 28.667v-4h-4v-3.334h4v-4h3.334v4h4v3.334h-4v4z" />
<Path Fill="#FFFFFF" Data="M37.5 22h-4v-4h-2v4h-4v2h4v4h2v-4h4z" />
<Path Fill="#3898C6" Data="M24.5 35h16v2h-16zm0 4h12v2h-12zm0 4h14v2h-14z" />
<Path Fill="#FFFFFF" Data="M25.5 7h4v1h-4z" />
<Path Fill="#E5E5E5" Data="M5.5 45c-1.103 0-2-.897-2-2V3c0-1.103.897-2 2-2h24c1.103 0 2 .897 2 2v40c0 1.103-.897 2-2 2h-24z" />
<Path Fill="#7A7A7A" Data="M29.5 2c.551 0 1 .449 1 1v40c0 .551-.449 1-1 1h-24c-.551 0-1-.449-1-1V3c0-.551.449-1 1-1h24m0-2h-24a3 3 0 00-3 3v40a3 3 0 003 3h24a3 3 0 003-3V3a3 3 0 00-3-3z" />
<Path Fill="#FFFFFF" Data="M5.5 45c-1.103 0-2-.897-2-2V3c0-1.103.897-2 2-2h24c1.103 0 2 .897 2 2v40c0 1.103-.897 2-2 2h-24z" />
<Path Fill="#7A7A7A" Data="M29.5 2c.551 0 1 .449 1 1v40c0 .551-.449 1-1 1h-24c-.551 0-1-.449-1-1V3c0-.551.449-1 1-1h24m0-2h-24a3 3 0 00-3 3v40a3 3 0 003 3h24a3 3 0 003-3V3a3 3 0 00-3-3z" />
<Path Fill="#7A7A7A" Data="M4.5 2h26v6h-26z" />
<Path Fill="#FFFFFF" Data="M14.5 3h6v1h-6z" />
<Ellipse Fill="#57a300" Canvas.Left="8.5" Canvas.Top="10" Width="18" Height="18" />
<Path Fill="#0072c0" Data="M15.833 24.667v-4h-4v-3.334h4v-4h3.334v4h4v3.334h-4v4z" />
<Path Fill="#FFFFFF" Data="M22.5 18h-4v-4h-2v4h-4v2h4v4h2v-4h4z" />
<Path Fill="#3898C6" Data="M9.5 31h16v2h-16zm0 4h12v2h-12zm0 4h14v2h-14z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,60 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="18" Width="18">
<Canvas.Resources>
<LinearGradientBrush x:Key="3fe769a7-5a01-4d2d-8fe0-e8d731b660ed" StartPoint="0.0754000023007393,0.0494999997317791" EndPoint="0.0754000023007393,0.147200003266335" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.22" Color="#2BCDF2" />
<GradientStop Offset="0.47" Color="#2ACAF0" />
<GradientStop Offset="0.63" Color="#28C2E7" />
<GradientStop Offset="0.76" Color="#24B3DA" />
<GradientStop Offset="0.88" Color="#1F9EC6" />
<GradientStop Offset="0.99" Color="#1883AD" />
<GradientStop Offset="1" Color="#177FA9" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="3fe769a7-5a01-4d2d-8fe0-e8d731b660ee" StartPoint="0.521659970283508,0" EndPoint="0.56852000951767,0.566280007362366" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.22" Color="#2BCDF2" />
<GradientStop Offset="0.47" Color="#2ACAF0" />
<GradientStop Offset="0.63" Color="#28C2E7" />
<GradientStop Offset="0.76" Color="#24B3DA" />
<GradientStop Offset="0.88" Color="#1F9EC6" />
<GradientStop Offset="0.99" Color="#1883AD" />
<GradientStop Offset="1" Color="#177FA9" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="3fe769a7-5a01-4d2d-8fe0-e8d731b660ef" StartPoint="0.132200002670288,0.208000004291534" EndPoint="0.132200002670288,0.0612999983131886" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#006DCD" />
<GradientStop Offset="0.11" Color="#1175D3" />
<GradientStop Offset="0.34" Color="#2E83DE" />
<GradientStop Offset="0.56" Color="#428DE6" />
<GradientStop Offset="0.79" Color="#4F93EA" />
<GradientStop Offset="1" Color="#5395EC" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="3fe769a7-5a01-4d2d-8fe0-e8d731b660f0" StartPoint="0.132200002670288,0.168400004506111" EndPoint="0.132200002670288,0.0844999998807907" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#CBE7FF" />
<GradientStop Offset="1" Color="#EDFFFC" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Canvas.Resources>
<Canvas>
<Path Fill="{StaticResource 3fe769a7-5a01-4d2d-8fe0-e8d731b660ed}" Data="M12.37 13a1 1 0 001.05-1v-.12c-.42-3.29-2.29-6-5.87-6S2 8.09 1.66 11.79A1.06 1.06 0 002.6 13h9.77z" />
<Path Fill="#FFFFFF" Data="M7.55 6.6a3.24 3.24 0 01-1.79-.53l1.77 4.62L9.29 6.1a3.24 3.24 0 01-1.74.5z" Opacity="0.8"/>
<Path Fill="{StaticResource 3fe769a7-5a01-4d2d-8fe0-e8d731b660ee}" Data="M7.55 6.6a3.3 3.3 0 100-6.6 3.3 3.3 0 000 6.6z" />
<Path Fill="{StaticResource 3fe769a7-5a01-4d2d-8fe0-e8d731b660ef}" Data="M16.02 7.57h-5.61a.32.32 0 00-.32.32v9.8c0 .177.143.32.32.32h5.61a.32.32 0 00.32-.32v-9.8a.32.32 0 00-.32-.32z" />
<Path Fill="#EFEFEF" Data="M13.4 17.19h-.36a.17.17 0 00-.17.17v.26c0 .094.076.17.17.17h.36a.17.17 0 00.17-.17v-.26a.17.17 0 00-.17-.17zm.45-9.27h-1.26a.09.09 0 00-.09.09v.01c0 .05.04.09.09.09h1.26c.05 0 .09-.04.09-.09v-.01a.09.09 0 00-.09-.09z" />
<Path Fill="{StaticResource 3fe769a7-5a01-4d2d-8fe0-e8d731b660f0}" Data="M15.64 8.45H10.8a.12.12 0 00-.12.12v8.15c0 .066.054.12.12.12h4.84a.12.12 0 00.12-.12V8.57a.12.12 0 00-.12-.12z" Opacity="0.9"/>
</Canvas>
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,8 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#5AB3D9" Data="M43.75 50H6.25A6.25 6.25 0 010 43.75V6.25A6.25 6.25 0 016.25 0h37.5A6.25 6.25 0 0150 6.25v37.5A6.25 6.25 0 0143.75 50z" />
<Path Fill="#3898C6" Data="M43.75 3.125a3.129 3.129 0 013.125 3.125v37.5a3.129 3.129 0 01-3.125 3.125H6.25a3.129 3.129 0 01-3.125-3.125V6.25A3.129 3.129 0 016.25 3.125h37.5m0-3.125H6.25A6.25 6.25 0 000 6.25v37.5A6.25 6.25 0 006.25 50h37.5A6.25 6.25 0 0050 43.75V6.25A6.25 6.25 0 0043.75 0z" />
<Path Fill="#FFFFFF" Data="M7.105 16.318l-.722-.776a.507.507 0 01.028-.722l2.101-1.928a.512.512 0 01.348-.137.51.51 0 01.381.163l5.77 6.134 9.922-12.611a.53.53 0 01.727-.086l2.265 1.739a.5.5 0 01.195.34.494.494 0 01-.105.375L15.266 25l-8.161-8.682zm33.604 11.807h-.084v6.334a3.041 3.041 0 01-3.041 3.041h-9.459v.084a3.041 3.041 0 003.041 3.041h9.544a3.041 3.041 0 003.041-3.041v-6.419a3.042 3.042 0 00-3.042-3.04z" />
<Path Fill="#FFFFFF" Data="M34.46 34.375h-9.544a3.04 3.04 0 01-3.04-3.04v-6.419a3.04 3.04 0 013.04-3.04h9.544a3.04 3.04 0 013.04 3.04v6.419a3.04 3.04 0 01-3.04 3.04z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,18 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="18" Width="18">
<Canvas.Resources>
<LinearGradientBrush x:Key="a2546c3d-06f2-4d81-b3fa-b5b62d9f6f89" StartPoint="0.0900000035762787,0.170000001788139" EndPoint="0.0900000035762787,1" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#0078d4" />
<GradientStop Offset="0.16" Color="#1380da" />
<GradientStop Offset="0.53" Color="#3c91e5" />
<GradientStop Offset="0.82" Color="#559cec" />
<GradientStop Offset="1" Color="#5ea0ef" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Canvas.Resources>
<Path Fill="{StaticResource a2546c3d-06f2-4d81-b3fa-b5b62d9f6f89}" Data="M6.6 12.2h4.8V17H6.6zM1 5.8h4.8V1H1.67a.67.67 0 00-.67.67zM1.67 17H5.8v-4.8H1v4.13a.67.67 0 00.67.67zM1 11.4h4.8V6.6H1zM12.2 17h4.13a.67.67 0 00.67-.67V12.2h-4.8zm-5.6-5.6h4.8V6.6H6.6zm5.6 0H17V6.6h-4.8zm0-10.4v4.8H17V1.67a.67.67 0 00-.67-.67zM6.6 5.8h4.8V1H6.6z" />
</Canvas>
</Viewbox>

13
Xaml/Icons/Autopilot.xaml Normal file
View File

@@ -0,0 +1,13 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Data="M32 41c0 1.657-1.323 3-2.956 3H6.956C5.323 44 4 42.657 4 41V3c0-1.657 1.323-3 2.956-3h22.088C30.677 0 32 1.343 32 3v38z" Fill="#3e3e3e" />
<Path Data="M6 5h24v33H6z" Fill="#59b4d9" />
<Path Data="M23 2.817c0 .408-.53.738-1.186.738h-7.625c-.657 0-1.189-.33-1.189-.738s.532-.739 1.189-.739h7.625c.656 0 1.186.331 1.186.739" Fill="#ffffff" />
<Path Data="M26.021 0H7a3 3 0 00-3 3v38a3 3 0 003 3h2.6L26.021 0z" Fill="#ffffff" Opacity=".15" />
<Path Data="M32 11v7H18v-7z" Fill="#ffffff" />
<Path Data="M19 12h20v5H19z" Fill="#804998" />
<Path Data="M37 21.5v-14l10.5 6.462z" Fill="#804998" />
<Path Stroke="#3999C6" StrokeStartLineCap="round" StrokeEndLineCap="round" StrokeLineJoin="round" StrokeThickness="2" Data="M21.042 26.042h22.917v22.917H21.042z" Fill="#ffffff" />
<Path Fill="#3898C6" Data="M25 30h15v3H25zm0 6h12v3H25zm0 6h15v3H25z" />
</Canvas>
</Viewbox>

39
Xaml/Icons/Branding.xaml Normal file
View File

@@ -0,0 +1,39 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="18" Width="18">
<Canvas.Resources>
<LinearGradientBrush x:Key="b04c7825-41db-4c22-aba2-f5c44b816ed3" StartPoint="0.0356499999761581,0.170000001788139" EndPoint="0.0356499999761581,0.0375300012528896" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#fea11b" />
<GradientStop Offset="0.127" Color="#feac19" />
<GradientStop Offset="0.562" Color="#ffcb12" />
<GradientStop Offset="0.804" Color="#ffd70f" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="e3016781-9cad-4dda-b769-212e01557f4d" StartPoint="0.0900000035762787,0.170000001788139" EndPoint="0.0900000035762787,0.0375300012528896" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#5e9624" />
<GradientStop Offset="0.546" Color="#6dad2a" />
<GradientStop Offset="0.999" Color="#76bc2d" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="a5967715-2146-4485-8c36-86a8b43a627b" StartPoint="0.144350007176399,0.170000001788139" EndPoint="0.144350007176399,0.0375300012528896" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#1b93eb" />
<GradientStop Offset="1" Color="#6bb9f2" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Canvas.Resources>
<Rectangle Width="4.034" Height="13.247" Canvas.Left="1.367" Canvas.Top="3.753" Fill="{StaticResource b04c7825-41db-4c22-aba2-f5c44b816ed3}" RadiusX="0.517" RadiusY="0.517" />
<Rectangle Width="4.034" Height="13.247" Canvas.Left="6.802" Canvas.Top="3.753" Fill="{StaticResource e3016781-9cad-4dda-b769-212e01557f4d}" RadiusX="0.517" RadiusY="0.517" />
<Rectangle Width="4.034" Height="13.247" Canvas.Left="12.238" Canvas.Top="3.753" Fill="{StaticResource a5967715-2146-4485-8c36-86a8b43a627b}" RadiusX="0.517" RadiusY="0.517" />
<Path Fill="#faa21d" Data="M1.617 1h3.895a.251.251 0 01.251.251v2.871h-4.4V1.251A.251.251 0 011.617 1z" />
<Path Fill="#86d633" Data="M7.053 1h3.894a.251.251 0 01.251.251v2.871H6.8V1.251A.251.251 0 017.053 1z" />
<Path Fill="#5ea0ef" Data="M12.488 1h3.894a.251.251 0 01.251.251v2.871h-4.4V1.251A.251.251 0 0112.488 1z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,7 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Data="M43.75 3.125H9.375v43.75h31.25v-37.5h3.125z" Fill="#FFFFFF" />
<Path Fill="#5AB2D7" Data="M34.375 12.5V9.375H12.5V12.5h21.875zm0 6.25v-3.125H12.5v3.125h21.875zm0 6.25v-3.125H12.5V25h21.875zm0 6.25v-3.125H12.5v3.125h21.875z" />
<Path Fill="#5AB2D7" Data="M43.75 0H15.626C9.376 0 6.25 3.125 6.25 9.375L6.251 37.5H6.25a6.25 6.25 0 100 12.5H37.5c3.393 0 6.25-2.857 6.25-6.25V9.375h5.383A6.185 6.185 0 0050 6.25 6.25 6.25 0 0043.75 0zm0 3.126c-.006.003-3.124 1.549-3.124 6.249V37.5h-.001v4.688a4.688 4.688 0 01-9.376 0c0-2.038 1.309-4.042 3.125-4.688H9.376L9.375 9.375c0-3.889 2.396-6.25 6.251-6.25l28.124.001z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,7 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#57A300" Data="M38.185 5.96C27.169 4.745 25.326 0 25.326 0S22.847 6.242 7 6.242v25.611c0 3.097 1.721 5.997 4.104 8.532 5.402 5.748 14.223 9.616 14.223 9.616s18.327-8.029 18.327-18.149V6.242c-2.038 0-3.851-.103-5.469-.282z" />
<Path Fill="#B8D432" Data="M29.86 16.543L38.185 5.96C27.169 4.745 25.326 0 25.326 0S22.847 6.242 7 6.242v25.611c0 3.097 1.721 5.997 4.104 8.532l6.154-7.822 12.602-16.02z" Opacity=".4" />
<Path Fill="#FFFFFF" Data="M32.595 24.46h-1.066v-3.552a6.697 6.697 0 0 0-1.669-4.45c-.039-.043-.074-.09-.112-.133-1.107-1.186-2.683-1.948-4.422-1.947-1.736-.001-3.312.761-4.419 1.947a6.697 6.697 0 0 0-1.783 4.582v3.553h-1.065a.8.8 0 0 0-.801.801v9.392c0 .442.359.801.801.801h14.536a.801.801 0 0 0 .801-.801v-9.391a.801.801 0 0 0-.801-.802zm-4.011.001h-5.02l.001-.001H22.07v-3.552c0-1.022.386-1.927.988-2.57.605-.643 1.395-1.013 2.268-1.013.874 0 1.665.37 2.27 1.013.143.153.271.323.389.504l-.001.001c.373.579.6 1.288.6 2.064v3.554z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,9 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#3898C6" Data="M0 44.963c0 1.056.898 1.912 2.007 1.912h45.986c1.109 0 2.007-.857 2.007-1.912v-33.61H0v33.61z" />
<Path Fill="#7B7B7B" Data="M47.993 3.125H2.007A2.014 2.014 0 000 5.149V12.5h50V5.149a2.015 2.015 0 00-2.007-2.024z" />
<Path Data="M3.125 12.5h43.75v31.25H3.125z" Fill="#FFFFFF" />
<Path Fill="#3898C6" Data="M25 18.75h15.625v3.125H25zM25 25h12.5v3.125H25zm0 6.25h15.625v3.125H25zM9.375 18.75V37.5h12.5V18.75h-12.5zm9.375 15.625H12.5v-12.5h6.25v12.5z" />
<Path Fill="#FFFFFF" Data="M43.75 6.25h3.125v3.125H43.75zm-6.25 0h3.125v3.125H37.5zm-6.25 0h3.125v3.125H31.25z" />
</Canvas>
</Viewbox>

37
Xaml/Icons/Devices.xaml Normal file
View File

@@ -0,0 +1,37 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="18" Width="18">
<Canvas.Resources>
<LinearGradientBrush x:Key="aea576e5-fef8-4bf5-a6dd-590c075a08c5" StartPoint="0.0834000036120415,0.119599997997284" EndPoint="0.0834000036120415,0.0186000000685453" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#d2ebff" />
<GradientStop Offset="1" Color="#f0fffd" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ae1611cd-4cf1-4ed1-b5e1-db19220ee586" StartPoint="0.141499996185303,0.204099997878075" EndPoint="0.141499996185303,0.0233999993652105" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#0078d4" />
<GradientStop Offset="0.17" Color="#1c84dc" />
<GradientStop Offset="0.38" Color="#3990e4" />
<GradientStop Offset="0.59" Color="#4d99ea" />
<GradientStop Offset="0.8" Color="#5a9eee" />
<GradientStop Offset="1" Color="#5ea0ef" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="bb0a651b-bb97-4569-a23e-5fed56c1e359" StartPoint="0.141499996185303,0.155300006270409" EndPoint="0.141499996185303,0.0520000010728836" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Canvas.Resources> <Rectangle Width="16.68" Height="11.87" Canvas.Top="1.03" Fill="#0078d4" RadiusX="0.6" RadiusY="0.6" />
<Rectangle Width="14.74" Height="10.1" Canvas.Left="0.97" Canvas.Top="1.86" Fill="{StaticResource aea576e5-fef8-4bf5-a6dd-590c075a08c5}" Opacity='0.9' RadiusX="0.3" RadiusY="0.3" />
<Rectangle Width="7.7" Height="12.85" Canvas.Left="10.3" Canvas.Top="4.12" Fill="{StaticResource ae1611cd-4cf1-4ed1-b5e1-db19220ee586}" RadiusX="0.3" RadiusY="0.3" />
<Rectangle Width="1.77" Height="0.24" Canvas.Left="13.27" Canvas.Top="4.55" Fill="#f2f2f2" RadiusX="0.11" RadiusY="0.11" />
<Rectangle Width="6.25" Height="10.33" Canvas.Left="11.03" Canvas.Top="5.2" Fill="{StaticResource bb0a651b-bb97-4569-a23e-5fed56c1e359}" Opacity='0.9' RadiusX="0.14" RadiusY="0.14" />
<Rectangle Width="1.77" Height="0.24" Canvas.Left="7.48" Canvas.Top="1.4" Fill="#f2f2f2" RadiusX="0.11" RadiusY="0.11" />
<Rectangle Width=".86" Height="0.73" Canvas.Left="13.72" Canvas.Top="15.96" Fill="#f2f2f2" RadiusX="0.2" RadiusY="0.2" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,19 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="18" Width="18">
<Canvas.Resources>
<LinearGradientBrush x:Key="A" StartPoint="0.0703999996185303,0.75" EndPoint="0.0703999996185303,0.163499996066093" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.18" Color="#5ea0ef" />
<GradientStop Offset="1" Color="#0078d4" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Canvas.Resources>
<Path Data="M14 8c0 4.58-5.53 8.26-6.73 9a.47.47 0 0 1-.46 0C5.6 16.25.07 12.57.07 8V2.48a.44.44 0 0 1 .43-.43C4.8 1.93 3.8 0 7 0s2.23 1.9 6.54 2a.44.44 0 0 1 .42.43z" Fill="#5ea0ef" />
<Path Data="M13.42 8c0 4.2-5.08 7.57-6.18 8.26a.4.4 0 0 1-.42 0C5.72 15.6.65 12.23.65 8V3A.39.39 0 0 1 1 2.59C5 2.48 4.07.75 7 .75s2.05 1.73 6 1.84a.4.4 0 0 1 .4.4z" Fill="#60b0ef" />
<Path Data="M7 8.55V.75c3 0 2.05 1.73 6 1.84a.41.41 0 0 1 .4.4V8.5zm0 0H.67c.4 4 5.1 7.1 6.15 7.75a.34.34 0 0 0 .17.05H7z" Fill="{StaticResource A}" />
<Path Data="M1 2.6C5 2.48 4.07.75 7 .75v7.8H.67V3A.4.4 0 0 1 1 2.59zm12.4 5.95H7v7.8a.34.34 0 0 0 .17-.05c1.13-.66 5.83-3.8 6.22-7.75z" Fill="#0078d4" />
<Path Data="M14.13 17.8l.33-1.08.63-.37 1.1.48.7-.72V16l-.5-1 .3-.68 1.1-.4.12-.05v-1h-.14l-1.08-.33-.36-.63.47-1.1-.72-.7H16l-1 .5-.7-.3-.44-1.22h-1l-.05.14-.33 1.08-.7.3-1.18-.54-.7.72.07.13.52 1-.28.7-1.2.45v1l.14.05 1.08.33.3.7L10 16.3l.73.7.13-.07 1-.53.7.28.52 1.3h1zm-1.63-3.23a1.45 1.45 0 1 1 2 0 1.44 1.44 0 0 1-2 0z" Fill="#949494" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,15 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Data="M46 33c0 1.657-1.359 3-3.036 3H3.036C1.359 36 0 34.657 0 33V3c0-1.657 1.359-3 3.036-3h39.928C44.641 0 46 1.343 46 3v30z" Fill="#3E3E3E" />
<Path Fill="#3898C6" Data="M2.962 5H43v26H2.962z" />
<Path Data="M31 0H3a3 3 0 00-3 3v30a3 3 0 003 3h12L31 0z" Fill="#ffffff" Opacity=".15" />
<Path Data="M26 2.689c0 .38-.308.688-.688.688H20.89a.689.689 0 110-1.377h4.422c.38 0 .688.309.688.689" Fill="#ffffff" />
<Path Data="M50 47.545C50 48.901 48.913 50 47.572 50H29.428C28.087 50 27 48.901 27 47.545v-31.09C27 15.099 28.087 14 29.428 14h18.143C48.913 14 50 15.099 50 16.455v31.09z" Fill="#3E3E3E" />
<Path Fill="#5AB3D9" Data="M29 18h19v27H29z" />
<Path Data="M42.607 16.171c0 .335-.436.606-.974.606H35.37c-.54 0-.977-.271-.977-.606 0-.335.437-.607.977-.607h6.263c.538 0 .974.272.974.607" Fill="#ffffff" />
<Path Data="M45.089 14H29.464A2.46 2.46 0 0027 16.455v31.091A2.458 2.458 0 0029.464 50H31.6l13.489-36z" Opacity=".15" Fill="#ffffff" />
<Ellipse Canvas.Left="8" Canvas.Top="20" Width="27" Height="27" Fill="#B82025" />
<Path Fill="#2A3280" Data="M21.5 21C28.393 21 34 26.607 34 33.5S28.393 46 21.5 46 9 40.393 9 33.5 14.607 21 21.5 21m0-1C14.044 20 8 26.044 8 33.5S14.044 47 21.5 47 35 40.956 35 33.5 28.956 20 21.5 20z" Opacity=".5" />
<Path Data="M22.856 36l.679-11H19.46l.679 11h2.717zm-1.354 2.1a1.903 1.903 0 00-1.905 1.899c0 1.05.854 1.901 1.905 1.901a1.902 1.902 0 001.904-1.901 1.902 1.902 0 00-1.904-1.899z" Fill="#ffffff" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,11 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Data="M0 44.062C0 45.132.898 46 2.007 46h45.986C49.102 46 50 45.132 50 44.062V11H0v33.062z" Fill="#3999C6" />
<Path Data="M47.993 3H2.007C.898 3 0 3.966 0 5.159V12h50V5.159C50 3.966 49.101 3 47.993 3z" Fill="#7a7a7a" />
<Path Data="M2.014 3C.906 3 .007 3.861.007 4.923v39.153C.007 45.138.906 46 2.014 46h17.188L41.62 3H2.014z" Fill="#ffffff" Opacity=".1"/>
<Path Data="M3 12h44v31H3z" Fill="#ffffff" />
<Path Data="M25 19h16v3H25zm0 12h16v3H25z" Fill="#3999C6" />
<Path Data="M44 6h3v3h-3zm-6 0h3v3h-3zm-6 0h3v3h-3z" Fill="#ffffff" />
<Path Data="M7.161 32.753a.463.463 0 01-.123-.334.46.46 0 01.151-.315l1.21-1.119a.456.456 0 01.31-.122c.129 0 .245.052.334.149l3.208 3.44 5.622-7.202a.448.448 0 01.36-.176c.103 0 .199.034.28.098l1.31 1.011a.43.43 0 01.176.302c.01.1-.002.236-.108.346l-7.233 9.262a.33.33 0 01-.501.022l-4.996-5.362zm0-12.072a.463.463 0 01-.123-.334.46.46 0 01.151-.315l1.21-1.119a.456.456 0 01.31-.122c.129 0 .245.052.334.149l3.208 3.44 5.622-7.202a.448.448 0 01.36-.176c.103 0 .199.034.28.098l1.31 1.011a.43.43 0 01.176.302c.01.1-.002.236-.108.346l-7.233 9.262a.33.33 0 01-.501.022l-4.996-5.362z" Fill="#3999C6" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,5 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#2072B8" Data="M25 4.885v16.99h21.875V3.124zM3.125 6.647v15.228h18.75V5.137zM25 41.989v-16.99h21.875V43.75zM3.125 40.227V24.999h18.75v16.738z" />
</Canvas>
</Viewbox>

37
Xaml/Icons/Intune.xaml Normal file
View File

@@ -0,0 +1,37 @@
<Viewbox Width="18" Height="18" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox.Resources>
<LinearGradientBrush x:Key="49fe045b-cfda-452f-85cf-d603e1d9f1ff" StartPoint="0.0804999992251396,0.113200001418591" EndPoint="0.0804999992251396,0.0126000000163913" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#0078d4" />
<GradientStop Offset="0.82" Color="#5ea0ef" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="49fe045b-cfda-452f-85cf-d603e1d9f200" StartPoint="0.0804999992251396,0.152099996805191" EndPoint="0.0804999992251396,0.113200001418591" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#1490df" />
<GradientStop Offset="0.98" Color="#1f56a3" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="49fe045b-cfda-452f-85cf-d603e1d9f201" StartPoint="0.0804999992251396,0.0786999985575676" EndPoint="0.0804999992251396,0.0494000017642975" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#d2ebff" />
<GradientStop Offset="1" Color="#f0fffd" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Viewbox.Resources>
<Canvas Height="18" Width="18">
<Rectangle Width="15.1" Height="10.06" Canvas.Left="0.5" Canvas.Top="1.26" Fill="{StaticResource 49fe045b-cfda-452f-85cf-d603e1d9f1ff}" RadiusX="0.5" />
<Rectangle Width="13.42" Height="8.39" Canvas.Left="1.34" Canvas.Top="2.1" Fill="#ffffff" RadiusX="0.28"/>
<Path Fill="{StaticResource 49fe045b-cfda-452f-85cf-d603e1d9f200}" Data="M11.08 14.37c-1.5-.23-1.56-1.31-1.55-3h-3c0 1.74-.06 2.82-1.55 3a.87.87 0 00-.74.84h7.54a.88.88 0 00-.7-.84z" />
<Path Fill="#32bedd" Data="M17.17 5.91h-6.88a2.31 2.31 0 100 .92H11v9.58a.33.33 0 00.33.33h5.83a.33.33 0 00.33-.33V6.24a.33.33 0 00-.32-.33z" />
<Rectangle Width="5.27" Height="8.7" Canvas.Left="11.62" Canvas.Top="6.82" Fill="#ffffff" RadiusX="0.12" />
<Ellipse Canvas.Left="6.5900000000000007" Canvas.Top="4.95" Width="2.92" Height="2.92" Fill="{StaticResource 49fe045b-cfda-452f-85cf-d603e1d9f201}" />
<Path Fill="#0078d4" Data="M14.88 10.82L13.76 9.7a.06.06 0 00-.1.05v.68a.06.06 0 01-.06.06H11v.83h2.6a.06.06 0 01.06.06v.69a.06.06 0 00.1 0L14.88 11a.12.12 0 000-.18z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,5 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="16" Width="16">
<Path Fill="#000000" Data="M8 0a7.6 7.6 0 012.1.3 6.4 6.4 0 011.9.8 10.4 10.4 0 011.7 1.2A10.4 10.4 0 0114.9 4a6.4 6.4 0 01.8 1.9 7.5 7.5 0 010 4.2 6.4 6.4 0 01-.8 1.9 10.4 10.4 0 01-1.2 1.7 10.4 10.4 0 01-1.7 1.2 6.4 6.4 0 01-1.9.8 7.5 7.5 0 01-4.2 0 6.4 6.4 0 01-1.9-.8 10.4 10.4 0 01-1.7-1.2A10.4 10.4 0 011.1 12a6.4 6.4 0 01-.8-1.9 7.5 7.5 0 010-4.2A6.4 6.4 0 011.1 4a10.4 10.4 0 011.2-1.7A10.4 10.4 0 014 1.1 6.4 6.4 0 015.9.3 7.6 7.6 0 018 0zM1 8a6.4 6.4 0 00.3 2h2.8A3.4 3.4 0 004 9V7a3.4 3.4 0 00.1-1H1.3A6.4 6.4 0 001 8zm4.7-6.6a3.4 3.4 0 00-1.2.6l-1.2.8-.9 1A7.5 7.5 0 001.7 5h2.6a2.9 2.9 0 01.2-.9l.3-1 .4-.9a5.6 5.6 0 01.5-.8zm-4 9.6a7.5 7.5 0 00.7 1.2l.9 1 1.2.8a3.4 3.4 0 001.2.6 5.6 5.6 0 01-.5-.8l-.4-.9-.3-1a2.9 2.9 0 01-.2-.9zm9.2-1a3.4 3.4 0 01.1-1V7a3.4 3.4 0 01-.1-1H5.1A3.4 3.4 0 015 7v2a3.4 3.4 0 01.1 1zM8 1l-.7.2-.6.6-.5.7a3.6 3.6 0 00-.4.9l-.3.9a2.5 2.5 0 00-.2.7h5.4a2.5 2.5 0 00-.2-.7l-.3-.9a3.6 3.6 0 00-.4-.9l-.5-.7-.6-.6zm0 14l.7-.2.6-.6.5-.7a3.6 3.6 0 00.4-.9l.3-.9a2.5 2.5 0 00.2-.7H5.3a2.5 2.5 0 00.2.7l.3.9a3.6 3.6 0 00.4.9l.5.7.6.6zm6.3-10a7.5 7.5 0 00-.7-1.2l-.9-1-1.2-.8-1.2-.6a5.6 5.6 0 01.5.8l.4.9.3 1a2.9 2.9 0 01.2.9zm-4 9.6a3.4 3.4 0 001.2-.6l1.2-.8.9-1a7.5 7.5 0 00.7-1.2h-2.6a2.9 2.9 0 01-.2.9l-.3 1-.4.9a5.6 5.6 0 01-.5.8zM15 8a6.4 6.4 0 00-.3-2h-2.8a3.4 3.4 0 00.1 1v2a3.4 3.4 0 00-.1 1h2.8a6.4 6.4 0 00.3-2z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,16 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="64" Width="64">
<Ellipse Canvas.Left="1.75" Canvas.Top="1.75" Width="60.5" Height="60.5" StrokeThickness="1.5" Stroke="#707070" />
<Canvas Height="64" Width="64">
<Canvas.RenderTransform>
<MatrixTransform Matrix=".9 0 0 .9 10.4 10.4" />
</Canvas.RenderTransform>
<Rectangle Canvas.Left="13.3" Canvas.Top="12.3" Width="21.4" Height="28.5" StrokeThickness="2.5" Stroke="#707070" RadiusX="0.6" RadiusY="0.6" />
<Ellipse Canvas.Top="21.799999999999997" Canvas.Left="20.4" Width="7.2" Height="7.2" StrokeThickness="2.5" Stroke="#707070" />
<Path Data="M18 35a1 1 0 1112 0" StrokeThickness="2.5" Stroke="#707070" />
</Canvas>
<Canvas>
<Path Data="M36.68 14h2.34l-3.24 6.75h-2.43zM24.89 14h2.43l5.58 11.25a1.046 1.046 0 01-1.791 1.08l-.549-1.08z" Fill="#707070" />
</Canvas>
</Canvas>
</Viewbox>

12
Xaml/Icons/Logon.xaml Normal file
View File

@@ -0,0 +1,12 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="64" Width="64">
<Ellipse Canvas.Left="1.75" Canvas.Top="1.75" Width="60.5" Height="60.5" StrokeThickness="1.5" Stroke="#707070" />
<Canvas Height="64" Width="64">
<Canvas.RenderTransform>
<MatrixTransform Matrix="1.1 0 0 1.1 8.8 5.61" />
</Canvas.RenderTransform>
<Ellipse Canvas.Top="10.5" Canvas.Left="13" Width="14" Height="14" StrokeThickness="2.5" Stroke="#707070" />
<Path Data="M30 35h10m-5-5v10M30.833 32.09A11 11 0 009 34" StrokeThickness="2.5" Stroke="#707070" />
</Canvas>
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,22 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox.Resources>
<LinearGradientBrush x:Key="2234a2b0-8e35-4cb8-93a2-033d950b05a2" StartPoint="0.090379998087883,0.101590000092983" EndPoint="0.090379998087883,0.0783400014042854" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#5e9624" />
<GradientStop Offset="0.241" Color="#6fb02a" />
<GradientStop Offset="0.501" Color="#7cc52f" />
<GradientStop Offset="0.756" Color="#83d232" />
<GradientStop Offset="1" Color="#86d633" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Viewbox.Resources>
<Canvas Height="18" Width="18">
<Path Fill="{StaticResource 2234a2b0-8e35-4cb8-93a2-033d950b05a2}" Data="M13.9 8.989a1.158 1.158 0 11-1.159-1.155A1.157 1.157 0 0113.9 8.989zm-4.866-1.15a1.158 1.158 0 101.159 1.156 1.157 1.157 0 00-1.159-1.156zm-3.7 0A1.158 1.158 0 106.493 9a1.158 1.158 0 00-1.159-1.156z" />
<Path Fill="#50e6ff" Data="M6.184 13.633l-.664.665a.3.3 0 01-.424 0L.184 9.402a.6.6 0 01-.001-.848l.664-.666 5.335 5.32a.3.3 0 010 .425z" />
<Path Fill="#1490df" Data="M5.421 3.701l.67.667a.3.3 0 010 .425l-5.245 5.26-.666-.664a.6.6 0 010-.849L5 3.706a.3.3 0 01.425 0z" />
<Path Fill="#50e6ff" Data="M17.154 7.885l.664.665a.6.6 0 01-.001.849l-4.912 4.897a.3.3 0 01-.424 0l-.664-.666a.3.3 0 010-.424l5.337-5.321z" />
<Path Fill="#1490df" Data="M17.823 9.386l-.665.664-5.245-5.26a.3.3 0 010-.424l.67-.668a.3.3 0 01.424 0l4.82 4.834a.6.6 0 01-.002.849z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,8 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="20.9" Width="19.9">
<Path Data="M8 17.1c-.2 0-.4.3-.4.8 0 1.5 1.2 2.6 2.7 2.6S13 19.4 13 18c0-.5-.1-.9-.4-.9H8z" Fill="#FCD116" />
<Path Data="M17 16.1V6.7c0-3.4-3.4-6.2-7-6.2S3 3.3 3 6.7v9.4H1v2h18v-2h-2z" Fill="#FF8C00" />
<Path Data="M14.6 2.3C13.4 1.2 11.6.5 9.7.5 6.1.5 3 3.3 3 6.7v7L14.6 2.3z" Opacity="0.2" Fill="#FFFFFF" />
<Path Data="M1 16.1h18v2H1z" Fill="#1e1e1e" Opacity="0.2" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,24 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="18" Width="18">
<Canvas.Resources>
<LinearGradientBrush x:Key="de1cccc6-47f0-46c5-9f1a-e61eeb0d70ee" StartPoint="0.0966000035405159,0.152300000190735" EndPoint="0.0966000035405159,0.0500999987125397" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#0078d4" />
<GradientStop Offset="0.82" Color="#5ea0ef" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Canvas.Resources>
<Path Data="M4.37 3.58h7.97v9.68H4.37z" Fill="#FFFFFF" />
<Path Fill="#0078d4" Data="M5.08 13h-.46V3.83h7.48v3.94h.5V3.58a.25.25 0 00-.25-.25h-8a.28.28 0 00-.25.25v9.69a.27.27 0 00.08.18.26.26 0 00.17.07h.71z" />
<Path Data="M9.84 4.61H5.42a.35.35 0 00-.35.39v9.38a.35.35 0 00.35.34h7.68a.35.35 0 00.34-.35V8.12a.35.35 0 00-.35-.35h-2.54a.35.35 0 01-.35-.35V5a.34.34 0 00-.36-.39z" Fill="#FFFFFF" />
<Path Fill="{StaticResource de1cccc6-47f0-46c5-9f1a-e61eeb0d70ee}" Data="M9.68 5.05V7.4a.86.86 0 00.87.86H13v6H5.55V5.05h4.13m.17-.52H5.37a.36.36 0 00-.37.35v9.52a.36.36 0 00.36.35h7.77a.35.35 0 00.36-.35V8.09a.34.34 0 00-.36-.34h-2.57a.35.35 0 01-.35-.35V4.88a.36.36 0 00-.36-.35z" />
<Path Fill="#0078d4" Data="M13.36 7.81l-3.28-3.2v2.61a.59.59 0 00.59.6z" />
<Path Fill="#4d4d4d" Data="M11.72 9.34h-5a.17.17 0 01-.18-.17.18.18 0 01.22-.17h5a.18.18 0 01.18.18.17.17 0 01-.22.16zm0 1h-5a.18.18 0 01-.18-.18.18.18 0 01.22-.16h5a.18.18 0 01.18.17.18.18 0 01-.22.17zm0 1.01h-5a.18.18 0 01-.18-.18.17.17 0 01.22-.17h5a.17.17 0 01.18.17.18.18 0 01-.22.18z" />
<Path Fill="#949494" Data="M.5 15.39a.15.15 0 00.09.14l1.23.69 2.1 1.17a.17.17 0 00.23-.06l.71-1.18a.17.17 0 00-.06-.23l-2.46-1.37a.16.16 0 01-.08-.14V3.59a.16.16 0 01.08-.14L4.8 2.08a.17.17 0 00.06-.23L4.15.67a.17.17 0 00-.23-.06L1.86 1.76l-1.27.71a.15.15 0 00-.09.14v12.78z" />
<Path Fill="#a3a3a3" Data="M2.25 3.51a.13.13 0 01.07-.06l2.45-1.37a.17.17 0 00.06-.23L4.13.67a.19.19 0 00-.24-.06l-2 1.15-1.33.71a.17.17 0 00-.06.06l1 .53zm2.52 12.41l-2.45-1.37a.2.2 0 01-.08-.08l-1.73 1h.05l1.24.69 2.09 1.17a.19.19 0 00.24-.06l.7-1.18a.17.17 0 00-.06-.17z" />
<Path Fill="#949494" Data="M17.5 15.39a.15.15 0 01-.09.14l-1.23.69-2.1 1.17a.17.17 0 01-.23-.06l-.71-1.18a.17.17 0 01.06-.23l2.46-1.37a.16.16 0 00.08-.14V3.59a.16.16 0 00-.08-.14L13.2 2.08a.17.17 0 01-.06-.23l.71-1.18a.17.17 0 01.23-.06l2.06 1.15 1.27.71a.15.15 0 01.09.14v12.78z" />
<Path Fill="#a3a3a3" Data="M15.75 3.51a.13.13 0 00-.07-.06l-2.45-1.37a.17.17 0 01-.06-.23l.7-1.18a.19.19 0 01.24-.06l2.05 1.15 1.28.71a.17.17 0 01.06.06l-1 .53zm-2.52 12.41l2.45-1.37a.2.2 0 00.08-.08l1.73 1-1.24.69-2.09 1.17a.19.19 0 01-.24-.06l-.7-1.18a.17.17 0 01.01-.17z" />
</Canvas>
</Viewbox>

5
Xaml/Icons/Refresh.xaml Normal file
View File

@@ -0,0 +1,5 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="16" Width="16">
<Path Fill="#000000" Data="M12.5 1.4a10.7 10.7 0 011.9 1.8 7.8 7.8 0 011.2 2.2A7.5 7.5 0 0116 8a7.6 7.6 0 01-.3 2.1 6.4 6.4 0 01-.8 1.9 10.4 10.4 0 01-1.2 1.7 10.4 10.4 0 01-1.7 1.2 6.4 6.4 0 01-1.9.8 7.5 7.5 0 01-4.2 0 6.4 6.4 0 01-1.9-.8 10.4 10.4 0 01-1.7-1.2A10.4 10.4 0 011.1 12a6.4 6.4 0 01-.8-1.9 7.5 7.5 0 010-4.2 11.9 11.9 0 01.8-2 10.1 10.1 0 011.3-1.6A10.9 10.9 0 014.1 1H2V0h4v4H5V1.7a6.2 6.2 0 00-1.7 1.1 6.1 6.1 0 00-1.2 1.5A5.3 5.3 0 001.3 6 6.9 6.9 0 001 8a6.3 6.3 0 00.3 1.9 4.6 4.6 0 00.7 1.6 4.9 4.9 0 001.1 1.4A4.9 4.9 0 004.5 14l1.6.8L8 15l1.9-.2 1.6-.8a4.9 4.9 0 001.4-1.1 4.9 4.9 0 001.1-1.4 8 8 0 00.8-1.6A12.3 12.3 0 0015 8a6.2 6.2 0 00-.4-2.3 6.9 6.9 0 00-1-1.9 8.7 8.7 0 00-1.7-1.6 7.2 7.2 0 00-2-.9l.2-1a6.6 6.6 0 012.4 1.1z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,30 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="18" Width="18">
<Canvas.Resources>
<LinearGradientBrush x:Key="de1cccc6-47f0-46c5-9f1a-e61eeb0d7154" StartPoint="0.0793000012636185,0.179499998688698" EndPoint="0.0793000012636185,0.0562000013887882" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#5e9624" />
<GradientStop Offset="1" Color="#b4ec36" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="de1cccc6-47f0-46c5-9f1a-e61eeb0d7155" StartPoint="0.0794999971985817,0.0921000018715858" EndPoint="0.0794999971985817,0" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#5e9624" />
<GradientStop Offset="1" Color="#b4ec36" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Canvas.Resources>
<Path Fill="{StaticResource de1cccc6-47f0-46c5-9f1a-e61eeb0d7154}" Data="M14 16.85a1.3 1.3 0 001.32-1.31.81.81 0 000-.16c-.52-4.15-2.88-7.53-7.4-7.53S1 10.71.51 15.39a1.34 1.34 0 001.19 1.46H14z" />
<Path Data="M8 8.83a4.16 4.16 0 01-2.26-.66L7.92 14l2.22-5.79A4.2 4.2 0 018 8.83z" Fill="#ffffff" />
<Ellipse Canvas.Left="3.7800000000000002" Canvas.Top="0.5" Width="8.34" Height="8.34" Fill="{StaticResource de1cccc6-47f0-46c5-9f1a-e61eeb0d7155}" />
<Path Fill="#32bedd" Data="M17.49 11.13v4.24l-3.64 2.13v-4.24l3.64-2.13z" />
<Path Fill="#9cebff" Data="M17.49 11.13l-3.64 2.13-3.64-2.13L13.85 9l3.64 2.13z" />
<Path Fill="#50e6ff" Data="M13.85 13.26v4.24l-3.64-2.13v-4.24l3.64 2.13z" />
<Path Fill="#9cebff" Data="M10.21 15.37l3.64-2.11v4.24l-3.64-2.13z" />
<Path Fill="#50e6ff" Data="M17.49 15.37l-3.64-2.11v4.24l3.64-2.13z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,7 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="17" Width="13">
<Path Fill="#0f0f0f" Data="M2.7 7.3L1.4 6l5-5H10v2h1V0H6L0 6l2 2 .7-.7zM8 6l-6 6 5 5 6-6V6zm4 4.6l-5 5L3.4 12l5-5H12z" />
<Path Fill="#0f0f0f" Data="M3.7 10.3L2.4 9l5-5H11v2h1V3H7L1 9l2 2 .7-.7z" />
<Ellipse Fill="#0f0f0f" Canvas.Left="10" Canvas.Top="8" Width="1" Height="1" />
</Canvas>
</Viewbox>

21
Xaml/Icons/Scripts.xaml Normal file
View File

@@ -0,0 +1,21 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox.Resources>
<LinearGradientBrush x:Key="a24f9983-911f-4df7-920f-f964c8c10f82" StartPoint="0.0900000035762787,0.158340007066727" EndPoint="0.0900000035762787,0.0578799992799759" MappingMode="RelativeToBoundingBox">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#32bedd" />
<GradientStop Offset="0.175" Color="#32caea" />
<GradientStop Offset="0.41" Color="#32d2f2" />
<GradientStop Offset="0.775" Color="#32d4f5" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Viewbox.Resources>
<Canvas Height="18" Width="18">
<Path Fill="{StaticResource a24f9983-911f-4df7-920f-f964c8c10f82}" Data="M.5 5.788h17v9.478a.568.568 0 01-.568.568H1.068a.568.568 0 01-.568-.568V5.788z" />
<Path Fill="#0078d4" Data="M1.071 2.166h15.858a.568.568 0 01.568.568v3.054H.5V2.734a.568.568 0 01.571-.568z" />
<Path Fill="#f2f2f2" Data="M2.825 7.979l.369-.37a.167.167 0 01.236-.001l2.732 2.724a.335.335 0 010 .474l-.368.37-2.968-2.96a.167.167 0 010-.237z" />
<Path Fill="#e6e6e6" Data="M3.249 13.504l-.37-.37a.167.167 0 010-.236l2.916-2.925.37.368a.335.335 0 010 .474l-2.683 2.691a.167.167 0 01-.236 0z" />
<Rectangle Width="4.771" Height="1.011" Canvas.Left="7.221" Canvas.Top="12.64" Fill="#f2f2f2" RadiusX=".291" RadiusY=".291" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,11 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="18" Width="18">
<Path Fill="#3898C6" Data="M0 13.316c0 .378.287.684.641.684H14.36c.353 0 .64-.306.64-.684V3H0v10.316z" />
<Path Fill="#7B7B7B" Data="M14.359 0H.641C.287 0 0 .322 0 .72V3h15V.72c0-.398-.287-.72-.641-.72z" />
<Path Fill="#FFFFFF" Opacity=".1" Data="M.644 0C.29 0 .002.307.002.687v12.626c0 .379.288.687.642.687H5l6.854-14H.644z" />
<Path Fill="#FFFFFF" Data="M1 3h13v10H1zm8-2h1v1H9zm2 0h1v1h-1zm2 0h1v1h-1z" />
<Path Fill="#3898C6" Data="M5 5h6.5v1H5zM2 7h2v2H2zm0 3h2v2H2zm0-6h2v2H2zm3 4h6v1H5zm0 3h6v1H5z" />
<Path Fill="#57D432" Data="M14.806 7.372C12.402 7.129 12 6 12 6s-.541 1.429-4 1.429v4.942c0 .619.376 1.199.896 1.706C10.075 15.226 12 16 12 16s4-1.606 4-3.63V7.429c-.445 0-.841-.021-1.194-.057z" />
<Path Fill="#B8D432" Data="M14.806 7.372C12.402 7.129 12 6 12 6s-.541 1.429-4 1.429v4.942c0 .619.376 1.199.896 1.706l5.91-6.705z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,12 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#3898C6" Data="M3.125 0h31.25l12.5 12.5V50H3.125z" />
<Path Data="M31.25 15.625v-12.5h-25v43.75h37.5v-31.25z" Fill="#ffffff" />
<Path Fill="#3898C6" Data="M9.375 9.375H25V12.5H9.375zm0 21.875h6.25v3.125h-6.25zm0-12.5H31.25v3.125H9.375zm0 6.25H31.25v3.125H9.375z" />
<Path Fill="#3898C6" Data="M19.609 35.068l-.722-.776a.507.507 0 01.028-.722l2.101-1.928a.512.512 0 01.348-.137.51.51 0 01.381.163l5.77 6.134 9.922-12.611a.53.53 0 01.728-.086l2.265 1.739a.5.5 0 01.195.34.494.494 0 01-.105.375l-12.75 16.19-8.161-8.681z" />
<Canvas>
<Path Data="M31.75 15.125V.5h2.418l12.207 12.207v2.418z" Fill="#3898C6" />
<Path Data="M33.961 1l11.914 11.914v1.711H32.25V1h1.711m.414-1H31.25v15.625h15.625V12.5L34.375 0z" Fill="#3898C6" />
</Canvas>
</Canvas>
</Viewbox>

20
Xaml/Icons/Trash.xaml Normal file
View File

@@ -0,0 +1,20 @@
<!-- This file was generated by the AiToXaml tool.-->
<!-- Tool Version: 14.0.22307.0 -->
<Viewbox Width="16" Height="16" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1M4,16C2.897,16,2,15.103,2,14L2,5 1,5 1,2 4,2C4,0.897,4.897,0,6,0L9,0C10.103,0,11,0.897,11,2L14,2 14,5 13,5 13,14C13,15.103,12.103,16,11,16z" />
<GeometryDrawing Brush="#FFEFEFF0" Geometry="F1M10,12L9,12 9,6 10,6z M8,12L7,12 7,6 8,6z M6,12L5,12 5,6 6,6z M4,14L11,14 11,4 4,4z" />
<GeometryDrawing Brush="#FF424242" Geometry="F1M11,4L4,4 4,14 11,14z M6,3L9,3 9,2 6,2z M13,3L13,4 12,4 12,14C12,14.552,11.552,15,11,15L4,15C3.448,15,3,14.552,3,14L3,4 2,4 2,3 5,3 5,2C5,1.448,5.448,1,6,1L9,1C9.552,1,10,1.448,10,2L10,3z M10,6L9,6 9,12 10,12z M8,6L7,6 7,12 8,12z M6,12L5,12 5,6 6,6z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>

View File

@@ -0,0 +1,5 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#2072B8" Data="M25 4.885v16.99h21.875V3.124zM3.125 6.647v15.228h18.75V5.137zM25 41.989v-16.99h21.875V43.75zM3.125 40.227V24.999h18.75v16.738z" />
</Canvas>
</Viewbox>

View File

@@ -0,0 +1,11 @@
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas Height="50" Width="50">
<Path Fill="#1D1D1D" Data="M28.125 46.875h-25A3.125 3.125 0 010 43.75V3.125A3.125 3.125 0 013.125 0h25a3.125 3.125 0 013.125 3.125V43.75a3.125 3.125 0 01-3.125 3.125z" />
<Path Fill="#5AB3D9" Data="M3.125 3.125h25v37.5h-25z" />
<Path Fill="#3898C6" Data="M28.125 40.625h-25V32.67l25-18.465z" />
<Path Data="M25 6.25V37.5H6.25V6.25H25m3.125-3.125h-25v37.5h25v-37.5z" Opacity=".4" Fill="#FFFFFF" />
<Path Fill="#E4E4E4" Data="M12.5 40.625h6.25v3.125H12.5z" />
<Path Fill="#7FBA42" Data="M37.5 15.625h6.25V50H37.5z" />
<Path Fill="#7FBA42" Data="M40.625 6.25l-9.375 12.5H50z" />
</Canvas>
</Viewbox>

112
Xaml/ImportForm.xaml Normal file
View File

@@ -0,0 +1,112 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5" Grid.IsSharedSizeScope='True'>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Name="grdImportProperties">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<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,0,5,0" >
<Label Content="Import folder" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This folder where files to import are located" />
</StackPanel>
<Grid Grid.Column='1' Grid.Row='0'>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="" Name="txtImportPath" />
<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">
<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" />
<StackPanel Orientation="Horizontal" Grid.Row='2' 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='2' Name='chkImportScopes' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='3' 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='3' Name='chkImportAssignments' VerticalAlignment="Center" IsChecked="true" />
<StackPanel Orientation="Horizontal" Grid.Row='4' 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='4' Name='chkReplaceDependencyIDs' VerticalAlignment="Center" IsChecked="true" />
</Grid>
<Grid Grid.Row='1' VerticalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Margin="0,0,5,0" Name="grdFilesHeader">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Label Content="Import files" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Files that can be imported. Note: These must match the object type being imported!" />
</StackPanel>
</Grid>
<ListBox Name="lstFiles" Grid.Column='1'
SelectionMode="Single"
VerticalAlignment="Stretch"
Grid.IsSharedSizeScope='True'>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="SelectedColumn" />
<ColumnDefinition Width="Auto" SharedSizeGroup="FileNameColumn" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding Selected}" />
<TextBlock Text="{Binding fileName}" Grid.Column='1' Margin="5,0,0,0" />
<TextBlock Text="{Binding displayName}" Grid.Column='2' Margin="5,0,0,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<CheckBox Grid.Column='1' Grid.Row='2' Margin="7,2,0,0" IsChecked="true" Name="chkCheckAll" ToolTip="Select/Deselect all" />
</Grid>
<StackPanel Name="spImportSubMenu" Grid.Row='2' Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,0,5">
<Button Name="btnGetFiles" Content="Get files" Width='100' Margin="5,0,0,0" />
<Button Name="btnImportSelected" Content="Import" Width='100' Margin="5,0,0,0" />
<Button Name="btnCancel" Content="Cancel" Width='100' Margin="5,0,0,0" />
</StackPanel>
</Grid>

22
Xaml/InputDialog.xaml Normal file
View File

@@ -0,0 +1,22 @@
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Name="txtLabel" Grid.Column="1"></Label>
<TextBox Name="txtValue" Grid.Column="1" Grid.Row="1" MinWidth="250"></TextBox>
<WrapPanel Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="0,15,0,0">
<Button IsDefault="True" Name="btnOk" MinWidth="60" Margin="0,0,10,0">_Ok</Button>
<Button IsCancel="True" Name="btnCancel" MinWidth="60">_Cancel</Button>
</WrapPanel>
</Grid>
</Window>

8
Xaml/LoginPanel.xaml Normal file
View File

@@ -0,0 +1,8 @@
<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
BorderBrush="Black" BorderThickness="1" Padding="5" Background="White">
<Grid Grid.Row="8" Name="grdAccounts" Grid.ColumnSpan="2" Margin="5,0,5,0" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</Border>

61
Xaml/MSALPreReqForm.xaml Normal file
View File

@@ -0,0 +1,61 @@
<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
BorderThickness = "0"
Margin="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock>
Could not find Microsoft Authentication Library (MSAL) file <Bold>Microsoft.Identity.Client.dll</Bold>.
<LineBreak/><LineBreak/>
The full path can be be specified in Settings or the application can automatically find it in the Az or MSAL.PS modules.
<LineBreak/>
Note that old versions of the Az module might not have the file.
</TextBlock>
<StackPanel Grid.Row='1' Orientation="Horizontal" Margin="0,5,0,0">
<Button Name="btnInstallMSALPS" Width="100" VerticalAlignment="Center" >Install MSAL.PS</Button>
<Label Content="Installs the MSAL.PS module e.g. running Install-Module -Name MSAL.PS" Margin="0,5,0,0"/>
</StackPanel>
<StackPanel Grid.Row='2' Orientation="Horizontal" Margin="0,5,0,0" >
<Button Name="btnInstallAz" Width="100" VerticalAlignment="Center" >Install Az</Button>
<Label Content="Installs the Az module e.g. running Install-Module -Name Az" Margin="0,5,0,0" />
</StackPanel>
<StackPanel Grid.Row='3' Margin="0,5,0,0">
<Label Content="Additional parameters for the Install-Module command:" />
<CheckBox Name="chkCurrentUser" IsChecked="True" Margin="0,5,0,0" >As current user</CheckBox>
<CheckBox Name="chkAllowClobber" Margin="0,5,0,0" >Allow clobber</CheckBox>
<CheckBox Name="chkSkipPublisherCheck" Margin="0,5,0,0" >Skip publisher check</CheckBox>
<!-- <CheckBox Name="chkAcceptLicense" Margin="0,5,0,0" >Accept license</CheckBox> -->
</StackPanel>
<StackPanel Grid.Row='4' Name="spPowerShellGet" Margin="0,5,0,0" >
<Label Content="PowerShellGet is either missing or not correct version (Min version: 2.0.0)" />
<CheckBox Name="chkInstallPowerShellGet" IsChecked="True" IsEnabled="False" Margin="0,5,0,0" >Install PowerShellGet</CheckBox>
</StackPanel>
<StackPanel Grid.Row='5' Name="spNuGet" Margin="0,5,0,0" >
<Label Content="NuGet is either missing or not correct version (Min version: 2.8.5.201)" />
<TextBlock Name="txtNotAdmin" Foreground="Red">
NuGet must be installed as admin and this script was not started with admin credentials.
<LineBreak/>
Restart the script as Admin
<LineBreak/>
or
<LineBreak/>
Quit the script, install NuGet manually and start the script
</TextBlock>
<CheckBox Name="chkInstallNuGet" IsChecked="True" IsEnabled="False" Margin="0,5,0,0" >Install NuGet</CheckBox>
</StackPanel>
</Grid>
</Border>

114
Xaml/MainWindow.xaml Normal file
View File

@@ -0,0 +1,114 @@
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Cloud API PowerShell Management"
WindowStartupLocation="CenterScreen"
x:Name="Window">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes\Default.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid x:Name="Grid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="grdMenu" Grid.ColumnSpan="2" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="5"/>
</Grid.ColumnDefinitions>
<Menu Name="mnuMain" Padding="0,5,0,5" Grid.ColumnSpan="2" >
<MenuItem Header="_File" >
<MenuItem Header="_Settings" Name="mnuSettings" />
<MenuItem Header="_About" Name="mnuAbout" />
<MenuItem Header="_Exit" Name="mnuExit" />
</MenuItem>
<MenuItem Name="mnuViews" Header="_Views" >
</MenuItem>
</Menu>
</Grid>
<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.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="" Name="lblMenuTitle" FontWeight="Bold" Margin="0,0,0,5" Background="{DynamicResource TitleBackgroundColor}" />
<ListBox Grid.Row="1" Name="lstMenuItems" SelectionMode="Single" Grid.IsSharedSizeScope='True' Background="#e9e9e9" > <!-- ItemContainerStyle="{DynamicResource MainList}" -->
<ListBox.ItemTemplate>
<DataTemplate>
<Grid > <!-- Margin="0,0,0,0" -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="ImageColumn" />
<ColumnDefinition Width="Auto" SharedSizeGroup="TitleColumn" />
</Grid.ColumnDefinitions>
<ContentControl Content="{Binding IconImage}" Width="16" Height="16" Margin="0,0,5,0" />
<TextBlock Text="{Binding Title}" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<!-- Popup with no background e.g. drop down menu -->
<Grid Name="grdPopup" Grid.ColumnSpan="2" Grid.RowSpan="4" Visibility="Collapsed">
<Grid.Background>
<SolidColorBrush Opacity="0" />
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas Name="cvsPopup" />
</Grid>
<!-- Modal popup with background -->
<Grid Name="grdModal" Grid.ColumnSpan="2" Grid.RowSpan="4" Visibility="Collapsed">
<Grid.Background>
<SolidColorBrush Opacity="0.5" Color="Black"/>
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="15*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
</Grid>
<Grid Name="grdStatus" Grid.ColumnSpan="2" Grid.RowSpan="4" Visibility="Collapsed">
<Grid.Background>
<SolidColorBrush Opacity="0.5" Color="Black" />
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Name="txtInfo" Content="" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{DynamicResource TitleBackgroundColor}" />
</Grid>
</Grid>
</Window>

17
Xaml/ModalForm.xaml Normal file
View File

@@ -0,0 +1,17 @@
<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
BorderBrush="Black" BorderThickness="1" Padding="5" Background="White">
<Grid HorizontalAlignment="Stretch" Name="grdModalContainer" VerticalAlignment="Stretch" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Background="{DynamicResource TitleBackgroundColor}" BorderThickness="0">
<TextBlock Name="txtTitle" Margin="5" FontWeight="Bold" />
</Border>
<StackPanel Name="spButtons" Grid.Row="2" HorizontalAlignment="Right" Orientation="Horizontal" Margin="0,5,0,5">
<Button Name="btnClose" Width="100" Margin="15,0,0,0">Close</Button>
</StackPanel>
</Grid>
</Border>

24
Xaml/ObjectDetails.xaml Normal file
View File

@@ -0,0 +1,24 @@
<Grid Margin="0,0,0,5" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox Name="txtValue"
Grid.Column="1" Grid.Row="1"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True"
IsReadOnly="True"
MinWidth="250" Margin="0" AcceptsReturn="True" />
<WrapPanel Name="pnlButtons" Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="0,10,0,0">
<Button Name="btnFull" MinWidth="100" Margin="0,0,5,0" ToolTip="Load full info of the object">Load full</Button>
<Button Name="btnCopy" MinWidth="100" Margin="0,0,0,0" ToolTip="Copy text to clipboard">Copy</Button>
</WrapPanel>
</Grid>

44
Xaml/ProfileInfo.Xaml Normal file
View File

@@ -0,0 +1,44 @@
<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
BorderBrush="Black" BorderThickness="1" Padding="5" Background="White">
<Grid Name="ProfileInfo" Background="White">
<Grid.RowDefinitions>
<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"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Margin="5" Name="txtOrganization" FontWeight="Bold" />
<Button Margin="5" Name="lnkLogout" Content="Sign out" Grid.Column="2" Style="{DynamicResource LinkButton}" HorizontalAlignment="Right"/>
<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" />
<StackPanel Margin="5" Grid.Row="3" Grid.ColumnSpan="2">
<TextBlock Text="Application:" />
<TextBlock Name="txtAppName" />
<TextBlock Name="txtAppId" />
</StackPanel>
<StackPanel Grid.Row="5" Grid.ColumnSpan="2" Orientation="Horizontal">
<Button Margin="5" Name="lnkTokeninfo" Content="MSAL Token" Cursor="Hand" Style="{DynamicResource LinkButton}" />
<Button Margin="5" Name="lnkAccessTokenInfo" ToolTip="Show the decoded JWT info of the AccessToken" Content="Access Token" Cursor="Hand" Style="{DynamicResource LinkButton}" />
<Button Margin="5" Name="lnkIdTokenInfo" ToolTip="Show the decoded JWT info of the IdToken" Content="Id Token" Cursor="Hand" Style="{DynamicResource LinkButton}" />
<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">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</Grid>
</Border>

38
Xaml/RefreshButton.xaml Normal file
View File

@@ -0,0 +1,38 @@
<!-- This file was generated by the AiToXaml tool.-->
<!-- Tool Version: 14.0.22307.0 -->
<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Button.Template>
<ControlTemplate>
<Rectangle Height="16" Width="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#FF777777" Geometry="M12.5 1.4a10.7 10.7 0 011.9 1.8 7.8 7.8 0 011.2 2.2A7.5 7.5 0 0116 8a7.6 7.6 0 01-.3 2.1 6.4 6.4 0 01-.8 1.9 10.4 10.4 0 01-1.2 1.7 10.4 10.4 0 01-1.7 1.2 6.4 6.4 0 01-1.9.8 7.5 7.5 0 01-4.2 0 6.4 6.4 0 01-1.9-.8 10.4 10.4 0 01-1.7-1.2A10.4 10.4 0 011.1 12a6.4 6.4 0 01-.8-1.9 7.5 7.5 0 010-4.2 11.9 11.9 0 01.8-2 10.1 10.1 0 011.3-1.6A10.9 10.9 0 014.1 1H2V0h4v4H5V1.7a6.2 6.2 0 00-1.7 1.1 6.1 6.1 0 00-1.2 1.5A5.3 5.3 0 001.3 6 6.9 6.9 0 001 8a6.3 6.3 0 00.3 1.9 4.6 4.6 0 00.7 1.6 4.9 4.9 0 001.1 1.4A4.9 4.9 0 004.5 14l1.6.8L8 15l1.9-.2 1.6-.8a4.9 4.9 0 001.4-1.1 4.9 4.9 0 001.1-1.4 8 8 0 00.8-1.6A12.3 12.3 0 0015 8a6.2 6.2 0 00-.4-2.3 6.9 6.9 0 00-1-1.9 8.7 8.7 0 00-1.7-1.6 7.2 7.2 0 00-2-.9l.2-1a6.6 6.6 0 012.4 1.1z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
<!--
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1M16,8C16,12.411 12.411,16 8,16 3.589,16 0,12.411 0,8 0,6.597 0.384,5.212 1.088,4L0,4 0,0 8,0 8,8 4,8C4,10.206 5.794,12 8,12 10.206,12 12,10.206 12,8 12,6.656 11.331,5.41 10.21,4.666L9.377,4.112 11.592,0.78 12.425,1.333C14.663,2.822,16,5.314,16,8" />
<GeometryDrawing Brush="#FF777777" Geometry="F1M15,8C15,11.859 11.859,15 8,15 4.14,15 1,11.859 1,8 1,6.076 1.801,4.292 3.121,3L1,3 1,1 7,1 7,7 5,7 5,4.002C3.766,4.931 3,6.401 3,8 3,10.757 5.243,13 8,13 10.757,13 13,10.757 13,8 13,6.321 12.164,4.763 10.764,3.833L11.871,2.167C13.83,3.469,15,5.649,15,8" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
-->
</ControlTemplate>
</Button.Template>
</Button>

32
Xaml/SettingsForm.xaml Normal file
View File

@@ -0,0 +1,32 @@
<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
BorderBrush="Black" BorderThickness="1" Padding="5" Background="White">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<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="*" />
</Grid.ColumnDefinitions>
</Grid>
</ScrollViewer>
<StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal" Margin="0,5,0,5">
<Button Name="btnSave" Width="100">Save</Button>
<Button Name="btnClose" Width="100" Margin="15,0,0,0">Close</Button>
</StackPanel>
</Grid>
</Border>

30
Xaml/SplashScreen.xaml Normal file
View File

@@ -0,0 +1,30 @@
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SplashScreenView"
Height="150" Width="420"
WindowStartupLocation="CenterScreen" WindowStyle="None"
ShowInTaskbar="False" Topmost="True" AllowsTransparency="True"
ResizeMode="NoResize" Background="#7F000000" Foreground="White">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--
<Image Grid.Row="0" Width="64" Height="64" Margin="10,0,10,0" ... />
<Grid Grid.Column="1" Margin="0,10,0,0">
-->
<Grid Grid.Column="1" Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="txtSplashTitle" Text="" FontSize="18" FontWeight="Bold" VerticalAlignment="Top"/>
<TextBlock Name="txtSplashText" Text="" Grid.Row="1" VerticalAlignment="Center" />
</Grid>
</Grid>
</Window>

54
Xaml/Welcome.xaml Normal file
View File

@@ -0,0 +1,54 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Name="scrollViewerObj"
Margin="5">
<TextBlock
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="{Binding ElementName=scrollViewerObj, Path=ViewportHeight}"
Width="{Binding ElementName=scrollViewerObj, Path=ViewportWidth}"
MinWidth="700"
MinHeight="390"
>
<Bold>Welcome!</Bold>
<LineBreak/><LineBreak/>
This software uses public APIs (e.g. Microsoft Graph etc.) to manage and view objects.
<LineBreak/>
It uses the BETA version of Microsoft Graph so some functionallity might change or break.
<LineBreak /><LineBreak />
Please report any issues to the GitHub repository.
<LineBreak/>
This is developed outside work hours so please respect that any support is based on best effort.
<LineBreak /><LineBreak />
See <Hyperlink Name="gitHubLink" NavigateUri="https://github.com/Micke-K/IntuneManagement">GitHub</Hyperlink> repository for documentation, issue tracking etc.
<LineBreak /><LineBreak />
This software has <Bold>NO</Bold> association with Microsoft.
<LineBreak /><LineBreak />
This software is provided AS IS and it is licensed under the MIT license. See <Hyperlink Name="licenseLink" NavigateUri="https://github.com/Micke-K/IntuneManagement/blob/master/LICENSE">LicenseInfo</Hyperlink> for more information.
<LineBreak /><LineBreak />
<Bold>Note:</Bold>
<LineBreak />
The 'Microsoft Intune PowerShell' Enterprise App in Azure is used by default for API calls.
<LineBreak />
Go to Settings if you want to use 'Microsoft Graph PowerShell' or a custom App.
<LineBreak />
This software might use permissions not granted for the existing App.
<LineBreak />
A grant request will be displayed if permissions are missing.
<LineBreak />
Enable 'Use Default Permissions' in Settings to only use existing App permissions. Some objects might not be supported.
</TextBlock>
</ScrollViewer>
<StackPanel Grid.Row='1' Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,5,0,5">
<CheckBox Name='chkAcceptConditions' VerticalAlignment="Center" IsChecked="false" Margin="5,0,0,0" >Accept conditions</CheckBox>
<Button Name="btnAcceptConditions" Content="OK" IsEnabled="false" Width='100' Margin="5,0,0,0" />
<Button Name="btnCancel" Content="Cancel" Width='100' Margin="5,0,0,0" />
</StackPanel>
</Grid>