Skip to content

Commit

Permalink
Merge pull request #1 from KelvinTegelaar/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
lwhitelock authored Oct 26, 2021
2 parents c1c7c31 + ac029c4 commit 4a4dc78
Show file tree
Hide file tree
Showing 13 changed files with 363 additions and 13 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ local.settings.json
tenants.cache.json
chocoapps.cache
*.log
.vscode/
.vscode/
Cache_BestPracticeAnalyser/
9 changes: 9 additions & 0 deletions BestPracticeAnalyser_All/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"bindings": [
{
"name": "tenant",
"direction": "in",
"type": "activityTrigger"
}
]
}
231 changes: 231 additions & 0 deletions BestPracticeAnalyser_All/run.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
param($tenant)

# Prepare tokens, connections and variables that will be used multiple times later
$uri = "https://login.microsoftonline.com/$($Tenant)/oauth2/token"
$body = "resource=https://admin.microsoft.com&grant_type=refresh_token&refresh_token=$($ENV:ExchangeRefreshToken)"
try {
$token = Invoke-RestMethod $uri -Body $body -ContentType "application/x-www-form-urlencoded" -ErrorAction SilentlyContinue -Method post
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Token retrieved for Best Practice Analyser on $($tenant)" -sev "Info"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Unable to Retrieve token for Best Practice Analyser $($tenant) Error: $($_.exception.message)" -sev "Error"
}
$upn = "[email protected]"

# Build up the result object that will be passed back to the durable function
$Result = [PSCustomObject]@{
Tenant = $tenant
GUID = $($Tenant.Replace('.', ''))
LastRefresh = $(Get-Date (Get-Date).ToUniversalTime() -UFormat '+%Y-%m-%dT%H:%M:%S.000Z')
SecureDefaultState = ""
PrivacyEnabled = ""
UnifiedAuditLog = ""
MessageCopyForSend = ""
MessageCopyForSendAsCount = ""
MessageCopyForSendOnBehalfCount = ""
MessageCopyForSendList = ""
ShowBasicAuthSettings = ""
EnableModernAuth = ""
AllowBasicAuthActiveSync = ""
AllowBasicAuthImap = ""
AllowBasicAuthPop = ""
AllowBasicAuthWebServices = ""
AllowBasicAuthPowershell = ""
AllowBasicAuthAutodiscover = ""
AllowBasicAuthMapi = ""
AllowBasicAuthOfflineAddressBook = ""
AllowBasicAuthRpc = ""
AllowBasicAuthSmtp = ""
AdminConsentForApplications = ""
DoNotExpirePasswords = ""
SelfServicePasswordReset = ""
DisabledSharedMailboxLogins = ""
DisabledSharedMailboxLoginsCount = ""
}

# Starting the Best Practice Analyser
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Started Best Practice Analyser Durable Function on $($tenant)" -sev "Info"

