chore: add setup script to modify security defaults

This commit is contained in:
2025-08-17 00:44:03 +10:00
parent 48848aa767
commit 4676809b95
5 changed files with 306 additions and 96 deletions

View File

@ -1,25 +0,0 @@
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "DeviceManagementConfiguration.ReadWrite.All", "Organization.Read.All", "Group.ReadWrite.All", "Directory.ReadWrite.All" -NoWelcome
$policies = Get-ChildItem ./policies/compliance
ForEach ($policie in $policies) {
$PolicieName = $policie.name
$JsonData = Get-Content -Path ./policies/compliance/$PolicieName -Raw
$JsonDataUpdated = $JsonData -replace '\$tenantId', $tenantId
$PolicyObject = $JsonDataUpdated | ConvertFrom-Json
try {
$uri = "https://graph.microsoft.com/beta/deviceManagement/deviceCompliancePolicies" # Using the beta version
$response = Invoke-MgGraphRequest -Method POST -Uri $uri -Body ($PolicyObject | ConvertTo-Json -Depth 10)
Write-Host "$PolicieName - successfully imported!"
#$response
} catch {
Write-Error "❌ An error occurred while importing the policy: $_"
}
}
# Disconnect from Graph
$null = Disconnect-Graph -ErrorAction SilentlyContinue

View File

