Skip to content

Commit

Permalink
Merge pull request #36 from KelvinTegelaar/master
Browse files Browse the repository at this point in the history
[pull] master from KelvinTegelaar:master
  • Loading branch information
pull[bot] authored Jun 14, 2024
2 parents e3adedc + 285e24c commit 68f1bf5
Show file tree
Hide file tree
Showing 19 changed files with 323 additions and 66 deletions.
22 changes: 22 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Editor configuration, see http://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
insert_final_newline = true

[*.{ps1, psd1, psm1}]
indent_size = 4
end_of_line = crlf
trim_trailing_whitespace = true

[*.json]
indent_size = 2
end_of_line = crlf
trim_trailing_whitespace = true

[*.{md, txt}]
end_of_line = crlf
max_line_length = off
trim_trailing_whitespace = false
4 changes: 3 additions & 1 deletion Cache_SAMSetup/SAMManifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@
{ "id": "885f682f-a990-4bad-a642-36736a74b0c7", "type": "Scope" },
{ "id": "913b9306-0ce1-42b8-9137-6a7df690a760", "type": "Role" },
{ "id": "cb8f45a0-5c2e-4ea1-b803-84b870a7d7ec", "type": "Scope" },
{ "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" }
{ "id": "4c06a06a-098a-4063-868e-5dfee3827264", "type": "Scope" },
{ "id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9", "type": "Role" },
{ "id": "e67e6727-c080-415e-b521-e3f35d5248e9", "type": "Scope" }
]
},
{
Expand Down
6 changes: 2 additions & 4 deletions Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ function Test-CIPPAccess {
$Request,
[switch]$TenantList
)

if ($Request.Params.CIPPEndpoint -eq 'ExecSAMSetup') { return $true }
if (!$Request.Headers.'x-ms-client-principal') {
# Direct API Access
$CustomRoles = @('CIPP-API')
Expand Down Expand Up @@ -47,7 +47,6 @@ function Test-CIPPAccess {
$Permission.AllowedTenants | Where-Object { $Permission.BlockedTenants -notcontains $_ }
}
}
Write-Information ($LimitedTenantList | ConvertTo-Json)
return $LimitedTenantList
}

