Az module is required for Native Azure objects (Conditional access, Azure branding and MDM/MAM settings) Fixed limit on Conditional Access objects Remove properties before import (date etc.) Added WIP policies Added support for installing Intune module for user only
221 lines
6.5 KiB
PowerShell
221 lines
6.5 KiB
PowerShell
#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
|
|
} |