$global:creds; function getExistingApp { Write-Information -MessageData "" -InformationAction Continue Write-Information -MessageData "================================================================================" -InformationAction Continue Write-Information -MessageData "* Either hit enter to list all Azure AD apps in your organisation (potentially *" -InformationAction Continue Write-Information -MessageData "* very slow) or enter the name (or the first few characters of the name) to *" -InformationAction Continue Write-Information -MessageData "* filter the list. *" -InformationAction Continue Write-Information -MessageData "================================================================================" -InformationAction Continue $appFilter = Read-Host -Prompt 'Azure AD App display name filter' if (!$appFilter) { $allApps = az ad app list --all --only-show-errors | ConvertFrom-Json } else { $allApps = az ad app list --filter "startswith(displayName, '$appFilter')" --only-show-errors | ConvertFrom-Json } $data = @() foreach ($item in $allApps) { $row = "" | Select-Object displayName, appId, objectId $row.displayName = $item.displayName $row.appId = $item.appId $row.objectId = $item.objectId $data += $row } $allApps = $data $GridArguments = @{ OutputMode = 'Single' Title = 'Please select an Azure AD Application and click OK' } Write-Information -MessageData "==================== Selecting Application ====================" -InformationAction Continue $selectedApp = $allApps | Out-GridView @GridArguments if (!$selectedApp) { Write-Error -Message "==================== Error: Selecting Application ====================" return } $selectedApp } function createNewApp { do { $appName = Read-Host -Prompt ‘Enter the name for your Azure AD application' } while (!$appName) Write-Information -MessageData "==================== Get my details ====================" -InformationAction Continue $myDetails = az ad signed-in-user show --only-show-errors | ConvertFrom-Json if (!$myDetails) { "==================== Error: Failed to get my details ====================" return } $newGuid = [guid]::NewGuid() Write-Information -MessageData "==================== Create the Azure application ====================" -InformationAction Continue $replyUrls = "$webServiceUrl/auth/openid" if ($webClientUrl) { $replyUrls = $replyUrls + " $webClientUrl/serviceapi/auth/openid" } if($mobileClientUrl) { $replyUrls = $replyUrls + " $webServiceUrl/auth/mobile" } $MyArray = $($replyUrls -split " ") $resourceResponse = Invoke-RestMethod -Uri "https://raw.githubusercontent.com/content-manager-sdk/Community/master/docs/files/101/requiredResourceManifest.json" $resourceResponse | ConvertTo-Json -depth 100 | Out-File $curDir/resman.json $appDetails = az ad app create --oauth2-allow-implicit-flow true --display-name "$appName" ` --identifier-uris "api://$myDomain/$newGuid"` --required-resource-accesses "$curDir/resman.json"` --reply-urls @MyArray --only-show-errors $appObject = $appDetails | ConvertFrom-Json if (!$appObject) { "==================== Error: Failed to create the app ====================" return } Write-Information -MessageData "==================== Set me as the App Owner ====================" -InformationAction Continue az ad app owner add --id $appObject.appId --owner-object-id $myDetails.objectId --only-show-errors Write-Information -MessageData "==================== Set the App Id Uri ====================" -InformationAction Continue $newAppUri = "api://$myDomain/" + $appObject.appId az ad app update --id $appObject.appId --identifier-uris $newAppUri --only-show-errors Write-Information -MessageData "==================== Grant consent ====================" -InformationAction Continue Start-Sleep -Seconds 40 $tryConsent = "" do { try { $tryConsent = "" $consent = az ad app permission admin-consent --only-show-errors --id $appObject.appId } catch { $tryConsent = Read-Host -Prompt "try again? (y/n)" } } while ($tryConsent -eq "y") if ($tryConsent -eq "n") { "==================== Error: Failed to grant consent - please do this manually ====================" } Write-Information -MessageData "==================== Set the client secret ====================" -InformationAction Continue $global:creds = az ad app credential reset --id $appObject.appId --append --only-show-errors | ConvertFrom-Json if (!$global:creds) { return } Write-Information -MessageData "==================== Fetch the existing scopes ====================" -InformationAction Continue az ad app show --id $appObject.appId --query="oauth2Permissions" --only-show-errors > $curDir/scopes.json $scopesObject = Get-Content -Raw -Path $curDir/scopes.json | ConvertFrom-Json $scopesObject[0].isEnabled = $FALSE Write-Information -MessageData "==================== Add the Office and Teams Scopes ====================" -InformationAction Continue $newTeamsGuid = [guid]::NewGuid() $newOfficeGuid = [guid]::NewGuid() $scopesObject += "[{ `"adminConsentDescription`": `"CM Teams Tab`", `"adminConsentDisplayName`": `"CM Teams Tab`", `"id`": `"$newTeamsGuid`", `"isEnabled`": true, `"lang`": null, `"origin`": `"Application`", `"type`": `"User`", `"userConsentDescription`": `"CM Teams Tab`", `"userConsentDisplayName`": `"CM Teams Tab`", `"value`": `"access_as_teams_user`" }]" | ConvertFrom-Json $scopesObject += "[{ `"adminConsentDescription`": `"Office Integration`", `"adminConsentDisplayName`": `"Office Integration`", `"id`": `"$newOfficeGuid`", `"isEnabled`": true, `"lang`": null, `"origin`": `"Application`", `"type`": `"User`", `"userConsentDescription`": null, `"userConsentDisplayName`": null, `"value`": `"access_for_office`" }]" | ConvertFrom-Json $scopesObject | ConvertTo-Json -depth 100 | Out-File $curDir/new_scopes.json $officeGuids = @("08e18876-6177-487e-b8b5-cf950c1e598c", "93d53678-613d-4013-afc1-62e9e444a0a5", "ea5a67f6-b6f3-4338-b240-c655ddc3cc8e", "d3590ed6-52b3-4102-aeff-aad2292ab01c", "bc59ab01-8403-45c6-8796-ac3ef710b3e3", "57fb890c-0dab-4253-a5e0-7188c88b2bb4") $preAuthBody = "{`"api`": {`"preAuthorizedApplications`": []}}" | ConvertFrom-Json Foreach ($g in $officeGuids) { $preAuthBody.api.preAuthorizedApplications += "[{ `"appId`": `"$g`", `"permissionIds`": [ `"$newOfficeGuid`" ] }]" | ConvertFrom-Json } $teamsGuids = @("1fec8e78-bce4-4aaf-ab1b-5451cc387264", "5e3ce6c0-2b1f-4285-8d4b-75ee78787346") Foreach ($t in $teamsGuids) { $preAuthBody.api.preAuthorizedApplications += "[{ `"appId`": `"$t`", `"permissionIds`": [ `"$newTeamsGuid`" ] }]" | ConvertFrom-Json } az ad app update --id $appObject.appId --set oauth2Permissions=@$curDir/new_scopes.json $token_result = az account get-access-token --tenant $tenantId --resource https://graph.microsoft.com | ConvertFrom-Json $preAuthBody = $preAuthBody | ConvertTo-Json -depth 100 -Compress $headers = New-Object 'System.Collections.Generic.Dictionary[String,String]' $headers.Add("Content-Type", "application/json") $headers.Add("Authorization", "Bearer " + $token_result.accessToken) $headers.Add("Accept", "*/*" ) Write-Information -MessageData "==================== Create the authorized client applications ====================" -InformationAction Continue Start-Sleep -Seconds 20 $tryClient = "n" $requrl = "https://graph.microsoft.com/beta/applications/" + $appObject.objectId do { try { $tryClient = "n" $clientSetResponse = Invoke-RestMethod -Uri $requrl -Method PATCH -Body $preAuthBody -Headers $headers } catch { $tryClient = Read-Host -Prompt "The request to add client applications has failed, this can be due to the Azure App not being ready, it is worth trying again, you wish to try again? (y/n)" } } while ($tryClient -eq "y") if($mobileClientUrl) { Write-Information -MessageData "==================== Adding for Mobile client applications ====================" -InformationAction Continue $body = "{`"publicClient`":{`"redirectUris`":[`"trimapp://mobile`"]}}" | ConvertTo-Json az rest --method PATCH --uri $requrl --headers 'Content-Type=application/json' --body $body --only-show-errors } Remove-Item "$curDir/scopes.json" Remove-Item "$curDir/new_scopes.json" Remove-Item "$curDir/resman.json" $appObject } $curDir = Split-Path $script:MyInvocation.MyCommand.Path $login = az login --allow-no-subscriptions --only-show-errors | ConvertFrom-Json if (!$login) { "==================== Error: Login ====================" return } if ($login.Length -gt 1) { $GridArguments = @{ OutputMode = 'Single' Title = 'Please select an Azure AD Tenant and click OK' } "==================== Selecting Tenant ====================" $tenant = $login | Out-GridView @GridArguments if (!$tenant) { "==================== Error: Selecting Tenant ====================" return } } else { $tenant = $login[0] } $tenantId = $tenant.tenantid $subDetails = az account set --subscription $tenantId do { $myDomain = Read-Host -Prompt ‘Enter the domain name for your web server (e.g. intranet.acme.com)' if ($myDomain.StartsWith("http://")) { $myDomain = ""; "The domain must support HTTPS not only HTTP" } if ($myDomain.StartsWith("https://")) { $myDomain = $myDomain.Substring(8) } } while (!$myDomain) $defaultWebServiceUrl = "https://$mydomain/cmserviceapi" $webServiceUrl = Read-Host -Prompt "Enter the ServiceAPI URL [$defaultWebServiceUrl]" if (!$webServiceUrl) { $webServiceUrl = $defaultWebServiceUrl } $webClientUrl = "" $includeWebClient = Read-Host -Prompt "Do you want to link to the Content Manager Web Client from Teams and Office? (y/n)" if ($includeWebClient -eq "y") { $defaultWebClientUrl = "https://$mydomain/contentmanager" $webClientUrl = Read-Host -Prompt "Enter the Web Client URL [$defaultWebClientUrl]" if (!$webClientUrl) { $webClientUrl = $defaultWebClientUrl } } $mobileClientUrl = "" do { $createAppAction = Read-Host -Prompt ‘Either create a new Azure App or use an existing one, do you wish to create a new Azure App (y/n)' } while (!$createAppAction) if ($createAppAction -eq "y" -or $createAppAction -eq "Y") { $includeMobileClient = Read-Host -Prompt "Do you want to include support for the Content Manager Mobile Client? (y/n)" if ($includeMobileClient -eq "y") { $mobileClientUrl = "trimapp://mobile"; } $newAppDetails = createNewApp } else { $newAppDetails = getExistingApp } $newAppDetails = az ad app show --id $newAppDetails.objectId --only-show-errors | ConvertFrom-Json $newAppUri = $newAppDetails.identifierUris[0] $OutlookManifest = Invoke-RestMethod -Uri "https://raw.githubusercontent.com/content-manager-sdk/Community/master/docs/files/101/outlook-addin-manifest-template.xml" [IO.File]::WriteAllLines("$curDir/outlook-addin-manifest.xml", $OutlookManifest.Replace("[MANIFESTGUID]", [guid]::NewGuid()).Replace("[APPCLIENTID]", $newAppDetails.appId).Replace("[APPIDURI]", $newAppUri).Replace("[SERVICEAPIURL]", $webServiceUrl)) $officeDomain = "https://$myDomain" $officeManifestGuid = [guid]::NewGuid() $OfficeManifest = Invoke-RestMethod -Uri "https://raw.githubusercontent.com/content-manager-sdk/Community/master/docs/files/101/office-addin-manifest-template.xml" [xml]$officeManifestXML=$OfficeManifest.OuterXml.Replace("[MANIFESTGUID]", $officeManifestGuid).Replace("[APPCLIENTID]", $newAppDetails.appId).Replace("[APPIDURI]", $newAppUri).Replace("[SERVICEAPIURL]", $webServiceUrl).Replace("[DOMAIN]", $officeDomain) $officeManifestXML.Save("$curDir/office-addin-manifest.xml") $webClientAttr = "" if ($webClientUrl) { $webClientAttr = "`r`n `"websiteUrl`": `"$webClientUrl`"," } $TeamsManifest = Invoke-RestMethod -Uri "https://raw.githubusercontent.com/content-manager-sdk/Community/master/docs/files/101/teams-addin-manifest-template.json" $TeamsManifest.Replace("[WEBSITEURLATTR]", $webClientAttr).Replace("[MANIFESTGUID]", [guid]::NewGuid()).Replace("[APPCLIENTID]", $newAppDetails.appId).Replace("[APPIDURI]", $newAppUri).Replace("[SERVICEAPIURL]", $webServiceUrl).Replace("[DOMAIN]", $myDomain) > "$curDir/manifest.json" Invoke-WebRequest https://raw.githubusercontent.com/content-manager-sdk/Community/aba15c6fe5d3b34af219aba0dd635704fe18f9a6/docs/files/101/color.png -OutFile "$curDir/color.png" Invoke-WebRequest https://raw.githubusercontent.com/content-manager-sdk/Community/aba15c6fe5d3b34af219aba0dd635704fe18f9a6/docs/files/101/outline.png -OutFile "$curDir/outline.png" $teamsZip = "$curDir/content-manager-teams.zip" Compress-Archive -Force -LiteralPath "$curDir/manifest.json" -DestinationPath $teamsZip Compress-Archive -Update -LiteralPath "$curDir/color.png" -DestinationPath $teamsZip Compress-Archive -Update -LiteralPath "$curDir/outline.png" -DestinationPath $teamsZip $appId = $newAppDetails.appId $secret = $global:creds.password $xmlManifest = [xml]$OfficeManifest $version = $xmlManifest.OfficeApp.Version # "==================== Write the sample authentication settings for Web Service ====================" $authFile = "$curDir\authentication.xml" Set-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "`t" Add-Content $authFile "`t`t" Add-Content $authFile "`t" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "" if($mobileClientUrl) { # "==================== Write the sample authentication settings for Mobile Client ====================" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "`t" Add-Content $authFile "`t`t" Add-Content $authFile "`t" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "" } # "==================== Write the sample authentication settings for Web Client ====================" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "`t" Add-Content $authFile "`t`t" Add-Content $authFile "`t" Add-Content $authFile "" Add-Content $authFile "" Add-Content $authFile "" Add-Content "$curDir\authentication.xml" "" Add-Content "$curDir\authentication.xml" "" "==================== Authentication details for ServiceAPI and Web Client written to $authFile ====================" "==================== Teams manifest written to $teamsZip ====================" "==================== Outlook manifest written to $curDir/outlook-addin-manifest.xml ====================" "==================== Office manifest written to $curDir/office.xml ====================" Remove-Item "$curDir/manifest.json" Remove-Item "$curDir/color.png" Remove-Item "$curDir/outline.png"