# Get the Secure Default State
try {
$SecureDefaultsState = (New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy" -tenantid $tenant)
$Result.SecureDefaultState = $SecureDefaultsState.IsEnabled

Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Security Defaults State on $($tenant) is $($SecureDefaultsState.IsEnabled)" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Security Defaults State on $($tenant) Error: $($_.exception.message)" -sev "Error"
}


# Get the Privacy Enabled State
try {
$Result.PrivacyEnabled = Invoke-RestMethod -ContentType "application/json;charset=UTF-8" -Uri 'https://admin.microsoft.com/admin/api/reports/config/GetTenantConfiguration' -Method Get -Headers @{
Authorization = "Bearer $($token.access_token)";
"x-ms-client-request-id" = [guid]::NewGuid().ToString();
"x-ms-client-session-id" = [guid]::NewGuid().ToString()
'x-ms-correlation-id' = [guid]::NewGuid()
'X-Requested-With' = 'XMLHttpRequest'
} | Select-Object -ExpandProperty Output | ConvertFrom-Json | Select-Object -ExpandProperty PrivacyEnabled
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Privacy Enabled State on $($tenant) is $($Result.PrivacyEnabled)" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Privacy Enabled State on $($tenant) Error: $($_.exception.message)" -sev "Error"
}


# Build up and enter an Exchange PSSession for the next section
try {
$tokenvalue = ConvertTo-SecureString (Get-GraphToken -AppID 'a0c73c16-a7e3-4564-9a95-2bdf47383716' -RefreshToken $ENV:ExchangeRefreshToken -Scope 'https://outlook.office365.com/.default' -Tenantid $($Tenant)).Authorization -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($upn, $tokenValue)
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell-liveid?DelegatedOrg=$($Tenant)&BasicAuthToOAuthConversion=true" -Credential $credential -Authentication Basic -AllowRedirection -ErrorAction Continue
Import-PSSession $session -ea Silentlycontinue -AllowClobber -CommandName "Get-Mailbox", "Set-mailbox", "Get-AdminAuditLogConfig", "Get-OrganizationConfig", "Enable-OrganizationCustomization" | Out-Null
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Exchange PS Sesssion Generated on $($tenant) is successful" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Exchange PS Session on $($tenant) Error: $($_.exception.message)" -sev "Error"
}


# Get Send and Send Behalf Of
try {
# Send and Send Behalf Of
$MailboxBPA = Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox, SharedMailbox
$TotalMailboxes = $MailboxBPA | Measure-Object | Select-Object -ExpandProperty Count
$TotalMessageCopyForSentAsEnabled = $MailboxBPA | Where-Object { $_.MessageCopyForSentAsEnabled -eq $true } | Measure-Object | Select-Object -ExpandProperty Count
$TotalMessageCopyForSendOnBehalfEnabled = $MailboxBPA | Where-Object { $_.MessageCopyForSendOnBehalfEnabled -eq $true } | Measure-Object | Select-Object -ExpandProperty Count
If (($TotalMailboxes -eq $TotalMessageCopyForSentAsEnabled) -and ($TotalMailboxes -eq $TotalMessageCopyForSendOnBehalfEnabled)) {
$Result.MessageCopyForSend = "PASS"
$Result.MessageCopyForSendAsCount = $TotalMessageCopyForSentAsEnabled
$Result.MessageCopyForSendOnBehalfCount = $TotalMessageCopyForSendOnBehalfEnabled
}
else {
$Result.MessageCopyForSend = "FAIL"
$Result.MessageCopyForSendAsCount = $MailboxBPA | Where-Object { $_.MessageCopyForSentAsEnabled -eq $false } | Measure-Object | Select-Object -ExpandProperty Count
$Result.MessageCopyForSendOnBehalfCount = $MailboxBPA | Where-Object { $_.MessageCopyForSendOnBehalfEnabled -eq $false } | Measure-Object | Select-Object -ExpandProperty Count
$Result.MessageCopyForSendList = ($MailboxBPA | Where-Object { ($_.MessageCopyForSendOnBehalfEnabled -eq $false) -or ( $_.MessageCopyForSendOnBehalfEnabled -eq $false) } | Select-Object -ExpandProperty userPrincipalName) -join "<br />"
}
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Send and Send Behalf Of on $($tenant) is $($Result.MessageCopyForSend)" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Send and Send Behalf Of on $($tenant) Error: $($_.exception.message)" -sev "Error"
}


# Get Unified Audit Log
try {
$Result.UnifiedAuditLog = Get-AdminAuditLogConfig | Select-Object -ExpandProperty UnifiedAuditLogIngestionEnabled
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Unified Audit Log on $($tenant) is $($Result.UnifiedAuditLog)" -sev "Debug"

}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Unified Audit Log on $($tenant). Error: $($_.exception.message)" -sev "Error"
}


# Important to clean up the remote session
try {
Get-PSSession | Remove-PSSession
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Error cleaning up PSSession on $($tenant). Error: $($_.exception.message)" -sev "Error"
}


# Get Basic Auth States
try {
$BasicAuthDisable = Invoke-RestMethod -ContentType "application/json;charset=UTF-8" -Uri 'https://admin.microsoft.com/admin/api/services/apps/modernAuth' -Method GET -Headers @{
Authorization = "Bearer $($token.access_token)";
"x-ms-client-request-id" = [guid]::NewGuid().ToString();
"x-ms-client-session-id" = [guid]::NewGuid().ToString()
'x-ms-correlation-id' = [guid]::NewGuid()
'X-Requested-With' = 'XMLHttpRequest'
}

$Result.ShowBasicAuthSettings = $BasicAuthDisable.ShowBasicAuthSettings
$Result.EnableModernAuth = $BasicAuthDisable.EnableModernAuth
$Result.AllowBasicAuthActiveSync = $BasicAuthDisable.AllowBasicAuthActiveSync
$Result.AllowBasicAuthImap = $BasicAuthDisable.AllowBasicAuthImap
$Result.AllowBasicAuthPop = $BasicAuthDisable.AllowBasicAuthPop
$Result.AllowBasicAuthWebServices = $BasicAuthDisable.AllowBasicAuthWebServices
$Result.AllowBasicAuthPowershell = $BasicAuthDisable.AllowBasicAuthPowershell
$Result.AllowBasicAuthAutodiscover = $BasicAuthDisable.AllowBasicAuthAutodiscover
$Result.AllowBasicAuthMapi = $BasicAuthDisable.AllowBasicAuthMapi
$Result.AllowBasicAuthOfflineAddressBook = $BasicAuthDisable.AllowBasicAuthOfflineAddressBook
$Result.AllowBasicAuthRpc = $BasicAuthDisable.AllowBasicAuthRpc
$Result.AllowBasicAuthSmtp = $BasicAuthDisable.AllowBasicAuthSmtp
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Basic Auth States on $($tenant) run" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Basic Auth States on $($tenant). Error: $($_.exception.message)" -sev "Error"
}


