mirror of
https://github.com/Micke-K/IntuneManagement.git
synced 2026-09-28 10:55:38 +02:00
Compare commits
3
Commits
1.0
..
archive/ver2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dfaf1bfba | ||
|
|
3545af455d | ||
|
|
b4c737dd6d |
@@ -198,6 +198,16 @@ function Get-AppProtectionObjectType
|
|||||||
{
|
{
|
||||||
"androidManagedAppProtections"
|
"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
|
function Get-AppProtectionObjectForExport
|
||||||
@@ -257,10 +267,8 @@ function Import-AppProtection
|
|||||||
if(($obj | GM -MemberType NoteProperty -Name "Apps"))
|
if(($obj | GM -MemberType NoteProperty -Name "Apps"))
|
||||||
{
|
{
|
||||||
$apps = $obj.Apps
|
$apps = $obj.Apps
|
||||||
# Remove apps properties
|
|
||||||
Remove-ObjectProperty $obj "apps"
|
|
||||||
Remove-ObjectProperty $obj "apps@odata.context"
|
|
||||||
}
|
}
|
||||||
|
Start-PreImport $obj -RemoveProperties @("apps","apps@odata.context")
|
||||||
|
|
||||||
Write-Status "Import $($obj.displayName)"
|
Write-Status "Import $($obj.displayName)"
|
||||||
|
|
||||||
|
|||||||
+1
-11
@@ -247,17 +247,7 @@ function Import-Application
|
|||||||
{
|
{
|
||||||
param($obj)
|
param($obj)
|
||||||
|
|
||||||
Remove-ObjectProperty $obj "uploadState"
|
Start-PreImport $obj -RemoveProperties @("uploadState","publishingState","isAssigned","roleScopeTagIds","dependentAppCount","committedContentVersion","id","isFeatured","size")
|
||||||
Remove-ObjectProperty $obj "publishingState"
|
|
||||||
Remove-ObjectProperty $obj "isAssigned"
|
|
||||||
Remove-ObjectProperty $obj "roleScopeTagIds"
|
|
||||||
Remove-ObjectProperty $obj "dependentAppCount"
|
|
||||||
Remove-ObjectProperty $obj "committedContentVersion"
|
|
||||||
Remove-ObjectProperty $obj "id"
|
|
||||||
Remove-ObjectProperty $obj "createdDateTime"
|
|
||||||
Remove-ObjectProperty $obj "lastModifiedDateTime"
|
|
||||||
Remove-ObjectProperty $obj "isFeatured"
|
|
||||||
Remove-ObjectProperty $obj "size"
|
|
||||||
|
|
||||||
Write-Status "Import $($obj.displayName)"
|
Write-Status "Import $($obj.displayName)"
|
||||||
|
|
||||||
|
|||||||
@@ -203,6 +203,8 @@ function Import-AutoPilot
|
|||||||
|
|
||||||
Write-Status "Import $($obj.displayName)"
|
Write-Status "Import $($obj.displayName)"
|
||||||
|
|
||||||
|
Start-PreImport $obj
|
||||||
|
|
||||||
Invoke-GraphRequest -Url "/deviceManagement/windowsAutopilotDeploymentProfiles" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
|
Invoke-GraphRequest -Url "/deviceManagement/windowsAutopilotDeploymentProfiles" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+124
-72
@@ -1,6 +1,82 @@
|
|||||||
|
#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
|
||||||
#
|
#
|
||||||
# Azure functions are based on: ???
|
# 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 {
|
function Invoke-AzureNativeRequest {
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
@@ -19,7 +95,7 @@ function Invoke-AzureNativeRequest {
|
|||||||
$Body,
|
$Body,
|
||||||
|
|
||||||
#Specify the HTTP Method you wish to use. Defaults to GET
|
#Specify the HTTP Method you wish to use. Defaults to GET
|
||||||
[ValidateSet("GET","POST","OPTIONS","DELETE", "PATCH", "PUT")]
|
[ValidateSet("GET","POST","OPTIONS","DELETE","PATCH")]
|
||||||
$Method = "GET",
|
$Method = "GET",
|
||||||
|
|
||||||
#The base URI for the Portal API. Typically you don't need to change this
|
#The base URI for the Portal API. Typically you don't need to change this
|
||||||
@@ -29,101 +105,76 @@ function Invoke-AzureNativeRequest {
|
|||||||
|
|
||||||
#The request ID for the session. You can generate one with [guid]::NewGuid().guid.
|
#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
|
#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
|
$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
|
#Combine the BaseURI and Target
|
||||||
[String]$ApiAction = $Target.TrimStart('/')
|
[String]$ApiAction = $Target.TrimStart('/')
|
||||||
|
|
||||||
if ($Action)
|
if ($Action) {
|
||||||
{
|
|
||||||
$ApiAction = $ApiAction + '/' + $Action
|
$ApiAction = $ApiAction + '/' + $Action
|
||||||
}
|
}
|
||||||
|
|
||||||
if($global:tokresponse -and [DateTimeOffset]::Now.ToUnixTimeSeconds() -gt $global:tokresponse.expires_on)
|
$uriStr = "$baseURI$ApiAction"
|
||||||
|
|
||||||
|
if($allowPaging)
|
||||||
{
|
{
|
||||||
$global:tokresponse = $null
|
$uri = [Uri]::New("$uriStr&nextLink=null")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$uri = [Uri]::New($baseURI,$ApiAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
$Context = Get-AzureRmContext
|
if(-not $global:AzToken.AccessToken.tostring())
|
||||||
|
|
||||||
if(-not $context -or -not $global:tokresponse)
|
|
||||||
{
|
{
|
||||||
if($Context)
|
Write-Log "No access token available" 3
|
||||||
{
|
return
|
||||||
if($global:Me -and $global:Organization)
|
|
||||||
{
|
|
||||||
$refreshToken = ($Context.TokenCache.ReadItems() | Where { $_.DisplayableId -eq $global:Me.userPrincipalName -and $_.TenantId -eq $global:Organization.Id }).RefreshToken
|
|
||||||
if($refreshToken -and $refreshToken.ExpiresOn -lt (Get-Date))
|
|
||||||
{
|
|
||||||
# Expired...force login
|
|
||||||
# $refreshToken = $null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(-not $refreshToken)
|
|
||||||
{
|
|
||||||
$user = Connect-AzureRmAccount
|
|
||||||
if(-not $user) { return }
|
|
||||||
$Context = Get-AzureRmContext
|
|
||||||
if(-not $Context) { return }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
if(-not $global:tokresponse)
|
|
||||||
{
|
|
||||||
$refreshToken = $null # Fore read again in case of login
|
|
||||||
if($global:Me -and $global:Organization)
|
|
||||||
{
|
|
||||||
$refreshToken = ($Context.TokenCache.ReadItems() | Where { $_.DisplayableId -eq $global:Me.userPrincipalName -and $_.TenantId -eq $global:Organization.Id }).RefreshToken
|
|
||||||
}
|
|
||||||
# Make sure we are using the same user as Intune login
|
|
||||||
if(-not $refreshToken)
|
|
||||||
{
|
|
||||||
[System.Windows.MessageBox]::Show("Failed to find login token for AzureRM", "Invalid AzureRM login!", "OK", "Error")
|
|
||||||
return $global:tokresponse
|
|
||||||
}
|
|
||||||
|
|
||||||
$curToken = $Context.TokenCache.ReadItems() | Where { $_.DisplayableId -eq $global:Me.userPrincipalName -and $_.TenantId -eq $global:Organization.Id }
|
|
||||||
$tenantid = $curToken.TenantId
|
|
||||||
$refreshToken = $curToken.RefreshToken
|
|
||||||
$loginUrl = "https://login.windows.net/$tenantid/oauth2/token"
|
|
||||||
$bodyTmp = "grant_type=refresh_token&refresh_token=$($refreshToken)" #&resource=74658136-14ec-4630-ad9b-26e160ff0fc6"
|
|
||||||
$response = Invoke-RestMethod $loginUrl -Method POST -Body $bodyTmp -ContentType 'application/x-www-form-urlencoded'
|
|
||||||
|
|
||||||
$global:tokresponse = Invoke-RestMethod $loginUrl -Method POST -Body ($bodyTmp + "&resource=74658136-14ec-4630-ad9b-26e160ff0fc6")
|
|
||||||
|
|
||||||
if(-not $global:tokresponse) { return }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$InvokeRestMethodParams = @{
|
$InvokeRestMethodParams = @{
|
||||||
Uri = [Uri]::New($baseURI,$ApiAction)
|
Uri = $uri
|
||||||
Method = $Method
|
Method = $Method
|
||||||
Header = [ordered]@{
|
Header = [ordered]@{
|
||||||
Authorization = 'Bearer ' + $global:tokresponse.access_token
|
Authorization = 'Bearer ' + $global:AzToken.AccessToken.tostring()
|
||||||
'Content-Type' = 'application/json'
|
'Content-Type' = 'application/json'
|
||||||
'x-ms-client-request-id' = $requestID
|
'x-ms-client-request-id' = $requestID
|
||||||
'Host' = $baseURI.Host
|
'Host' = $baseURI.Host
|
||||||
'Origin' = $requestOrigin
|
'Origin' = 'https://iam.hosting.portal.azure.net'
|
||||||
}
|
}
|
||||||
Body = $Body
|
Body = $Body
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
$max = 100
|
||||||
|
$cur = 0
|
||||||
|
|
||||||
|
$retObj = Invoke-RestMethod @InvokeRestMethodParams
|
||||||
|
if(($retObj | GM -MemberType NoteProperty -Name "nextLink"))
|
||||||
{
|
{
|
||||||
Invoke-RestMethod @InvokeRestMethodParams
|
while($retObj.nextLink)
|
||||||
if($? -eq $false)
|
|
||||||
{
|
{
|
||||||
throw $global:error[0]
|
# 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
$retObj
|
||||||
Write-LogError "Failed to invoke Invoke-RestMethod for Azure" $_.Exception
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-AzureNativeObjects
|
function Get-AzureNativeObjects
|
||||||
@@ -135,10 +186,11 @@ function Get-AzureNativeObjects
|
|||||||
$property,
|
$property,
|
||||||
[Array]
|
[Array]
|
||||||
$exclude,
|
$exclude,
|
||||||
$SortProperty = "")
|
$SortProperty = "",
|
||||||
|
[switch]$allowPaging)
|
||||||
|
|
||||||
$objects = @()
|
$objects = @()
|
||||||
$nativeObjects =Invoke-AzureNativeRequest $Target
|
$nativeObjects = Invoke-AzureNativeRequest $Target -allowPaging:($allowPaging -eq $true)
|
||||||
|
|
||||||
if(($nativeObjects | GM -Name "items"))
|
if(($nativeObjects | GM -Name "items"))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ function Import-IntuneBranding
|
|||||||
{
|
{
|
||||||
param($obj)
|
param($obj)
|
||||||
|
|
||||||
Remove-ObjectProperty $obj "@odata.context"
|
Start-PreImport $obj -RemoveProperties @("@odata.context")
|
||||||
|
|
||||||
$newObject = @"
|
$newObject = @"
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -201,6 +201,8 @@ function Import-CompliancePolicy
|
|||||||
{
|
{
|
||||||
param($obj)
|
param($obj)
|
||||||
|
|
||||||
|
Start-PreImport $obj
|
||||||
|
|
||||||
$json = ConvertTo-Json $obj -Depth 5
|
$json = ConvertTo-Json $obj -Depth 5
|
||||||
$json = $json.Trim().TrimEnd('}').Trim()
|
$json = $json.Trim().TrimEnd('}').Trim()
|
||||||
$json += @"
|
$json += @"
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ function Get-ConditionalAccess
|
|||||||
function Get-ConditionalAccessObjects
|
function Get-ConditionalAccessObjects
|
||||||
{
|
{
|
||||||
#https://main.iam.ad.ext.azure.com/api/Policies/Policies?top=10&nextLink=null&appId=&includeBaseline=true
|
#https://main.iam.ad.ext.azure.com/api/Policies/Policies?top=10&nextLink=null&appId=&includeBaseline=true
|
||||||
Get-AzureNativeObjects "Policies/Policies?top=10&nextLink=null&appId=&includeBaseline=true" -property @('policyName')
|
Get-AzureNativeObjects "Policies/Policies?top=10&appId=&includeBaseline=true" -property @('policyName') -allowPaging
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-ConditionalAccessObject
|
function Get-ConditionalAccessObject
|
||||||
@@ -214,6 +214,8 @@ function Import-ConditionalAccess
|
|||||||
{
|
{
|
||||||
param($obj)
|
param($obj)
|
||||||
|
|
||||||
|
Start-PreImport $obj
|
||||||
|
|
||||||
$json = Update-JsonForEnvironment $json
|
$json = Update-JsonForEnvironment $json
|
||||||
|
|
||||||
if($obj.baselineType -eq 0)
|
if($obj.baselineType -eq 0)
|
||||||
|
|||||||
@@ -206,14 +206,10 @@ function Import-DeviceConfiguration
|
|||||||
{
|
{
|
||||||
param($obj)
|
param($obj)
|
||||||
|
|
||||||
if(($obj | GM -MemberType NoteProperty -Name "supportsScopeTags"))
|
|
||||||
{
|
|
||||||
# Remove read-only property
|
|
||||||
$obj.PSObject.Properties.Remove('supportsScopeTags')
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Status "Import $($obj.displayName)"
|
Write-Status "Import $($obj.displayName)"
|
||||||
|
|
||||||
|
Start-PreImport $obj
|
||||||
|
|
||||||
Invoke-GraphRequest -Url "/deviceManagement/deviceConfigurations" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
|
Invoke-GraphRequest -Url "/deviceManagement/deviceConfigurations" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -222,6 +222,8 @@ function Import-ESP
|
|||||||
{
|
{
|
||||||
param($obj)
|
param($obj)
|
||||||
|
|
||||||
|
Start-PreImport $obj
|
||||||
|
|
||||||
if($obj.id -like "*_default*")
|
if($obj.id -like "*_default*")
|
||||||
{
|
{
|
||||||
Write-Status "Update $($obj.displayName)"
|
Write-Status "Update $($obj.displayName)"
|
||||||
|
|||||||
@@ -261,6 +261,8 @@ function Import-GPOSetting
|
|||||||
|
|
||||||
Write-Status "Import $($obj.displayName)"
|
Write-Status "Import $($obj.displayName)"
|
||||||
|
|
||||||
|
Start-PreImport $obj
|
||||||
|
|
||||||
# Import Administrative Template profile
|
# Import Administrative Template profile
|
||||||
$response = Invoke-GraphRequest -Url "/deviceManagement/groupPolicyConfigurations" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
|
$response = Invoke-GraphRequest -Url "/deviceManagement/groupPolicyConfigurations" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
|
||||||
|
|
||||||
@@ -268,6 +270,8 @@ function Import-GPOSetting
|
|||||||
{
|
{
|
||||||
foreach($setting in $settings)
|
foreach($setting in $settings)
|
||||||
{
|
{
|
||||||
|
Start-PreImport $setting
|
||||||
|
|
||||||
# Import each setting for the Administrative Template profile
|
# 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
|
$response2 = Invoke-GraphRequest -Url "/deviceManagement/groupPolicyConfigurations/$($response.id)/definitionValues" -Content (ConvertTo-Json $setting -Depth 5) -HttpMethod POST
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,33 +3,34 @@ function Invoke-InitializeModule
|
|||||||
$module = Get-Module -Name Microsoft.Graph.Intune -ListAvailable
|
$module = Get-Module -Name Microsoft.Graph.Intune -ListAvailable
|
||||||
if(-not $module)
|
if(-not $module)
|
||||||
{
|
{
|
||||||
$ret = [System.Windows.MessageBox]::Show("Intune PowerShell module not found!`n`nDo you want to install it?`n`nYes = Install intune module (Requires admin or it will fail)`nNo = Contune without module (No Azure modules will be loaded)`nCancel = Quit", "Error", "YesNoCancel", "Error")
|
$ret = [System.Windows.MessageBox]::Show("Intune PowerShell module not found!`n`nDo you want to install it as admin?`n`nYes = Install intune module as Admin (Requires admin or it will fail)`nNo = Install module for current user`nCancel = Quit", "Error", "YesNoCancel", "Error")
|
||||||
if($ret -eq "Yes")
|
if($ret -eq "Cancel")
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Install-Module -Name Microsoft.Graph.Intune -Force -ErrorAction SilentlyContinue
|
|
||||||
}
|
|
||||||
catch {}
|
|
||||||
if(-not (Get-Module -Name Microsoft.Graph.Intune -ListAvailable -Refresh))
|
|
||||||
{
|
|
||||||
[System.Windows.MessageBox]::Show("Failed to install Intune PowerShell module!`n`nRestart this as admin and try again`nor`nStart PowerShell as admin and run:`nInstall-Module -Name Microsoft.Graph.Intune", "Error", "OK", "Error")
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif($ret -eq "Cancel")
|
|
||||||
{
|
{
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
$params = @{}
|
||||||
|
if($ret -eq "No")
|
||||||
{
|
{
|
||||||
return
|
$params.Add("Scope", "CurrentUser")
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Install-Module -Name Microsoft.Graph.Intune -Force -ErrorAction SilentlyContinue @params
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
|
||||||
|
if(-not (Get-Module -Name Microsoft.Graph.Intune -ListAvailable -Refresh))
|
||||||
|
{
|
||||||
|
[System.Windows.MessageBox]::Show("Failed to install Intune PowerShell module!`n`nRestart this as admin and try again`nor`nStart PowerShell as admin and run:`nInstall-Module -Name Microsoft.Graph.Intune", "Error", "OK", "Error")
|
||||||
|
exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(-not $global:authentication)
|
if(-not $global:authentication)
|
||||||
{
|
{
|
||||||
if((Get-Command Connect-MSGraph))
|
if((Get-Command Connect-MSGraph -ErrorAction SilentlyContinue))
|
||||||
{
|
{
|
||||||
$global:authentication = Connect-MSGraph -PassThru
|
$global:authentication = Connect-MSGraph -PassThru
|
||||||
}
|
}
|
||||||
@@ -41,6 +42,7 @@ function Invoke-InitializeModule
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Write-Log "Get current user"
|
||||||
$global:Me = Invoke-GraphRequest "ME"
|
$global:Me = Invoke-GraphRequest "ME"
|
||||||
|
|
||||||
if(-not $global:Me)
|
if(-not $global:Me)
|
||||||
@@ -48,6 +50,8 @@ function Invoke-InitializeModule
|
|||||||
[System.Windows.MessageBox]::Show("Failed to get information about current logged on Azure user!`n`nVerify connection and try again`n`nNo Intune modules will be imported!", "Error", "OK", "Error")
|
[System.Windows.MessageBox]::Show("Failed to get information about current logged on Azure user!`n`nVerify connection and try again`n`nNo Intune modules will be imported!", "Error", "OK", "Error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Write-Log "Get organization info"
|
||||||
$global:Organization = (Invoke-GraphRequest "Organization").Value
|
$global:Organization = (Invoke-GraphRequest "Organization").Value
|
||||||
|
|
||||||
$global:graphURL = "https://graph.microsoft.com/beta"
|
$global:graphURL = "https://graph.microsoft.com/beta"
|
||||||
@@ -59,6 +63,8 @@ function Invoke-InitializeModule
|
|||||||
Values = @()
|
Values = @()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Write-Log "Add settings and menu items"
|
||||||
|
|
||||||
Add-SettingsObject (New-Object PSObject -Property @{
|
Add-SettingsObject (New-Object PSObject -Property @{
|
||||||
Title = "Root folder"
|
Title = "Root folder"
|
||||||
Key = "IntuneRootFolder"
|
Key = "IntuneRootFolder"
|
||||||
@@ -76,6 +82,7 @@ function Invoke-InitializeModule
|
|||||||
Key = "AddObjectType"
|
Key = "AddObjectType"
|
||||||
Type = "Boolean"
|
Type = "Boolean"
|
||||||
DefaultValue = $true
|
DefaultValue = $true
|
||||||
|
Description = "Default setting for adding object type to the export folder"
|
||||||
}) "IntuneAzure"
|
}) "IntuneAzure"
|
||||||
|
|
||||||
Add-SettingsObject (New-Object PSObject -Property @{
|
Add-SettingsObject (New-Object PSObject -Property @{
|
||||||
@@ -83,6 +90,7 @@ function Invoke-InitializeModule
|
|||||||
Key = "AddCompanyName"
|
Key = "AddCompanyName"
|
||||||
Type = "Boolean"
|
Type = "Boolean"
|
||||||
DefaultValue = $true
|
DefaultValue = $true
|
||||||
|
Description = "Default setting for adding company name to the export folder"
|
||||||
}) "IntuneAzure"
|
}) "IntuneAzure"
|
||||||
|
|
||||||
Add-SettingsObject (New-Object PSObject -Property @{
|
Add-SettingsObject (New-Object PSObject -Property @{
|
||||||
@@ -90,6 +98,7 @@ function Invoke-InitializeModule
|
|||||||
Key = "ExportIntuneAssignments"
|
Key = "ExportIntuneAssignments"
|
||||||
Type = "Boolean"
|
Type = "Boolean"
|
||||||
DefaultValue = $true
|
DefaultValue = $true
|
||||||
|
Description = "Default setting for exporting assignments"
|
||||||
}) "IntuneAzure"
|
}) "IntuneAzure"
|
||||||
|
|
||||||
Add-SettingsObject (New-Object PSObject -Property @{
|
Add-SettingsObject (New-Object PSObject -Property @{
|
||||||
@@ -97,6 +106,7 @@ function Invoke-InitializeModule
|
|||||||
Key = "CreateIntuneGroupOnImport"
|
Key = "CreateIntuneGroupOnImport"
|
||||||
Type = "Boolean"
|
Type = "Boolean"
|
||||||
DefaultValue = $true
|
DefaultValue = $true
|
||||||
|
Description = "Default setting for creating groups during import"
|
||||||
}) "IntuneAzure"
|
}) "IntuneAzure"
|
||||||
|
|
||||||
Add-SettingsObject (New-Object PSObject -Property @{
|
Add-SettingsObject (New-Object PSObject -Property @{
|
||||||
@@ -104,6 +114,7 @@ function Invoke-InitializeModule
|
|||||||
Key = "ConvertIntuneSyncedGroupOnImport"
|
Key = "ConvertIntuneSyncedGroupOnImport"
|
||||||
Type = "Boolean"
|
Type = "Boolean"
|
||||||
DefaultValue = $true
|
DefaultValue = $true
|
||||||
|
Description = "Convert AD synched groups to Azure AD group during import if the group does not exist"
|
||||||
}) "IntuneAzure"
|
}) "IntuneAzure"
|
||||||
|
|
||||||
Add-SettingsObject (New-Object PSObject -Property @{
|
Add-SettingsObject (New-Object PSObject -Property @{
|
||||||
@@ -178,7 +189,6 @@ $xmlStr = @"
|
|||||||
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="This will export all objects to a sub-directory of the export path with name based on object type" />
|
<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>
|
</StackPanel>
|
||||||
<CheckBox Grid.Column='1' Grid.Row='1' Name='chkAddObjectType' VerticalAlignment="Center" IsEnabled="false" IsChecked="true" />
|
<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">
|
<StackPanel Orientation="Horizontal" Grid.Row='2' Margin="0,0,5,0">
|
||||||
<Label Content="Add company name to path" />
|
<Label Content="Add company name to path" />
|
||||||
@@ -1575,4 +1585,30 @@ function Get-GraphAssignmentsObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
$tmpAssignments
|
$tmpAssignments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Policy Functions
|
||||||
|
function Start-PreImport
|
||||||
|
{
|
||||||
|
param($obj, $removeProperties = @())
|
||||||
|
|
||||||
|
|
||||||
|
foreach($removeProp in @('lastModifiedDateTime','createdDateTime','supportsScopeTags','id'))
|
||||||
|
{
|
||||||
|
if($removeProperties -notcontains $removeProp)
|
||||||
|
{
|
||||||
|
$removeProperties += $removeProp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($prop in $removeProperties)
|
||||||
|
{
|
||||||
|
if(($obj | GM -MemberType NoteProperty -Name $prop))
|
||||||
|
{
|
||||||
|
Write-Log "Remove property $prop"
|
||||||
|
$obj.PSObject.Properties.Remove($prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|||||||
@@ -243,11 +243,7 @@ function Import-PowerShellScript
|
|||||||
{
|
{
|
||||||
param($obj)
|
param($obj)
|
||||||
|
|
||||||
Remove-ObjectProperty $obj "id"
|
Start-PreImport $obj -RemoveProperties @("id","assignments@odata.context","assignments")
|
||||||
Remove-ObjectProperty $obj "createdDateTime"
|
|
||||||
Remove-ObjectProperty $obj "lastModifiedDateTime"
|
|
||||||
Remove-ObjectProperty $obj "assignments@odata.context"
|
|
||||||
Remove-ObjectProperty $obj "assignments"
|
|
||||||
|
|
||||||
Write-Status "Import $($obj.displayName)"
|
Write-Status "Import $($obj.displayName)"
|
||||||
|
|
||||||
|
|||||||
@@ -210,6 +210,8 @@ function Import-TermsAndCondition
|
|||||||
|
|
||||||
Write-Status "Import $($obj.displayName)"
|
Write-Status "Import $($obj.displayName)"
|
||||||
|
|
||||||
|
Start-PreImport $obj
|
||||||
|
|
||||||
Invoke-GraphRequest -Url "/deviceManagement/termsAndConditions" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
|
Invoke-GraphRequest -Url "/deviceManagement/termsAndConditions" -Content (ConvertTo-Json $obj -Depth 5) -HttpMethod POST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+129
-19
@@ -97,7 +97,7 @@ function global:Write-LogError
|
|||||||
{
|
{
|
||||||
param($Text, $Exception)
|
param($Text, $Exception)
|
||||||
|
|
||||||
if($Text)
|
if($Text -and $Exception.message)
|
||||||
{
|
{
|
||||||
$Text += " Exception: $($Exception.message)"
|
$Text += " Exception: $($Exception.message)"
|
||||||
}
|
}
|
||||||
@@ -532,6 +532,12 @@ function global:Add-SettingValue
|
|||||||
$settingObj = Add-SettingTextBox $id $value
|
$settingObj = Add-SettingTextBox $id $value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$descriptionInfo = ""
|
||||||
|
if($settingValue.Description)
|
||||||
|
{
|
||||||
|
$descriptionInfo = "<Rectangle Style=`"{DynamicResource InfoIcon}`" ToolTip=`"$($settingValue.Description)`" Margin=`"5,0,0,0`" />"
|
||||||
|
}
|
||||||
|
|
||||||
$xaml = @"
|
$xaml = @"
|
||||||
<Border Margin="0,5,0,0" $wpfNS>
|
<Border Margin="0,5,0,0" $wpfNS>
|
||||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
|
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
|
||||||
@@ -544,8 +550,13 @@ function global:Add-SettingValue
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="5,0,5,0">
|
||||||
|
<TextBlock Text="$($settingValue.Title)" VerticalAlignment="Center"/>
|
||||||
|
$descriptionInfo
|
||||||
|
</StackPanel>
|
||||||
|
<!--
|
||||||
<TextBlock Text="$($settingValue.Title)" VerticalAlignment="Center" Margin="5,0,0,0" />
|
<TextBlock Text="$($settingValue.Title)" VerticalAlignment="Center" Margin="5,0,0,0" />
|
||||||
|
-->
|
||||||
<Border Grid.Column="2" Name="border_$($id)" />
|
<Border Grid.Column="2" Name="border_$($id)" />
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -873,15 +884,23 @@ function global:Add-MenuItem
|
|||||||
|
|
||||||
function global:Invoke-ModuleFunction
|
function global:Invoke-ModuleFunction
|
||||||
{
|
{
|
||||||
param($funtion)
|
param($function)
|
||||||
|
|
||||||
|
Write-Log "Trigger function $function"
|
||||||
|
|
||||||
foreach($module in $global:loadedModules)
|
foreach($module in $global:loadedModules)
|
||||||
{
|
{
|
||||||
# Get command with ExportedFunctions instead of Get-Command
|
# Get command with ExportedFunctions instead of Get-Command
|
||||||
$cmd = $module.ExportedFunctions[$funtion]
|
$cmd = $module.ExportedFunctions[$function]
|
||||||
if($cmd)
|
if($cmd)
|
||||||
{
|
{
|
||||||
|
Write-Log "Trigger $function in $($module.Name)"
|
||||||
Invoke-Command -ScriptBlock $cmd.ScriptBlock
|
Invoke-Command -ScriptBlock $cmd.ScriptBlock
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#Write-Log "$function not found in $($module.Name)" 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,6 +924,12 @@ function global:Initialize-Menu
|
|||||||
Script = [ScriptBlock]{ Show-AboutDialog }
|
Script = [ScriptBlock]{ Show-AboutDialog }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Add-MenuItem (New-Object PSObject -Property @{
|
||||||
|
Title = 'Reload'
|
||||||
|
MenuID = "General"
|
||||||
|
ShowForm = $false
|
||||||
|
Script = [ScriptBlock]{ Start-Reload }
|
||||||
|
})
|
||||||
|
|
||||||
Add-MenuItem (New-Object PSObject -Property @{
|
Add-MenuItem (New-Object PSObject -Property @{
|
||||||
Title = 'Exit'
|
Title = 'Exit'
|
||||||
@@ -956,6 +981,38 @@ public static extern IntPtr GetConsoleWindow();
|
|||||||
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
|
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
|
||||||
'
|
'
|
||||||
|
|
||||||
|
function global:Set-MainTitle
|
||||||
|
{
|
||||||
|
if(-not $global:window) { return }
|
||||||
|
|
||||||
|
Write-Log "Set main title"
|
||||||
|
|
||||||
|
$mainTitle = $title
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if($global:Me.userPrincipalName)
|
||||||
|
{
|
||||||
|
$IntuneId = $global:Me.userPrincipalName
|
||||||
|
$mainTitle += " - IntuneGraph: $($global:Me.userPrincipalName)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$ctx = Get-AzContext -ErrorAction SilentlyContinue
|
||||||
|
if($ctx.Account.Id)
|
||||||
|
{
|
||||||
|
$azureADId = $ctx.Account.Id
|
||||||
|
$mainTitle += " - AzureAD: $($ctx.Account.Id)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {}
|
||||||
|
|
||||||
|
$global:window.Title = $mainTitle
|
||||||
|
}
|
||||||
|
|
||||||
function Show-Console
|
function Show-Console
|
||||||
{
|
{
|
||||||
$consolePtr = [Console.Window]::GetConsoleWindow()
|
$consolePtr = [Console.Window]::GetConsoleWindow()
|
||||||
@@ -984,6 +1041,68 @@ function Hide-Console
|
|||||||
[Console.Window]::ShowWindow($consolePtr, 0)
|
[Console.Window]::ShowWindow($consolePtr, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Module functions
|
||||||
|
|
||||||
|
function Import-AllModules
|
||||||
|
{
|
||||||
|
foreach($file in (Get-Item -path "$modulesPath\*.psm1"))
|
||||||
|
{
|
||||||
|
$module = Import-Module $file -PassThru -Force -ErrorAction SilentlyContinue
|
||||||
|
if($module)
|
||||||
|
{
|
||||||
|
$global:loadedModules += $module
|
||||||
|
Write-Host "Module $($module.Name) loaded successfully"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Write-Warning "Failed to load module $file"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Start-Reload
|
||||||
|
{
|
||||||
|
if([System.Windows.MessageBox]::Show("Are you sure you want to reload all modules and settings?", "Exit?", "YesNo", "Question") -eq "No")
|
||||||
|
{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Status "Reloading modules"
|
||||||
|
|
||||||
|
$global:menuObjects = @()
|
||||||
|
$tmpList = @()
|
||||||
|
$spMenu.Children.Clear()
|
||||||
|
|
||||||
|
foreach($tmpModule in $global:loadedModules)
|
||||||
|
{
|
||||||
|
Remove-Module $tmpModule
|
||||||
|
|
||||||
|
$module = Import-Module $tmpModule.Path -PassThru -Force -ErrorAction SilentlyContinue
|
||||||
|
if($module)
|
||||||
|
{
|
||||||
|
$tmpList += $module
|
||||||
|
Write-Host "Module $($module.Name) loaded successfully"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Write-Warning "Failed to load module $file"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$global:loadedModules = $tmpList
|
||||||
|
|
||||||
|
Add-DefaultSettings
|
||||||
|
|
||||||
|
Invoke-ModuleFunction "Invoke-InitializeModule"
|
||||||
|
|
||||||
|
Initialize-Menu
|
||||||
|
|
||||||
|
Write-Status ""
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#####################################################################################################
|
#####################################################################################################
|
||||||
@@ -1113,25 +1232,14 @@ $global:menuObjects = @()
|
|||||||
|
|
||||||
# Load all modules in the Modules folder
|
# Load all modules in the Modules folder
|
||||||
$modulesPath = [IO.Path]::GetDirectoryName($PSCommandPath) + "\Extensions"
|
$modulesPath = [IO.Path]::GetDirectoryName($PSCommandPath) + "\Extensions"
|
||||||
|
|
||||||
if(Test-Path $modulesPath)
|
if(Test-Path $modulesPath)
|
||||||
{
|
{
|
||||||
foreach($file in (Get-Item -path "$modulesPath\*.psm1"))
|
Import-AllModules
|
||||||
{
|
|
||||||
$module = Import-Module $file -PassThru -Force -ErrorAction SilentlyContinue
|
|
||||||
if($module)
|
|
||||||
{
|
|
||||||
$global:loadedModules += $module
|
|
||||||
Write-Host "Module $($module.Name) loaded successfully"
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write-Warning "Failed to load module $file"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Write-Warning "Modules folder $modulesPath not wound. Aborting..." 3
|
Write-Warning "Modules folder $modulesPath not found. Aborting..." 3
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1149,6 +1257,8 @@ if($ShowConsoleWindow -ne $true)
|
|||||||
Hide-Console
|
Hide-Console
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set-MainTitle
|
||||||
|
|
||||||
# Show main window
|
# Show main window
|
||||||
# Workaround for ISE crash
|
# Workaround for ISE crash
|
||||||
# https://gist.github.com/altrive/6227237
|
# https://gist.github.com/altrive/6227237
|
||||||
|
|||||||
@@ -8,6 +8,22 @@ This makes it easy to backup or clone a complete Intune environment. The scripts
|
|||||||
|
|
||||||
**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.
|
**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.
|
||||||
|
|
||||||
|
## Change log
|
||||||
|
**Version 2**
|
||||||
|
|
||||||
|
**Breaking changes**
|
||||||
|
* Removed support for AzureRM
|
||||||
|
|
||||||
|
**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
|
## Intune objects
|
||||||
* Administrative Templates
|
* Administrative Templates
|
||||||
* App Protection/Configuration policies
|
* App Protection/Configuration policies
|
||||||
@@ -34,14 +50,14 @@ This makes it easy to backup or clone a complete Intune environment. The scripts
|
|||||||
* .Net 4.7
|
* .Net 4.7
|
||||||
* Intune PowerShell Module
|
* Intune PowerShell Module
|
||||||
* Install by running 'Install-Module -Name Microsoft.Graph.Intune'
|
* Install by running 'Install-Module -Name Microsoft.Graph.Intune'
|
||||||
* AzueRM PowerShell Module
|
* Az PowerShell Module
|
||||||
* Install by running 'Install-Module -Name AzureRM -AllowClobber'
|
* Install by running 'Install-Module -Name Az -AllowClobber'
|
||||||
* Permissions in Azure to manage objects in Intune and Azure
|
* Permissions in Azure to manage objects in Intune and Azure
|
||||||
|
|
||||||
## References
|
## References
|
||||||
* [Microsoft Graph API](https://docs.microsoft.com/en-us/graph/api/overview?toc=./ref/toc.json&view=graph-rest-beta)
|
* [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 Intune PowerShell Module](https://github.com/microsoft/Intune-PowerShell-SDK)
|
||||||
* [AzureRM PowerShellModule](https://docs.microsoft.com/en-us/powershell/azure/azurerm/install-azurerm-ps?view=azurermps-6.13.0)
|
* [Az PowerShellModule](https://docs.microsoft.com/en-us/powershell/azure/new-azureps-module-az)
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
The app enryption and upload is based on [PowerShell Intune Examples](https://github.com/microsoftgraph/powershell-intune-samples)
|
The app enryption and upload is based on [PowerShell Intune Examples](https://github.com/microsoftgraph/powershell-intune-samples)
|
||||||
@@ -57,8 +73,6 @@ The script will create a group if it is missing in the destination environment.
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
If you want to test co-management and/or sync with on-prem AD, you can download [DeleMate](http://delemate.com). This tool can install anything from an AD-only environment to a complete SCCM environment in a quick and easy way. If you have a public domain registered, you can then install the AD domain with that name and add that domain to a test Azure environment and then configure AAD Sync and co-managment.
|
|
||||||
|
|
||||||
## License
|
## 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
|
||||||
|
|||||||
Reference in New Issue
Block a user