AzureADPIM.psm1
$script:URLs = @{ LoginURL = "https://login.microsoft.com" Resource = "https://graph.microsoft.com" PrivilegedRoles = "https://graph.microsoft.com/beta/privilegedRoles" PrivilegedRoleAssignments = "https://graph.microsoft.com/beta/privilegedRoleAssignments" PrivilegedRoleAssignmentRequests = "https://graph.microsoft.com/beta/privilegedRoleAssignmentRequests" PrivilegedOperationEvents = "https://graph.microsoft.com/beta/PrivilegedOperationEvents" } $script:OAuth = $null $script:AzureADAdmin = $null Function Connect-AzureADPIM { <# .SYNOPSIS Authenticates to Azure AD and Microsoft Graph API app to get an OAuth token .DESCRIPTION Authenticates to Azure AD and Microsoft Graph API app to get an OAuth token. The token must be stored in a variable. This token can be passed to other cmdlets in this module to provide authentication. Before using this you must set up an app registration in Azure AD with the following permissions: Microsoft Graph API: -Delegated: Directory.AccessAsUser.All PrivilegedAccess.ReadWrite.AzureAD PrivilegedAccess.ReadWrite.AzureResources User.Read -Application: Directory.Read.All Directory.ReadWrite.All .EXAMPLE $OAuth = Connect-AzureADPIM -TenantDomain yourtenant.onmicrosoft.com -ClientId 27450a41-2843-4ba2-bc16-9df3dbe72cca -ClientSecret 'MR8Ur/J*N8fgEyIY' .Parameter TenantDomain Specify a the Azure AD tenant domain: yourtenant.onmicrosoft.com .Parameter ClientId Specify the client id for the Microsoft Graph API app you've created in Azure AD .Parameter ClientSecret Specify the client secret for the Microsoft Graph API app you've created in Azure AD .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding()] Param ( [Parameter(Mandatory)] [ValidateScript({ $_ -like "*.onmicrosoft.com" })] [String]$TenantDomain, [Parameter(Mandatory)] [ValidateScript({try { [System.Guid]::Parse($_); $True } catch { $False }})] [String]$ClientId, [Parameter(Mandatory)] [String]$ClientSecret, [pscredential]$Credential ) Begin { if (-Not (Get-Module -Name AzureADPreview -ListAvailable)) { Install-Module -Name AzureADPreview } Import-Module -Name AzureADPreview -Global } Process { if (-Not $PSBoundParameters.ContainsKey('Credential')) { $Credential = Get-Credential -Message "Azure AD Administrator Credentials" } $Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password)) # Connect to Azure AD $script:AzureADAdmin = Connect-AzureAD -Credential $Credential # Authenticate to Microsoft Graph API $Body = @{ client_id = $ClientID client_secret = $ClientSecret username = $Credential.UserName password = $Password grant_type = 'password' resource = $URLs.Resource scope = 'openid' } $Result = Invoke-RestMethod -Method Post -Uri "$($URLs.LoginURL)/$TenantDomain/oauth2/token" -Body $Body $script:OAuth = $Result Write-Output -InputObject $Result } End { } } Function Get-AzureADPIMRole { <# .SYNOPSIS Get a list of all Azure AD Roles managed by Azure AD Privileged Identity Management .DESCRIPTION Get a list of all Azure AD Roles managed by Azure AD Privileged Identity Management .EXAMPLE $OAuth | Get-AzureADPIMRole .EXAMPLE Get-AzureADPIMRole -OAuth $OAuth .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding()] Param ( [ValidateScript({try { [System.Guid]::Parse($_); $True } catch { $False }})] [String]$Id, [SupportsWildcards()] [String]$Name = "*", [ValidateScript({ $null -ne $_.access_token })] [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { if ($PSBoundParameters.ContainsKey("Id")) { # Fetch data about all privileged roles $Result = (Invoke-WebRequest -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoles)/$Id").Content | ConvertFrom-Json } else { # Fetch data about all privileged roles $Result = ((Invoke-WebRequest -UseBasicParsing -Headers $HeaderParams -Uri $URLs.PrivilegedRoles).Content | ConvertFrom-Json).Value } Write-Output -InputObject ($Result | Where-Object Name -like $Name) } End { } } Function Get-AzureADPIMRoleSetting { <# .SYNOPSIS Get settings for one or more Azure AD PIM Roles .DESCRIPTION Get settings for one or more Azure AD PIM Roles .EXAMPLE Get-AzureADPIMRoleSetting -Id fe930be7-5e62-47db-91af-98c3a49a38b1 -OAuth $OAuth .EXAMPLE Get-AzureADPIMRole -Name 'Global Administrator' | Get-AzureADPimRoleSetting .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding(DefaultParameterSetName = "byId")] Param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, ParameterSetName = "byId")] [ValidateScript({try { [System.Guid]::Parse($_); $True } catch { $False }})] [String]$Id, [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "byName")] [String]$Name, [ValidateScript({ $null -ne $_.access_token })] [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { if ($PSBoundParameters.ContainsKey("Name")) { $Id = Get-AzureADPIMRole -OAuth $OAuth -Name $Name | Select-Object -ExpandProperty Id } $Result = (Invoke-WebRequest -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoles)/$Id/Settings").Content | ConvertFrom-Json Write-Output -InputObject $Result } End { } } Function Get-AzureADPIMRoleSummary { <# .SYNOPSIS Get summary information for one or more Azure AD PIM Roles .DESCRIPTION Get summary information for one or more Azure AD PIM Roles .EXAMPLE Get-AzureADPIMRoleSummary -Id fe930be7-5e62-47db-91af-98c3a49a38b1 .EXAMPLE Get-AzureADPIMRoles | Get-AzureADPIMRoleSummary .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding(DefaultParameterSetName = "byId")] Param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, ParameterSetName = "byId")] [ValidateScript({try { [System.Guid]::Parse($_); $True } catch { $False }})] [String]$Id, [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "byName")] [String]$Name, [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { if ($PSBoundParameters.ContainsKey("Name")) { $Id = Get-AzureADPIMRole -OAuth $OAuth -Name $Name | Select-Object -ExpandProperty Id } $Result = (Invoke-WebRequest -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoles)/$Id/summary").Content | ConvertFrom-Json Write-Output -InputObject $Result } End { } } Function Get-AzureADPIMAssignment { <# .SYNOPSIS Get assignments for one or more Azure AD PIM Roles or admins .DESCRIPTION Get assignments for one or more Azure AD PIM Roles or admins .EXAMPLE Get-AzureADPIMAssignment .EXAMPLE Get-AzureADPIMAssignment -RoleName 'Global Administrator' .EXAMPLE Get-AzureADPIMAssignment -UserPrincipalName *admin_martin* .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding()] Param ( [Parameter(ValueFromPipelineByPropertyName)] [ValidateScript({try { [System.Guid]::Parse($_); $True } catch { $False }})] [String]$RoleId, [Parameter(ValueFromPipelineByPropertyName)] [String]$RoleName, [Parameter(ValueFromPipelineByPropertyName)] [SupportsWildcards()] [String]$UserPrincipalName = "*", [SupportsWildcards()] [String]$AssignmentId = "*", [Switch]$My, [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { if ($PSBoundParameters.ContainsKey("RoleName")) { $RoleId = Get-AzureADPIMRole -OAuth $OAuth -Name $RoleName | Select-Object -ExpandProperty Id } if ($PSBoundParameters.ContainsKey("RoleName") -or $PSBoundParameters.ContainsKey("RoleId")) { $Result = (Invoke-WebRequest -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoles)/$RoleId/assignments").Content | ConvertFrom-Json } else { $Result = (Invoke-WebRequest -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoleAssignments)").Content | ConvertFrom-Json } if ($My.IsPresent) { $UserPrincipalName = $script:AzureADAdmin.Account.Id } $Roles = Get-AzureADPIMRole -OAuth $OAuth $Result.Value | ForEach-Object ` { $User = Get-AzureADUser -ObjectId $_.userId $Role = $Roles | Where-Object Id -eq $_.roleId New-Object -TypeName psobject -Property @{ AssignmentId = $_.Id UserId = $_.userId RoleId = $Role.Id User = $User.UserPrincipalName Role = $Role.Name IsElevated = $_.isElevated ExpirationDateTime = $_.expirationDateTime ResultMessage = $_.resultMessage } } | Where-Object { $_.User -like $UserPrincipalName -and $_.AssignmentId -like $AssignmentId } } End { } } Function New-AzureADPIMRoleAssignment { <# .SYNOPSIS Create an Azure AD PIM Role assignment for one administrator .DESCRIPTION Create an Azure AD PIM Role assignment for one administrator .EXAMPLE New-AzureADPIMRoleAssignment -RoleId 729827e3-9c14-49f7-bb1b-9608f156bbb8 -UserPrincipalName admin_traale@preprodbanenor.onmicrosoft.com .EXAMPLE New-AzureADPIMRoleAssignment -RoleName 'HelpDesk Administrator' -UserPrincipalName admin_traale@preprodbanenor.onmicrosoft.com .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding()] Param ( [Parameter(Mandatory, ParameterSetName = 'byId')] [ValidateScript({try { [System.Guid]::Parse($_); $True } catch { $False }})] [String]$RoleId, [Parameter(Mandatory, ParameterSetName = 'byName')] [String]$RoleName, [Parameter(Mandatory, ParameterSetName = 'byId')] [Parameter(Mandatory, ParameterSetName = 'byName')] [String]$UserPrincipalName, [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { if ($PSBoundParameters.ContainsKey("RoleName")) { $RoleId = Get-AzureADPIMRole -OAuth $OAuth -Name $RoleName | Select-Object -ExpandProperty Id } $UserId = Get-AzureADUser -SearchString $UserPrincipalName | Select-Object -ExpandProperty ObjectId $AssignRole = @{ userId = $UserId roleId = $RoleId } $Result = (Invoke-WebRequest -Method Post -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoleAssignments)" -Body $AssignRole).Content | ConvertFrom-Json Write-Output $Result } End { } } Function Remove-AzureADPIMAssignment { <# .SYNOPSIS Removes an Azure AD PIM Role assignment .DESCRIPTION Removes an Azure AD PIM Role assignment .EXAMPLE Remove-AzureADPIMAssignment -AssignmentId 5a0e1f49-52a9-44f1-bfc1-bbe532327e38_729827e3-9c14-49f7-bb1b-9608f156bbb8 .EXAMPLE Get-AzureADPIMAssignment -UserPrincipalName *admin_martin* | Remove-AzureADPIMAssignment .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact='High')] Param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [String]$AssignmentId, [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { $Assignment = Get-AzureADPIMAssignment -AssignmentId $AssignmentId -OAuth $OAuth if ($PSCmdlet.ShouldProcess($Assignment.User, "Remove assignment on role $($Assignment.Role)")) { (Invoke-WebRequest -Method Delete -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoleAssignments)/$AssignmentId").Content } } End { } } Function Set-AzureADPIMAssignmentType { <# .SYNOPSIS Set an Azure AD PIM Role assignment as eligible or permanent .DESCRIPTION Set an Azure AD PIM Role assignment as eligible or permanent .EXAMPLE Set-AzureADPIMAssignmentType -AssignmentId 5a0e1f49-52a9-44f1-bfc1-bbe532327e38_729827e3-9c14-49f7-bb1b-9608f156bbb8 -Type Permanent .EXAMPLE Get-AzureADPIMAssignment -UserPrincipalName *admin_martin* -RoleName 'Reports Reader' | Set-AzureADPIMAssignmentType -Type Eligible .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact='High')] Param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [String]$AssignmentId, [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateSet('Eligible', 'Permanent')] [String]$Type, [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { $Assignment = Get-AzureADPIMAssignment -AssignmentId $AssignmentId -OAuth $OAuth if ($PSCmdlet.ShouldProcess($Assignment.User, "Change assignment on role $($Assignment.Role) to $Type")) { $Result = (Invoke-WebRequest -Method Post -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoleAssignments)/$AssignmentId/make$Type").Content | ConvertFrom-Json } $Result } End { } } Function New-AzureADPIMAssignmentRequest { <# .SYNOPSIS Create a new Azure AD PIM Role assignment request .DESCRIPTION Create a new Azure AD PIM Role assignment request. Roles that require Multi-Factor Authentication is not going to work. .EXAMPLE New-AzureADPIMAssignmentRequest -RoleName 'HelpDesk Administrator' -Reason 'Reset users password' -Duration 1 .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding(DefaultParameterSetName = 'byId')] Param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'byId')] [ValidateScript({try { [System.Guid]::Parse($_); $True } catch { $False }})] [String]$RoleId, [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'byName')] [String]$RoleName, [ValidateRange(1, 72)] [Int]$Duration = 3, [Parameter(Mandatory)] [ValidateLength(1, 500)] [String]$Reason, [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { if ($PSBoundParameters.ContainsKey("RoleName")) { $RoleId = Get-AzureADPIMRole -OAuth $OAuth -Name $RoleName | Select-Object -ExpandProperty Id } $Request = @{ roleId = $RoleId type = 'UserAdd' duration = $Duration reason = $Reason } Try { $Result = (Invoke-WebRequest -Method Post -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.privilegedRoleAssignmentRequests)" -Body $Request).Content | ConvertFrom-Json Write-Output $Result } Catch { if ("$_" -like "*(403) Forbidden*") { Write-Error -Message "This role requires MFA, and is thus not supported by this module." } } } End { } } Function Get-AzureADPIMAssignmentRequest { <# .SYNOPSIS Get Azure AD PIM Role assignment requests .DESCRIPTION Get Azure AD PIM Role assignment requests .EXAMPLE Get-AzureADPIMAssignmentRequest .EXAMPLE Get-AzureADPIMAssignmentRequest -My .EXAMPLE Get-AzureADPIMAssignmentRequest -RoleName 'HelpDesk Administrator' .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding()] Param ( [Parameter(ValueFromPipelineByPropertyName)] [ValidateScript({try { [System.Guid]::Parse($_); $True } catch { $False }})] [String]$RoleId, [Parameter(ValueFromPipelineByPropertyName)] [String]$RoleName, [Parameter(ValueFromPipelineByPropertyName)] [SupportsWildcards()] [String]$UserPrincipalName = "*", [Switch]$My, [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { if ($PSBoundParameters.ContainsKey("RoleName")) { $RoleId = Get-AzureADPIMRole -OAuth $OAuth -Name $RoleName | Select-Object -ExpandProperty Id } $Result = ((Invoke-WebRequest -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedRoleAssignmentRequests)").Content | ConvertFrom-Json).Value if ($PSBoundParameters.ContainsKey("RoleName") -or $PSBoundParameters.ContainsKey("RoleId")) { $Result = $Result | Where-Object roleId -eq $RoleId } if ($My.IsPresent) { $UserPrincipalName = $script:AzureADAdmin.Account.Id } $Roles = Get-AzureADPIMRole -OAuth $OAuth $Result | ForEach-Object ` { $User = Get-AzureADUser -ObjectId $_.userId $Role = $Roles | Where-Object Id -eq $_.roleId New-Object -TypeName psobject -Property @{ RequestId = $_.Id UserId = $_.userId RoleId = $Role.Id User = $User.UserPrincipalName Role = $Role.Name AssignmentState = $_.assignmentState RequestedDateTime = $_.requestedDateTime Status = $_.status Duration = $_.duration Reason = $_.Reason TicketNumber = $_.ticketNumber TicketSystem = $_.ticketSystem Schedule = $_.schedule } } | Where-Object { $_.User -like $UserPrincipalName } } End { } } Function Get-AzureADPIMAuditEvent { <# .SYNOPSIS Get Azure AD PIM audit events .DESCRIPTION Get Azure AD PIM audit events .EXAMPLE Get-AzureADPIMAuditEvent .NOTES Author: Martin Norlunn Updated: 08.09.2019 #> [CmdletBinding()] Param ( [PSCustomObject]$OAuth ) Begin { if (-Not $PSBoundParameters.ContainsKey('OAuth')) { $OAuth = $script:OAuth } $HeaderParams = @{ Authorization = "$($OAuth.token_type) $($OAuth.access_token)" } } Process { $Result = (Invoke-WebRequest -UseBasicParsing -Headers $HeaderParams -Uri "$($URLs.PrivilegedOperationEvents)").Content | ConvertFrom-Json Write-Output -InputObject $Result.Value } End { } } |