# Get OAuth Admin Consenst
try {
$Result.AdminConsentForApplications = Invoke-RestMethod -ContentType "application/json;charset=UTF-8" -Uri 'https://admin.microsoft.com/admin/api/settings/apps/IntegratedApps' -Method GET -Headers @{
Authorization = "Bearer $($token.access_token)";
"x-ms-client-request-id" = [guid]::NewGuid().ToString();
"x-ms-client-session-id" = [guid]::NewGuid().ToString()
'x-ms-correlation-id' = [guid]::NewGuid()
'X-Requested-With' = 'XMLHttpRequest'
}
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "OAuth Admin Consent on $($tenant). Admin Consent for Applications $($Result.AdminConsentForApplications) and password reset is $($Result.SelfServicePasswordReset)" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "OAuth Admin Consent on $($tenant). Error: $($_.exception.message)" -sev "Error"
}

# Get Self Service Password Reset State
try {
$bodypasswordresetpol = "resource=74658136-14ec-4630-ad9b-26e160ff0fc6&grant_type=refresh_token&refresh_token=$($ENV:ExchangeRefreshToken)"
$tokensspr = Invoke-RestMethod $uri -Body $bodypasswordresetpol -ContentType "application/x-www-form-urlencoded" -ErrorAction SilentlyContinue -method post
$SSPRGraph = Invoke-RestMethod -contenttype "application/json;charset=UTF-8" -uri 'https://main.iam.ad.ext.azure.com/api/PasswordReset/PasswordResetPolicies' -method GET -Headers @{
Authorization = "Bearer $($tokensspr.access_token)";
"x-ms-client-request-id" = [guid]::NewGuid().ToString();
"x-ms-client-session-id" = [guid]::NewGuid().ToString()
'x-ms-correlation-id' = [guid]::NewGuid()
'X-Requested-With' = 'XMLHttpRequest'
}
If ($SSPRGraph.enablementType -eq 0) { $Result.SelfServicePasswordReset = "Off" }
If ($SSPRGraph.enablementType -eq 1) { $Result.SelfServicePasswordReset = "Specific Users" }
If ($SSPRGraph.enablementType -eq 2) { $Result.SelfServicePasswordReset = "On" }
If ([string]::IsNullOrEmpty($SSPRGraph.enablementType)) { $Result.SelfServicePasswordReset = "Unknown" }
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Basic Self Service Password State on $($tenant) is $($Result.SelfServicePasswordReset) run" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Self Service Password Reset on $($tenant). Error: $($_.exception.message)" -sev "Error"
}

# Get Passwords set to Never Expire
try {
$Result.DoNotExpirePasswords = Invoke-RestMethod -contenttype "application/json; charset=utf-8" -uri 'https://admin.microsoft.com/admin/api/Settings/security/passwordpolicy' -method GET -Headers @{Authorization = "Bearer $($token.access_token)"; "x-ms-client-request-id" = [guid]::NewGuid().ToString(); "x-ms-client-session-id" = [guid]::NewGuid().ToString(); 'X-Requested-With' = 'XMLHttpRequest'; 'x-ms-correlation-id' = [guid]::NewGuid() } | Select-Object -ExpandProperty NeverExpire
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Passwords never expire setting on $($tenant). $($Result.DoNotExpirePasswords)" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Passwords never expire setting on $($tenant). Error: $($_.exception.message)" -sev "Error"
}


