Home

Example how to create Azure AD access reviews using Microsoft Graph app permissions with PowerShell

%3CLINGO-SUB%20id%3D%22lingo-sub-807241%22%20slang%3D%22en-US%22%3EExample%20how%20to%20create%20Azure%20AD%20access%20reviews%20using%20Microsoft%20Graph%20app%20permissions%20with%20PowerShell%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-807241%22%20slang%3D%22en-US%22%3E%3CP%3EThe%20Azure%20AD%20access%20reviews%20feature%20is%20part%20of%20Microsoft%20Graph%2C%20with%20a%20list%20of%20methods%20at%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fresources%2Faccessreviews-root%3Fview%3Dgraph-rest-beta%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fresources%2Faccessreviews-root%3Fview%3Dgraph-rest-beta%3C%2FA%3E.%26nbsp%3B%20An%20earlier%20blog%20post%20included%20an%20example%20of%20how%20a%20user%2C%20such%20as%20a%20Security%20Reader%2C%20could%20retrieve%20all%20the%20programs%2C%20controls%20and%20access%20reviews%20via%20Microsoft%20Graph%2C%20in%20PowerShell.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EIn%20this%20post%2C%20I'll%20show%20an%20example%20PowerShell%20script%20that%20uses%20the%20new%20application%20permission%20%3CSTRONG%3EAccessReview.ReadWrite.Membership%3C%2FSTRONG%3E.%20.%20Application%20permissions%20don%E2%80%99t%20need%20the%20app%20to%20have%20a%20logged%20in%20user%20to%20call%20Graph%2C%20so%20you%20can%20use%20this%20to%20automatically%20to%20create%20and%20retrieve%20access%20reviews%20from%20scheduled%20jobs%20or%20as%20part%20of%20your%20existing%20automation.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId-1816566640%22%20id%3D%22toc-hId-1816566641%22%3ECode%20Sample%20Prerequisite%20%231%3A%20Azure%20AD%20PowerShell%3C%2FH2%3E%0A%3CP%3ETo%20set%20up%20this%20code%20sample%2C%20you%E2%80%99ll%20need%20an%20Azure%20AD%20tenant%20where%20you%E2%80%99re%20a%20global%20administrator.%20In%20this%20example%2C%20as%20with%20the%20previous%20blog%20post%2C%20the%20sample%20code%20to%20use%20the%20API%20leverages%20the%20ADAL%20library%20to%20retrieve%20an%20access%20token%20used%20by%20Microsoft%20Graph.%20The%20ADAL%20library%20is%20automatically%20installed%20when%20you%20install%20Azure%20AD%20PowerShell%20cmdlets.%20So%20before%20you%20begin%2C%20ensure%20that%20you%20have%20PowerShell%203.0%20or%20later%2C.NET%20Framework%204.5%20and%20either%20the%20Azure%20AD%20PowerShell%20v2%20General%20Availability%20or%20Preview%20modules%20installed%20on%20your%20computer.%20If%20you%20don%E2%80%99t%20have%20Azure%20AD%20PowerShell%20installed%20yet%2C%20see%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fpowershell%2Fazure%2Factive-directory%2Finstall-adv2%3Fview%3Dazureadps-2.0%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fpowershell%2Fazure%2Factive-directory%2Finstall-adv2%3Fview%3Dazureadps-2.0%3C%2FA%3E.%20Try%20the%20%3CSTRONG%3EConnect-AzureAD%3C%2FSTRONG%3Ecommand%20to%20ensure%20that%20you%20can%20authenticate%20to%20Azure%20AD%20as%20a%20global%20administrator.%26nbsp%3B%20Also%20try%20%3CSTRONG%3EGet-AzureADUser%3C%2FSTRONG%3Eto%20make%20sure%20you%20can%20retrieve%20users%2C%20as%20you'll%20need%20a%20user%20ID%20later%20on.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId--735590321%22%20id%3D%22toc-hId--735590320%22%3ECode%20Sample%20Prerequisite%20%232%3A%20Azure%20AD%20access%20reviews%20%3CBR%20%2F%3E%3CBR%20%2F%3E%3C%2FH2%3E%0A%3CP%3EThis%20example%20assumes%20you%20have%20already%20onboarded%20Azure%20AD%20access%20reviews%20in%20your%20tenant%20directory.%26nbsp%3B%20If%20you%20have%20already%20done%20so%2C%20then%20skip%20to%20the%20next%20section%20%E2%80%9CRegister%20an%20Azure%20AD%20application%E2%80%9D.%26nbsp%3B%20Otherwise%2C%20continue%20with%20these%20steps%20to%20ensure%20the%20feature%20is%20onboarded%20so%20the%20APIs%20will%20allow%20access%20reviews%20to%20be%20created%20and%20return%20some%20data.%3C%2FP%3E%0A%3COL%3E%0A%3CLI%3ELog%20into%20the%20Azure%20portal%20as%20a%20global%20administrator.%3C%2FLI%3E%0A%3CLI%3EEnsure%20that%20your%20organization%20has%20Azure%20AD%20Premium%20P2%20or%20EMS%20E5%20subscription%20active.%20If%20not%2C%20click%20%3CA%20href%3D%22https%3A%2F%2Fportal.azure.com%2F%23blade%2FMicrosoft_AAD_IAM%2FTryBuyProductBlade%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fportal.azure.com%2F%23blade%2FMicrosoft_AAD_IAM%2FTryBuyProductBlade%3C%2FA%3Eand%20activate%20a%20trial%20of%20Enterprise%20Mobility%20%2B%20Security%20E5.%20Otherwise%2C%20if%20your%20organization%20has%20an%20active%20subscription%2C%20continue%20at%20the%20next%20step.%3C%2FLI%3E%0A%3CLI%3ENavigate%20to%20%3CSTRONG%3EAzure%20Active%20Directory%3C%2FSTRONG%3E%2C%20and%20then%20click%20%3CSTRONG%3EIdentity%20Governance%3C%2FSTRONG%3Eon%20the%20left%20hand%20side.%3C%2FLI%3E%0A%3CLI%3EClick%20%3CSTRONG%3EAccess%20reviews%3C%2FSTRONG%3E.%20If%20no%20one%20has%20onboarded%20Azure%20AD%20access%20reviews%20in%20your%20organization%2C%20onboard%20it%20now.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CH2%20id%3D%22toc-hId-1007220014%22%20id%3D%22toc-hId-1007220015%22%3ERegister%20an%20Azure%20AD%20application%3C%2FH2%3E%0A%3CP%3ENext%2C%20you'll%20need%20to%20create%20an%20app%20registration%20with%20the%20new%20permission%2C%20to%20allow%20your%20application%20to%20call%20the%20access%20reviews%20API%20in%20Microsoft%20Graph.%20If%20you%20haven%E2%80%99t%20created%20an%20app%20registration%20lately%2C%20the%20user%20interface%20in%20the%20Azure%20portal%20has%20changed.%20Here%E2%80%99s%20how%20to%20create%20an%20app%20with%20the%20updated%20UI.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%225%22%3E%0A%3CLI%3ELog%20into%20the%20Azure%20portal%20as%20a%20global%20administrator.%3C%2FLI%3E%0A%3CLI%3EIn%20the%20Azure%20portal%2C%20go%20to%20%3CSTRONG%3EAzure%20Active%20Directory%3C%2FSTRONG%3E%2C%20and%20then%20click%20%3CSTRONG%3EApp%20registrations%3C%2FSTRONG%3Eon%20the%20left.%3C%2FLI%3E%0A%3CLI%3EClick%20%3CSTRONG%3ENew%20registration%3C%2FSTRONG%3E.%20Give%20your%20app%20a%20name%2C%20and%20then%20click%20%3CSTRONG%3ERegister%3C%2FSTRONG%3E.%3C%2FLI%3E%0A%3CLI%3ECopy%20and%20save%20for%20later%20the%20%3CSTRONG%3Eapplication%20(client)%20ID%3C%2FSTRONG%3Ethat%20appears%20after%20the%20app%20is%20registered.%3C%2FLI%3E%0A%3CLI%3EOn%20the%20left%2C%20click%20%3CSTRONG%3EAPI%20permissions%3C%2FSTRONG%3E.%3C%2FLI%3E%0A%3CLI%3EClick%20%3CSTRONG%3EAdd%20a%20permission%3C%2FSTRONG%3E%2C%20click%20%3CSTRONG%3EMicrosoft%20Graph%3C%2FSTRONG%3E%2C%20and%20then%20click%20%3CSTRONG%3EApplication%20permissions%3C%2FSTRONG%3E.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CDIV%20id%3D%22tinyMceEditorclipboard_image_0%22%20class%3D%22mceNonEditable%20lia-copypaste-placeholder%22%3E%26nbsp%3B%3C%2FDIV%3E%0A%3COL%20start%3D%2211%22%3E%0A%3CLI%3EIn%20the%20Select%20permissions%20list%2C%20expand%20%3CSTRONG%3EAccessReview%3C%2FSTRONG%3Eand%20select%20%3CSTRONG%3EAccessReview.ReadWrite.Membership%3C%2FSTRONG%3E.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CDIV%20id%3D%22tinyMceEditorclipboard_image_1%22%20class%3D%22mceNonEditable%20lia-copypaste-placeholder%22%3E%26nbsp%3B%3C%2FDIV%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%2212%22%3E%0A%3CLI%3EWhile%20here%2C%20though%20not%20required%20for%20this%20sample%2C%20you%20might%20want%20to%20expand%20%3CSTRONG%3EGroup%3C%2FSTRONG%3Eand%20give%20the%20app%20the%20permission%20%3CSTRONG%3EGroup.Read.All%3C%2FSTRONG%3E%2C%20and%20expand%20%3CSTRONG%3EUser%3C%2FSTRONG%3Eand%20give%20the%20app%20the%20%3CSTRONG%3EUser.Read.All%3C%2FSTRONG%3Epermission%2C%3C%2FLI%3E%0A%3CLI%3EClick%20Add%20permissions.%3C%2FLI%3E%0A%3CLI%3EClick%20to%20%3CSTRONG%3EGrant%20admin%20consent%20for%20%3CYOUR%20tenant%3D%22%22%3E%3C%2FYOUR%3E%3C%2FSTRONG%3Eand%20then%20click%20%3CSTRONG%3EYes%3C%2FSTRONG%3E.%20The%20status%20for%20each%20permission%20the%20app%20needs%20should%20change%20to%20a%20green%20checkmark%2C%20indicating%20consent%20was%20granted.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CDIV%20id%3D%22tinyMceEditorclipboard_image_2%22%20class%3D%22mceNonEditable%20lia-copypaste-placeholder%22%3E%26nbsp%3B%3C%2FDIV%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%2215%22%3E%0A%3CLI%3EOn%20the%20left%2C%20click%20%3CSTRONG%3ECertificates%20%26amp%3B%20secrets%3C%2FSTRONG%3E.%3C%2FLI%3E%0A%3CLI%3EClick%20%3CSTRONG%3ENew%20client%20secret%3C%2FSTRONG%3Eand%20then%20for%20Expires%20select%20%3CSTRONG%3ENever%3C%2FSTRONG%3E.%3C%2FLI%3E%0A%3CLI%3EClick%20Add.%3C%2FLI%3E%0A%3CLI%3ECopy%20and%20save%20locally%20the%20value%20of%20the%20secret%20that%20appears-%20you%20won%E2%80%99t%20see%20it%20again%20after%20you%20leave%20this%20part%20of%20the%20UI.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EAt%20this%20point%2C%20you%E2%80%99ll%20have%20a%20client%20app%20ID%20and%20a%20client%20secret.%20In%20real%20life%20you'd%20probably%20want%20to%20store%20the%20secret%20in%20Azure%20Automation%2C%20Azure%20Key%20Vault%2C%20or%20similar.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId--1544936947%22%20id%3D%22toc-hId--1544936946%22%3ECreate%20and%20retrieve%20access%20reviews%20using%20Graph%3C%2FH2%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ENext%2C%20here's%20how%20to%20try%20out%20Microsoft%20Graph%20API%20requests%20when%20authenticated%20as%20an%20application%2C%20using%20a%20PowerShell%20script%20to%20be%20your%20application.%20I'll%20assume%20you%20have%20Azure%20AD%20v2%20PowerShell%20cmdlets%20already%20installed%20-%20the%20script%20uses%20the%20Azure%20AD%20library%20included%20in%20those%20modules%20for%20authentication.%3C%2FP%3E%0A%3COL%20start%3D%2219%22%3E%0A%3CLI%3ESave%20the%20PowerShell%20below%20to%20a%20file%20named%20sample-ar-app-permissions.psm1.%3C%2FLI%3E%0A%3CLI%3EOpen%20a%20new%20PowerShell%20window%2C%20change%20to%20the%20directory%20where%20the%20file%20is%20located%20and%20type%20%3CSTRONG%3EImport-Module%3C%2FSTRONG%3E.%5Csample-ar-app-permissions.psm1%3C%2FLI%3E%0A%3CLI%3E%3CBR%20%2F%3EType%20%3CSTRONG%3EConnect-AzureADMSARSample%3C%2FSTRONG%3E.%20This%20obtains%20a%20token%20needed%20for%20the%20service%20principal%20to%20call%20Graph.%20You%E2%80%99ll%20be%20prompted%20to%20provide%20the%20following%20information%3A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CUL%3E%0A%3CLI%3EClientApplicationId%3C%2FLI%3E%0A%3CLI%3EClientSecret%3C%2FLI%3E%0A%3CLI%3ETenantDomain%20(e.g.%20demo%E2%80%A6.onmicrosoft.com)%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3COL%20start%3D%2222%22%3E%0A%3CLI%3ETo%20create%20a%20new%20access%20review%2C%20use%20the%20command%20%3CSTRONG%3ENew-AzureADMSARSampleAccessReview%3C%2FSTRONG%3E.%20To%20try%20out%20this%20command%2C%20you%E2%80%99ll%20need%20to%20have%20an%20Azure%20AD%20group%20with%20members%20and%20owners%20%E2%80%93%20the%20owners%20will%20be%20the%20reviewers.%20You%E2%80%99ll%20be%20prompted%20to%20provide%20the%20following%20information%3A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CUL%3E%0A%3CLI%3EDisplayName%3A%20(a%20display%20name%20for%20the%20access%20review)%3C%2FLI%3E%0A%3CLI%3EReviewedEntityId%3A%20(the%20object%20ID%20of%20a%20group%20whose%20members%20are%20to%20be%20reviewed)%3C%2FLI%3E%0A%3CLI%3EOwnerUserId%3A%20(the%20object%20ID%20of%20a%20user%20such%20as%20an%20admin%20who%20will%20be%20listed%20as%20the%20owner%20of%20a%20review%20%E2%80%93%20since%20apps%20can%E2%80%99t%20own%20access%20reviews)%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3EIf%20successful%2C%20the%20command%20will%20return%20the%20ID%20of%20the%20new%20access%20review.%20If%20you%20see%20an%20error%20about%20permissions%2C%20please%20note%20that%20app%20registration%20may%20take%20a%20few%20minutes%20to%20be%20set%20up%20in%20the%20directory%20%E2%80%93%20if%20the%20Graph%20calls%20don%E2%80%99t%20work%20right%20away%2C%20try%20again%20an%20hour%20later.%3C%2FP%3E%0A%3COL%20start%3D%2223%22%3E%0A%3CLI%3EType%20%3CSTRONG%3EGet-AzureADMSARSampleAccessReview%3C%2FSTRONG%3Eto%20see%20the%20access%20review%20that%20you've%20created.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EI%20expect%20we%E2%80%99ll%20bring%20commands%20to%20create%20and%20query%20access%20reviews%20into%20the%20Azure%20AD%20PowerShell%20module%20in%20the%20future%2C%20which%20will%20remove%20the%20need%20for%20Connect-AzureADMSARSample.%20Please%20let%20us%20know%20about%20any%20other%20feedback%2Fsuggestions%20you%20have%20for%20more%20code%20samples.%20Thanks%2C%20Mark%20Wahl%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-c%22%3E%3CCODE%3E%23%20Example%20for%20creating%20and%20retrieving%20the%20results%20of%20an%20Azure%20AD%20access%20review%20via%20Microsoft%20Graph%20using%20application%20permissions%0A%23%0A%23%20This%20material%20is%20provided%20%22AS-IS%22%20and%20has%20no%20warranty.%0A%23%20%0A%23%20Last%20updated%20August%202019%0A%23%0A%23%20This%20example%20is%20adapted%20from%20the%20documentation%20example%20located%20at%20%0A%23%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fintune%2Fintune-graph-apis%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fintune%2Fintune-graph-apis%3C%2FA%3E%0A%23%0A%23%0A%0A%23%20the%20following%20functions%20are%20from%20Intune%20graph%20API%20samples%2C%20adapted%20for%20service%20principal%20authentication%0A%0Afunction%20Get-GraphExampleAuthTokenServicePrincipal%20%7B%0A%20%20%20%20%5Bcmdletbinding()%5D%0A%20%20%20%20param%0A%20%20%20%20(%0A%20%20%20%20%20%20%20%20%5BParameter(Mandatory%20%3D%20%24true)%5D%0A%20%20%20%20%20%20%20%20%24ClientId%2C%0A%0A%20%20%20%20%20%20%20%20%5BParameter(Mandatory%20%3D%20%24true)%5D%0A%20%20%20%20%20%20%20%20%24ClientSecret%2C%0A%0A%20%20%20%20%20%20%20%20%5BParameter(Mandatory%20%3D%20%24true)%5D%0A%20%20%20%20%20%20%20%20%24TenantDomain%0A%20%20%20%20)%0A%0A%0A%20%20%20%20%24tenant%20%3D%20%24TenantDomain%0A%20%20%20%20%0A%0A%20%20%20%20Write-Verbose%20%22Checking%20for%20AzureAD%20module...%22%0A%0A%20%20%20%20%24AadModule%20%3D%20Get-Module%20-Name%20%22AzureAD%22%20-ListAvailable%0A%20%20%20%20if%20(%24AadModule%20-eq%20%24null)%20%7B%0A%20%20%20%20%20%20%20%20write-verbose%20%22AzureAD%20PowerShell%20module%20not%20found%2C%20looking%20for%20AzureADPreview%22%0A%20%20%20%20%20%20%20%20%24AadModule%20%3D%20Get-Module%20-Name%20%22AzureADPreview%22%20-ListAvailable%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(%24AadModule%20-eq%20%24null)%20%7B%0A%20%20%20%20%20%20%20%20write-output%0A%20%20%20%20%20%20%20%20write-error%20%22AzureAD%20Powershell%20module%20not%20installed...%22%0A%20%20%20%20%20%20%20%20write-output%20%22Install%20by%20running%20'Install-Module%20AzureAD'%20or%20'Install-Module%20AzureADPreview'%20from%20an%20elevated%20PowerShell%20prompt%22%0A%20%20%20%20%20%20%20%20write-output%20%22Script%20can't%20continue...%22%0A%20%20%20%20%20%20%20%20write-output%0A%20%20%20%20%20%20%20%20return%20%22%22%0A%20%20%20%20%7D%0A%0A%20%20%20%20%23%20Getting%20path%20to%20ActiveDirectory%20Assemblies%0A%20%20%20%20%23%20If%20the%20module%20count%20is%20greater%20than%201%20find%20the%20latest%20version%0A%0A%20%20%20%20if%20(%24AadModule.count%20-gt%201)%20%7B%0A%20%20%20%20%20%20%20%20write-verbose%20%22multiple%20module%20versions%22%0A%20%20%20%20%20%20%20%20%24Latest_Version%20%3D%20(%24AadModule%20%7C%20select%20version%20%7C%20Sort-Object)%5B-1%5D%0A%20%20%20%20%20%20%20%20%24aadModule%20%3D%20%24AadModule%20%7C%20%3F%20%7B%20%24_.version%20-eq%20%24Latest_Version.version%20%7D%0A%20%20%20%20%20%20%20%20%24adal%20%3D%20Join-Path%20%24AadModule.ModuleBase%20%22Microsoft.IdentityModel.Clients.ActiveDirectory.dll%22%0A%20%20%20%20%20%20%20%20%24adalforms%20%3D%20Join-Path%20%24AadModule.ModuleBase%20%22Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll%22%0A%20%20%20%20%7D%0A%0A%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20write-verbose%20%22single%20module%20version%22%0A%20%20%20%20%20%20%20%20%24adal%20%3D%20Join-Path%20%24AadModule.ModuleBase%20%22Microsoft.IdentityModel.Clients.ActiveDirectory.dll%22%0A%20%20%20%20%20%20%20%20%24adalforms%20%3D%20Join-Path%20%24AadModule.ModuleBase%20%22Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll%22%0A%20%20%20%20%7D%0A%0A%20%20%20%20Write-verbose%20%22loading%20%24adal%20and%20%24adalforms%22%0A%0A%0A%20%20%20%20%5BSystem.Reflection.Assembly%5D%3A%3ALoadFrom(%24adal)%20%7C%20Out-Null%0A%20%20%20%20%5BSystem.Reflection.Assembly%5D%3A%3ALoadFrom(%24adalforms)%20%7C%20Out-Null%0A%0A%20%20%20%20write-verbose%20%22DLLs%20loaded%22%0A%20%20%0A%20%20%20%20%23%20%24redirectUri%20%3D%20%22urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob%22%0A%20%20%20%20%24resourceAppIdURI%20%3D%20%22%3CA%20href%3D%22https%3A%2F%2Fgraph.microsoft.com%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgraph.microsoft.com%3C%2FA%3E%22%0A%0A%20%20%20%20%24authority%20%3D%20%22%3CA%20href%3D%22https%3A%2F%2Flogin.microsoftonline.com%2F%24Tenant%22%20target%3D%22_blank%22%20rel%3D%22nofollow%20noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Flogin.microsoftonline.com%2F%24Tenant%3C%2FA%3E%22%0A%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20write-verbose%20%22instantiating%20ADAL%20objects%20for%20%24authority%22%0A%20%20%20%20%20%20%20%20%24authContext%20%3D%20New-Object%20%22Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext%22%20-ArgumentList%20%24authority%0A%0A%20%20%20%20%20%20%20%20write-verbose%20%22client%20%24ClientId%20%24clientSecret%22%0A%0A%20%20%20%20%20%20%20%20%24clientCredential%20%3D%20New-Object%20%22Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential%22%20-ArgumentList%20(%24ClientId%2C%24ClientSecret)%0A%20%0A%20%20%20%20%20%20%20%20write-verbose%20%22acquiring%20token%20for%20%24resourceAppIdURI%22%0A%20%20%20%20%20%20%20%20%23%20%20%20AuthenticationResult%20authResult%20%3D%20await%20authContext.AcquireTokenAsync(BatchResourceUri%2C%20new%20ClientCredential(ClientId%2C%20ClientKey))%3B%0A%20%20%20%20%20%20%20%20%23%20if%20you%20get%20an%20error%20about%20PowerShell%20not%20being%20able%20to%20find%20this%20method%20with%202%20parameters%2C%20it%20means%20there%20is%20another%20version%20of%20ADAL%20DLL%20already%20in%20the%20process%20space%20of%20your%20PowerShell%20environment.%0A%0A%20%20%20%20%20%20%20%20%24authResult%20%3D%20%24authContext.AcquireTokenAsync(%24resourceAppIdURI%2C%20%24clientCredential).Result%0A%20%20%20%20%20%20%20%20%23%20If%20the%20accesstoken%20is%20valid%20then%20create%20the%20authentication%20header%0A%20%20%20%20%20%20%20%20if%20(%24authResult.AccessToken)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20write-verbose%20%22acquired%20token%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Creating%20header%20for%20Authorization%20token%0A%20%20%20%20%20%20%20%20%20%20%20%20%24authHeader%20%3D%20%40%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20'Content-Type'%20%3D%20'application%2Fjson'%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20'Authorization'%20%3D%20%22Bearer%20%22%20%2B%20%24authResult.AccessToken%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20'ExpiresOn'%20%3D%20%24authResult.ExpiresOn%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%24authHeader%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20write-output%20%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20write-output%20%22Authorization%20Access%20Token%20is%20null%2C%20please%20re-run%20authentication...%22%0A%20%20%20%20%20%20%20%20%20%20%20%20write-output%20%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20catch%20%7B%0A%20%20%20%20%20%20%20%20write-output%20%24_.Exception.Message%0A%20%20%20%20%20%20%20%20write-output%20%24_.Exception.ItemName%0A%20%20%20%20%20%20%20%20write-output%20%22%22%0A%20%20%20%20%20%20%20%20break%0A%20%20%20%20%7D%20%20%20%0A%7D%0A%0A%24_SampleInternalAuthNHeaders%20%3D%20%40()%0A%0A%23%20exported%20module%20member%0Afunction%20Connect-AzureADMSARSample%20%7B%20%0A%20%20%20%20%5BCmdletBinding()%5D%0A%20%20%20%20param(%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5BValidateScript(%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5BSystem.Guid%5D%3A%3AParse(%24_)%20%7C%20Out-Null%0A%20%20%20%20%20%20%20%20%20%20%20%20%24true%0A%20%20%20%20%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20%22%24_%20is%20not%20a%20valid%20GUID%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%5D%0A%20%20%20%20%5Bstring%5D%24ClientApplicationId%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%24ClientSecret%2C%20%20%23%20base64%20client%20secret.%20%20Note%20this%20as%20a%20command%20line%20parameter%20is%20for%20testing%20purposes%20only%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%24TenantDomain%20%23%20e.g.%2C%20microsoft.onmicrosoft.com%0A%20%20%20%20)%0A%20%20%20%0A%20%20%20%20%24script%3A_SampleInternalAuthNHeaders%20%3D%20%40()%0A%0A%0A%20%20%20%20%24authHeaders%20%3D%20Get-GraphExampleAuthTokenServicePrincipal%20-ClientId%20%24ClientApplicationId%20-ClientSecret%20%24ClientSecret%20-TenantDomain%20%24TenantDomain%0A%0A%20%20%20%20%24script%3A_SampleInternalAuthNHeaders%20%3D%20%24authHeaders%0A%0A%7D%0A%0A%0Afunction%20Get-InternalAuthNHeaders%20%7B%0A%20%20%5BCmdletBinding()%5D%0A%20%20param()%0A%20%20%0A%20%20%20%20try%20%7B%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%24authResult%20%3D%20%24script%3A_SampleInternalAuthNHeaders%0A%20%20%20%20%20%20%20%20if%20(%24authResult.Length%20-eq%20%40())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20Throw%20%22Connect-AzureADMSARSample%20must%20be%20called%20first%22%20%20%20%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%0A%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20Throw%20%23%20%22Connect-AzureADMSControls%20must%20be%20called%20first%22%0A%20%20%20%20%7D%0A%20%20%20%20return%20%24authResult%0A%7D%0A%0A%0Afunction%20New-GraphExampleAccessReview(%24authHeaders%2C%24displayName%2C%24reviewedObjectId%2C%24reviewerType%2C%24businessFlowTemplateId%2C%24description%2C%24durationInDays%2C%24ownerUserId)%20%7B%0A%0A%0A%20%20%20%20%24recurrenceSettings%20%3D%20%40%7B%0A%20%20%20%20%20%20%20%20recurrenceType%20%3D%20%22onetime%22%3B%0A%20%20%20%20%20%20%20%20recurrenceEndType%20%3D%20%22endBy%22%3B%0A%20%20%20%20%20%20%20%20durationInDays%20%3D%200%3B%0A%20%20%20%20%20%20%20%20recurrenceCount%20%3D%200%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24autoReviewSettings%20%3D%20%40%7B%0A%20%20%20%20%20%20%20%20notReviewedResult%20%3D%20%22Approve%22%20%20%23%20also%20use%20%22Deny%22%20or%20%22Recommendation%22%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24settings%20%3D%20%40%7B%0A%20%20%20%20%20%20%20%20mailNotificationsEnabled%20%3D%20%24true%3B%0A%20%20%20%20%20%20%20%20remindersEnabled%20%3D%20%24true%3B%0A%20%20%20%20%20%20%20%20justificationRequiredOnApproval%20%3D%20%24false%3B%0A%20%20%20%20%20%20%20%20autoReviewEnabled%20%3D%20%24true%3B%0A%20%20%20%20%20%20%20%20activityDurationInDays%20%3D%2030%3B%0A%20%20%20%20%20%20%20%20autoApplyReviewResultsEnabled%20%3D%20%24false%3B%0A%20%20%20%20%20%20%20%20accessRecommendationsEnabled%20%3D%20%24true%3B%0A%20%20%20%20%20%20%20%20recurrenceSettings%20%3D%20%24recurrenceSettings%3B%0A%20%20%20%20%20%20%20%20autoReviewSettings%20%3D%20%24autoReviewSettings%3B%0A%20%20%20%20%7D%0A%20%20%20%20%0A%20%20%20%20%24reviewedEntity%20%3D%20%5Bpscustomobject%5D%40%7B%0A%20%20%20%20%20%20%20%20id%20%3D%20%24reviewedObjectId%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24owner%20%3D%20%5Bpscustomobject%5D%40%7B%0A%20%20%20%20%20%20%20%20id%20%3D%20%24ownerUserId%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24now%20%3D%20Get-Date%0A%20%20%20%20%24ts%20%3D%20Get-Date%20%24now.ToUniversalTime()%20-format%20%22s%22%0A%20%20%20%20%24startDate%20%3D%20%24ts%20%2B%20%22Z%22%0A%20%20%20%20%24ts%20%3D%20Get-Date%20%24now.AddDays(%24durationInDays).ToUniversalTime()%20-format%20%22s%22%0A%20%20%20%20%24endDate%20%3D%20%24ts%20%2B%20%22Z%22%0A%0A%20%20%20%20%24bodyObj%20%3D%20%5Bpscustomobject%5D%40%7B%0A%20%20%20%20%20%20%20%20displayName%20%3D%20%24displayName%3B%0A%20%20%20%20%20%20%20%20startDateTime%20%3D%20%24startDate%3B%0A%20%20%20%20%20%20%20%20endDateTime%20%3D%20%24endDate%3B%0A%20%20%20%20%20%20%20%20reviewedEntity%20%3D%20%24reviewedEntity%3B%0A%20%20%20%20%20%20%20%20reviewerType%20%3D%20%24reviewerType%3B%0A%20%20%20%20%20%20%20%20businessFlowTemplateId%20%3D%20%24businessFlowTemplateId%3B%0A%20%20%20%20%20%20%20%20description%20%3D%20%24description%3B%0A%20%20%20%20%20%20%20%20settings%20%3D%20%24settings%3B%0A%20%20%20%20%20%20%20%20createdBy%20%3D%20%24owner%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%23%20%20%20%20%20%20%20%20%20%0A%0A%20%20%20%20%24body%20%3D%20ConvertTo-Json%20%24bodyObj%20-compress%0A%0A%0A%20%20%20%20%23%20ensure%20it%20contains%20%20%22Content-Type%22%20%3D%20%22application%2Fjson%22%3B%0A%0A%20%20%20%20%24requestHeadersp%20%3D%20%40%7B%0A%20%20%20%20%20%20%20%20%22Content-Length%22%20%3D%20%24body.Length%0A%20%20%20%20%7D%0A%20%20%20%20%24requestHeadersp%20%2B%3D%20%24authHeaders%0A%20%20%20%20%0A%20%20%20%20%24uri1%20%3D%20%22%3CA%20href%3D%22https%3A%2F%2Fgraph.microsoft.com%2Fbeta%2FaccessReviews%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgraph.microsoft.com%2Fbeta%2FaccessReviews%3C%2FA%3E%22%0A%0A%20%20%20%20%24resp1%20%3D%20Invoke-WebRequest%20-UseBasicParsing%20-Headers%20%24requestHeadersp%20-Uri%20%24uri1%20-Method%20Post%20-Body%20%24body%0A%20%0A%20%20%20%20if%20(%24resp1%20-eq%20%24null%20-or%20%24resp1.Content%20-eq%20%24null)%20%7B%0A%20%20%20%20%20%20%20%20throw%20%22error%20repsonse%20from%20%24uri1%22%0A%20%20%20%20%20%7D%0A%0A%20%20%20%20%24val1%20%3D%20ConvertFrom-Json%20%24resp1.Content%0A%0A%20%20%20%20return%20%24val1.id%0A%7D%0A%0A%0Afunction%20New-AzureADMSARSampleAccessReview%20%7B%0A%20%20%20%20%5BCmdletBinding()%5D%0A%20%20%20%20param(%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5Bstring%5D%24DisplayName%2C%20%20%23%20of%20the%20review%20to%20create%20%0A%0A%20%20%20%20%5BParameter()%5D%0A%20%20%20%20%5Bstring%5D%24Description%20%3D%20%22%22%2C%20%23%20of%20the%20review%20to%20create%0A%0A%20%20%20%20%5BParameter()%5D%0A%20%20%20%20%5Bint%5D%24DurationInDays%3D30%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5BValidateScript(%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5BSystem.Guid%5D%3A%3AParse(%24_)%20%7C%20Out-Null%0A%20%20%20%20%20%20%20%20%20%20%20%20%24true%0A%20%20%20%20%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20%22%24_%20is%20not%20a%20valid%20GUID%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%5D%0A%20%20%20%20%5Bstring%5D%24ReviewedEntityId%2C%0A%0A%20%20%20%20%5BParameter()%5D%0A%20%20%20%20%20%20%20%20%5BValidateScript(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BSystem.Guid%5D%3A%3AParse(%24_)%20%7C%20Out-Null%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24true%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20throw%20%22%24_%20is%20not%20a%20valid%20GUID%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D)%5D%0A%20%20%20%20%5Bstring%5D%24BusinessFlowTemplateId%20%3D%20%226e4f3d20-c5c3-407f-9695-8460952bcc68%22%2C%0A%20%20%20%20%23business%20flow%20template%206e4f3d20-c5c3-407f-9695-8460952bcc68%20for%20Access%20reviews%20of%20memberships%20of%20a%20group%0A%20%20%20%0A%0A%20%20%20%20%5BParameter()%5D%0A%20%20%20%20%5Bstring%5D%24ReviewerType%20%3D%20%22entityOwners%22%2C%0A%0A%20%20%20%20%5BParameter(Mandatory%3D%24true)%5D%0A%20%20%20%20%5BValidateScript(%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5BSystem.Guid%5D%3A%3AParse(%24_)%20%7C%20Out-Null%0A%20%20%20%20%20%20%20%20%20%20%20%20%24true%0A%20%20%20%20%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20%22%24_%20is%20not%20a%20valid%20GUID%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%5D%0A%20%20%20%20%5Bstring%5D%24OwnerUserId%20%20%23%20a%20user%20who%20has%20an%20email%20address%0A%20%20%20%20)%0A%0A%20%20%20%20%24authHeaders%20%3D%20Get-InternalAuthNHeaders%0A%0A%20%20%20%20%24reviewId%20%3D%20New-GraphExampleAccessReview%20%24authHeaders%20%24DisplayName%20%24ReviewedEntityId%20%24ReviewerType%20%24BusinessFlowTemplateId%20%24Description%20%24durationInDays%20%24OwnerUserId%0A%0A%20%20%20%20return%20%24reviewId%0A%7D%0A%0A%0A%0Afunction%20Get-GraphExampleAccessReviews(%24authHeaders%2C%24businessFlowTemplateId)%0A%7B%0A%0A%20%20%20%20%24uri1%20%3D%20'%3CA%20href%3D%22https%3A%2F%2Fgraph.microsoft.com%2Fbeta%2FaccessReviews%3F%24filter%3DbusinessFlowTemplateId%2520eq%2520%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgraph.microsoft.com%2Fbeta%2FaccessReviews%3F%24filter%3DbusinessFlowTemplateId%2520eq%2520%3C%2FA%3E'%20%2B%20%20%22'%22%20%2B%20%24businessFlowTemplateId%20%2B%20%22'%22%0A%0A%20%20%20%20%24results%20%3D%20%40()%0A%0A%20%20%20%20do%20%7B%0A%0A%20%20%20%20%20%20%20%20%24resp1%20%3D%20Invoke-WebRequest%20-UseBasicParsing%20-headers%20%24authHeaders%20-Uri%20%24uri1%20-Method%20Get%0A%0A%20%20%20%20%20%20%20%20if%20(%24resp1%20-eq%20%24null%20-or%20%24resp1.Content%20-eq%20%24null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20%22error%20response%20from%20%24uri1%22%0A%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%24val1%20%3D%20ConvertFrom-Json%20%24resp1.Content%0A%0A%20%20%20%20%20%20%20%20foreach%20(%24i%20in%20%24val1.value)%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24results%20%2B%3D%20%24i%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%0A%0A%20%20%20%20%20%20%20%20%24uri1%20%3D%20%24val1.'%40odata.nextLink'%0A%20%20%20%20%20%20%20%20%23%20Odata%20list%20may%20have%20more%0A%0A%20%20%20%20%7D%20while%20(%24uri1%20-ne%20%24null)%0A%0A%0A%20%20%20%20return%20%24results%0A%0A%7D%0A%0Afunction%20Get-GraphExampleAccessReview(%24authHeaders%2C%24reviewId)%0A%7B%0A%20%20%20%20%24uri1%20%3D%20%22%3CA%20href%3D%22https%3A%2F%2Fgraph.microsoft.com%2Fbeta%2FaccessReviews%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%20noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgraph.microsoft.com%2Fbeta%2FaccessReviews%2F%3C%2FA%3E%22%20%2B%20%24reviewId%0A%0A%20%20%20%20%24resp1%20%3D%20Invoke-WebRequest%20-UseBasicParsing%20-headers%20%24authHeaders%20-Uri%20%24uri1%20-Method%20Get%0A%0A%20%20%20%20if%20(%24resp1%20-eq%20%24null%20-or%20%24resp1.Content%20-eq%20%24null)%20%7B%0A%20%20%20%20%20%20%20%20throw%20%22error%20response%20from%20%24uri1%22%0A%20%20%20%20%20%7D%0A%20%20%20%20%0A%20%20%20%20%24val1%20%3D%20ConvertFrom-Json%20%24resp1.Content%0A%0A%20%20%20%20return%20%24val1%0A%0A%7D%0A%0Afunction%20Get-AzureADMSARSampleAccessReview%20%7B%0A%20%20%20%20%5BCmdletBinding()%5D%0A%20%20%20%20param(%0A%20%20%20%20%20%20%20%20%5BParameter()%5D%0A%20%20%20%20%20%20%20%20%5BValidateScript(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BSystem.Guid%5D%3A%3AParse(%24_)%20%7C%20Out-Null%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24true%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20throw%20%22%24_%20is%20not%20a%20valid%20GUID%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D)%5D%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24ReviewId%2C%0A%0A%20%20%20%20%20%20%20%20%5BParameter()%5D%0A%20%20%20%20%20%20%20%20%5BValidateScript(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5BSystem.Guid%5D%3A%3AParse(%24_)%20%7C%20Out-Null%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24true%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20throw%20%22%24_%20is%20not%20a%20valid%20GUID%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D)%5D%0A%20%20%20%20%20%20%20%20%5Bstring%5D%24BusinessFlowTemplateId%20%3D%20%226e4f3d20-c5c3-407f-9695-8460952bcc68%22%0A%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%0A%23business%20flow%20template%20842169fe-e1b7-4ce9-98b6-6a9db02eec6b%20for%20Access%20reviews%20of%20guest%20user%20memberships%20of%20a%20group%0A%23business%20flow%20template%207fbc909b-efe1-4c72-8ae6-99cb30b882de%20for%20Access%20reviews%20of%20guest%20user%20assignments%20to%20an%20application%0A%23business%20flow%20template%2050839a84-e23c-44a7-a8cc-16e162afc656%20for%20Access%20reviews%20of%20assignments%20to%20an%20application%0A%23business%20flow%20template%206e4f3d20-c5c3-407f-9695-8460952bcc68%20for%20Access%20reviews%20of%20memberships%20of%20a%20group%0A%0A%0A%20%20%20%20%24authHeaders%20%3D%20Get-InternalAuthNHeaders%0A%0A%20%20%20%20if%20(%24ReviewId%20-ne%20%24null)%20%7B%0A%20%20%20%20%20%20%20%20if%20(%24ReviewId.Length%20-ge%201)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24reviewObj%20%3D%20Get-GraphExampleAccessReview%20%24authHeaders%20%24ReviewId%0A%20%20%20%20%20%20%20%20%20%20%20%20%24reviews%20%3D%20%40()%0A%20%20%20%20%20%20%20%20%20%20%20%20%24reviews%20%2B%3D%20%24reviewObj%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%24reviewObj%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24res%20%3D%20Get-GraphExampleAccessReviews%20%24authHeaders%20%24BusinessFlowTemplateId%0A%0A%20%20%20%20return%20%24res%20%0A%7D%0A%0A%0A%23%23%23%0A%0Aexport-modulemember%20-function%20Connect-AzureADMSARSample%0Aexport-modulemember%20-function%20Get-AzureADMSARSampleAccessReview%0Aexport-modulemember%20-function%20New-AzureADMSARSampleAccessReview%0A%0A%0A%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-LABS%20id%3D%22lingo-labs-807241%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EAccess%20Management%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EAzure%20AD%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EIdentity%20Management%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E
Mark Wahl
Microsoft

The Azure AD access reviews feature is part of Microsoft Graph, with a list of methods at https://docs.microsoft.com/en-us/graph/api/resources/accessreviews-root?view=graph-rest-beta.  An earlier blog post included an example of how a user, such as a Security Reader, could retrieve all the programs, controls and access reviews via Microsoft Graph, in PowerShell.

 

In this post, I'll show an example PowerShell script that uses the new application permission AccessReview.ReadWrite.Membership. . Application permissions don’t need the app to have a logged in user to call Graph, so you can use this to automatically to create and retrieve access reviews from scheduled jobs or as part of your existing automation.

 

Code Sample Prerequisite #1: Azure AD PowerShell

To set up this code sample, you’ll need an Azure AD tenant where you’re a global administrator. In this example, as with the previous blog post, the sample code to use the API leverages the ADAL library to retrieve an access token used by Microsoft Graph. The ADAL library is automatically installed when you install Azure AD PowerShell cmdlets. So before you begin, ensure that you have PowerShell 3.0 or later,.NET Framework 4.5 and either the Azure AD PowerShell v2 General Availability or Preview modules installed on your computer. If you don’t have Azure AD PowerShell installed yet, see https://docs.microsoft.com/en-us/powershell/azure/active-directory/install-adv2?view=azureadps-2.0. Try the Connect-AzureAD command to ensure that you can authenticate to Azure AD as a global administrator.  Also try Get-AzureADUser to make sure you can retrieve users, as you'll need a user ID later on.

 

Code Sample Prerequisite #2: Azure AD access reviews

This example assumes you have already onboarded Azure AD access reviews in your tenant directory.  If you have already done so, then skip to the next section “Register an Azure AD application”.  Otherwise, continue with these steps to ensure the feature is onboarded so the APIs will allow access reviews to be created and return some data.

  1. Log into the Azure portal as a global administrator.
  2. Ensure that your organization has Azure AD Premium P2 or EMS E5 subscription active. If not, click https://portal.azure.com/#blade/Microsoft_AAD_IAM/TryBuyProductBlade and activate a trial of Enterprise Mobility + Security E5. Otherwise, if your organization has an active subscription, continue at the next step.
  3. Navigate to Azure Active Directory, and then click Identity Governance on the left hand side.
  4. Click Access reviews. If no one has onboarded Azure AD access reviews in your organization, onboard it now.

Register an Azure AD application

Next, you'll need to create an app registration with the new permission, to allow your application to call the access reviews API in Microsoft Graph. If you haven’t created an app registration lately, the user interface in the Azure portal has changed. Here’s how to create an app with the updated UI.

 

  1. Log into the Azure portal as a global administrator.
  2. In the Azure portal, go to Azure Active Directory, and then click App registrations on the left.
  3. Click New registration. Give your app a name, and then click Register.
  4. Copy and save for later the application (client) ID that appears after the app is registered.
  5. On the left, click API permissions.
  6. Click Add a permission, click Microsoft Graph, and then click Application permissions.

 

 
  1. In the Select permissions list, expand AccessReview and select AccessReview.ReadWrite.Membership.

 

 

 

 

  1. While here, though not required for this sample, you might want to expand Group and give the app the permission Group.Read.All, and expand User and give the app the User.Read.All permission,
  2. Click Add permissions.
  3. Click to Grant admin consent for <your tenant> and then click Yes. The status for each permission the app needs should change to a green checkmark, indicating consent was granted.

 

 

 

  1. On the left, click Certificates & secrets.
  2. Click New client secret and then for Expires select Never.
  3. Click Add.
  4. Copy and save locally the value of the secret that appears- you won’t see it again after you leave this part of the UI.

 

At this point, you’ll have a client app ID and a client secret. In real life you'd probably want to store the secret in Azure Automation, Azure Key Vault, or similar.

 

Create and retrieve access reviews using Graph

 

Next, here's how to try out Microsoft Graph API requests when authenticated as an application, using a PowerShell script to be your application. I'll assume you have Azure AD v2 PowerShell cmdlets already installed - the script uses the Azure AD library included in those modules for authentication.

  1. Save the PowerShell below to a file named sample-ar-app-permissions.psm1.
  2. Open a new PowerShell window, change to the directory where the file is located and type Import-Module .\sample-ar-app-permissions.psm1

  3. Type Connect-AzureADMSARSample. This obtains a token needed for the service principal to call Graph. You’ll be prompted to provide the following information:
  • ClientApplicationId
  • ClientSecret
  • TenantDomain (e.g. demo….onmicrosoft.com)
  1. To create a new access review, use the command New-AzureADMSARSampleAccessReview. To try out this command, you’ll need to have an Azure AD group with members and owners – the owners will be the reviewers. You’ll be prompted to provide the following information:
  • DisplayName: (a display name for the access review)
  • ReviewedEntityId: (the object ID of a group whose members are to be reviewed)
  • OwnerUserId: (the object ID of a user such as an admin who will be listed as the owner of a review – since apps can’t own access reviews)

If successful, the command will return the ID of the new access review. If you see an error about permissions, please note that app registration may take a few minutes to be set up in the directory – if the Graph calls don’t work right away, try again an hour later.

  1. Type Get-AzureADMSARSampleAccessReview to see the access review that you've created.

 

I expect we’ll bring commands to create and query access reviews into the Azure AD PowerShell module in the future, which will remove the need for Connect-AzureADMSARSample. Please let us know about any other feedback/suggestions you have for more code samples. Thanks, Mark Wahl

 

 

# Example for creating and retrieving the results of an Azure AD access review via Microsoft Graph using application permissions
#
# This material is provided "AS-IS" and has no warranty.
# 
# Last updated August 2019
#
# This example is adapted from the documentation example located at 
# https://docs.microsoft.com/en-us/intune/intune-graph-apis
#
#

# the following functions are from Intune graph API samples, adapted for service principal authentication

function Get-GraphExampleAuthTokenServicePrincipal {
    [cmdletbinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        $ClientId,

        [Parameter(Mandatory = $true)]
        $ClientSecret,

        [Parameter(Mandatory = $true)]
        $TenantDomain
    )


    $tenant = $TenantDomain
    

    Write-Verbose "Checking for AzureAD module..."

    $AadModule = Get-Module -Name "AzureAD" -ListAvailable
    if ($AadModule -eq $null) {
        write-verbose "AzureAD PowerShell module not found, looking for AzureADPreview"
        $AadModule = Get-Module -Name "AzureADPreview" -ListAvailable
    }

    if ($AadModule -eq $null) {
        write-output
        write-error "AzureAD Powershell module not installed..."
        write-output "Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt"
        write-output "Script can't continue..."
        write-output
        return ""
    }

    # Getting path to ActiveDirectory Assemblies
    # If the module count is greater than 1 find the latest version

    if ($AadModule.count -gt 1) {
        write-verbose "multiple module versions"
        $Latest_Version = ($AadModule | select version | Sort-Object)[-1]
        $aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version }
        $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
        $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
    }

    else {
        write-verbose "single module version"
        $adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
        $adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
    }

    Write-verbose "loading $adal and $adalforms"


    [System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
    [System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null

    write-verbose "DLLs loaded"
  
    # $redirectUri = "urn:ietf:wg:oauth:2.0:oob"
    $resourceAppIdURI = "https://graph.microsoft.com"

    $authority = "https://login.microsoftonline.com/$Tenant"

    try {
        write-verbose "instantiating ADAL objects for $authority"
        $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority

        write-verbose "client $ClientId $clientSecret"

        $clientCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential" -ArgumentList ($ClientId,$ClientSecret)
 
        write-verbose "acquiring token for $resourceAppIdURI"
        #   AuthenticationResult authResult = await authContext.AcquireTokenAsync(BatchResourceUri, new ClientCredential(ClientId, ClientKey));
        # if you get an error about PowerShell not being able to find this method with 2 parameters, it means there is another version of ADAL DLL already in the process space of your PowerShell environment.

        $authResult = $authContext.AcquireTokenAsync($resourceAppIdURI, $clientCredential).Result
        # If the accesstoken is valid then create the authentication header
        if ($authResult.AccessToken) {
            write-verbose "acquired token"
            # Creating header for Authorization token
            $authHeader = @{
                'Content-Type' = 'application/json'
                'Authorization' = "Bearer " + $authResult.AccessToken
                'ExpiresOn' = $authResult.ExpiresOn
            }
            return $authHeader
        }
        else {
            write-output ""
            write-output "Authorization Access Token is null, please re-run authentication..."
            write-output ""
            break
        }
    }
    catch {
        write-output $_.Exception.Message
        write-output $_.Exception.ItemName
        write-output ""
        break
    }   
}

$_SampleInternalAuthNHeaders = @()

# exported module member
function Connect-AzureADMSARSample { 
    [CmdletBinding()]
    param(
    [Parameter(Mandatory=$true)]
    [ValidateScript({
        try {
            [System.Guid]::Parse($_) | Out-Null
            $true
        } catch {
            throw "$_ is not a valid GUID"
        }
    })]
    [string]$ClientApplicationId,

    [Parameter(Mandatory=$true)]
    [string]$ClientSecret,  # base64 client secret.  Note this as a command line parameter is for testing purposes only

    [Parameter(Mandatory=$true)]
    [string]$TenantDomain # e.g., microsoft.onmicrosoft.com
    )
   
    $script:_SampleInternalAuthNHeaders = @()


    $authHeaders = Get-GraphExampleAuthTokenServicePrincipal -ClientId $ClientApplicationId -ClientSecret $ClientSecret -TenantDomain $TenantDomain

    $script:_SampleInternalAuthNHeaders = $authHeaders

}


function Get-InternalAuthNHeaders {
  [CmdletBinding()]
  param()
  
    try {
    
        $authResult = $script:_SampleInternalAuthNHeaders
        if ($authResult.Length -eq @()) {
             Throw "Connect-AzureADMSARSample must be called first"   
        }
  
    } catch {
        Throw # "Connect-AzureADMSControls must be called first"
    }
    return $authResult
}


function New-GraphExampleAccessReview($authHeaders,$displayName,$reviewedObjectId,$reviewerType,$businessFlowTemplateId,$description,$durationInDays,$ownerUserId) {


    $recurrenceSettings = @{
        recurrenceType = "onetime";
        recurrenceEndType = "endBy";
        durationInDays = 0;
        recurrenceCount = 0;
    }

    $autoReviewSettings = @{
        notReviewedResult = "Approve"  # also use "Deny" or "Recommendation"
    }

    $settings = @{
        mailNotificationsEnabled = $true;
        remindersEnabled = $true;
        justificationRequiredOnApproval = $false;
        autoReviewEnabled = $true;
        activityDurationInDays = 30;
        autoApplyReviewResultsEnabled = $false;
        accessRecommendationsEnabled = $true;
        recurrenceSettings = $recurrenceSettings;
        autoReviewSettings = $autoReviewSettings;
    }
    
    $reviewedEntity = [pscustomobject]@{
        id = $reviewedObjectId
    }

    $owner = [pscustomobject]@{
        id = $ownerUserId
    }

    $now = Get-Date
    $ts = Get-Date $now.ToUniversalTime() -format "s"
    $startDate = $ts + "Z"
    $ts = Get-Date $now.AddDays($durationInDays).ToUniversalTime() -format "s"
    $endDate = $ts + "Z"

    $bodyObj = [pscustomobject]@{
        displayName = $displayName;
        startDateTime = $startDate;
        endDateTime = $endDate;
        reviewedEntity = $reviewedEntity;
        reviewerType = $reviewerType;
        businessFlowTemplateId = $businessFlowTemplateId;
        description = $description;
        settings = $settings;
        createdBy = $owner;
    }

    #         

    $body = ConvertTo-Json $bodyObj -compress


    # ensure it contains  "Content-Type" = "application/json";

    $requestHeadersp = @{
        "Content-Length" = $body.Length
    }
    $requestHeadersp += $authHeaders
    
    $uri1 = "https://graph.microsoft.com/beta/accessReviews"

    $resp1 = Invoke-WebRequest -UseBasicParsing -Headers $requestHeadersp -Uri $uri1 -Method Post -Body $body
 
    if ($resp1 -eq $null -or $resp1.Content -eq $null) {
        throw "error repsonse from $uri1"
     }

    $val1 = ConvertFrom-Json $resp1.Content

    return $val1.id
}


function New-AzureADMSARSampleAccessReview {
    [CmdletBinding()]
    param(
    [Parameter(Mandatory=$true)]
    [string]$DisplayName,  # of the review to create 

    [Parameter()]
    [string]$Description = "", # of the review to create

    [Parameter()]
    [int]$DurationInDays=30,

    [Parameter(Mandatory=$true)]
    [ValidateScript({
        try {
            [System.Guid]::Parse($_) | Out-Null
            $true
        } catch {
            throw "$_ is not a valid GUID"
        }
    })]
    [string]$ReviewedEntityId,

    [Parameter()]
        [ValidateScript({
            try {
                [System.Guid]::Parse($_) | Out-Null
                $true
            } catch {
                throw "$_ is not a valid GUID"
            }
        })]
    [string]$BusinessFlowTemplateId = "6e4f3d20-c5c3-407f-9695-8460952bcc68",
    #business flow template 6e4f3d20-c5c3-407f-9695-8460952bcc68 for Access reviews of memberships of a group
   

    [Parameter()]
    [string]$ReviewerType = "entityOwners",

    [Parameter(Mandatory=$true)]
    [ValidateScript({
        try {
            [System.Guid]::Parse($_) | Out-Null
            $true
        } catch {
            throw "$_ is not a valid GUID"
        }
    })]
    [string]$OwnerUserId  # a user who has an email address
    )

    $authHeaders = Get-InternalAuthNHeaders

    $reviewId = New-GraphExampleAccessReview $authHeaders $DisplayName $ReviewedEntityId $ReviewerType $BusinessFlowTemplateId $Description $durationInDays $OwnerUserId

    return $reviewId
}



function Get-GraphExampleAccessReviews($authHeaders,$businessFlowTemplateId)
{

    $uri1 = 'https://graph.microsoft.com/beta/accessReviews?$filter=businessFlowTemplateId%20eq%20' +  "'" + $businessFlowTemplateId + "'"

    $results = @()

    do {

        $resp1 = Invoke-WebRequest -UseBasicParsing -headers $authHeaders -Uri $uri1 -Method Get

        if ($resp1 -eq $null -or $resp1.Content -eq $null) {
            throw "error response from $uri1"
         }

        $val1 = ConvertFrom-Json $resp1.Content

        foreach ($i in $val1.value) {

                $results += $i
            
        }
        

        $uri1 = $val1.'@odata.nextLink'
        # Odata list may have more

    } while ($uri1 -ne $null)


    return $results

}

function Get-GraphExampleAccessReview($authHeaders,$reviewId)
{
    $uri1 = "https://graph.microsoft.com/beta/accessReviews/" + $reviewId

    $resp1 = Invoke-WebRequest -UseBasicParsing -headers $authHeaders -Uri $uri1 -Method Get

    if ($resp1 -eq $null -or $resp1.Content -eq $null) {
        throw "error response from $uri1"
     }
    
    $val1 = ConvertFrom-Json $resp1.Content

    return $val1

}

function Get-AzureADMSARSampleAccessReview {
    [CmdletBinding()]
    param(
        [Parameter()]
        [ValidateScript({
            try {
                [System.Guid]::Parse($_) | Out-Null
                $true
            } catch {
                throw "$_ is not a valid GUID"
            }
        })]
        [string]$ReviewId,

        [Parameter()]
        [ValidateScript({
            try {
                [System.Guid]::Parse($_) | Out-Null
                $true
            } catch {
                throw "$_ is not a valid GUID"
            }
        })]
        [string]$BusinessFlowTemplateId = "6e4f3d20-c5c3-407f-9695-8460952bcc68"
    )

       
#business flow template 842169fe-e1b7-4ce9-98b6-6a9db02eec6b for Access reviews of guest user memberships of a group
#business flow template 7fbc909b-efe1-4c72-8ae6-99cb30b882de for Access reviews of guest user assignments to an application
#business flow template 50839a84-e23c-44a7-a8cc-16e162afc656 for Access reviews of assignments to an application
#business flow template 6e4f3d20-c5c3-407f-9695-8460952bcc68 for Access reviews of memberships of a group


    $authHeaders = Get-InternalAuthNHeaders

    if ($ReviewId -ne $null) {
        if ($ReviewId.Length -ge 1) {
           $reviewObj = Get-GraphExampleAccessReview $authHeaders $ReviewId
            $reviews = @()
            $reviews += $reviewObj
            return $reviewObj
        }
    }

    $res = Get-GraphExampleAccessReviews $authHeaders $BusinessFlowTemplateId

    return $res 
}


###

export-modulemember -function Connect-AzureADMSARSample
export-modulemember -function Get-AzureADMSARSampleAccessReview
export-modulemember -function New-AzureADMSARSampleAccessReview


 

 

Related Conversations
Tabs and Dark Mode
cjc2112 in Discussions on
38 Replies
Extentions Synchronization
Deleted in Discussions on
3 Replies
flashing a white screen while open new tab
Deleted in Discussions on
14 Replies
Stable version of Edge insider browser
HotCakeX in Discussions on
35 Replies
Security Community Webinars
Valon_Kolica in Security, Privacy & Compliance on
13 Replies