diff --git a/CompliancePolicy.ps1 b/CompliancePolicy.ps1 deleted file mode 100644 index 8aa9be1..0000000 --- a/CompliancePolicy.ps1 +++ /dev/null @@ -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 diff --git a/ImportPolicies.ps1 b/ImportPolicies.ps1 index 6bf5f0e..a1ac0b4 100644 --- a/ImportPolicies.ps1 +++ b/ImportPolicies.ps1 @@ -10,7 +10,7 @@ if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Beta)) { # 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 $tenant = Get-MgOrganization diff --git a/NewAppReg.ps1 b/NewAppReg.ps1 index 5061cf3..cfda0e9 100644 --- a/NewAppReg.ps1 +++ b/NewAppReg.ps1 @@ -1,16 +1,15 @@ # Ensure Microsoft.Graph module is installed 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 } # Ensure ExchangeOnlineManagement module is installed -if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) { - Write-Host "Installing ExchangeOnlineManagement Module..." +if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) { + Write-Host "✅ Installing ExchangeOnlineManagement Module..." Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber } - # Import necessary modules Import-Module Microsoft.Graph.Authentication Import-Module Microsoft.Graph.Applications @@ -21,7 +20,40 @@ Connect-MgGraph -Scopes "Application.ReadWrite.All", "Directory.ReadWrite.All", # Application details $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 $graphSp = Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'" @@ -76,11 +108,10 @@ if (-not $app) { Write-Host "✅ Application Created: $($app.Id)" # Wait for the application to propagate -Start-Sleep -Seconds 10 Write-Host "âŗ Waiting for application propagation..." +Start-Sleep -Seconds 10 # Create Service Principal -Write-Host "Creating Service Principal..." $servicePrincipal = New-MgServicePrincipal -AppId $app.AppId if (-not $servicePrincipal) { @@ -147,32 +178,6 @@ Write-Host "🔑 Client ID: $($app.AppId)" Write-Host "đŸ•ĩī¸â€â™‚ī¸ Client Secret: $($clientSecret.SecretText)" 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 \ No newline at end of file diff --git a/Setup.ps1 b/Setup.ps1 new file mode 100644 index 0000000..bcf52f7 --- /dev/null +++ b/Setup.ps1 @@ -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)" +} + + diff --git a/UpdateRings.ps1 b/UpdateRings.ps1 deleted file mode 100644 index 9127035..0000000 --- a/UpdateRings.ps1 +++ /dev/null @@ -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 \ No newline at end of file