# Get Shared Mailbox Stuff
try {
$SharedMailboxList = (New-GraphGetRequest -uri "https://outlook.office365.com/adminapi/beta/$($tenant)/Mailbox" -Tenantid $tenant -scope ExchangeOnline | Where-Object -propert RecipientTypeDetails -EQ "SharedMailbox")
$AllUsersAccountState = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?select=userPrincipalName,accountEnabled" -tenantid $Tenant
$EnabledUsersWithSharedMailbox = foreach ($SharedMailbox in $SharedMailboxList) {
# Match the User
$User = $AllUsersAccountState | Where-Object { $_.userPrincipalName -eq $SharedMailbox.userPrincipalName } | Select-Object -First 1
if ($User.accountEnabled) {
$User.userPrincipalName
}
}

if (($EnabledUsersWithSharedMailbox | Measure-Object | Select-Object -ExpandProperty Count) -gt 0) { $Result.DisabledSharedMailboxLogins = ($EnabledUsersWithSharedMailbox) -join "<br />" } else { $Result.DisabledSharedMailboxLogins = "PASS" }
$Result.DisabledSharedMailboxLoginsCount = $EnabledUsersWithSharedMailbox | Measure-Object | Select-Object -ExpandProperty Count
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Shared Mailbox Enabled Accounts on $($tenant). $($Result.DisabledSharedMailboxLogins)" -sev "Debug"
}
catch {
Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Shared Mailbox Enabled Accounts on $($tenant). Error: $($_.exception.message)" -sev "Error"
}

# Send Output of all the Results to the Stream
$Result
9 changes: 9 additions & 0 deletions BestPracticeAnalyser_GetQueue/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"bindings": [
{
"name": "name",
"type": "activityTrigger",
"direction": "in"
}
]
}
9 changes: 9 additions & 0 deletions BestPracticeAnalyser_GetQueue/run.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
param($name)

$Tenants = Get-Content ".\tenants.cache.json" | ConvertFrom-Json

$object = foreach ($Tenant in $Tenants) {
$Tenant.defaultDomainName
}

$object
19 changes: 19 additions & 0 deletions BestPracticeAnalyser_List/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
}
20 changes: 20 additions & 0 deletions BestPracticeAnalyser_List/run.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using namespace System.Net

# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

$APIName = $TriggerMetadata.FunctionName
Log-Request -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Accessed this API" -Sev "Debug"


# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."

# Get all the things
$Results = Get-ChildItem ".\Cache_BestPracticeAnalyser\*.json" | %{Get-Content $_.FullName | Out-String | ConvertFrom-Json}

# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = @($Results)
})
9 changes: 9 additions & 0 deletions BestPracticeAnalyser_Orchestration/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"bindings": [
{
"name": "Context",
"type": "orchestrationTrigger",
"direction": "in"
}
]
}
18 changes: 18 additions & 0 deletions BestPracticeAnalyser_Orchestration/run.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
param($Context)

Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Best Practice Analyser has Started" -sev Info

$Batch = (Invoke-ActivityFunction -FunctionName 'BestPracticeAnalyser_GetQueue' -Input 'LetsGo')
$ParallelTasks = foreach ($Item in $Batch) {
Invoke-DurableActivity -FunctionName "BestPracticeAnalyser_All" -Input $item -NoWait
}

$Outputs = Wait-ActivityFunction -Task $ParallelTasks

foreach ($item in $Outputs) {
write-host $Item | Out-String
$Object = $Item | ConvertTo-Json
Set-Content "Cache_BestPracticeAnalyser\$($item.tenant).BestPracticeAnalysis.json" -Value $Object -Force
}

Log-request -API "BestPracticeAnalyser" -tenant $tenant -message "Best Practice Analyser has Finished" -sev Info
24 changes: 24 additions & 0 deletions BestPracticeAnalyser_OrchestrationStarter/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"bindings": [
{
"authLevel": "anonymous",
"name": "Request",
"type": "httpTrigger",
"direction": "in",
"methods": [
"post",
"get"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
},
{
"name": "starter",
"type": "durableClient",
"direction": "in"
}
]
}
12 changes: 12 additions & 0 deletions BestPracticeAnalyser_OrchestrationStarter/run.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using namespace System.Net

param($Request, $TriggerMetadata)

$InstanceId = Start-NewOrchestration -FunctionName 'BestPracticeAnalyser_Orchestration'
Write-Host "Started orchestration with ID = '$InstanceId'"

$Response = New-OrchestrationCheckStatusResponse -Request $Request -InstanceId $InstanceId

Write-Host ($Response | ConvertTo-Json)

Log-request -API "BestPracticeAnalyser" -message "Started applying the standard templates to tenants." -sev Info
11 changes: 0 additions & 11 deletions UpdateTokens/readme.md

This file was deleted.

Loading

0 comments on commit 4a4dc78

Please sign in to comment.