Public/AzureAD/Import-AzureADAppAndPermissions.ps1
function Import-AzureADAppAndPermissions { <# .SYNOPSIS Import Azure AD App name & API permissions from filesystem or GIST-based xml .DESCRIPTION Import Azure AD App name & API permissions from filesystem or GIST-based xml .PARAMETER Owner The owner of the application. For convenience, should be the owner that can grant admin consent of the requested API permissions .PARAMETER XMLPath Filesystem path to the XML created by Export-AzureADAppAndPermissions Choose this or the Github paramters to grab the xml from a GIST .PARAMETER GithubUsername Github username where the GIST you wish to import lives .PARAMETER GistFilename filename of GIST, example: Test.xml .PARAMETER SecretDuration How many years the secret should live. Current Options are 1, 2, and None 1 year, 2 years or None (no secret created) .PARAMETER Name Name of the App to create in the target AzureAD tenant. If left blank, will use source tenant app name (plus timestamp of export) .PARAMETER OpenConsentInBrowser Will open the admin consent page where the admin can login to the target Azure AD tenant and "grant admin consent" for those APIs that require it .EXAMPLE Import-AzureADAppAndPermissions -Owner admin@thesourceonline.onmicrosoft.com -GithubUsername kevinblumenfeld ` -GistFilename test.xml -Name NewApp09 -SecretDuration 1 -OpenConsentInBrowser .EXAMPLE Import-AzureADAppAndPermissions -Owner admin@thesourceonline.onmicrosoft.com ` -XMLPath C:\Users\kevin\Desktop\Posh365\GraphApps\kevdev\TestApp-20200712-0757.xml` -Name NewApp01 -SecretDuration 1 -OpenConsentInBrowser .NOTES If SecretDuration is choosen the Secret will be include with the one object this function produces Example: ApplicationId : adecd1ee-abcd-4c66-bcf1-4bfb0b610818 TenantId : f8f6d77c-abcd-4a11-ae04-39bfaff70e00 ObjectId : c57f335d-abcd-492e-bc90-6cd1a85eecd6 Secret : pA00W2xLLabcdZLL5g8dS85HiXAjuI1UFKnwdsAlpAk= #> [cmdletbinding(DefaultParameterSetName = 'PlaceHolder')] param ( [Parameter(Mandatory, ParameterSetName = 'FileSystem')] [Parameter(Mandatory, ParameterSetName = 'GIST')] [mailaddress] $Owner, [Parameter(Mandatory, ParameterSetName = 'FileSystem')] [string] [ValidateScript( { Test-Path $_ })] $XMLPath, [Parameter(Mandatory, ParameterSetName = 'GIST')] [string] $GithubUsername, [Parameter(Mandatory, ParameterSetName = 'GIST')] [string] $GistFilename, [Parameter(ParameterSetName = 'FileSystem')] [Parameter(ParameterSetName = 'GIST')] [ValidateSet('None', 1, 2)] $SecretDuration, [Parameter(Mandatory, ParameterSetName = 'FileSystem')] [Parameter(Mandatory, ParameterSetName = 'GIST')] [string] $Name, [Parameter(ParameterSetName = 'FileSystem')] [Parameter(ParameterSetName = 'GIST')] [Parameter(ParameterSetName = 'ConnectPoshGraph')] [switch] $ExportToConnectPoshGraphDelegated, [Parameter(ParameterSetName = 'FileSystem')] [Parameter(ParameterSetName = 'GIST')] [Parameter(ParameterSetName = 'ConnectPoshGraph')] [switch] $ExportToConnectPoshGraphApplication, [Parameter(Mandatory, ParameterSetName = 'FileSystem')] [Parameter(Mandatory, ParameterSetName = 'GIST')] [switch] $OpenConsentInBrowser ) $AppOwner = Get-AzureADUser -ObjectId $Owner -ErrorAction SilentlyContinue if (-not ($AppOwner)) { Write-Host "Owner $Owner, not found. Halting script" -ForegroundColor Red continue } $ExistingApp = Get-AzureADApplication -filter "DisplayName eq '$Name'" if ($ExistingApp) { Write-Host "Azure AD Application Name: $Name already exists" -ForegroundColor Red Write-Host "Choose a new name with the -Name parameter" -ForegroundColor Cyan continue } if ($PSCmdlet.ParameterSetName -eq 'FileSystem') { $Hash = Import-Clixml $XMLPath } else { try { $Tempfilepath = Join-Path -Path $Env:TEMP -ChildPath ('{0}.xml' -f [guid]::newguid().guid) (Get-GitHubGist -Username $GithubUserName -Filename $GistFilename).content | Set-Content -Path $Tempfilepath -ErrorAction Stop $Hash = Import-Clixml $Tempfilepath } catch { Write-Host "Error importing GIST $($_.Exception.Message)" -ForegroundColor Red continue } finally { Remove-Item -Path $Tempfilepath -Force -Confirm:$false -ErrorAction SilentlyContinue } } $Tenant = Get-AzureADTenantDetail $TargetApp = New-AzureADApplication -DisplayName $Name -ReplyUrls 'https://portal.azure.com/' $Result = [ordered]@{ } $Result['DisplayName'] = $Name $Result['ApplicationId'] = $TargetApp.AppId $Result['TenantId'] = $Tenant.ObjectID $Result['ObjectId'] = $TargetApp.ObjectId $Result['Owner'] = $Owner $RequiredObject = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]::new() $AccessObject = [System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess]]::new() $ResourceList = $Hash['ResourceList'] foreach ($Resource in $ResourceList) { $AccessObject.Add([Microsoft.Open.AzureAD.Model.ResourceAccess]@{ Id = $Resource.Id Type = $Resource.Type }) } $ServicePrincipal = Get-AzureADServicePrincipal -filter ("DisplayName eq '{0}'" -f $Hash['ServicePrincipalName']) $RequiredObject.ResourceAppId = $ServicePrincipal.AppId $RequiredObject.ResourceAccess = $AccessObject Set-AzureADApplication -ObjectId $TargetApp.ObjectId -RequiredResourceAccess $RequiredObject Add-AzureADApplicationOwner -ObjectId $TargetApp.ObjectId -RefObjectId $AppOwner.ObjectId if ($SecretDuration -ne 'None') { $Date = Get-Date $Params = @{ ObjectId = $TargetApp.ObjectId EndDate = $Date.AddYears($SecretDuration) CustomKeyIdentifier = "{0}-{1}" -f $TargetApp.Displayname, $Date.ToString("yyyyMMddTHHmm") } $SecretResult = New-AzureADApplicationPasswordCredential @Params $Result['Secret'] = $SecretResult.value } Write-Host "Grant Admin Consent by logging in as $Owner here:" -ForegroundColor Cyan $ConsentURL = 'https://login.microsoftonline.com/{0}/v2.0/adminconsent?client_id={1}&state=12345&redirect_uri={2}&scope={3}&prompt=admin_consent' -f @( $Tenant.ObjectID, $TargetApp.AppId, 'https://portal.azure.com/', 'https://graph.microsoft.com/.default') Write-Host $ConsentURL -ForegroundColor White [PSCustomObject]$Result if ($ExportToConnectPoshGraphDelegated) { $SaveSplat = @{ Tenant = $Name Secret = $Result['Secret'] ApplicationId = $Result['ApplicationId'] TenantId = $Result['TenantId'] } if ($ExportToConnectPoshGraphDelegated) { $SaveSplat['PromptForDelegatedCredentials'] = $true } Save-GraphConfig @SaveSplat Write-Host "To connect with Graph use: " -ForegroundColor Cyan Write-Host " Connect-PoshGraph -Tenant $Name" -ForegroundColor Green } if ($OpenConsentInBrowser) { Start $ConsentURL } } |