@ -10,7 +10,7 @@ if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Beta)) {
# Connect to Microsoft Graph # Connect to Microsoft Graph
Connect-MgGraph -Scopes "DeviceManagementConfiguration.ReadWrite.All", "Organization.Read.All", "Group.ReadWrite.All", "Directory.ReadWrite.All" -NoWelcome Connect-MgGraph -Scopes "Device.ReadWrite.All","DeviceManagementConfiguration.ReadWrite.All", "Organization.Read.All", "Group.ReadWrite.All", "Directory.ReadWrite.All" -NoWelcome
# Get Tenant ID # Get Tenant ID
$tenant = Get-MgOrganization $tenant = Get-MgOrganization

View File

@ -1,16 +1,15 @@
# Ensure Microsoft.Graph module is installed # Ensure Microsoft.Graph module is installed
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) { if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) {
Write-Host "Installing Microsoft.Graph module..." Write-Host "Installing Microsoft.Graph module..."
Install-Module -Name Microsoft.Graph -Force -AllowClobber Install-Module -Name Microsoft.Graph -Force -AllowClobber
} }
# Ensure ExchangeOnlineManagement module is installed # Ensure ExchangeOnlineManagement module is installed
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) { if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) {
Write-Host "Installing ExchangeOnlineManagement Module..." Write-Host "Installing ExchangeOnlineManagement Module..."
Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber
} }
# Import necessary modules # Import necessary modules
Import-Module Microsoft.Graph.Authentication Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Applications Import-Module Microsoft.Graph.Applications
@ -21,7 +20,40 @@ Connect-MgGraph -Scopes "Application.ReadWrite.All", "Directory.ReadWrite.All",
# Application details # Application details
$Name = "GraphAPI" $Name = "GraphAPI"
$Scope = "Application.ReadWrite.All", "DeviceManagementApps.ReadWrite.All", "DeviceManagementConfiguration.ReadWrite.All", "DeviceManagementServiceConfig.ReadWrite.All", "Group.ReadWrite.All", "Policy.ReadWrite.ApplicationConfiguration", "User.ReadWrite.All" $Scope = "Application.ReadWrite.All", "DeviceManagementApps.ReadWrite.All", "DeviceManagementConfiguration.ReadWrite.All", "DeviceManagementServiceConfig.ReadWrite.All", "Group.ReadWrite.All", "Policy.ReadWrite.ApplicationConfiguration", "User.ReadWrite.All", "Policy.ReadWrite.AuthenticationMethod"
# -------------------------------
# Check for existing apps with the same name
# -------------------------------
Write-Host "🔍 Checking for existing applications named '$Name'..."
$existingApps = Get-MgApplication -All | Where-Object { $_.DisplayName -eq $Name }
if ($existingApps) {
Write-Host "⚠️ Found $($existingApps.Count) existing application(s) with this name. Removing them..."
foreach ($existingApp in $existingApps) {
try {
# Remove associated Service Principal first
$sp = Get-MgServicePrincipal -Filter "AppId eq '$($existingApp.AppId)'" -ErrorAction SilentlyContinue
if ($sp) {
Remove-MgServicePrincipal -ServicePrincipalId $sp.Id -Confirm:$false
Write-Host " ➜ Removed Service Principal: $($sp.Id)"
}
# Remove the application
Remove-MgApplication -ApplicationId $existingApp.Id -Confirm:$false
Write-Host " ➜ Removed Application: $($existingApp.Id)"
} catch {
Write-Warning " ❌ Failed to remove application $($existingApp.Id): $_"
}
}
# Optional pause to ensure deletion propagates
Write-Host "⏳ Waiting for application deletion..."
Start-Sleep -Seconds 10
} else {
Write-Host "✅ No existing applications found with name '$Name'."
}
# Fetch Microsoft Graph Service Principal # Fetch Microsoft Graph Service Principal
$graphSp = Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'" $graphSp = Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'"
@ -76,11 +108,10 @@ if (-not $app) {
Write-Host "✅ Application Created: $($app.Id)" Write-Host "✅ Application Created: $($app.Id)"
# Wait for the application to propagate # Wait for the application to propagate
Start-Sleep -Seconds 10
Write-Host "⏳ Waiting for application propagation..." Write-Host "⏳ Waiting for application propagation..."
Start-Sleep -Seconds 10
# Create Service Principal # Create Service Principal
Write-Host "Creating Service Principal..."
$servicePrincipal = New-MgServicePrincipal -AppId $app.AppId $servicePrincipal = New-MgServicePrincipal -AppId $app.AppId
if (-not $servicePrincipal) { if (-not $servicePrincipal) {
@ -147,32 +178,6 @@ Write-Host "🔑 Client ID: $($app.AppId)"
Write-Host "🕵️‍♂️ Client Secret: $($clientSecret.SecretText)" Write-Host "🕵️‍♂️ Client Secret: $($clientSecret.SecretText)"
Write-Host "----------------------------------" Write-Host "----------------------------------"
#Connect-ExchangeOnline -ShowBanner:$false
$scope = "https://graph.microsoft.com/.default"
$tokenEndpoint = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
# Create the body for the token request
$body = @{
client_id = "$($app.AppId)"
scope = $scope
client_secret = "$($clientSecret.SecretText)"
grant_type = "client_credentials"
}
# Request the token
$tokenResponse = Invoke-RestMethod -Method Post -Uri $tokenEndpoint -ContentType "application/x-www-form-urlencoded" -Body $body
$accessToken = $tokenResponse.access_token
# Use the token in subsequent requests
$headers = @{
Authorization = "Bearer $accessToken"
}
$templates = Invoke-RestMethod -Method Get -Uri "https://graph.microsoft.com/beta/deviceManagement/templates" -Headers $headers
# Output the templates
$templates
$null = Disconnect-Graph -ErrorAction SilentlyContinue
$null = Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue
$null = Disconnect-Graph -ErrorAction SilentlyContinue
$null = Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue

265
Setup.ps1 Normal file
View File

@ -0,0 +1,265 @@
function Get-OrCreateGroup {
param(
[string]$DisplayName,
[string]$MailNickname
)
$group = Get-MgGroup -Filter "displayName eq '$DisplayName'" -ConsistencyLevel eventual -CountVariable count
if ($group) {
Write-Host "🚫 Group '$DisplayName' already exists. Using existing GroupId: $($group.Id)"
return $group
}
else {
Write-Host "✅ Creating group '$DisplayName'..."
return New-MgGroup -BodyParameter @{
DisplayName = $DisplayName
MailEnabled = $false
MailNickname = $MailNickname
SecurityEnabled = $true
}
}
}
# Function to get or create CA policy
function Get-OrCreatePolicy {
param(
[string]$DisplayName,
[hashtable]$BodyParams
)
$policy = Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq '$DisplayName'"
if ($policy) {
Write-Host "🚫 Policy '$DisplayName' already exists. Skipping creation."
return $policy
}
else {
Write-Host "✅ Creating policy '$DisplayName'..."
return New-MgIdentityConditionalAccessPolicy -BodyParameter $BodyParams
}
}
function Get-OrCreateCountryNamedLocations {
param(
[string[]]$Countries # ISO codes
)
$namedLocationIds = @()
foreach ($c in $Countries) {
$displayName = "Country - $c"
# Check if it exists
$existing = Get-MgIdentityConditionalAccessNamedLocation -Filter "displayName eq '$displayName'" -ErrorAction SilentlyContinue
if ($existing) {
Write-Host "🚫 Named Location for $c already exists: $($existing.Id)"
$namedLocationIds += $existing.Id
}
else {
# Create new Named Location
$newLoc = New-MgIdentityConditionalAccessNamedLocation -BodyParameter @{
"@odata.type" = "#microsoft.graph.countryNamedLocation"
DisplayName = $displayName
CountriesAndRegions = @($c)
IncludeUnknownCountriesAndRegions = $false
}
Write-Host "✅ Created Named Location for $c $($newLoc.Id)"
$namedLocationIds += $newLoc.Id
}
}
return $namedLocationIds
}
Connect-MgGraph -NoWelcome -Scopes `
"Policy.ReadWrite.SecurityDefaults", `
"Policy.ReadWrite.ConditionalAccess", `
"Policy.Read.All", `
"Group.ReadWrite.All", `
"Directory.ReadWrite.All", `
"UserAuthenticationMethod.ReadWrite.All", `
"Application.ReadWrite.All"
Write-Host "Connected to Microsoft Graph"
Write-Host "✅ Disabling Security Defaults..."
Update-MgPolicyIdentitySecurityDefaultEnforcementPolicy -BodyParameter @{ isEnabled = $false }
Write-Host " Checking/Creating Exclusion Groups..."
$teamsRoomsGroup = Get-OrCreateGroup -DisplayName "TeamsRoomsExclusions" -MailNickname "TeamsRoomsExcl"
$osTravelGroup = Get-OrCreateGroup -DisplayName "OSTravelExclusions" -MailNickname "OSTravelExcl"
Write-Host " Teams Rooms GroupId: $($teamsRoomsGroup.Id)"
Write-Host " OS Travel GroupId: $($osTravelGroup.Id)"
Write-Host " Checking/Creating Conditional Access Policy for Country Blocking..."
$AllowedCountries = @("AU","NZ","US","GB","DE","FR") # Add any ISO codes here
$allowedLocationIds = Get-OrCreateCountryNamedLocations -Countries $AllowedCountries
# 2. Wait for consistency
foreach ($locId in $allowedLocationIds) {
$retries = 0
do {
Start-Sleep -Seconds 2
$check = Get-MgIdentityConditionalAccessNamedLocation -Filter "id eq '$locId'" -ErrorAction SilentlyContinue
$retries++
} while (-not $check -and $retries -lt 10)
if (-not $check) { throw "⚠️ Named Location $locId not found in directory." }
}
$countryPolicyParams = @{
DisplayName = "Block countries except allowed"
State = "disabled"
Conditions = @{
Users = @{
IncludeUsers = @("All")
ExcludeGroups = @($osTravelGroup.Id)
}
Locations = @{
IncludeLocations = @("All")
ExcludeLocations = $allowedLocationIds
}
Applications = @{
IncludeApplications = @("All")
ExcludeApplications = @()
}
ClientAppTypes = @("all")
}
GrantControls = @{
Operator = "OR"
BuiltInControls = @("block")
}
}
$Policy = Get-OrCreatePolicy -DisplayName "Block countries except allowed" -BodyParams $countryPolicyParams
# Define the policy from your JSON
$policyParams = @{
DisplayName = "Require multifactor authentication for admins"
State = "enabled"
Conditions = @{
Users = @{
IncludeRoles = @(
"62e90394-69f5-4237-9190-012177145e10" # Global Administrator
"194ae4cb-b126-40b2-bd5b-6091b380977d" # Privileged Role Administrator
"f28a1f50-f6e7-4571-818b-6a12f2af6b6c" # Security Reader
"29232cdf-9323-42fd-ade2-1d097af3e4de" # Exchange Administrator
"b1be1c3e-b65d-4f19-8427-f6fa0d97feb9" # SharePoint Administrator
"729827e3-9c14-49f7-bb1b-9608f156bbb8" # Security Administrator
"b0f54661-2d74-4c50-afa3-1ec803f12efe" # Helpdesk Administrator
"fe930be7-5e62-47db-91af-98c3a49a38b1" # User Administrator
"c4e39bd9-1100-46d3-8c65-fb160da0071f" # Authentication Administrator
"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3" # Conditional Access Administrator
"158c047a-c907-4556-b7ef-446551a6b5f7" # Security Operator
"966707d0-3269-4727-9be2-8c3a10f19b9d" # Reports Reader
"7be44c8a-adaf-4e2a-84d6-ab2649e08a13" # Billing Administrator
"e8611ab8-c189-46e8-94e1-60213ab1f814" # Cloud Application Administrator
)
ExcludeRoles = @(
"d29b2b05-8046-44ba-8758-1e26182fcf32" # Directory Synchronization Accounts
)
}
Applications = @{
IncludeApplications = @("All")
ExcludeApplications = @()
}
ClientAppTypes = @("all")
}
GrantControls = @{
Operator = "OR"
BuiltInControls = @("mfa")
}
}
# Create the Conditional Access policy
$policy = Get-OrCreatePolicy -DisplayName "Require multifactor authentication for admins" -BodyParams $policyParams
# Define the policy from your JSON
$policyParams = @{
DisplayName = "Require multifactor authentication for all users"
State = "enabled"
Conditions = @{
Users = @{
IncludeUsers = @("All")
ExcludeGroups = @($osTravelGroup.Id)
ExcludeRoles = @(
"d29b2b05-8046-44ba-8758-1e26182fcf32" # Directory Synchronization Accounts
)
}
Applications = @{
IncludeApplications = @("All")
ExcludeApplications = @()
}
ClientAppTypes = @("all")
}
GrantControls = @{
Operator = "OR"
BuiltInControls = @("mfa")
}
}
# Create the Conditional Access policy
$policy = Get-OrCreatePolicy -DisplayName "Require multifactor authentication for all users" -BodyParams $policyParams
# Define the policy from your JSON
$policyParams = @{
DisplayName = "Require multifactor authentication for Azure management"
State = "enabled"
Conditions = @{
Users = @{
IncludeUsers = @("All")
ExcludeRoles = @(
"d29b2b05-8046-44ba-8758-1e26182fcf32" # Directory Synchronization Accounts
)
}
Applications = @{
IncludeApplications = @(
"797f4846-ba00-4fd7-ba43-dac1f8f63013" # Azure Management
)
ExcludeApplications = @()
}
ClientAppTypes = @("all")
}
GrantControls = @{
Operator = "OR"
BuiltInControls = @("mfa")
}
}
# Create the Conditional Access policy
$policy = Get-OrCreatePolicy -DisplayName "Require multifactor authentication for Azure management" -BodyParams $policyParams
# Get Graph token for REST calls
$token = (Get-MgContext).AccessToken
$headers = @{ Authorization = "Bearer $token"; "Content-Type" = "application/json" }
# Get all users
$users = Get-MgUser -All -Property "id,userPrincipalName,accountEnabled,strongAuthenticationRequirements"
foreach ($u in $users) {
# Skip disabled accounts
if (-not $u.AccountEnabled) {
Write-Host "🚫 Skipping disabled user $($u.UserPrincipalName)"
continue
}
# Skip if MFA already not set
if (-not $u.StrongAuthenticationRequirements -or $u.StrongAuthenticationRequirements.Count -eq 0) {
Write-Host " No per-user MFA set for $($u.UserPrincipalName) skipping"
continue
}
# Clear per-user MFA
$body = @{ strongAuthenticationRequirements = @() } | ConvertTo-Json -Depth 3
Invoke-RestMethod -Method PATCH `
-Headers $headers `
-Uri "https://graph.microsoft.com/v1.0/users/$($u.Id)" `
-Body $body
Write-Host "✅ Disabled per-user MFA for $($u.UserPrincipalName)"
}

View File

@ -1,35 +0,0 @@
# Check if the Microsoft Graph PowerShell SDK is installed
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) {
Install-Module -Name Microsoft.Graph -Scope CurrentUser -Force
}
# Check if the Microsoft Graph PowerShell SDK is installed
if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Beta)) {
Install-Module -Name Microsoft.Graph.Beta -Scope CurrentUser -Force
}
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "DeviceManagementConfiguration.ReadWrite.All", "Organization.Read.All", "Group.ReadWrite.All", "Directory.ReadWrite.All" -NoWelcome
$params = @{
"@odata.type"= "#microsoft.graph.windowsUpdateForBusinessConfiguration"
"displayName"= "Win - OIB - WUfB Drivers - Ring 1 - Pilot - v3.0"
"description"= "" # Empty string if description is not needed
"automaticUpdateMode"= "autoInstallAndRebootAtMaintenanceTime" # You can adjust based on requirements
"qualityUpdatesDeferralPeriodInDays"= 7 # Example deferral value
"featureUpdatesDeferralPeriodInDays"= 30 # Example deferral value
"allowMicrosoftUpdate"= $true # Enables updates for Microsoft products
"roleScopeTagIds"= @("0") # Example role scope tag ID
"assignments"= @() # Empty array for assignments
}
# Use the display name from the parameters for identification
$ring = $params.displayName
# Create the driver update profile
$null = New-MgDeviceManagementDeviceConfiguration -BodyParameter $params
Write-Host "✅ Successfully created $ring"
$null = Disconnect-Graph -ErrorAction SilentlyContinue