Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions Modules/CIPPCore/Public/Alerts/Get-CIPPAlertVulnerabilities.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ function Get-CIPPAlertVulnerabilities {
$AgeThresholdHours = if ($InputValue.VulnerabilityAgeHours) { [int]$InputValue.VulnerabilityAgeHours } else { 0 }
# Autocomplete inputs store value in .value subproperty
$CVSSSeverity = if ($InputValue.CVSSSeverity.value) { $InputValue.CVSSSeverity.value } else { 'low' }
# Switch inputs are stored as boolean
$NewerThanMode = [bool]($InputValue.NewerThanMode)
# Multi-select autocomplete returns array of objects with .value
if ($InputValue.ExploitabilityLevels) {
foreach ($level in $InputValue.ExploitabilityLevels) {
$ExploitabilityLevels.Add($(if ($level.value) { $level.value } else { $level }))
}
}
} else {
$NewerThanMode = $false
# Backward compatibility: simple value = hours threshold
$AgeThresholdHours = if ($InputValue) { [int]$InputValue } else { 0 }
$CVSSSeverity = 'low'
Expand Down Expand Up @@ -52,9 +55,17 @@ function Get-CIPPAlertVulnerabilities {
$FirstVuln = $Group.Group | Sort-Object firstSeenTimestamp | Select-Object -First 1
$HoursOld = [math]::Round(((Get-Date) - [datetime]$FirstVuln.firstSeenTimestamp).TotalHours)

# Skip if vulnerability is not old enough
if ($HoursOld -lt $AgeThresholdHours) {
continue
# Skip based on age threshold mode
if ($NewerThanMode) {
# Newer-than mode: only alert on items newer than threshold
if ($HoursOld -gt $AgeThresholdHours) {
continue
}
} else {
# Older-than mode (default): only alert on items older than threshold
if ($HoursOld -lt $AgeThresholdHours) {
continue
}
}

# Skip if CVSS score is below minimum threshold
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,33 @@ function Push-DomainAnalyserDomain {
}

$Result = [PSCustomObject]@{
Tenant = $Tenant.Tenant
TenantID = $Tenant.TenantGUID
GUID = $($Domain.Replace('.', ''))
LastRefresh = $(Get-Date (Get-Date).ToUniversalTime() -UFormat '+%Y-%m-%dT%H:%M:%S.000Z')
Domain = $Domain
NSRecords = (Read-NSRecord -Domain $Domain).Records
ExpectedSPFRecord = ''
ActualSPFRecord = ''
SPFPassAll = ''
ActualMXRecords = ''
MXPassTest = ''
DMARCPresent = ''
DMARCFullPolicy = ''
DMARCActionPolicy = ''
DMARCReportingActive = ''
DMARCPercentagePass = ''
DNSSECPresent = ''
MailProvider = ''
DKIMEnabled = ''
DKIMRecords = ''
MSCNAMEDKIMSelectors = ''
Score = ''
MaximumScore = 160
ScorePercentage = ''
ScoreExplanation = ''
Tenant = $Tenant.Tenant
TenantID = $Tenant.TenantGUID
GUID = $($Domain.Replace('.', ''))
LastRefresh = $(Get-Date (Get-Date).ToUniversalTime() -UFormat '+%Y-%m-%dT%H:%M:%S.000Z')
Domain = $Domain
NSRecords = (Read-NSRecord -Domain $Domain).Records
ExpectedSPFRecord = ''
ActualSPFRecord = ''
SPFPassAll = ''
ActualMXRecords = ''
MXPassTest = ''
DMARCPresent = ''
DMARCFullPolicy = ''
DMARCActionPolicy = ''
DMARCReportingActive = ''
DMARCPercentagePass = ''
DNSSECPresent = ''
MailProvider = ''
DKIMEnabled = ''
DKIMRecords = ''
MSCNAMEDKIMSelectors = ''
EnterpriseEnrollment = ''
EnterpriseRegistration = ''
Score = ''
MaximumScore = 160
ScorePercentage = ''
ScoreExplanation = ''
}

$Scores = [PSCustomObject]@{
Expand Down Expand Up @@ -246,6 +248,51 @@ function Push-DomainAnalyserDomain {
}
#EndRegion DKIM Check

#Region Intune Enrollment CNAME Check
try {
# Check enterpriseenrollment CNAME
$EnrollmentResult = Resolve-DnsHttpsQuery -Domain "enterpriseenrollment.$Domain" -RecordType CNAME
if ($EnrollmentResult.Answer) {
$EnrollmentCNAME = ($EnrollmentResult.Answer | Where-Object { $_.type -eq 5 }).data -replace '\.$'
if ($EnrollmentCNAME -eq 'enterpriseenrollment-s.manage.microsoft.com') {
$Result.EnterpriseEnrollment = 'Correct'
} elseif ($EnrollmentCNAME -eq 'enterpriseenrollment.manage.microsoft.com') {
$Result.EnterpriseEnrollment = 'Legacy'
$ScoreExplanation.Add('Enterprise Enrollment CNAME points to legacy endpoint (enterpriseenrollment.manage.microsoft.com)') | Out-Null
} else {
$Result.EnterpriseEnrollment = "Unexpected: $EnrollmentCNAME"
$ScoreExplanation.Add('Enterprise Enrollment CNAME points to unexpected target') | Out-Null
}
} else {
$Result.EnterpriseEnrollment = 'No CNAME'
$ScoreExplanation.Add('No Enterprise Enrollment CNAME record found') | Out-Null
}
} catch {
$Result.EnterpriseEnrollment = 'Error'
Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message "Enterprise Enrollment CNAME error for $Domain" -LogData (Get-CippException -Exception $_) -sev Error
}

try {
# Check enterpriseregistration CNAME
$RegistrationResult = Resolve-DnsHttpsQuery -Domain "enterpriseregistration.$Domain" -RecordType CNAME
if ($RegistrationResult.Answer) {
$RegistrationCNAME = ($RegistrationResult.Answer | Where-Object { $_.type -eq 5 }).data -replace '\.$'
if ($RegistrationCNAME -eq 'enterpriseregistration.windows.net') {
$Result.EnterpriseRegistration = 'Correct'
} else {
$Result.EnterpriseRegistration = "Unexpected: $RegistrationCNAME"
$ScoreExplanation.Add('Enterprise Registration CNAME points to unexpected target') | Out-Null
}
} else {
$Result.EnterpriseRegistration = 'No CNAME'
$ScoreExplanation.Add('No Enterprise Registration CNAME record found') | Out-Null
}
} catch {
$Result.EnterpriseRegistration = 'Error'
Write-LogMessage -API 'DomainAnalyser' -tenant $DomainObject.TenantId -message "Enterprise Registration CNAME error for $Domain" -LogData (Get-CippException -Exception $_) -sev Error
}
#EndRegion Intune Enrollment CNAME Check

#Region MSCNAME DKIM Records
# Get Microsoft DKIM CNAME selector Records
# Ugly, but i needed to create a scope/loop i could break out of without breaking the rest of the function
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
function Invoke-ListActiveSyncDevices {
<#
.FUNCTIONALITY
Entrypoint
.ROLE
Exchange.Mailbox.Read
#>
[CmdletBinding()]
param($Request, $TriggerMetadata)

$TenantFilter = $Request.Query.TenantFilter

try {
$GraphRequest = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MobileDevice' -cmdParams @{ ResultSize = 'Unlimited' } |
Select-Object @{ Name = 'userDisplayName'; Expression = { $_.UserDisplayName } },
@{ Name = 'userPrincipalName'; Expression = { ($_.Identity -split '\\')[0] } },
@{ Name = 'deviceFriendlyName'; Expression = { if ([string]::IsNullOrEmpty($_.FriendlyName)) { 'Unknown' } else { $_.FriendlyName } } },
@{ Name = 'deviceModel'; Expression = { $_.DeviceModel } },
@{ Name = 'deviceOS'; Expression = { $_.DeviceOS } },
@{ Name = 'deviceType'; Expression = { $_.DeviceType } },
@{ Name = 'clientType'; Expression = { $_.ClientType } },
@{ Name = 'clientVersion'; Expression = { $_.ClientVersion } },
@{ Name = 'deviceAccessState'; Expression = { $_.DeviceAccessState } },
@{ Name = 'firstSyncTime'; Expression = { if ($_.FirstSyncTime) { $_.FirstSyncTime.ToString('yyyy-MM-ddTHH:mm:ssZ') } else { '' } } },
@{ Name = 'lastSyncAttemptTime'; Expression = { if ($_.LastSyncAttemptTime) { $_.LastSyncAttemptTime.ToString('yyyy-MM-ddTHH:mm:ssZ') } else { '' } } },
@{ Name = 'lastSuccessSync'; Expression = { if ($_.LastSuccessSync) { $_.LastSuccessSync.ToString('yyyy-MM-ddTHH:mm:ssZ') } else { '' } } },
@{ Name = 'deviceID'; Expression = { $_.DeviceId } },
@{ Name = 'identity'; Expression = { $_.Identity } },
@{ Name = 'Guid'; Expression = { $_.Guid } }
$StatusCode = [HttpStatusCode]::OK
} catch {
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message
$StatusCode = [HttpStatusCode]::Forbidden
$GraphRequest = $ErrorMessage
}
return ([HttpResponseContext]@{
StatusCode = $StatusCode
Body = @($GraphRequest)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function Set-CIPPDefaultAPDeploymentProfile {
)

try {
if ($Language -in @('user-select', 'os-default')) { $Language = '' }
if ($Language -in @('user-select', 'os-default')) { $Language = "$null" }

# userType in outOfBoxExperienceSetting is only valid for user-driven (singleUser) mode.
# The Intune API rejects it for self-deploying (shared) mode.
Expand Down