Expand Down Expand Up @@ -77,11 +76,10 @@ function Test-CIPPAccess {
} else {
$Tenant = ($Tenants | Where-Object { $Request.Query.TenantFilter -eq $_.customerId -or $Request.Body.TenantFilter -eq $_.customerId -or $Request.Query.TenantFilter -eq $_.defaultDomainName -or $Request.Body.TenantFilter -eq $_.defaultDomainName }).customerId
if ($Role.AllowedTenants -contains 'AllTenants') {
$AllowedTenants = $Tenants
$AllowedTenants = $Tenants.customerId
} else {
$AllowedTenants = $Role.AllowedTenants
}

if ($Tenant) {
$TenantAllowed = $AllowedTenants -contains $Tenant -and $Role.BlockedTenants -notcontains $Tenant
if (!$TenantAllowed) { continue }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ function Invoke-ExecCustomRole {
if ($Role.AllowedTenants) {
$Role.AllowedTenants = @($Role.AllowedTenants | ConvertFrom-Json)
} else {
$Role | Add-Member -NotePropertyName AllowedTenants -NotePropertyValue @()
$Role | Add-Member -NotePropertyName AllowedTenants -NotePropertyValue @() -Force
}
if ($Role.BlockedTenants) {
$Role.BlockedTenants = @($Role.BlockedTenants | ConvertFrom-Json)
} else {
$Role | Add-Member -NotePropertyName BlockedTenants -NotePropertyValue @()
$Role | Add-Member -NotePropertyName BlockedTenants -NotePropertyValue @() -Force
}
$Role
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
function Invoke-ExecPerUserMFA {
<#
.FUNCTIONALITY
Entrypoint
.ROLE
Identity.User.ReadWrite
#>
Param(
$Request,
$TriggerMetadata
)

$Request = @{
userId = $Request.Body.userId
TenantFilter = $Request.Body.TenantFilter
State = $Request.Body.State
executingUser = $Request.Headers.'x-ms-client-principal'
}
$Result = Set-CIPPPerUserMFA @Request
$Body = @{
Results = @($Result)
}
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $Body
})
}
20 changes: 9 additions & 11 deletions Modules/CIPPCore/Public/Get-CIPPMFAState.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ function Get-CIPPMFAState {
$APIName = 'Get MFA Status',
$ExecutingUser
)

$users = foreach ($user in (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?$select=id,UserPrincipalName,DisplayName,accountEnabled,assignedLicenses' -tenantid $TenantFilter)) {
$PerUserMFAState = Get-CIPPPerUserMFA -TenantFilter $TenantFilter -AllUsers $true
$users = foreach ($user in (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/users?$top=999&$select=id,UserPrincipalName,DisplayName,accountEnabled,assignedLicenses' -tenantid $TenantFilter)) {
[PSCustomObject]@{
UserPrincipalName = $user.UserPrincipalName
isLicensed = [boolean]$user.assignedLicenses.skuid
accountEnabled = $user.accountEnabled
DisplayName = $user.DisplayName
ObjectId = $user.id
StrongAuthenticationRequirements = @{StrongAuthenticationRequirement = @{state = 'See Documentation' } }
UserPrincipalName = $user.UserPrincipalName
isLicensed = [boolean]$user.assignedLicenses.skuid
accountEnabled = $user.accountEnabled
DisplayName = $user.DisplayName
ObjectId = $user.id
}
}

$SecureDefaultsState = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -tenantid $TenantFilter ).IsEnabled
$CAState = New-Object System.Collections.ArrayList

Expand Down Expand Up @@ -62,7 +61,6 @@ function Get-CIPPMFAState {
Write-Host 'Processing users'
$UserCAState = New-Object System.Collections.ArrayList
foreach ($CA in $CAState) {
Write-Host 'Looping CAState'
if ($CA -like '*All Users*') {
if ($ExcludeAllUsers -contains $_.ObjectId) { $UserCAState.Add("Excluded from $($policy.displayName) - All Users") | Out-Null }
else { $UserCAState.Add($CA) | Out-Null }
Expand All @@ -75,7 +73,7 @@ function Get-CIPPMFAState {
}
}

$PerUser = if ($_.StrongAuthenticationRequirements.StrongAuthenticationRequirement.state -ne $null) { $_.StrongAuthenticationRequirements.StrongAuthenticationRequirement.state } else { 'Disabled' }
$PerUser = if ($PerUserMFAState -eq $null) { $null } else { ($PerUserMFAState | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName).PerUserMFAState }

$MFARegUser = if (($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName).IsMFARegistered -eq $null) { $false } else { ($MFARegistration | Where-Object -Property UserPrincipalName -EQ $_.UserPrincipalName) }

Expand Down
34 changes: 34 additions & 0 deletions Modules/CIPPCore/Public/Get-CIPPPerUserMFA.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
function Get-CIPPPerUserMFA {
[CmdletBinding()]
param(
$TenantFilter,
$userId,
$executingUser,
$AllUsers = $false
)
try {
if ($AllUsers -eq $true) {
$AllUsers = New-graphGetRequest -Uri "https://graph.microsoft.com/beta/users?`$top=999&`$select=UserPrincipalName,Id" -tenantid $tenantfilter
$Requests = foreach ($id in $AllUsers.userPrincipalName) {
@{
id = $int++
method = 'GET'
url = "users/$id/authentication/requirements"
}
}
$Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true
if ($Requests.body) {
$UsersWithoutMFA = $Requests.body | Select-Object peruserMFAState, @{Name = 'UserPrincipalName'; Expression = { [System.Web.HttpUtility]::UrlDecode($_.'@odata.context'.split("'")[1]) } }
return $UsersWithoutMFA
}
} else {
$MFAState = New-graphGetRequest -Uri "https://graph.microsoft.com/beta/users/$($userId)/authentication/requirements" -tenantid $tenantfilter
return [PSCustomObject]@{
PerUserMFAState = $MFAState.perUserMfaState
UserPrincipalName = $userId
}
}
} catch {
"Failed to get MFA State for $id : $_"
}
}
11 changes: 8 additions & 3 deletions Modules/CIPPCore/Public/Get-CIPPSchemaExtensions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ function Get-CIPPSchemaExtensions {
name = 'autoExpandingArchiveEnabled'
type = 'Boolean'
}
@{
name = 'perUserMfaState'
type = 'String'
}
)
}
)
Expand All @@ -40,18 +44,19 @@ function Get-CIPPSchemaExtensions {
$SchemaFound = $true
$Schema = $Schemas | Where-Object { $_.id -match $SchemaDefinition.id }
$Patch = @{}
if (Compare-Object -ReferenceObject ($SchemaDefinition.properties | Select-Object name, type) -DifferenceObject $Schema.properties) {
$Patch.properties = $Properties
if (Compare-Object -ReferenceObject ($SchemaDefinition.properties | Select-Object name, type) -DifferenceObject ($Schema.properties | Select-Object name, type)) {
$Patch.properties = $SchemaDefinitions.Properties
}
if ($Schema.status -ne 'Available') {
$Patch.status = 'Available'
}
if ($Schema.targetTypes -ne $SchemaDefinition.targetTypes) {
$Patch.targetTypes = $SchemaDefinition.targetTypes
}
if ($Patch.Keys.Count -gt 0) {
if ($Patch -and $Patch.Keys.Count -gt 0) {
Write-Information "Updating $($Schema.id)"
$Json = ConvertTo-Json -Depth 5 -InputObject $Patch
Write-Information $Json
New-GraphPOSTRequest -type PATCH -Uri "https://graph.microsoft.com/v1.0/schemaExtensions/$($Schema.id)" -Body $Json -AsApp $true -NoAuthCheck $true
} else {
$Schema
Expand Down
12 changes: 11 additions & 1 deletion Modules/CIPPCore/Public/GraphHelper/New-ExoRequest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,25 @@ function New-ExoRequest ($tenantid, $cmdlet, $cmdParams, $useSystemMailbox, $Anc
if ($cmdparams.Identity) { $Anchor = $cmdparams.Identity }
if ($cmdparams.anr) { $Anchor = $cmdparams.anr }
if ($cmdparams.User) { $Anchor = $cmdparams.User }
if ($cmdparams.mailbox) { $Anchor = $cmdparams.mailbox }

if (!$Anchor -or $useSystemMailbox) {
if (!$Tenant.initialDomainName) {
if (!$Tenant.initialDomainName -or $Tenant.initialDomainName -notlike '*onmicrosoft.com*') {
$OnMicrosoft = (New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains?$top=999' -tenantid $tenantid -NoAuthCheck $NoAuthCheck | Where-Object -Property isInitial -EQ $true).id
} else {
$OnMicrosoft = $Tenant.initialDomainName
}
$anchor = "UPN:SystemMailbox{8cc370d3-822a-4ab8-a926-bb94bd0641a9}@$($OnMicrosoft)"
}
#if the anchor is a GUID, try looking up the user.
if ($Anchor -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') {
$Anchor = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$Anchor" -tenantid $tenantid -NoAuthCheck $NoAuthCheck
if ($Anchor) {
$Anchor = $Anchor.UserPrincipalName
} else {
Write-Error "Failed to find user with GUID $Anchor"
}
}
}
Write-Host "Using $Anchor"
$Headers = @{
Expand Down
3 changes: 2 additions & 1 deletion Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ function New-GraphBulkRequest {
$req = @{}
# Use select to create hashtables of id, method and url for each call
$req['requests'] = ($Requests[$i..($i + 19)])
Invoke-RestMethod -Uri $URL -Method POST -Headers $headers -ContentType 'application/json; charset=utf-8' -Body ($req | ConvertTo-Json -Depth 10)
$ReqBody = ($req | ConvertTo-Json -Depth 10)
Invoke-RestMethod -Uri $URL -Method POST -Headers $headers -ContentType 'application/json; charset=utf-8' -Body $ReqBody
}

foreach ($MoreData in $ReturnedData.Responses | Where-Object { $_.body.'@odata.nextLink' }) {
Expand Down
4 changes: 3 additions & 1 deletion Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ function New-GraphGetRequest {
if ($noPagination) { $nextURL = $null } else { $nextURL = $data.'@odata.nextLink' }
}
} catch {
$Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message
try {
$Message = ($_.ErrorDetails.Message | ConvertFrom-Json -ErrorAction SilentlyContinue).error.message
} catch { $Message = $null }
if ($Message -eq $null) { $Message = $($_.Exception.Message) }
if ($Message -ne 'Request not applicable to target tenant.' -and $Tenant) {
$Tenant.LastGraphError = $Message
Expand Down
69 changes: 69 additions & 0 deletions Modules/CIPPCore/Public/Set-CIPPPerUserMFA.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
function Set-CIPPPerUserMFA {
<#
.SYNOPSIS
Change Per-User MFA State for a User
.DESCRIPTION
Change the Per-User MFA State for a user via the /users/{id}/authentication/requirements endpoint
.PARAMETER TenantFilter
Tenant where the user resides
.PARAMETER userId
One or more User IDs to set the MFA state for (GUID or UserPrincipalName)
.PARAMETER State
State to set the user to (enabled, disabled, enforced)
.PARAMETER executingUser
User executing the command
.EXAMPLE
Set-CIPPPerUserMFA -TenantFilter 'contoso.onmicrosoft.com' -userId [email protected] -State 'disabled' -executingUser '[email protected]'
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$TenantFilter,
[Parameter(Mandatory = $true)]
[string[]]$userId,
[ValidateSet('enabled', 'disabled', 'enforced')]
$State = 'enabled',
[string]$executingUser = 'CIPP'
)
try {
$int = 0
$Body = @{
perUserMFAstate = $State
}
$Requests = foreach ($id in $userId) {
@{
id = $int++
method = 'PATCH'
url = "users/$id/authentication/requirements"
body = $Body
'headers' = @{
'Content-Type' = 'application/json'
}
}
}


$Requests = New-GraphBulkRequest -tenantid $tenantfilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true
"Successfully set Per user MFA State for $userId"

$Users = foreach ($id in $userId) {
@{
userId = $id
Properties = @{
perUserMfaState = $State
}
}
}
Set-CIPPUserSchemaProperties -TenantFilter $TenantFilter -Users $Users
Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Successfully set Per user MFA State to $State for $id" -Sev 'Info' -tenant $TenantFilter
} catch {
"Failed to set MFA State for $id : $_"
Write-LogMessage -user $executingUser -API 'Set-CIPPPerUserMFA' -message "Failed to set MFA State to $State for $id : $_" -Sev 'Error' -tenant $TenantFilter
}
}
46 changes: 46 additions & 0 deletions Modules/CIPPCore/Public/Set-CIPPUserSchemaProperties.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
function Set-CIPPUserSchemaProperties {
<#
.SYNOPSIS
Set Schema Properties for a user
.DESCRIPTION
Uses scheam extensions to set properties for a user
.PARAMETER TenantFilter
Tenant for user
.PARAMETER UserId
One or more user ids to set properties for
.PARAMETER Properties
Hashtable of properties to set
#>
[CmdletBinding(SupportsShouldProcess = $true)]
Param(
[Parameter(Mandatory = $true)]
[string]$TenantFilter,
[Parameter(Mandatory = $true)]
[object]$Users
)

$Schema = Get-CIPPSchemaExtensions | Where-Object { $_.id -match '_cippUser' }
$int = 0
$Requests = foreach ($User in $Users) {
@{
id = $int++
method = 'PATCH'
url = "users/$($User.userId)"
body = @{
"$($Schema.id)" = $User.Properties
}
'headers' = @{
'Content-Type' = 'application/json'
}
}
}

if ($PSCmdlet.ShouldProcess("User: $($Users.userId -join ', ')", 'Set Schema Properties')) {
$Requests = New-GraphBulkRequest -tenantid $tenantfilter -Requests @($Requests)
}
}
Loading

0 comments on commit 68f1bf5

Please sign in to comment.