-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathUse-AzureAD.psm1
3154 lines (2886 loc) · 150 KB
/
Use-AzureAD.psm1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#
## Created by: lucas.cueff[at]lucas-cueff.com
#
## released on 09/2021
#
# v0.5 - first public release - beta version - cmdlets to manage your Azure Active Directory Tenant (focusing on Administrative Unit features) when AzureADPreview cannot handle it correctly ;-)
# Note : currently Powershell Core and AzureADPreview are not working well together (logon / token request issue) : https://github.com/PowerShell/PowerShell/issues/10473 ==> this module will work only with Windows Powershell 5.1
# - cmdlet to get a valid access token (MFA supported) for Microsoft Graph Beta APIs
# - cmdlet to get a valid token for Microsoft Graph API standard / cloud endpoint (ressource graph.windows.net) and be able to use AzureADPreview cmdlets without reauthenticating
# - cmdlet to get all properties available (ex : extensionattribute) for an AAD user account
# - cmdlet to set a web proxy to be used with Use-AzureAD and AzureADPreview cmdlets
# - cmdlet to get all info for current logged in (@ Azure AD Tenant and Graph APIs) AAD user account
# - cmdlet to create / synchronize your on premise Active Directory OUs with Azure AD Administrive Units (not managed currently through Azure AD Connect or other Microsoft cmdlets / modules)
# - cmdlet to add / synchronize your on premise Active Directory users DN with Azure AD Administrative Unit membership (not managed currently through Azure AD Connect or other Microsoft cmdlets / modules)
# - cmdlet to add / remove Azure AD user account in Administrative Unit Role (everything managed in an easy and smooth way including, enabling the AAD role if missing and so on)
# - cmdlet to list all members of an Azure AD Administrative Unit (limited @ first 100 objets with default MS cmdlet... #WTF)
# v0.6 - beta version - focus on Azure AD Connect Cloud Provisionning Tools
# - cmdlet to get your current schema for a specific provisionning agent / service principal
# - cmdlet to update your current schema for a specific provisionning agent / service principal
# - cmdlet to get your default schema (template) for Azure AD Connect Cloud Provisionning
# - cmdlet to get a valid token (MFA supported) for Microsoft Graph API standard / cloud endpoint and MSOnline endpoint and be able to use MSOnline cmdlets without reauthenticating
# v0.7 - beta version - update Administrative Unit features (missing features from Microsoft Cmdlets and new API features)
# - cmdlet to create an Administrative Unit with hidden members
# - cmdlet to get Administrative Units with hidden members
# - cmdlet to create delta view for users, groups, admin units objects
# - cmdlet to get all updates from a delta view for users, groups, admin units objects
# v0.8 - beta version - fix azuread proxy bug when using SSO, add cmdlets to manage Azure AD Dynamic Security Groups
# - fix Set-AzureADproxy cmdlet : not able to set correctly the parameter *ProxyUseDefaultCredentials*
# - new cmdlets to add, get, update Azure AD Dynamic Membership security groups
# - cmdlet to test Dynamic membership for users
# Note : in current release of AzureADPreview I have found a bug regarding Dynamic group (all *-AzureADMSGroup cmdlets). When you try to use them, you have a Null Reference Exception :
# System.NullReferenceException,Microsoft.Open.MSGraphBeta.PowerShell.NewMSGroup
# v0.9 - beta version - add functions / cmdlets related to group and licensing stuff
# - cmdlet to get all Azure AD User with licensing error members of a particular group
# - cmdlet to get licensing info of a particular group
# - cmdlet to add or remove a license on an Azure AD Group
# - cmdlet to get licensing assignment type (group or user) of a particular user
# v1.0 - beta version - add service principal management for authentication and fix / improve code using DaveyRance remark : https://github.com/DaveyRance
# v1.1 - beta version - update authority URL for Service Principal to be compliant with last version of ADAL library
# v1.2 - beta version - add several functions to be able to manage OU to Admin unit sync in a service principal security context with delegated rights on API (must use MS Graph API only instead of mixing Azure AD Graph and MS Graph APIs) :
# - update Sync-ADOUtoAzureADAdministrativeUnit
# - update cmdlet Sync-ADUsertoAzureADAdministrativeUnitMember
# - update cmdlet Get-AzureADUserCustom (Get-AzureADUserallproperties)
# - add cmdlet Get-AzureADServicePrincipalCustom
# - add cmdlet Get-AzureADAdministrativeUnitCustom
# - add cmdlet Add-AzureADAdministrativeUnitMemberCustom
# - add cmdlet New-AzureADAdministrativeUnitCustom (New-AzureADAdministrativeUnitHidden)
# - add cmdlet Watch-AzureADAccessToken (be able to watch and auto renew Access Token of a service principal before expiration - useful in a script context when operation can take more than one hour)
# - update cmdlet Set-AzureADProxy (add bypassproxy on local option)
# v1.3 - beta version - add function to get administrative units of a user account and remove a user account from an administrative unit
# - Get-AzureADUserAdministrativeUnitMemberOfCustom
# - Remove-AzureADAdministrativeUnitMemberCustom
# v1.4 - beta version - add functions to get and update organization information
# - Get-AzureADOrganizationCustom
# - Update-AzureADOrganizationCustom
# v1.5.1 - beta version - add function to get Azure AD Connect synchronization errors through MS Graph API to replace Get-MsolDirSyncProvisioningError
# - Get-AzureADOnPremisesProvisionningErrors
# v1.6 - beta version - fix CallDepthOverflow on huge pages response
#
# v1.7 - last public version - beta version - add functions to create / update Office 365 groups with resourceBehaviorOptions and resourceProvisioningOptions : https://docs.microsoft.com/en-us/graph/group-set-options
# - New-AzureADMSGroupCustom
# - Set-AzureADMSGroupCustom
#
#'(c) 2021 lucas-cueff.com - Distributed under Artistic Licence 2.0 (https://opensource.org/licenses/artistic-license-2.0).'
<#
.SYNOPSIS
cmdlets to use several APIs of Microsoft Graph Beta web service (mainly users,me,AdministrativeUnit)
extend AzureADPreview capabilities in Azure AD Administrative Unit management
.DESCRIPTION
use-AzureAD.psm1 module provides easy to use cmdlets to manage your Azure AD tenant with a focus on Administrative Unit objects.
.EXAMPLE
C:\PS> import-module use-AzureAD.psm1
#>
Function Watch-AzureADAccessToken {
<#
.SYNOPSIS
Follow an Azure Access Token requested for a service principal and auto renew it before expiration
.DESCRIPTION
Follow an Azure Access Token requested for a service principal and auto renew it before expiration
.PARAMETER StartAutoRenewal
-StartAutoRenewal switch
Start autorenewal for an existing Azure AD Access Token (must be requested first with Get-AzureADAccessToken)
limited use with service principal only for security purpose
.PARAMETER StopAutoRenewal
-StopAutoRenewal switch
stop autorenewal for an existing Azure AD Access Token
.OUTPUTS
none
.EXAMPLE
Start to watch Azure AD Access Token requested for Service Principal 38846352-a67c-4a9a-a94c-c115be1fc52f and auto renew it before expiration
C:\PS> Get-AzureADAccessToken -ServicePrincipalCertThumbprint E22EE5AE84909C49D4BF66C12BF88B2D0A53CDC2 -ServicePrincipalApplicationID 38846352-a67c-4a9a-a94c-c115be1fc52f -ServicePrincipalTenantDomain mydomain.tld
C:\PS> Watch-AzureADAccessToken -StartAutoRenewal
.EXAMPLE
Stop autorenewal of Azure AD Access Token for Service Principal 38846352-a67c-4a9a-a94c-c115be1fc52f
C:\PS> Watch-AzureADAccessToken -StopAutoRenewal
#>
[cmdletbinding()]
Param (
[parameter(Mandatory=$false)]
[switch]$StartAutoRenewal,
[parameter(Mandatory=$false)]
[switch]$StopAutoRenewal
)
process {
if ($StartAutoRenewal.IsPresent) {
Test-AzureADAccessTokenExpiration | out-null
if (!($global:AADConnectInfo.ServicePrincipalName)) {
throw "please request an Access token with a Service Principal to use this function - exit"
}
if (!($global:AADConnectInfo.TokenWatch)) {
$global:AADRunSpaceTool = [hashtable]::Synchronized(@{})
$global:AADRunSpaceTool.add('Host',$Host)
if ($VerbosePreference) {
$global:AADRunSpaceTool.add('Verbose',$true)
}
$global:AADConnectInfo.add('TokenWatch',$true)
$global:AADRunspace = [runspacefactory]::CreateRunspace()
$global:AADRunspace.Open()
$global:AADRunspace.SessionStateProxy.SetVariable('AADConnectInfo',$AADConnectInfo)
$global:AADRunspace.SessionStateProxy.SetVariable('AADRunSpaceTool',$AADRunSpaceTool)
$global:AADPwsh = [powershell]::Create()
$global:AADPwsh.Runspace = $global:AADRunspace
$scriptblock = {
import-module Use-AzureAD -force
while ($AADConnectInfo.TokenWatch) {
if (Test-AzureADAccessTokenExpiration) {
if ($AADRunSpaceTool.verbose) {
$AADRunSpaceTool.host.ui.WriteVerboseLine("expired token found")
}
if ($AADConnectInfo.ServicePrincipalName) {
Clear-AzureADAccessToken -ServicePrincipalTenantDomain $AADConnectInfo.TenantName
Get-AzureADAccessToken -ServicePrincipalCertThumbprint $AADConnectInfo.ServicePrincipalCertificate -ServicePrincipalApplicationID $AADConnectInfo.ServicePrincipalName -ServicePrincipalTenantDomain $AADConnectInfo.TenantName
if ($AADRunSpaceTool.verbose) {
$AADRunSpaceTool.host.ui.WriteVerboseLine($AADConnectInfo.AccessToken)
}
}
}
start-sleep -Seconds 300
if ($AADRunSpaceTool.verbose) {
$AADRunSpaceTool.host.ui.WriteVerboseLine("token not expired")
}
}
}
$global:AADPwsh.AddScript($scriptblock) | Out-Null
$global:AADTokenWatch = $global:AADPwsh.BeginInvoke()
} else {
write-warning -Message "Azure AD Access token already monitored"
}
}
if ($StopAutoRenewal.IsPresent) {
if ($global:AADTokenWatch -and $global:AADConnectInfo.TokenWatch) {
$global:AADConnectInfo.TokenWatch = $false
$global:AADPwsh.EndInvoke($global:AADTokenWatch)
$global:AADRunspace.close()
$global:AADPwsh.Dispose()
$global:AADConnectInfo.remove('TokenWatch')
$global:AADConnectInfo.remove('host')
Remove-Variable -Name AADTokenWatch -Force -Scope Global
Remove-Variable -Name AADPwsh -Force -Scope Global
Remove-Variable -Name AADRunspace -Force -Scope Global
Remove-Variable -Name AADRunSpaceTool -Force -Scope Global
}
}
}
}
Function Get-AzureADAccessToken {
<#
.SYNOPSIS
Get a valid Access Token / Refresh Token for MS Graph APIs and MS Graph APIs Beta
.DESCRIPTION
Get a valid Access Token / Refresh Token for MS Graph APIs and MS Graph APIs Beta, using ADAL library, all authentication supported including MFA. Tenant ID automatically resolved.
.PARAMETER adminUPN
-adminUPN System.Net.Mail.MailAddress
UserPrincipalName of an Azure AD account with rights on Directory (for instance a user with Global Admin right)
.PARAMETER ServicePrincipalCertThumbprint
-ServicePrincipalCertThumbprint string
certificate thumbprint of the certificate to load (local machine certificate only)
.PARAMETER ServicePrincipalApplicationID
-ServicePrincipalApplicationID GUID
guid of the application using the service principal
.PARAMETER ServicePrincipalTenantDomain
-ServicePrincipalTenantDomain string
domain name / tenant name
.OUTPUTS
TypeName : System.Collections.Hashtable+SyncHashtable
.EXAMPLE
Get an access token for my admin account (my-admin@mydomain.tld)
C:\PS> Get-AzureADAccessToken -adminUPN my-admin@mydomain.tld
.EXAMPLE
Get an access token for service principal with application ID 38846352-a67c-4a9a-a94c-c115be1fc52f and a certificate thumbprint of E22EE5AE84909C49D4BF66C12BF88B2D0A53CDC2
C:\PS> Get-AzureADAccessToken -ServicePrincipalCertThumbprint E22EE5AE84909C49D4BF66C12BF88B2D0A53CDC2 -ServicePrincipalApplicationID 38846352-a67c-4a9a-a94c-c115be1fc52f -ServicePrincipalTenantDomain mydomain.tld
#>
[cmdletbinding()]
Param (
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[System.Net.Mail.MailAddress]$adminUPN,
[parameter(Mandatory=$false)]
[ValidateScript({test-path "Cert:\LocalMachine\My\$_"})]
[string]$ServicePrincipalCertThumbprint,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[guid]$ServicePrincipalApplicationID,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]$ServicePrincipalTenantDomain
)
Process {
if ($ServicePrincipalCertThumbprint -and (!($ServicePrincipalApplicationID) -or !($ServicePrincipalTenantDomain))) {
throw "please use ServicePrincipalApplicationID with ServicePrincipalCertThumbprint and ServicePrincipalTenantDomain"
}
if ($ServicePrincipalApplicationID -and (!($ServicePrincipalCertThumbprint) -or !($ServicePrincipalTenantDomain))) {
throw "please use ServicePrincipalApplicationID with ServicePrincipalCertThumbprint and ServicePrincipalTenantDomain"
}
$AadModule = Test-ADModule -AzureAD
$adallib = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
[System.Reflection.Assembly]::LoadFrom($adallib) | Out-Null
if ($adminUPN) {
$clientId = "1b730954-1685-4b74-9bfd-dac224a7b894"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$($adminUPN.Host)"
try {
$adalformslib = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
[System.Reflection.Assembly]::LoadFrom($adalformslib) | Out-Null
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto"
$userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($adminUPN.Address, "OptionalDisplayableId")
$authResult = $authContext.AcquireTokenAsync($resourceURI, $ClientId, $redirectUri, $platformParameters, $userId)
} catch {
Write-Error -Message "$($_.Exception.Message)"
throw "Not able to log you on your Azure AD Tenant using user principal name provided - exiting"
}
if ($authResult.result) {
if (!($global:AADConnectInfo)) {
$global:AADConnectInfo = [hashtable]::Synchronized(@{})
$global:AADConnectInfo.add('UserName',$adminUPN)
$global:AADConnectInfo.add('AccessToken',$authResult.result.AccessToken)
$global:AADConnectInfo.add('TokenExpiresOn',$authResult.result.ExpiresOn)
$global:AADConnectInfo.add('ObjectID',(Get-AzureADMyInfo).id)
$global:AADConnectInfo.add('TenantID',(Get-AzureADTenantInfo -adminUPN $adminUPN).TenantID)
$global:AADConnectInfo.add('TenantName',$adminUPN.Host)
} else {
$global:AADConnectInfo.UserName = $adminUPN
$global:AADConnectInfo.AccessToken = $authResult.result.AccessToken
$global:AADConnectInfo.TokenExpiresOn = $authResult.result.ExpiresOn
$global:AADConnectInfo.ObjectID = (Get-AzureADMyInfo).id
$global:AADConnectInfo.TenantID = (Get-AzureADTenantInfo -adminUPN $adminUPN).TenantID
$global:AADConnectInfo.TenantName = $adminUPN.Host
if ($global:AADConnectInfo.ServicePrincipalCertificate) {
$global:AADConnectInfo.remove('ServicePrincipalCertificate')
}
if ($global:AADConnectInfo.ServicePrincipalName) {
$global:AADConnectInfo.remove('ServicePrincipalName')
}
}
} else {
$authResult
throw "Authorization Access Token is null, please re-run authentication - exiting"
}
}
if ($ServicePrincipalCertThumbprint -and $ServicePrincipalApplicationID -and $ServicePrincipalTenantDomain) {
$CertStore = "Cert:\LocalMachine\My"
$CertStorePath = Join-Path $CertStore $ServicePrincipalCertThumbprint
$Certificate = Get-Item $CertStorePath
if (!$Certificate) {
throw "not able to get certificate with $ServicePrincipalCertThumbprint thumbprint in local machine cert store - exiting"
}
$tenantinfo = Get-AzureADTenantInfo -ServicePrincipalTenantDomain $ServicePrincipalTenantDomain
$resourceURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$($tenantinfo.TenantID)"
try {
$ClientCert = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate" -ArgumentList ($ServicePrincipalApplicationID.guid, $Certificate)
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireTokenAsync($resourceURI, $ClientCert)
} catch {
Write-Error -Message "$($_.Exception.Message)"
throw "Not able to log you on your Azure AD Tenant using Service Principal information provided - exiting"
}
if ($authResult.result) {
if (!($global:AADConnectInfo)) {
$global:AADConnectInfo = [hashtable]::Synchronized(@{})
$global:AADConnectInfo.add('ServicePrincipalName',$ServicePrincipalApplicationID)
$global:AADConnectInfo.add('ServicePrincipalCertificate',$ServicePrincipalCertThumbprint)
$global:AADConnectInfo.add('AccessToken',$authResult.result.AccessToken)
$global:AADConnectInfo.add('TokenExpiresOn',$authResult.result.ExpiresOn)
$global:AADConnectInfo.add('ObjectID',(Get-AzureADServicePrincipalCustom -Filter "appid eq '$($ServicePrincipalApplicationID)'").id)
$global:AADConnectInfo.add('TenantID',$tenantinfo.TenantID)
$global:AADConnectInfo.add('TenantName',$ServicePrincipalTenantDomain)
} else {
$global:AADConnectInfo.ServicePrincipalName = $ServicePrincipalApplicationID
$global:AADConnectInfo.ServicePrincipalCertificate = $ServicePrincipalCertThumbprint
$global:AADConnectInfo.AccessToken = $authResult.result.AccessToken
$global:AADConnectInfo.TokenExpiresOn = $authResult.result.ExpiresOn
$global:AADConnectInfo.ObjectID = (Get-AzureADServicePrincipalCustom -Filter "appid eq '$($ServicePrincipalApplicationID)'").id
$global:AADConnectInfo.TenantID = $tenantinfo.TenantID
$global:AADConnectInfo.TenantName = $ServicePrincipalTenantDomain
if ($global:AADConnectInfo.UserName) {
$global:AADConnectInfo.remove('UserName')
}
}
} else {
$authResult
throw "Authorization Access Token is null, please re-run authentication - exiting"
}
}
$global:AADConnectInfo
}
}
Function Get-AzureADMyInfo {
<#
.SYNOPSIS
Get all Azure AD account properties of current logged in user
.DESCRIPTION
Get all Azure AD account properties of current logged in user. Note : including hidden properties like extensionattribute.
.OUTPUTS
TypeName : System.Management.Automation.PSCustomObject
.EXAMPLE
Get all user account properties of my current account (my-admin@mydomain.tld)
C:\PS> Get-AzureADMyInfo
#>
[cmdletbinding()]
Param ()
process {
Test-AzureADAccessTokenExpiration | out-null
Invoke-APIMSGraphBeta -API "me" -Method "GET"
}
}
Function Get-AzureADTenantInfo {
<#
.SYNOPSIS
Get a valid Access Tokem / Refresh Token for MS Graph APIs and MS Graph APIs Beta
.DESCRIPTION
Get a valid Access Tokem / Refresh Token for MS Graph APIs and MS Graph APIs Beta, using ADAL library, all authentication supported including MFA. Tenant ID automatically resolved.
.PARAMETER adminUPN
-adminUPN System.Net.Mail.MailAddress
UserPrincipalName of an Azure AD account with rights on Directory (for instance a user with Global Admin right)
.PARAMETER ServicePrincipalTenantDomain
-ServicePrincipalTenantDomain string
Tenant domain name of your Service Principal account
.OUTPUTS
TypeName : System.Management.Automation.PSCustomObject
.EXAMPLE
Get tenant info from my useraccount (my-admin@mydomain.tld)
C:\PS> Get-AzureADTenantInfo -adminUPN my-admin@mydomain.tld
.EXAMPLE
Get tenant info from my service principal tenant domain name (mydomain.tld)
C:\PS> Get-AzureADTenantInfo -ServicePrincipalTenantDomain mydomain.tld
#>
[cmdletbinding()]
Param (
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[System.Net.Mail.MailAddress]$adminUPN,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]$ServicePrincipalTenantDomain
)
process {
if ($adminUPN) {
$url = "https://login.microsoftonline.com/$($adminUPN.Host)/.well-known/openid-configuration"
write-verbose -Message "GET method to $($url)"
}
if ($ServicePrincipalTenantDomain) {
$url = "https://login.microsoftonline.com/$($ServicePrincipalTenantDomain)/.well-known/openid-configuration"
write-verbose -Message "GET method to $($url)"
}
Try {
$tmpobj = (Invoke-WebRequest $url).content | ConvertFrom-Json
} catch {
$tmpobj = $_ | ConvertFrom-Json
}
if ($tmpobj.issuer) {
$tmpobj | Add-Member -MemberType NoteProperty -Name 'TenantID' -Value ([uri]$tmpobj.issuer).AbsolutePath.Replace("/","")
}
$tmpobj
}
}
Function Connect-AzureADFromAccessToken {
<#
.SYNOPSIS
Connect to your Azure AD Tenant / classic MS Graph endpoint used by AzureADPreview module using an existing Access token requested with Get-AzureADAccessToken
.DESCRIPTION
Connect to your Azure AD Tenant / classic MS Graph endpoint used by AzureADPreview module using an existing Access token requested with Get-AzureADAccessToken
.OUTPUTS
TypeName : Microsoft.Open.Azure.AD.CommonLibrary.PSAzureContext
.EXAMPLE
Connect to your Azure AD Tenant / classic MS Graph endpoint used by AzureADPreview module using an existing Access token requested with Get-AzureADAccessToken
C:\PS> Connect-AzureADFromAccessToken
#>
[cmdletbinding()]
Param ()
Test-AzureADAccessTokenExpiration | out-null
$AadModule = Test-ADModule -AzureAD
if ($global:AADConnectInfo.AccessToken) {
if ($global:AADConnectInfo.UserName) {
$resourceURI = "https://graph.windows.net"
$clientId = "1b730954-1685-4b74-9bfd-dac224a7b894"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$authority = "https://login.microsoftonline.com/$(($global:AADConnectInfo.UserName).host)"
try {
$adallib = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalformslib = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
[System.Reflection.Assembly]::LoadFrom($adallib) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalformslib) | Out-Null
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto"
$userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($global:AADConnectInfo.UserName, "OptionalDisplayableId")
$authResult = $authContext.AcquireTokenAsync($resourceURI, $ClientId, $redirectUri, $platformParameters, $userId)
} catch {
Write-Error -Message "$($_.Exception.Message)"
throw "Not Able to log you on your Azure AD Tenant - exiting"
}
connect-azuread -tenantid $global:AADConnectInfo.TenantID -AadAccessToken $authResult.result.AccessToken -MsAccessToken $global:AADConnectInfo.AccessToken -AccountId $global:AADConnectInfo.ObjectID
}
if ($global:AADConnectInfo.ServicePrincipalName) {
$CertStore = "Cert:\LocalMachine\My"
$CertStorePath = Join-Path $CertStore $global:AADConnectInfo.ServicePrincipalCertificate
$Certificate = Get-Item $CertStorePath
if (!$Certificate) {
throw "not able to get certificate with $ServicePrincipalCertThumbprint thumbprint in local machine cert store - exiting"
}
connect-azuread -tenantid $global:AADConnectInfo.TenantID -ApplicationId $global:AADConnectInfo.ServicePrincipalName -CertificateThumbprint $global:AADConnectInfo.ServicePrincipalCertificate
}
} else {
throw "No valid Access Token found - exiting"
}
}
Function Connect-MSOnlineFromAccessToken {
<#
.SYNOPSIS
Connect to your Azure AD Tenant / classic MS Graph endpoint used by MSOnline module using an existing Access token requested with Get-AzureADAccessToken
.DESCRIPTION
Connect to your Azure AD Tenant / classic MS Graph endpoint used by MSOnline module using an existing Access token requested with Get-AzureADAccessToken
.OUTPUTS
None
.EXAMPLE
Connect to your Azure AD Tenant / classic MS Graph endpoint used by MSOnline module using an existing Access token requested with Get-AzureADAccessToken
C:\PS> Connect-MSOnlineFromAccessToken
#>
[cmdletbinding()]
Param ()
Test-AzureADAccessTokenExpiration | out-null
Test-ADModule -MSOnline | out-null
$AadModule = Test-ADModule -AzureAD
if ($global:AADConnectInfo.AccessToken) {
if ($global:AADConnectInfo.UserName) {
$resourceURI = "https://graph.windows.net"
$clientId = "1b730954-1685-4b74-9bfd-dac224a7b894"
$redirectUri = new-object System.Uri("http://localhost/")
$authority = "https://login.microsoftonline.com/$(($global:AADConnectInfo.UserName).host)"
try {
$adallib = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalformslib = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
[System.Reflection.Assembly]::LoadFrom($adallib) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalformslib) | Out-Null
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto"
$userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($global:AADConnectInfo.UserName, "OptionalDisplayableId")
$authResult = $authContext.AcquireTokenAsync($resourceURI, $ClientId, $redirectUri, $platformParameters, $userId)
} catch {
Write-Error -Message "$($_.Exception.Message)"
throw "Not Able to log you on your Azure AD Tenant - exiting"
}
Connect-MsolService -AccessToken $authResult.result.AccessToken
}
if ($global:AADConnectInfo.ServicePrincipalName) {
Write-Warning -message "Service Principals are not supported for passthrough token to MSOnline."
}
} else {
throw "No valid Access Token found - exiting"
}
}
Function Set-AzureADProxy {
<#
.SYNOPSIS
Set a web proxy to connect to Azure AD graph API
.DESCRIPTION
Set / remove a proxy to connect to your Azure AD environment using AzureADPreview module or this module. Can handle anonymous proxy or authenticating proxy.
.PARAMETER DirectNoProxy
-DirectNoProxy Swith
Remove proxy set, set to "direct" connection
.PARAMETER Proxy
-Proxy uri
Set the proxy settings to URI provided. Must be provided as a valid URI like http://proxy:port
.PARAMETER ProxyCredential
-ProxyCredential Management.Automation.PSCredential
must be use with Proxy parameter
Set the credential to be used with the proxy to set. Must be provided as a valid PSCredential object (can be generated with Get-Credential)
.PARAMETER ProxyUseDefaultCredentials
-ProxyUseDefaultCredentials Swith
must be use with Proxy parameter
Set the credential to be used with the proxy to set. this switch will tell the system to use the current logged in credential to be authenticated with the proxy service.
.OUTPUTS
TypeName : System.Net.WebProxy
.EXAMPLE
Remove Proxy
C:\PS> Set-AzureADProxy -DirectNoProxy
.EXAMPLE
Set a local anonymous proxy 127.0.0.1:8888
C:\PS> Set-AzureADProxy -Proxy "http://127.0.0.1:8888"
.EXAMPLE
Set a local anonymous proxy 127.0.0.1:8888 and request local traffic to not be sent to proxy
C:\PS> Set-AzureADProxy -Proxy "http://127.0.0.1:8888" -BypassProxyOnLocal
#>
[cmdletbinding()]
Param (
[Parameter(Mandatory=$false)]
[switch]$DirectNoProxy,
[Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
[uri]$Proxy,
[Parameter(Mandatory=$false)]
[Management.Automation.PSCredential]$ProxyCredential,
[Parameter(Mandatory=$false)]
[Switch]$ProxyUseDefaultCredentials,
[Parameter(Mandatory=$false)]
[switch]$BypassProxyOnLocal
)
process {
if ($DirectNoProxy.IsPresent){
[System.Net.WebRequest]::DefaultWebProxy = $null
} ElseIf ($Proxy) {
$proxyobj = New-Object System.Net.WebProxy $proxy.AbsoluteUri
if ($ProxyCredential){
$proxyobj.Credentials = $ProxyCredential
} Elseif ($ProxyUseDefaultCredentials.IsPresent){
$proxyobj.UseDefaultCredentials = $true
}
if ($BypassProxyOnLocal.IsPresent) {
$proxyobj.BypassProxyOnLocal = $true
}
[System.Net.WebRequest]::DefaultWebProxy = $proxyobj
$proxyobj
}
}
}
Function Clear-AzureADAccessToken {
<#
.SYNOPSIS
Clear an existing MS Graph APIs and MS Graph APIs Beta Access Token
.DESCRIPTION
Clear an existing MS Graph APIs and MS Graph APIs Beta Access Token. Required to be already authenticated.
.PARAMETER adminUPN
-adminUPN System.Net.Mail.MailAddress
UserPrincipalName of the Azure AD account currently logged in that you want the access token to be removed
.PARAMETER ServicePrincipalTenantDomain
-ServicePrincipalTenantDomain string
domain name / tenant name
.OUTPUTS
None
.EXAMPLE
clear an access token for my admin account (my-admin@mydomain.tld)
C:\PS> Clear-AzureADAccessToken -adminUPN my-admin@mydomain.tld
.EXAMPLE
clear an access token for a service principal from mydomain.tld
C:\PS> Clear-AzureADAccessToken -ServicePrincipalTenantDomain mydomain.tld
#>
[cmdletbinding()]
Param (
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[System.Net.Mail.MailAddress]$adminUPN,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]$ServicePrincipalTenantDomain
)
if ($adminUPN) {
$authority = "https://login.microsoftonline.com/$($adminUPN.Host)"
}
if ($ServicePrincipalTenantDomain) {
$authority = "https://login.microsoftonline.com/$($ServicePrincipalTenantDomain)"
}
if (!($adminUPN) -and !($ServicePrincipalTenantDomain)) {
throw "please use ServicePrincipalTenantDomain or adminUPN parameter"
}
Test-ADModule -AzureAD | Out-Null
try {
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authContext.TokenCache.Clear()
} catch {
throw "Not Able to clear your current tokens and disconnect your session - exiting"
}
}
Function Sync-ADOUtoAzureADAdministrativeUnit {
<#
.SYNOPSIS
Create new Azure AD Administrative Unit based on on premise AD Organizational Unit
.DESCRIPTION
Create new Azure AD Administrative Unit based on on premise AD Organizational Unit. Can be used to synchronize all existing on prem AD root OU with new cloud Admin unit.
.PARAMETER AllOUs
-AllOUs Switch
Synchronize all existing OU to new cloud Admin Unit (except default OU like Domain Controllers)
.PARAMETER OUsFilterName
-OUsFilterName string
must be used with AllOUs parameter
Set a regex filter to synchronize only OU based on a specific pattern.
.PARAMETER SearchBase
-SearchBase string
must be used with AllOUs parameter
set the default search base for OU (DN format)
.PARAMETER OUsDN
-OUsDN string / array of string
must not be used with AllOUs parameter. you must choose between these 2 parameters.
string must be a LDAP Distinguished Name. For instance : "OU=TP-VB,DC=domain,DC=xyz"
.OUTPUTS
TypeName : System.Management.Automation.PSCustomObject
.EXAMPLE
Create new cloud Azure AD administrative Unit for each on prem' OU found with a pattern like "AB-CD"
The verbose option can be used to write basic message on console (for instance when an admin unit already existing)
C:\PS> Sync-ADOUtoAzureADAdministrativeUnit -AllOUs -OUsFilterName "^([a-zA-Z]{2})(-)([a-zA-Z]{2})$" -SearchBase "DC=domain,DC=xyz" -Verbose
#>
[cmdletbinding()]
Param (
[parameter(Mandatory=$false)]
[switch]$AllOUs,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]$OUsFilterName,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string[]]$OUsDN,
[parameter(Mandatory=$false)]
[string]$SearchBase
)
process {
if (!($AllOUs.IsPresent) -and !($OUsDN)) {
throw "AllOUs switch parameter or OUsDN parameter must be used - exiting"
}
if ($AllOUs.IsPresent -and !($SearchBase)) {
throw "SearchBase parameter must be used with AllOUs switch - exiting"
}
Test-ADModule -AD | Out-Null
Test-AzureADAccessTokenExpiration | out-null
If ($AllOUs.IsPresent) {
if ($OUsFilterName) {
$OUs = Get-ADOrganizationalUnit -Filter * -SearchBase $SearchBase
$OUs = $OUs | where-object {$_.Name -match $OUsFilterName}
} else {
$Ous = Get-ADOrganizationalUnit -Filter {name -ne "Domain Controllers"} -SearchBase $SearchBase
}
} elseif ($OUsDN) {
$OUs = @()
foreach ($OU in $OUsDN) {
if ($OU -match "^(?:(?<cn>CN=(?<name>[^,]*)),)?(?:(?<path>(?:(?:CN|OU)=[^,]+,?)+),)?(?<domain>(?:DC=[^,]+,?)+)$") {
try {
$OU = Get-ADOrganizationalUnit -Identity $OU
} Catch {
write-verbose -message "OU $($OU) not found in directory"
}
if ($OU) {
$OUs += $OU
}
}
}
}
foreach ($OU in $OUs) {
If (!(Get-AzureADAdministrativeUnitCustom -Filter "displayname eq '$($OU.name)'").id) {
try {
New-AzureADAdministrativeUnitCustom -Description "Windows Server AD OU $($OU.DistinguishedName)" -DisplayName $OU.name
} catch {
write-error -message $_.Exception.Message
}
write-verbose -message "$($OU.name) Azure Administrative Unit created"
} else {
write-verbose -message "$($OU.name) Azure Administrative Unit already exists"
}
}
Get-AzureADAdministrativeUnitCustom -All
}
}
Function Sync-ADUsertoAzureADAdministrativeUnitMember {
<#
.SYNOPSIS
Add Azure AD user account into Azure AD Administrative Unit based on their on premise LDAP Distinguished Name
.DESCRIPTION
Add Azure AD user account into Azure AD Administrative Unit based on their on premise LDAP Distinguished Name.
.PARAMETER CloudUPNAttribute
-CloudUPNAttribute string
On premise AD user account attribute hosting the cloud Azure AD User userprincipal name. For instance, it could be also the userPrincipalName attribute or mail attribute.
.PARAMETER AllOUs
-AllOUs Switch
Synchronize all existing OU to new cloud Admin Unit (except default OU like Domain Controllers)
.PARAMETER OUsFilterName
-OUsFilterName string
must be used with AllOUs parameter
Set a regex filter to synchronize only OU based on a specific pattern.
.PARAMETER SearchBase
-SearchBase string
must be used with AllOUs parameter
set the default search base for OU (DN format)
.PARAMETER OUsDN
-OUsDN string / array of string
must not be used with AllOUs parameter. you must choose between these 2 parameters.
string must be a LDAP Distinguished Name. For instance : "OU=TP-VB,DC=domain,DC=xyz"
.OUTPUTS
None. verbose can be used to display message on console.
.EXAMPLE
Add Azure AD users to administrative unit based on their source Distinguished Name, do it only for users account with a DN containing a root OU name matching a pattern like "AB-CD"
The verbose option can be used to write basic message on console (for instance when a user is already member of an admin unit)
C:\PS> Sync-ADUsertoAzureADAdministrativeUnitMember -CloudUPNAttribute mail -AllOUs -OUsFilterName "^([a-zA-Z]{2})(-)([a-zA-Z]{2})$" -SearchBase "DC=domain,DC=xyz" -Verbose
#>
[cmdletbinding()]
Param (
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$CloudUPNAttribute,
[parameter(Mandatory=$false)]
[switch]$AllOUs,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]$OUsFilterName,
[parameter(Mandatory=$false)]
[string]$SearchBase,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string[]]$OUsDN,
[parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[string]$ADUserFilter
)
process {
if (!($AllOUs.IsPresent) -and !($OUsDN)) {
throw "AllOUs switch parameter or OUsDN parameter must be used - exiting"
}
if ($AllOUs.IsPresent -and !($SearchBase)) {
throw "SearchBase parameter must be used with AllOUs switch - exiting"
}
if (!($ADUserFilter)) {
$ADUserFilter = "*"
}
Test-ADModule -AD | Out-Null
Test-AzureADAccessTokenExpiration | out-null
If ($AllOUs.IsPresent) {
if ($OUsFilterName) {
$OUs = Get-ADOrganizationalUnit -Filter * -SearchScope OneLevel -SearchBase $SearchBase
$OUs = $OUs | where-object {$_.Name -match $OUsFilterName}
} else {
$Ous = Get-ADOrganizationalUnit -Filter {name -ne "Domain Controllers"} -SearchBase $SearchBase
}
} elseif ($OUsDN) {
$OUs = @()
foreach ($OU in $OUsDN) {
if ($OU -match "^(?:(?<cn>CN=(?<name>[^,]*)),)?(?:(?<path>(?:(?:CN|OU)=[^,]+,?)+),)?(?<domain>(?:DC=[^,]+,?)+)$") {
try {
$OU = Get-ADOrganizationalUnit -Identity $OU
} Catch {
write-error -message "OU $($OU) not found in directory"
}
if ($OU) {
write-verbose -message "OU $($OU) found in directory"
$OUs += $OU
}
}
}
}
foreach ($OU in $OUs) {
$AZADMUnit = Get-AzureADAdministrativeUnitCustom -Filter "displayname eq '$($OU.name)'"
If ($AZADMUnit.id) {
$AZADMUnitMember = Get-AzureADAdministrativeUnitAllMembers -objectid $AZADMUnit.ID
$users = Get-ADUser -SearchBase $OU.DistinguishedName -SearchScope Subtree -Filter $ADUserFilter -Properties $CloudUPNAttribute
foreach ($user in $users) {
$azureaduser = Get-AzureADUserCustom -userUPN $user.$CloudUPNAttribute
if ($azureaduser.error) {
write-verbose -message"Azure AD User $($user.$CloudUPNAttribute) not found"
} else {
if ($user.($CloudUPNAttribute)) {
write-verbose -message "Azure AD User $($user.$CloudUPNAttribute) found"
if ($AZADMUnitMember) {
if ($AZADMUnitMember.ID -contains $azureaduser.ID) {
write-verbose -message "Azure AD User $($user.($CloudUPNAttribute)) already member of $($OU.name) Azure Administrative Unit"
} else {
write-verbose -message "Azure AD User $($user.($CloudUPNAttribute)) not member of $($OU.name) Azure Administrative Unit"
try {
Add-AzureADAdministrativeUnitMemberCustom -ObjectId $AZADMUnit.ID -RefObjectId $azureaduser.ID -RefObjectType users
} catch {
write-error -message $_.Exception.Message
write-error -message "not able to add $($user.($CloudUPNAttribute)) Azure AD User in $($OU.name) Azure Administrative Unit"
}
write-verbose -message "Azure AD User $($user.($CloudUPNAttribute)) added in $($OU.name) Azure Administrative Unit"
}
} else {
write-verbose -message "Azure AD User $($user.($CloudUPNAttribute)) not member of $($OU.name) Azure Administrative Unit"
try {
Add-AzureADAdministrativeUnitMemberCustom -ObjectId $AZADMUnit.ID -RefObjectId $azureaduser.ID -RefObjectType users
} catch {
write-error -message $_.Exception.Message
write-error -message "not able to add $($user.($CloudUPNAttribute)) Azure AD User in $($OU.name) Azure Administrative Unit"
}
write-verbose -message "Azure AD User $($user.($CloudUPNAttribute)) added in $($OU.name) Azure Administrative Unit"
}
}
}
}
}
}
}
}
Function Set-AzureADAdministrativeUnitAdminRole {
<#
.SYNOPSIS
Add / remove Azure AD administrative unit role to Azure AD user
.DESCRIPTION
Add / remove Azure AD administrative unit role to Azure AD user
.PARAMETER AdministrativeUnit
-AdministrativeUnit string
Dynamic parameter built using the list of Administrative Unit created in your Tenant.
.PARAMETER AdministrativeRole
-AdministrativeRole string
Dynamic parameter built using the list of Role template available in your Tenant.
Note : warning, currently all roles are not compliant with Administrative Unit object.
.PARAMETER userUPN
-userUPN System.Net.Mail.MailAddress
user principal name of the account you want to add a new role
.PARAMETER RoleAction
-RoleAction string {Add, Remove}
Specify the action to be done with the target role on the Azure AD user object : add or remove the role
.OUTPUTS
TypeName : Microsoft.Open.AzureAD.Model.ScopedRoleMembership
.EXAMPLE
Give the role Password Administrator for the Admin unit TP-NF to my-admin-unit@mydomain.tld
C:\PS> Set-AzureADAdministrativeUnitAdminRole -userUPN my-admin-unit@mydomain.tld -RoleAction ADD -AdministrativeUnit TP-NF -AdministrativeRole 'Password Administrator' -Verbose
#>
[cmdletbinding()]
param (
[parameter(Mandatory=$true,Position=2)]
[ValidateNotNullOrEmpty()]
[System.Net.Mail.MailAddress]$userUPN,
[parameter(Mandatory=$true,position=4)]
[validateSet("Add","Remove")]
[string]$RoleAction
)
DynamicParam
{
$ParameterNameAdmUnit = 'AdministrativeUnit'
$RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
$ParameterAttribute.ValueFromPipeline = $false
$ParameterAttribute.ValueFromPipelineByPropertyName = $false
$ParameterAttribute.Mandatory = $true
$ParameterAttribute.Position = 1
$AttributeCollection.Add($ParameterAttribute)
$arrSet = (Get-AzureADAdministrativeUnit).displayname
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
$AttributeCollection.Add($ValidateSetAttribute)
$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterNameAdmUnit, [string], $AttributeCollection)
$RuntimeParameterDictionary.Add($ParameterNameAdmUnit, $RuntimeParameter)
$ParameterNameAdmRole = 'AdministrativeRole'
$AttributeCollection2 = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParameterAttribute2 = New-Object System.Management.Automation.ParameterAttribute
$ParameterAttribute2.ValueFromPipeline = $false
$ParameterAttribute2.ValueFromPipelineByPropertyName = $false
$ParameterAttribute2.Mandatory = $true
$ParameterAttribute2.Position = 3
$AttributeCollection2.Add($ParameterAttribute2)
$arrSet = (Get-AzureADDirectoryRoleTemplate).displayname
$ValidateSetAttribute2 = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
$AttributeCollection2.Add($ValidateSetAttribute2)
$RuntimeParameter2 = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterNameAdmRole, [string], $AttributeCollection2)
$RuntimeParameterDictionary.Add($ParameterNameAdmRole, $RuntimeParameter2)
return $RuntimeParameterDictionary
}
Process {
$AdminUnit = $PsBoundParameters[$ParameterNameAdmUnit]
$AdminRole = $PsBoundParameters[$ParameterNameAdmRole]
Test-ADModule -AzureAD | out-null
Test-AzureADAccessTokenExpiration | out-null
try {
$UserObj = Get-AzureADUser -ObjectId $userUPN.Address
} catch {
Write-Error -Message "$($_.Exception.Message)"
throw "Not able to find user $($userUPN.Address) - exiting"
}
$AdminUnitObj = Get-AzureADAdministrativeUnit -filter "DisplayName eq '$($AdminUnit)'"
if (!($AdminUnitObj)) {
throw "Not able to find $($AdminUnit) Azure AD Administrative Unit - exiting"
}
$AdminroleObj = Get-AzureADDirectoryRole -Filter "DisplayName eq '$($AdminRole)'"
if (!($AdminroleObj)) {
write-verbose -message "$($AdminRole) role currently disabled, needed to enable it before adding member"
try {
$AdminroleObj = Enable-AzureADDirectoryRole -RoleTemplateId (Get-AzureADDirectoryRoleTemplate | Where-Object {$_.Displayname -eq $AdminRole}).ObjectId
} catch {
Write-Error -Message "$($_.Exception.Message)"
throw "Not able to enable requested role $($AdminRole) - exiting"
}
}
try {
$AdminRoleMember = (Get-AzureADScopedRoleMembership -ObjectId $AdminUnitObj.ObjectID | Where-Object {$_.RoleObjectID -eq $AdminroleObj.ObjectID}).RoleMemberInfo
} catch {
Write-Error -Message "$($_.Exception.Message)"
}
If (($AdminRoleMember.ObjectId -contains $UserObj.ObjectId) -and ($RoleAction -eq "ADD")) {
write-verbose "User $($userUPN.Address) already member of $($AdminRole) role"
} elseif (($AdminRoleMember.ObjectId -notcontains $UserObj.ObjectId) -and ($RoleAction -eq "ADD")) {
try {
$AdmRoleMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ ObjectId = $UserObj.ObjectId }
Add-AzureADScopedRoleMembership -RoleObjectId $AdminroleObj.ObjectID -ObjectId $AdminUnitObj.ObjectID -RoleMemberInfo $AdmRoleMemberInfo
} catch {
Write-Error -Message "$($_.Exception.Message)"
throw "Not able to add $($userUPN.Address) user in $($AdminRole) role for $($AdminUnit) Azure administrative unit - exiting"
}
}
If (($AdminRoleMember.ObjectId -notcontains $UserObj.ObjectId) -and ($RoleAction -eq "Remove")) {
write-verbose "User $($userUPN.Address) already removed from $($AdminRole) role"
} elseif (($AdminRoleMember.ObjectId -contains $UserObj.ObjectId) -and ($RoleAction -eq "Remove")) {
try {
$AdmRoleMembershipID = (Get-AzureADScopedRoleMembership -ObjectId $AdminUnitObj.ObjectID | Where-Object {($_.RoleObjectID -eq $AdminroleObj.ObjectID) -and ($_.RoleMemberInfo.ObjectId -eq $UserObj.ObjectID)}).ID
Remove-AzureADScopedRoleMembership -ObjectId $AdminUnitObj.ObjectID -ScopedRoleMembershipId $AdmRoleMembershipID
} catch {
Write-Error -Message "$($_.Exception.Message)"
throw "Not able to remove $($userUPN.Address) user from $($AdminRole) role for $($AdminUnit) Azure administrative unit - exiting"
}
}
Get-AzureADScopedRoleMembership -ObjectId $AdminUnitObj.ObjectID
}
}
Function Get-AzureADUserCustom {
<#
.SYNOPSIS
Get all info available for an existing Azure AD account
.DESCRIPTION
Get all info available for an existing Azure AD account (all user properties available including all the hidden one not managed by Get-AzureADUsers)
.PARAMETER userUPN
-userUPN System.Net.Mail.MailAddress
UserPrincipalName of an Azure AD account