1
+
2
+ [CmdletBinding ()]
3
+ param (
4
+ [Parameter (Mandatory = $False , HelpMessage = ' Tenant ID (This is a GUID which represents the "Directory ID" of the AzureAD tenant into which you want to create the apps' )]
5
+ [string ] $tenantId ,
6
+ [Parameter (Mandatory = $False , HelpMessage = ' Azure environment to use while running the script. Default = Global' )]
7
+ [string ] $azureEnvironmentName
8
+ )
9
+
10
+ <#
11
+ This script creates the Azure AD applications needed for this sample and updates the configuration files
12
+ for the visual Studio projects from the data in the Azure AD applications.
13
+
14
+ In case you don't have Microsoft.Graph.Applications already installed, the script will automatically install it for the current user
15
+
16
+ There are four ways to run this script. For more information, read the AppCreationScripts.md file in the same folder as this script.
17
+ #>
18
+
19
+ # Adds the requiredAccesses (expressed as a pipe separated string) to the requiredAccess structure
20
+ # The exposed permissions are in the $exposedPermissions collection, and the type of permission (Scope | Role) is
21
+ # described in $permissionType
22
+ Function AddResourcePermission ($requiredAccess , `
23
+ $exposedPermissions , [string ]$requiredAccesses , [string ]$permissionType )
24
+ {
25
+ foreach ($permission in $requiredAccesses.Trim ().Split(" |" ))
26
+ {
27
+ foreach ($exposedPermission in $exposedPermissions )
28
+ {
29
+ if ($exposedPermission.Value -eq $permission )
30
+ {
31
+ $resourceAccess = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphResourceAccess
32
+ $resourceAccess.Type = $permissionType # Scope = Delegated permissions | Role = Application permissions
33
+ $resourceAccess.Id = $exposedPermission.Id # Read directory data
34
+ $requiredAccess.ResourceAccess += $resourceAccess
35
+ }
36
+ }
37
+ }
38
+ }
39
+
40
+ #
41
+ # Example: GetRequiredPermissions "Microsoft Graph" "Graph.Read|User.Read"
42
+ # See also: http://stackoverflow.com/questions/42164581/how-to-configure-a-new-azure-ad-application-through-powershell
43
+ Function GetRequiredPermissions ([string ] $applicationDisplayName , [string ] $requiredDelegatedPermissions , [string ]$requiredApplicationPermissions , $servicePrincipal )
44
+ {
45
+ # If we are passed the service principal we use it directly, otherwise we find it from the display name (which might not be unique)
46
+ if ($servicePrincipal )
47
+ {
48
+ $sp = $servicePrincipal
49
+ }
50
+ else
51
+ {
52
+ $sp = Get-MgServicePrincipal - Filter " DisplayName eq '$applicationDisplayName '"
53
+ }
54
+ $appid = $sp.AppId
55
+ $requiredAccess = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphRequiredResourceAccess
56
+ $requiredAccess.ResourceAppId = $appid
57
+ $requiredAccess.ResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Graph.PowerShell.Models.MicrosoftGraphResourceAccess ]
58
+
59
+ # $sp.Oauth2Permissions | Select Id,AdminConsentDisplayName,Value: To see the list of all the Delegated permissions for the application:
60
+ if ($requiredDelegatedPermissions )
61
+ {
62
+ AddResourcePermission $requiredAccess - exposedPermissions $sp.Oauth2PermissionScopes - requiredAccesses $requiredDelegatedPermissions - permissionType " Scope"
63
+ }
64
+
65
+ # $sp.AppRoles | Select Id,AdminConsentDisplayName,Value: To see the list of all the Application permissions for the application
66
+ if ($requiredApplicationPermissions )
67
+ {
68
+ AddResourcePermission $requiredAccess - exposedPermissions $sp.AppRoles - requiredAccesses $requiredApplicationPermissions - permissionType " Role"
69
+ }
70
+ return $requiredAccess
71
+ }
72
+
73
+
74
+ Function UpdateLine ([string ] $line , [string ] $value )
75
+ {
76
+ $index = $line.IndexOf (' :' )
77
+ $lineEnd = ' '
78
+
79
+ if ($line [$line.Length - 1 ] -eq ' ,' ){ $lineEnd = ' ,' }
80
+
81
+ if ($index -ige 0 )
82
+ {
83
+ $line = $line.Substring (0 , $index + 1 ) + " " + ' "' + $value + ' "' + $lineEnd
84
+ }
85
+ return $line
86
+ }
87
+
88
+ Function UpdateTextFile ([string ] $configFilePath , [System.Collections.HashTable ] $dictionary )
89
+ {
90
+ $lines = Get-Content $configFilePath
91
+ $index = 0
92
+ while ($index -lt $lines.Length )
93
+ {
94
+ $line = $lines [$index ]
95
+ foreach ($key in $dictionary.Keys )
96
+ {
97
+ if ($line.Contains ($key ))
98
+ {
99
+ $lines [$index ] = UpdateLine $line $dictionary [$key ]
100
+ }
101
+ }
102
+ $index ++
103
+ }
104
+
105
+ Set-Content - Path $configFilePath - Value $lines - Force
106
+ }
107
+
108
+
109
+ Function ConfigureApplications
110
+ {
111
+ <# . Description
112
+ This function creates the Azure AD applications for the sample in the provided Azure AD tenant and updates the
113
+ configuration files in the client and service project of the visual studio solution (App.Config and Web.Config)
114
+ so that they are consistent with the Applications parameters
115
+ #>
116
+
117
+ if (! $azureEnvironmentName )
118
+ {
119
+ $azureEnvironmentName = " Global"
120
+ }
121
+
122
+ # Connect to the Microsoft Graph API, non-interactive is not supported for the moment (Oct 2021)
123
+ Write-Host " Connecting to Microsoft Graph"
124
+ if ($tenantId -eq " " ) {
125
+ Connect-MgGraph - Scopes " Application.ReadWrite.All" - Environment $azureEnvironmentName
126
+ $tenantId = (Get-MgContext ).TenantId
127
+ }
128
+ else {
129
+ Connect-MgGraph - TenantId $tenantId - Scopes " Application.ReadWrite.All" - Environment $azureEnvironmentName
130
+ }
131
+
132
+
133
+ # Create the HybridFlowAspNetCore AAD application
134
+ Write-Host " Creating the AAD application (HybridFlowAspNetCore)"
135
+
136
+ # create the application
137
+ $HybridFlowAspNetCoreAadApplication = New-MgApplication - DisplayName " HybridFlowAspNetCore" `
138
+ - Web `
139
+ @ { `
140
+ RedirectUris = " https://localhost:7089/signin-oidc" ; `
141
+ ImplicitGrantSettings = @ { `
142
+ EnableIdTokenIssuance = $true ; `
143
+ } `
144
+ } `
145
+ - Spa `
146
+ @ { `
147
+ RedirectUris = " https://localhost:7089/" ; `
148
+ } `
149
+ - SignInAudience AzureADMyOrg `
150
+ # end of command
151
+ $tenantName = (Get-MgApplication - ApplicationId $HybridFlowAspNetCoreAadApplication.Id ).PublisherDomain
152
+ Update-MgApplication - ApplicationId $HybridFlowAspNetCoreAadApplication.Id - IdentifierUris @ (" https://$tenantName /HybridFlowAspNetCore" )
153
+
154
+ # Generate a certificate
155
+ Write-Host " Creating the HybridFlowAspNetCore application (HybridFlowAspNetCore)"
156
+
157
+ $certificateName = ' HybridFlowAspNetCore'
158
+
159
+ # temporarily disable the option and procees to certificate creation
160
+ # $isOpenSSL = Read-Host ' By default certificate is generated using New-SelfSignedCertificate. Do you want to generate cert using OpenSSL(Y/N)?'
161
+ $isOpenSSl = ' N'
162
+ if ($isOpenSSL -eq ' Y' )
163
+ {
164
+ $certificate = openssl req - x509 - newkey rsa:4096 - sha256 - days 365 - keyout " $certificateName .key" - out " $certificateName .cer" - nodes - batch
165
+ openssl pkcs12 - export - out " $certificateName .pfx" - inkey $certificateName.key -in " $certificateName .cer"
166
+ }
167
+ else
168
+ {
169
+ $certificate = New-SelfSignedCertificate - Subject $certificateName `
170
+ - CertStoreLocation " Cert:\CurrentUser\My" `
171
+ - KeyExportPolicy Exportable `
172
+ - KeySpec Signature
173
+
174
+ $thumbprint = $certificate.Thumbprint
175
+ $certificatePassword = Read-Host - Prompt " Enter password for your certificate (Please remember the password, you will need it when uploading to KeyVault): " - AsSecureString
176
+ Write-Host " Exporting certificate as a PFX file"
177
+ Export-PfxCertificate - Cert " Cert:\Currentuser\My\$thumbprint " - FilePath " $pwd \$certificateName .pfx" - ChainOption EndEntityCertOnly - NoProperties - Password $certificatePassword
178
+ Write-Host " PFX written to:"
179
+ Write-Host " $pwd \$certificateName .pfx"
180
+
181
+ # Add a Azure Key Credentials from the certificate for the application
182
+ $HybridFlowAspNetCoreKeyCredentials = Update-MgApplication - ApplicationId $HybridFlowAspNetCoreAadApplication.Id `
183
+ - KeyCredentials @ (@ {Type = " AsymmetricX509Cert" ; Usage = " Verify" ; Key = $certificate.RawData ; StartDateTime = $certificate.NotBefore ; EndDateTime = $certificate.NotAfter ;})
184
+
185
+ }
186
+
187
+
188
+ # create the service principal of the newly created application
189
+ $currentAppId = $HybridFlowAspNetCoreAadApplication.AppId
190
+ $HybridFlowAspNetCoreServicePrincipal = New-MgServicePrincipal - AppId $currentAppId - Tags {WindowsAzureActiveDirectoryIntegratedApp}
191
+
192
+ # add the user running the script as an app owner if needed
193
+ $owner = Get-MgApplicationOwner - ApplicationId $HybridFlowAspNetCoreAadApplication.Id
194
+ if ($owner -eq $null )
195
+ {
196
+ New-MgApplicationOwnerByRef - ApplicationId $HybridFlowAspNetCoreAadApplication.Id - BodyParameter = @ {" @odata.id" = " htps://graph.microsoft.com/v1.0/directoryObjects/$user .ObjectId" }
197
+ Write-Host " '$ ( $user.UserPrincipalName ) ' added as an application owner to app '$ ( $HybridFlowAspNetCoreServicePrincipal.DisplayName ) '"
198
+ }
199
+ Write-Host " Done creating the HybridFlowAspNetCore application (HybridFlowAspNetCore)"
200
+
201
+ # URL of the AAD application in the Azure portal
202
+ # Future? $HybridFlowAspNetCorePortalUrl = "https://portal.azure.com/#@"+$tenantName+"/blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/"+$HybridFlowAspNetCoreAadApplication.AppId+"/objectId/"+$HybridFlowAspNetCoreAadApplication.Id+"/isMSAApp/"
203
+ $HybridFlowAspNetCorePortalUrl = " https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/CallAnAPI/appId/" + $HybridFlowAspNetCoreAadApplication.AppId + " /objectId/" + $HybridFlowAspNetCoreAadApplication.Id + " /isMSAApp/"
204
+ Add-Content - Value " <tr><td>HybridFlowAspNetCore</td><td>$currentAppId </td><td><a href='$HybridFlowAspNetCorePortalUrl '>HybridFlowAspNetCore</a></td></tr>" - Path createdApps.html
205
+ $requiredResourcesAccess = New-Object System.Collections.Generic.List[Microsoft.Graph.PowerShell.Models.MicrosoftGraphRequiredResourceAccess ]
206
+
207
+
208
+ # Add Required Resources Access (from 'HybridFlowAspNetCore' to 'Microsoft Graph')
209
+ Write-Host " Getting access from 'HybridFlowAspNetCore' to 'Microsoft Graph'"
210
+ $requiredPermissions = GetRequiredPermissions - applicationDisplayName " Microsoft Graph" `
211
+ - requiredDelegatedPermissions " User.Read|Contacts.Read" `
212
+
213
+
214
+ $requiredResourcesAccess.Add ($requiredPermissions )
215
+ Update-MgApplication - ApplicationId $HybridFlowAspNetCoreAadApplication.Id - RequiredResourceAccess $requiredResourcesAccess
216
+ Write-Host " Granted permissions."
217
+
218
+ # Update config file for 'HybridFlowAspNetCore'
219
+ $configFile = $pwd.Path + " \..\appsettings.json"
220
+ $dictionary = @ { };
221
+
222
+ Write-Host " Updating the sample code ($configFile )"
223
+
224
+ UpdateTextFile - configFilePath $configFile - dictionary $dictionary
225
+
226
+ $appSettingsObject = (Get-Content ..\appsettings.json | ConvertFrom-Json )
227
+
228
+ # JSON is auto-generated.
229
+ $appSettingsObject.AzureAd = ConvertFrom-Json ' {"Instance":"https://login.microsoftonline.com/","Domain":"Auto","TenantId":"Auto","ClientId":"Auto","CallbackPath":"/signin-oidc","WithSpaAuthCode":true,"ClientCertificates":[{"SourceType":"StoreWithDistinguishedName","CertificateStorePath":"CurrentUser/My","CertificateDistinguishedName":"CN=HybridFlowAspNetCore"}]}' ;
230
+
231
+ $appSettingsObject.AzureAd.TenantId = $tenantId ;
232
+ $appSettingsObject.AzureAd.ClientId = $currentAppId ;
233
+ $appSettingsObject.AzureAd.Domain = $tenantName ;
234
+
235
+ # JSON is auto-generated.
236
+ $appSettingsObject.DownStreamApi = ConvertFrom-Json ' {"BaseUrl":"https://graph.microsoft.com/v1.0","Scopes":"User.Read Contacts.Read"}' ;
237
+
238
+ Write-Host " Updating the appsetings.json file at '..\appsettings.json'"
239
+ $appSettingsObject | ConvertTo-Json - Depth 3 | Out-File ..\appsettings.json
240
+
241
+ if ($isOpenSSL -eq ' Y' )
242
+ {
243
+ Write-Host - ForegroundColor Green " ------------------------------------------------------------------------------------------------"
244
+ Write-Host " You have generated certificate using OpenSSL so follow below steps: "
245
+ Write-Host " Install the certificate on your system from current folder."
246
+ Write-Host - ForegroundColor Green " ------------------------------------------------------------------------------------------------"
247
+ }
248
+ Add-Content - Value " </tbody></table></body></html>" - Path createdApps.html
249
+ }
250
+
251
+ # Pre-requisites
252
+ if ($null -eq (Get-Module - ListAvailable - Name " Microsoft.Graph.Applications" )) {
253
+ Install-Module " Microsoft.Graph.Applications" - Scope CurrentUser
254
+ }
255
+
256
+ Import-Module Microsoft.Graph.Applications
257
+
258
+ Set-Content - Value " <html><body><table>" - Path createdApps.html
259
+ Add-Content - Value " <thead><tr><th>Application</th><th>AppId</th><th>Url in the Azure portal</th></tr></thead><tbody>" - Path createdApps.html
260
+
261
+ $ErrorActionPreference = " Stop"
262
+
263
+ # Run interactively (will ask you for the tenant ID)
264
+ ConfigureApplications - tenantId $tenantId - environment $azureEnvironmentName
265
+
266
+ Write-Host " Disconnecting from tenant"
267
+ Disconnect-MgGraph
0 commit comments