├── .gitignore ├── 0.2-Import-microsoft.graph.authentication.ps1 ├── 1-Compare-ConditionalAccess-v1-and-Beta.ps1 ├── 10-Daniel-DC-Conditional Access Policy Deployment Script copy.ps1 ├── 11-Entra Group Cleanup Script copy 6.ps1 ├── 12-Conditional Access Report-Only Analysis Script copy 3.ps1 ├── 13-Copy-CAPs-For-BYOD-Pilot.ps1 ├── 14-Exclude-Include-Admins-Roles-CAPs copy 2.ps1 ├── 14-Exclude-Include-Admins-Roles-CAPs copy 3.ps1 ├── 2-Exclude-EntraGroup-AllConditionalAccessPolicies copy 9.ps1 ├── 2.1-Exclude-Intune-App-AllConditionalAccessPolicies copy 14.ps1 ├── 3-Move-ConditionalAccessPoliciesJSONfiles.ps1 ├── 4-Delete-allConditionalAccessPolicies-v4-CSV.ps1 ├── 4.1-Delete-allConditionalAccessPolicies-v4-API copy 4.ps1 ├── 5-recreateConditionalAccesspoliciesusingJSON-v7.ps1 ├── 6-RemoveCAOrphanedGroup.ps1 ├── 7-RemoveCAOrphanedUser copy 2.ps1 ├── 8-RemoveCAOrphanedobjects-dynamic copy.ps1 ├── 9-Conditional Access JSON Converter copy 4.ps1 ├── Archive ├── 15-Exclude-Include-Gues-Roles-CAPs copy 10.ps1 └── 15-Exclude-Include-Gues-Roles-CAPs copy 8.ps1 ├── CABaseline2025 ├── AppConfigurationManagedApp │ ├── ACP001 - iOSiPadOS - Outlook - Default Signature and External Mailtip.json │ └── ACP002 - Android - Outlook - Default Signature and External Mailtip.json ├── AppProtection │ ├── APP001 - Unmanaged - BYOD - iOSiPadOS - MAM - Require Min iOS version.json │ ├── APP002 - Unmanaged - BYOD - Android - MAM - Require Min OS version.json │ └── MAM for Edge.json ├── AssignmentFilters │ ├── Filter001 - Exclude Library Computers from Filehold Install.json │ ├── Filter002 - Unmanaged - BYOD - iOSiPad OS Devices.json │ └── Filter003 - Unmanaged - BYOD - Android OS Devices.json ├── AuthenticationStrengths │ ├── MS Auth app - WHFB - TAP.json │ ├── Multifactor authentication.json │ ├── Passwordless MFA.json │ └── Phishing-resistant MFA.json ├── CompliancePolicies │ └── Default compliance policy for Android.json ├── ConditionalAccess │ ├── CAD001-O365 Grant macOS access for All users when Modern Auth Clients and Compliant-v1.1.json │ ├── CAD002-O365 Grant Windows access for All users when Modern Auth Clients and Compliant-v1.1.json │ ├── CAD003-O365 Grant iOS and Android access for All users when Modern Auth Clients and ApprovedApp or Compliant-v1.2.json │ ├── CAD004-O365 Grant Require MFA for All users when Browser and Non-Compliant-v1.5.json │ ├── CAD005-O365 Block access for unsupported device platforms for All users when Modern Auth Clients-v1.2.json │ ├── CAD006-O365 Session block download on unmanaged device for All users when Browser and Modern App Clients and Non-Compliant-v1.5.json │ ├── CAD007-O365 Session set Sign-in Frequency for Apps for All users when Modern Auth Clients and Non-Compliant-v1.2.json │ ├── CAD008-All Session set Sign-in Frequency for All users when Browser and Non-Compliant-v1.1.json │ ├── CAD009-All Session disable browser persistence for All users when Browser and Non-Compliant-v1.2.json │ ├── CAD010-RJD Require MFA for device join or registration when Browser and Modern Auth Clients-v1.2.json │ ├── CAD011-O365 Grant Linux access for All users when Modern Auth Clients and Compliant-v1.0.json │ ├── CAD012-ALL Grant access for Admin users when Browser and Modern Auth Clients and Compliant- Remember to Exclude Trusted locationsv1.2.json │ ├── CAD014-O365 Require App Protection Policy for Edge on Windows for All users when Browser and Non-Compliant-v1.0.json │ ├── CAD015-All Grant access for All users when Browser and Modern Auth Clients and Compliant on Windows and macOS- v1.0 .json │ ├── CAD016-EXO_SPO Require token protection when Modern Auth Clients on Windows - v1.1.json │ ├── CAL002-RSI Require MFA registration from trusted locations only for All users when Browser and Modern Auth Clients-v1.5.json │ ├── CAL004-All Block access for Admins from non-trusted locations when Browser and Modern Auth Clients-v1.1.json │ ├── CAL011-Allow access from Trusted Countries Only v1.2.json │ ├── CAP001-All Block Legacy Authentication for All users when OtherClients-v1.1.json │ ├── CAP002-O365 Grant Exchange ActiveSync Clients for All users when Approved App-v1.0.json │ ├── CAU001-All Grant Require MFA for guests when Browser and Modern Auth Clients-v1.0.json │ ├── CAU002-All Grant Require MFA for All users when Browser and Modern Auth Clients-v1.2.json │ ├── CAU003-Selected Block unapproved apps for guests when Browser and Modern Auth Clients-v1.0.json │ ├── CAU005-Selected Session route through MDCA for All users when Browser on Compliant-v1.1.json │ ├── CAU008-All Grant Require Phishing-resistant MFA for Admins when Browser and Modern Auth Clients-Test if WHFB work from BYOD-v1.4.json │ ├── CAU009-Management BLOCK Admin Portals for All Users when Browser and Modern Auth Clients-v1.2.json │ ├── CAU013-All Grant Require phishing resistant MFA for All users when Browser and Modern Auth Clients - Keep for Admins initially-v1.1.json │ ├── GLOBAL - 1020 - BLOCK - Device Code Auth Flow.json │ ├── GLOBAL - 1040 - BLOCK - Countries not Allowed - Remember to Update Countries.json │ ├── GLOBAL - 1060 - BLOCK - Service Accounts (Trusted Locations Excluded) - Remember to add 1 service account per policy.json │ ├── GLOBAL - 1080 - BLOCK - Guest Access to Sensitive Apps.json │ ├── GLOBAL - 1085 - BLOCK - User Access to Sensitive Apps - v1.2.json │ ├── GLOBAL - 1090 - BLOCK - High-Med-Risk Sign-Ins - Entra ID P2 - v1.3.json │ ├── GLOBAL - 1100 - BLOCK - High-Med-Risk Users - Entra ID P2 - v1.3.json │ ├── GLOBAL - 2010 - GRANT - Low-Risk Sign-ins - Entra ID P2 - v1.3.json │ ├── GLOBAL - 2020 - GRANT - Low-Risk Users - Entra ID P2 - v1.3.json │ ├── GLOBAL - 2040 - GRANT - Terms of Use (All users) - Remember to update TOU v1.2.json │ ├── GLOBAL - 2050 - GRANT - MFA for All Users - need to exclude all Admins - v1.2.json │ ├── GLOBAL - 2060 - GRANT - Mobile Apps and Desktop Clients - Only for fully Blocking BYOD.json │ ├── GLOBAL - 2070 - GRANT - Mobile Device Access Requirements - v1.2.json │ ├── GLOBAL - 3010 - SESSION - ADMINS - Persistence.json │ ├── GLOBAL - 3020 - SESSION - BYOD Persistence.json │ ├── GLOBAL - 3030 - SESSION - Register Security Info Requirements - v1.2.json │ └── OVERRIDE - 0001 - GRANT - Example.json ├── Groups │ ├── AAD_UA_CAD001_Exclude.json │ ├── AAD_UA_CAD002_Exclude.json │ ├── AAD_UA_CAD003_Exclude.json │ ├── AAD_UA_CAD004_Exclude.json │ ├── AAD_UA_CAD005_Exclude.json │ ├── AAD_UA_CAD006_Exclude.json │ ├── AAD_UA_CAD007_Exclude.json │ ├── AAD_UA_CAD008_Exclude.json │ ├── AAD_UA_CAD009_Exclude.json │ ├── AAD_UA_CAD010_Exclude.json │ ├── AAD_UA_CAD012_Exclude.json │ ├── AAD_UA_CAD014_Exclude.json │ ├── AAD_UA_CAD015_Exclude.json │ ├── AAD_UA_CAD015_Include.json │ ├── AAD_UA_CAD016_Exclude.json │ ├── AAD_UA_CAD016_Include.json │ ├── AAD_UA_CAL002_Exclude.json │ ├── AAD_UA_CAL004_Exclude.json │ ├── AAD_UA_CAP001_Exclude.json │ ├── AAD_UA_CAP002_Exclude.json │ ├── AAD_UA_CAU001_Exclude.json │ ├── AAD_UA_CAU002_Exclude.json │ ├── AAD_UA_CAU003_Exclude.json │ ├── AAD_UA_CAU005_Exclude.json │ ├── AAD_UA_CAU008_Exclude.json │ ├── AAD_UA_CAU009_Exclude.json │ ├── AAD_UA_CAU013_Include.json │ ├── AAD_UA_ConAcc-Breakglass.json │ ├── AAD_UA_Update-Ring-02.json │ ├── Conditional Access Service Accounts.json │ ├── Excluded from Country Block List.json │ ├── Excluded from Device Code Auth Flow Block.json │ └── Information Technology and Systems.json ├── MigrationTable.json ├── NamedLocations │ ├── All Compliant Network locations.json │ ├── Allowed Countries.json │ ├── CCI - FortiGate VPN SSL.json │ ├── CCI JumpBox.json │ ├── Canada and USA.json │ ├── Fake Restrictive Location.json │ ├── HQ - Canada.json │ ├── High-Risk Countries.json │ └── Service Accounts Trusted IPs.json └── TermsOfUse │ ├── MSFT Terms of Use.json │ ├── Terms of Use.json │ ├── file-sample_150kB.pdf │ └── termsofuse.pdf ├── Compliance ├── Archive │ ├── Connect-MGGraphwithCert-Template-v1.1.ps1 │ ├── Find-MgGraphPermissions.ps1 │ ├── Get-ComplianceReportBasedonSignInLogs.ps1 │ ├── Get-LatestWinGetversion.Archive.ps1 │ ├── GraphCalls.ps1 │ ├── Invoke-MgGraphRequestwithAccessToken copy 2.ps1 │ ├── Invoke-MgGraphRequestwithAccessToken copy 3.ps1 │ ├── Invoke-MgGraphRequestwithAccessToken copy.ps1 │ ├── Invoke-MgGraphRequestwithAccessToken.ps1 │ ├── Logging.ps1 │ ├── Ondrej-Sebela-doitpshway copy 2.ps1 │ ├── Ondrej-Sebela-doitpshway copy.ps1 │ ├── Ondrej-Sebela-doitpshway.ps1 │ ├── get-allauditlogs copy 2.ps1 │ ├── get-allauditlogs copy 4.ps1 │ ├── get-allauditlogs copy 5-working-code-no-parallel.ps1 │ ├── get-allauditlogs copy 6-allmodulesinparallelblock.ps1 │ ├── get-allauditlogs copy 6-parallel.ps1 │ ├── get-allauditlogs copy 7-parallel-removed-boiler-plate.ps1 │ ├── get-allauditlogs copy.ps1 │ ├── get-allauditlogs.ps1 │ ├── helloworld.psm1 │ ├── test-LINQ-v2.ps1 │ ├── test-LINQ-v3.ps1 │ ├── test-LINQ.ps1 │ ├── test-Parallel-v2.ps1 │ ├── test-Parallel.ps1 │ └── tests │ │ ├── Async.Logging.PSF.test.ps1 │ │ ├── GetLatestVersion.Choco.test.ps1 │ │ ├── GetLatestVersion.Winget.test.ps1 │ │ ├── validatesoftware.test copy.ps1 │ │ └── validatesoftware.test.ps1 ├── Benchmarking │ ├── 1-Get-Content and ConvertFrom-Json.ps1 │ ├── 2-System.IO.StreamReader and ConvertFrom-Json.ps1 │ ├── 3-System.Text.Json.JsonDocument.ps1 │ ├── 4-System.Text.Json.JsonDocument.ps1 │ ├── 5-compare-json-file-read.ps1 │ ├── Test-DataStructures.ps1 │ ├── test-newtonsoft-linq.ps1 │ └── test-vscode-debugging.ps1 ├── CustomExports │ ├── BYODCompliant.csv │ ├── BYOD_AND_CORP_ER_Incompliant.csv │ ├── CorporateCompliant.csv │ ├── CorporateIncompliant.csv │ ├── MasterReport.csv │ ├── Report_Compliant.csv │ ├── Report_Error.csv │ ├── Report_External.csv │ ├── Report_NonCompliant.csv │ ├── Report_NonPremiumLicenses.csv │ ├── Report_PIIRemoved.csv │ ├── Report_PremiumLicenses.csv │ ├── Report_Present.csv │ └── StructuredReport.csv ├── Get-ComplianceReportBasedonSignInLogs-ALPHA-v1.ps1 ├── Modules.json ├── Readme.md ├── combine-allmodules.ps1 ├── config.json └── modulesexclusion.json ├── ConditionalAccess ├── Archive │ ├── Delete-allConditionalAccessPolicies-v2.ps1 │ ├── Delete-allConditionalAccessPolicies-v3.ps1 │ ├── Delete-allConditionalAccessPolicies.ps1 │ ├── Rename-ConditionalAccessPolicies-All-v2.ps1 │ ├── Rename-ConditionalAccessPolicies-All-v3.ps1 │ ├── Rename-ConditionalAccessPolicies-All-v4.ps1 │ ├── recreateConditionalAccesspoliciesusingJSON-v2.ps1 │ ├── recreateConditionalAccesspoliciesusingJSON-v3.ps1 │ ├── recreateConditionalAccesspoliciesusingJSON-v4.ps1 │ ├── recreateConditionalAccesspoliciesusingJSON-v5.ps1 │ ├── recreateConditionalAccesspoliciesusingJSON-v6.ps1 │ └── recreateConditionalAccesspoliciesusingJSON.ps1 ├── Conditional Access Policy Name Generator copy.ps1 ├── Conditional Access Policy Name Generator.ps1 ├── Delete-allConditionalAccessPolicies-v4.ps1 ├── Export-CAPolicy.ps1 ├── Rename-ConditionalAccessPolicies-All.ps1 └── Rename-ConditionalAccessPolicies.ps1 ├── Module ├── ConditionalAccess.psd1 ├── ConditionalAccess.psm1 ├── Example │ └── 15-Exclude-Include-Gues-Roles-CAPs copy 9.ps1 ├── Private │ ├── Get-GuestUserTypes.ps1 │ └── Show-GuestOperationMenu.ps1 ├── Public │ ├── Export-GuestPolicyReport.ps1 │ ├── Get-ConditionalAccessPoliciesDetails.ps1 │ └── Update-ConditionalAccessPolicyGuestTypes.ps1 └── en-US │ └── about_ConditionalAccess.help.txt ├── Modules.json ├── README.md ├── config.json ├── modulesexclusion.json └── scopes.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /Reports 3 | -------------------------------------------------------------------------------- /0.2-Import-microsoft.graph.authentication.ps1: -------------------------------------------------------------------------------- 1 | # Define error handling preferences 2 | $ErrorActionPreference = 'Stop' 3 | 4 | 5 | function Write-ConditionalAccessLog { 6 | param( 7 | [Parameter(Mandatory)] 8 | [string]$Message, 9 | 10 | [ValidateSet('Info', 'Warning', 'Error')] 11 | [string]$Level = 'Info' 12 | ) 13 | 14 | $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' 15 | $logMessage = "[$timestamp] [$Level] $Message" 16 | 17 | switch ($Level) { 18 | 'Info' { Write-Host $logMessage -ForegroundColor Green } 19 | 'Warning' { Write-Host $logMessage -ForegroundColor Yellow } 20 | 'Error' { Write-Host $logMessage -ForegroundColor Red } 21 | } 22 | } 23 | 24 | 25 | function Test-AdminAndPSVersion { 26 | Write-ConditionalAccessLog "Checking PowerShell version and administrative privileges..." 27 | 28 | $currentPrincipal = [Security.Principal.WindowsPrincipal]::new( 29 | [Security.Principal.WindowsIdentity]::GetCurrent() 30 | ) 31 | 32 | $isAdmin = $currentPrincipal.IsInRole( 33 | [Security.Principal.WindowsBuiltInRole]::Administrator 34 | ) 35 | $isPS5 = $PSVersionTable.PSVersion.Major -eq 5 36 | 37 | Write-ConditionalAccessLog "Current PowerShell Version: $($PSVersionTable.PSVersion.ToString())" 38 | Write-ConditionalAccessLog "Running as Administrator: $isAdmin" 39 | 40 | if (-not $isPS5) { 41 | Write-ConditionalAccessLog "PowerShell 5 check failed. Current version: $($PSVersionTable.PSVersion.ToString())" -Level Error 42 | throw [System.InvalidOperationException]::new( 43 | "PowerShell 5 is required. Current version: $($PSVersionTable.PSVersion.ToString())" 44 | ) 45 | } 46 | 47 | if (-not $isAdmin) { 48 | Write-ConditionalAccessLog "Administrator privileges check failed" -Level Error 49 | throw [System.UnauthorizedAccessException]::new( 50 | 'Administrator rights are required to run this script.' 51 | ) 52 | } 53 | 54 | Write-ConditionalAccessLog "All prerequisite checks passed successfully" 55 | return $true 56 | } 57 | 58 | function Install-RequiredModule { 59 | param( 60 | [Parameter(Mandatory)] 61 | [string]$ModuleName 62 | ) 63 | 64 | Write-ConditionalAccessLog "Checking module: $ModuleName" 65 | Test-AdminAndPSVersion | Out-Null 66 | 67 | if (Get-Module -ListAvailable -Name $ModuleName) { 68 | Write-ConditionalAccessLog "Module '$ModuleName' is already installed" 69 | $existingVersion = (Get-Module -ListAvailable -Name $ModuleName | Sort-Object Version -Descending | Select-Object -First 1).Version 70 | Write-ConditionalAccessLog "Current version: $existingVersion" 71 | } 72 | else { 73 | Write-ConditionalAccessLog "Module '$ModuleName' not found. Attempting installation..." 74 | $installParams = @{ 75 | Name = $ModuleName 76 | Force = $true 77 | AllowClobber = $true 78 | Scope = 'AllUsers' 79 | ErrorAction = 'Stop' 80 | } 81 | 82 | try { 83 | Install-Module @installParams 84 | $installedVersion = (Get-Module -ListAvailable -Name $ModuleName | Sort-Object Version -Descending | Select-Object -First 1).Version 85 | Write-ConditionalAccessLog "Successfully installed '$ModuleName' version $installedVersion" 86 | } 87 | catch { 88 | Write-ConditionalAccessLog "Failed to install module '$ModuleName': $_" -Level Error 89 | throw [System.Management.Automation.ItemNotFoundException]::new( 90 | "Failed to install module '$ModuleName': $_" 91 | ) 92 | } 93 | } 94 | } 95 | 96 | # Required modules 97 | $requiredModules = @( 98 | 'Microsoft.Graph.Users' 99 | 'Microsoft.Graph.Identity.DirectoryManagement' 100 | 'Microsoft.Graph.Authentication' 101 | 'ExchangeOnlineManagement' 102 | 'Microsoft.Graph.Beta.Identity.SignIns' 103 | 'Microsoft.Graph.Groups', 104 | 'Microsoft.Graph.Identity.SignIns', 105 | 'Microsoft.Graph.Beta.Identity.DirectoryManagement' 106 | 107 | ) 108 | 109 | # Main execution block 110 | try { 111 | Write-ConditionalAccessLog "=== Starting Module Installation Process ===" 112 | Write-ConditionalAccessLog "Required modules: $($requiredModules -join ', ')" 113 | 114 | foreach ($module in $requiredModules) { 115 | Install-RequiredModule -ModuleName $module 116 | } 117 | 118 | Write-ConditionalAccessLog "Importing all required modules..." 119 | Import-Module -Name $requiredModules -ErrorAction Stop 120 | Write-ConditionalAccessLog "=== Module Installation Process Completed Successfully ===" 121 | } 122 | catch { 123 | Write-ConditionalAccessLog "=== Module Installation Process Failed ===" -Level Error 124 | throw "Module installation failed: $_" 125 | } 126 | 127 | 128 | function Import-RequiredModules { 129 | [CmdletBinding()] 130 | param() 131 | 132 | $logParams = @{ 133 | Message = "Importing required Microsoft Graph modules" 134 | Level = "Info" 135 | } 136 | Write-ConditionalAccessLog @logParams 137 | 138 | try { 139 | # Remove existing modules first to avoid assembly conflicts 140 | $modulesToRemove = @( 141 | 'Microsoft.Graph.Users' 142 | 'Microsoft.Graph.Groups' 143 | 'Microsoft.Graph.Authentication' 144 | 'Microsoft.Graph.Beta.Identity.SignIns' 145 | ) 146 | 147 | foreach ($module in $modulesToRemove) { 148 | if (Get-Module $module) { 149 | $removeParams = @{ 150 | Name = $module 151 | Force = $true 152 | ErrorAction = "SilentlyContinue" 153 | } 154 | Remove-Module @removeParams 155 | } 156 | } 157 | 158 | # Import required modules 159 | $modulesToImport = @( 160 | 'Microsoft.Graph.Users' 161 | 'Microsoft.Graph.Identity.DirectoryManagement' 162 | 'Microsoft.Graph.Authentication' 163 | 'ExchangeOnlineManagement' 164 | 'Microsoft.Graph.Beta.Identity.SignIns' 165 | 'Microsoft.Graph.Groups', 166 | 'Microsoft.Graph.Identity.SignIns', 167 | 'Microsoft.Graph.Beta.Identity.DirectoryManagement' 168 | ) 169 | 170 | foreach ($module in $modulesToImport) { 171 | $importParams = @{ 172 | Name = $module 173 | Force = $true 174 | ErrorAction = "Stop" 175 | } 176 | Import-Module @importParams 177 | 178 | $logParams = @{ 179 | Message = "Successfully imported module: $module" 180 | Level = "Info" 181 | } 182 | Write-ConditionalAccessLog @logParams 183 | } 184 | 185 | return $true 186 | } 187 | catch { 188 | $logParams = @{ 189 | Message = "Failed to import required modules: $_" 190 | Level = "Error" 191 | } 192 | Write-ConditionalAccessLog @logParams 193 | throw 194 | } 195 | } 196 | 197 | 198 | Import-RequiredModules 199 | 200 | 201 | 202 | 203 | # Enhanced Connection Functions for Graph and Exchange Online 204 | 205 | function Connect-GraphWithScope { 206 | [CmdletBinding()] 207 | param() 208 | 209 | # Define the scopes in an array 210 | $requiredScopes = @( 211 | "RoleAssignmentSchedule.ReadWrite.Directory", 212 | "Domain.Read.All", 213 | "Domain.ReadWrite.All", 214 | "Directory.Read.All", 215 | "Policy.ReadWrite.ConditionalAccess", 216 | "DeviceManagementApps.ReadWrite.All", 217 | "DeviceManagementConfiguration.ReadWrite.All", 218 | "DeviceManagementManagedDevices.ReadWrite.All", 219 | "openid", 220 | "profile", 221 | "email", 222 | "offline_access", 223 | "Policy.ReadWrite.PermissionGrant", 224 | "RoleManagement.ReadWrite.Directory", 225 | "Policy.ReadWrite.DeviceConfiguration", 226 | "DeviceLocalCredential.Read.All", 227 | "DeviceManagementManagedDevices.PrivilegedOperations.All", 228 | "DeviceManagementServiceConfig.ReadWrite.All", 229 | "Policy.Read.All", 230 | "DeviceManagementRBAC.ReadWrite.All", 231 | "UserAuthenticationMethod.ReadWrite.All", 232 | "User.Read.All", 233 | "Group.ReadWrite.All", 234 | "Directory.ReadWrite.All", 235 | "User.ReadWrite.All", 236 | "Application.Read.All" 237 | ) 238 | 239 | Write-ConditionalAccessLog "Checking Microsoft Graph connection..." 240 | $currentContext = Get-MgContext 241 | 242 | if ($null -eq $currentContext) { 243 | Write-ConditionalAccessLog "No existing Graph connection found. Connecting..." -Level Warning 244 | Connect-MgGraph -Scopes $requiredScopes 245 | $newContext = Get-MgContext 246 | Write-ConditionalAccessLog "Connected to Microsoft Graph as: $($newContext.Account)" -Level Info 247 | return 248 | } 249 | 250 | $missingScopes = $requiredScopes | Where-Object { $_ -notin $currentContext.Scopes } 251 | 252 | if ($missingScopes) { 253 | Write-ConditionalAccessLog "Missing required scopes: $($missingScopes -join ', ')" -Level Warning 254 | Write-ConditionalAccessLog "Reconnecting with all required scopes..." -Level Warning 255 | Disconnect-MgGraph 256 | Connect-MgGraph -Scopes $requiredScopes 257 | $newContext = Get-MgContext 258 | Write-ConditionalAccessLog "Reconnected to Microsoft Graph as: $($newContext.Account)" -Level Info 259 | } 260 | else { 261 | Write-ConditionalAccessLog "Already connected to Microsoft Graph with required scopes as: $($currentContext.Account)" -Level Info 262 | } 263 | } 264 | 265 | function Connect-RequiredServices { 266 | [CmdletBinding()] 267 | param() 268 | 269 | Write-ConditionalAccessLog "=== Starting Service Connections ===" -Level Info 270 | 271 | try { 272 | Connect-GraphWithScope 273 | Write-ConditionalAccessLog "=== All Service Connections Completed Successfully ===" -Level Info 274 | } 275 | catch { 276 | Write-ConditionalAccessLog "=== Service Connection Process Failed ===" -Level Error 277 | throw "Failed to connect to required services: $_" 278 | } 279 | } 280 | 281 | 282 | 283 | Connect-RequiredServices -------------------------------------------------------------------------------- /1-Compare-ConditionalAccess-v1-and-Beta.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph 2 | Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess", "Group.ReadWrite.All", "Policy.Read.All" 3 | 4 | function Get-ConditionalAccessPoliciesViaMgGraph { 5 | param ( 6 | [string]$GraphVersion 7 | ) 8 | 9 | $uri = "https://graph.microsoft.com/$GraphVersion/identity/conditionalAccess/policies" 10 | $allPolicies = @() 11 | 12 | do { 13 | $response = Invoke-MgGraphRequest -Uri $uri -Method GET -Headers @{"Prefer"="odata.maxpagesize=999"} 14 | $policies = $response.Value 15 | $allPolicies += $policies 16 | $uri = if ($response.'@odata.nextLink') { $response.'@odata.nextLink' } else { $null } 17 | } while ($uri) 18 | 19 | return $allPolicies 20 | } 21 | 22 | # Fetch policies using Beta endpoint 23 | $betaPolicies = Get-ConditionalAccessPoliciesViaMgGraph -GraphVersion "beta" 24 | 25 | # Fetch policies using v1.0 endpoint 26 | $v1Policies = Get-ConditionalAccessPoliciesViaMgGraph -GraphVersion "v1.0" 27 | 28 | # Extract IDs into simple arrays 29 | $betaPolicyIds = $betaPolicies | ForEach-Object { $_.id } 30 | $v1PolicyIds = $v1Policies | ForEach-Object { $_.id } 31 | 32 | # Identify deprecated policies by comparing IDs 33 | $deprecatedPolicyIds = $betaPolicyIds | Where-Object { $_ -notin $v1PolicyIds } 34 | 35 | 36 | # Filter the full policy objects for deprecated policies 37 | $deprecatedPolicies = $betaPolicies | Where-Object { $deprecatedPolicyIds -contains $_.id } 38 | 39 | 40 | # Assuming $deprecatedPolicies contains hashtables with the desired keys 41 | 42 | # Prepare the data for CSV export and Out-GridView by accessing the hashtable properties directly 43 | $exportData = $deprecatedPolicies | ForEach-Object { 44 | [PSCustomObject]@{ 45 | id = $_.id 46 | displayName = $_.displayName 47 | createdDateTime = $_.createdDateTime 48 | state = $_.state 49 | } 50 | } 51 | 52 | 53 | # New-Item -Path 'D:\Code\CB\Entra\ICTC\Graph\export\' 54 | 55 | 56 | # Export to CSV 57 | # mkdir C:\Code\CB\Entra\Ambico\Graph\export 58 | 59 | # Define the tenant name variable 60 | $TenantName = "MSFT" 61 | 62 | # Construct the directory path using the tenant name 63 | $DirectoryPath = Join-Path -Path "C:\Code\CB\Entra" -ChildPath "$TenantName\Graph\export" 64 | 65 | # Check if the directory exists, and create it if it does not 66 | if (-not (Test-Path -Path $DirectoryPath)) { 67 | New-Item -Path $DirectoryPath -ItemType Directory -Force 68 | Write-Host "Directory created: $DirectoryPath" 69 | } else { 70 | Write-Host "Directory already exists: $DirectoryPath" 71 | } 72 | 73 | 74 | $exportData | Export-Csv -Path "$DirectoryPath\DeprecatedPolicies.csv" -NoTypeInformation 75 | 76 | # Display in Out-GridView 77 | $exportData | Out-GridView -Title "Deprecated Policies" 78 | 79 | # Output policy details to console in a well-formatted table 80 | Write-Host "Deprecated Policies:" 81 | $exportData | Format-Table -AutoSize -------------------------------------------------------------------------------- /10-Daniel-DC-Conditional Access Policy Deployment Script copy.ps1: -------------------------------------------------------------------------------- 1 | # Install required modules if not already installed 2 | function Install-RequiredModules { 3 | $modules = @( 4 | 'Microsoft.Graph.Authentication', 5 | 'Microsoft.Graph.Identity.SignIns', 6 | 'Microsoft.Graph.Groups', 7 | 'Microsoft.Graph.Users', 8 | 'Microsoft.Graph.Identity.Governance', 9 | 'Microsoft.Graph.Identity.DirectoryManagement', 10 | 'DCToolbox' 11 | ) 12 | 13 | foreach ($module in $modules) { 14 | if (-not (Get-Module -ListAvailable -Name $module)) { 15 | Write-Host "Installing $module..." -ForegroundColor Yellow 16 | Install-Module -Name $module -Force -AllowClobber -Scope CurrentUser 17 | } 18 | } 19 | } 20 | 21 | function Initialize-CADeployment { 22 | # Show warning message 23 | Write-Host @" 24 | IMPORTANT SAFETY NOTICE 25 | ---------------------- 26 | You are about to deploy Conditional Access policies. These policies can affect all users' 27 | ability to access your environment. Before proceeding, ensure you have: 28 | 29 | 1. Created a break glass account 30 | 2. Documented the break glass account credentials securely 31 | 3. Backed up any existing policies 32 | 4. Reviewed the policies that will be deployed 33 | 5. Have a plan to test each policy before enabling 34 | 35 | "@ -ForegroundColor Yellow 36 | 37 | $continue = Read-Host "Have you completed all the above steps? (yes/no)" 38 | if ($continue -ne "yes") { 39 | Write-Host "Deployment cancelled for safety. Please complete all preparatory steps first." -ForegroundColor Red 40 | return 41 | } 42 | 43 | # Install required modules 44 | Install-RequiredModules 45 | 46 | # Import required modules 47 | Import-Module Microsoft.Graph.Authentication 48 | Import-Module Microsoft.Graph.Identity.SignIns 49 | Import-Module Microsoft.Graph.Groups 50 | Import-Module Microsoft.Graph.Users 51 | Import-Module Microsoft.Graph.Identity.Governance 52 | Import-Module Microsoft.Graph.Identity.DirectoryManagement 53 | Import-Module DCToolbox 54 | 55 | # Connect to Microsoft Graph with required permissions 56 | $requiredScopes = @( 57 | 'Policy.ReadWrite.ConditionalAccess', 58 | 'Policy.Read.All', 59 | 'Directory.Read.All', 60 | 'Application.Read.All', 61 | 'Agreement.Read.All', 62 | 'GroupMember.Read.All', 63 | 'Agreement.ReadWrite.All' 64 | ) 65 | 66 | Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Yellow 67 | Connect-DCMsGraphAsUser -Scopes $requiredScopes 68 | 69 | # Deploy baseline policies 70 | Write-Host "Starting Conditional Access baseline deployment..." -ForegroundColor Green 71 | 72 | # Force Report-Only mode for safety 73 | $deployParams = @{ 74 | CreateDocumentation = $true 75 | SkipReportOnlyMode = $false # Always deploy in report-only mode first 76 | } 77 | 78 | try { 79 | # Create break glass account exclusion group if it doesn't exist 80 | Write-Host "Checking break glass account exclusion group..." -ForegroundColor Yellow 81 | 82 | # Deploy the baseline policies 83 | Deploy-DCConditionalAccessBaselinePoC @deployParams 84 | 85 | Write-Host "Deployment completed successfully!" -ForegroundColor Green 86 | Write-Host @" 87 | 88 | NEXT STEPS (DO NOT SKIP THESE): 89 | ------------------------------ 90 | 1. Add your break glass accounts to the 'Excluded from Conditional Access' group 91 | 2. Review each policy in the Azure Portal (https://portal.azure.com/#blade/Microsoft_AAD_IAM/ConditionalAccessBlade/Policies) 92 | 3. Test each policy in Report-Only mode and review the Insights 93 | 4. Document any changes needed based on your testing 94 | 5. Create a pilot group for initial testing 95 | 6. Enable policies one at a time, starting with least impactful 96 | 7. Monitor sign-in logs for issues 97 | 98 | SAFE ENABLEMENT PROCESS: 99 | ---------------------- 100 | 1. First, test with a pilot group: 101 | Set-DCConditionalAccessPoliciesPilotMode -PrefixFilter 'GLOBAL - ' -PilotGroupName 'Conditional Access Pilot' -EnablePilot 102 | 103 | 2. After successful pilot, enable individual policies: 104 | - Use Azure Portal to enable policies one at a time 105 | - Monitor between each enablement 106 | - Have your break glass account ready 107 | 108 | 3. DO NOT enable all policies at once using PowerShell commands 109 | 110 | Documentation has been generated - please review it thoroughly. 111 | 112 | "@ -ForegroundColor Yellow 113 | } 114 | catch { 115 | Write-Host "Error during deployment: $_" -ForegroundColor Red 116 | Write-Host "Please ensure you have Global Administrator or Security Administrator rights." -ForegroundColor Red 117 | } 118 | } 119 | 120 | # Execute the deployment 121 | Initialize-CADeployment -------------------------------------------------------------------------------- /13-Copy-CAPs-For-BYOD-Pilot.ps1: -------------------------------------------------------------------------------- 1 | # Function definitions 2 | function Test-PolicyJson { 3 | [CmdletBinding()] 4 | param( 5 | [Parameter(Mandatory)] 6 | [string]$FilePath 7 | ) 8 | 9 | try { 10 | $null = Get-Content $FilePath -Raw | ConvertFrom-Json 11 | return @{ 12 | IsValid = $true 13 | Error = $null 14 | } 15 | } 16 | catch { 17 | return @{ 18 | IsValid = $false 19 | Error = $_.Exception.Message 20 | } 21 | } 22 | } 23 | 24 | function Test-PolicyFiles { 25 | [CmdletBinding()] 26 | param ( 27 | [Parameter(Mandatory)] 28 | [string]$SourcePath, 29 | 30 | [Parameter(Mandatory)] 31 | [string[]]$ExpectedPolicies 32 | ) 33 | 34 | $results = [System.Collections.ArrayList]::new() 35 | 36 | foreach ($policy in $ExpectedPolicies) { 37 | $policyPath = Join-Path $SourcePath "$policy.json" 38 | $exists = Test-Path $policyPath 39 | 40 | $resultObject = [PSCustomObject]@{ 41 | PolicyName = $policy 42 | Exists = $exists 43 | FullPath = $policyPath 44 | IsValidJson = $false 45 | JsonError = $null 46 | } 47 | 48 | if ($exists) { 49 | $jsonTest = Test-PolicyJson -FilePath $policyPath 50 | $resultObject.IsValidJson = $jsonTest.IsValid 51 | $resultObject.JsonError = $jsonTest.Error 52 | } 53 | 54 | $null = $results.Add($resultObject) 55 | } 56 | 57 | return $results 58 | } 59 | 60 | function Copy-PolicyFiles { 61 | [CmdletBinding()] 62 | param ( 63 | [Parameter(Mandatory)] 64 | [string]$SourcePath, 65 | 66 | [Parameter(Mandatory)] 67 | [string]$DestinationPath, 68 | 69 | [Parameter(Mandatory)] 70 | [string[]]$Policies 71 | ) 72 | 73 | $results = [System.Collections.ArrayList]::new() 74 | 75 | foreach ($policy in $Policies) { 76 | try { 77 | $sourceFile = Join-Path $SourcePath "$policy.json" 78 | Copy-Item -Path $sourceFile -Destination $DestinationPath -Force -ErrorAction Stop 79 | 80 | $resultObject = [PSCustomObject]@{ 81 | PolicyName = $policy 82 | Status = 'Success' 83 | ErrorMessage = '' 84 | } 85 | } 86 | catch { 87 | $resultObject = [PSCustomObject]@{ 88 | PolicyName = $policy 89 | Status = 'Failed' 90 | ErrorMessage = $_.Exception.Message 91 | } 92 | } 93 | 94 | $null = $results.Add($resultObject) 95 | } 96 | 97 | return $results 98 | } 99 | 100 | function Export-PolicyCopyReport { 101 | param( 102 | [Parameter(Mandatory)] 103 | $Results, 104 | 105 | [Parameter(Mandatory)] 106 | [string]$OutputDir, 107 | 108 | [Parameter()] 109 | [string]$ReportName = "PolicyCopy_Report" 110 | ) 111 | 112 | $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" 113 | $htmlPath = Join-Path $OutputDir "$($ReportName)_$timestamp.html" 114 | $csvPath = Join-Path $OutputDir "$($ReportName)_$timestamp.csv" 115 | 116 | # Export to CSV 117 | $Results | Export-Csv -Path $csvPath -NoTypeInformation 118 | 119 | $metadata = @{ 120 | GeneratedBy = $env:USERNAME 121 | GeneratedOn = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 122 | TotalPolicies = $Results.Count 123 | SuccessCount = ($Results | Where-Object Status -eq "Success").Count 124 | FailureCount = ($Results | Where-Object Status -eq "Failed").Count 125 | } 126 | 127 | New-HTML -Title "Policy Copy Report" -FilePath $htmlPath -ShowHTML { 128 | New-HTMLSection -HeaderText "Copy Operation Summary" { 129 | New-HTMLPanel { 130 | New-HTMLText -Text @" 131 |

Report Details

132 | 139 | "@ 140 | } 141 | } 142 | 143 | New-HTMLSection -HeaderText "Policy Copy Results" { 144 | New-HTMLTable -DataTable $Results -ScrollX -Buttons @('copyHtml5', 'excelHtml5', 'csvHtml5') -SearchBuilder { 145 | New-TableCondition -Name 'Status' -ComparisonType string -Operator eq -Value 'Failed' -BackgroundColor Salmon -Color Black 146 | New-TableCondition -Name 'Status' -ComparisonType string -Operator eq -Value 'Success' -BackgroundColor LightGreen -Color Black 147 | } 148 | } 149 | } 150 | 151 | Write-Host "`nReports generated:" -ForegroundColor Green 152 | Write-Host "CSV Report: $csvPath" -ForegroundColor Green 153 | Write-Host "HTML Report: $htmlPath" -ForegroundColor Green 154 | 155 | return @{ 156 | CSVPath = $csvPath 157 | HTMLPath = $htmlPath 158 | } 159 | } 160 | 161 | function Copy-ConditionalAccessPolicies { 162 | [CmdletBinding()] 163 | param ( 164 | [Parameter(Mandatory)] 165 | [string]$SourcePath, 166 | 167 | [Parameter(Mandatory)] 168 | [string]$BaseDestPath, 169 | 170 | [Parameter(Mandatory)] 171 | [string[]]$ExpectedPolicies 172 | ) 173 | 174 | # Create timestamp for destination folder 175 | $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" 176 | $destPath = Join-Path $BaseDestPath "BYOD-Pilot-CAPs-$timestamp" 177 | 178 | # Test policy files 179 | $fileCheck = Test-PolicyFiles -SourcePath $SourcePath -ExpectedPolicies $ExpectedPolicies 180 | $missingFiles = $fileCheck | Where-Object { -not $_.Exists } 181 | $invalidJsonFiles = $fileCheck | Where-Object { $_.Exists -and -not $_.IsValidJson } 182 | 183 | $hasErrors = $false 184 | 185 | if ($missingFiles) { 186 | Write-Error "Missing policy files:" 187 | $missingFiles | ForEach-Object { 188 | Write-Error "- $($_.PolicyName)" 189 | } 190 | $hasErrors = $true 191 | } 192 | 193 | if ($invalidJsonFiles) { 194 | Write-Error "Invalid JSON found in policy files:" 195 | $invalidJsonFiles | ForEach-Object { 196 | Write-Error "- $($_.PolicyName): $($_.JsonError)" 197 | } 198 | $hasErrors = $true 199 | } 200 | 201 | if ($hasErrors) { 202 | return 203 | } 204 | 205 | # Create destination directory 206 | try { 207 | $null = New-Item -ItemType Directory -Path $destPath -Force 208 | Write-Host "Created destination directory: $destPath" -ForegroundColor Green 209 | } 210 | catch { 211 | Write-Error "Failed to create destination directory: $_" 212 | return 213 | } 214 | 215 | # Copy files and generate report 216 | $copyResults = Copy-PolicyFiles -SourcePath $SourcePath -DestinationPath $destPath -Policies $ExpectedPolicies 217 | Export-PolicyCopyReport -Results $copyResults -OutputDir $destPath 218 | 219 | return $copyResults 220 | } 221 | 222 | # Define paths and policies 223 | $sourcePath = "C:\CaaC\SandBox\Dec182024-v5\DC_KVS_AO_Combined\MSFT\ConditionalAccess" 224 | $baseDestPath = "C:\CaaC\SandBox" 225 | $expectedPolicies = @( 226 | "CAD004-O365 Grant Require MFA for All users when Browser and Non-Compliant-v1.5", 227 | "CAD005-O365 Block access for unsupported device platforms for All users when Modern Auth Clients-v1.2", 228 | "CAD006-O365 Session block download on unmanaged device for All users when Browser and Modern App Clients and Non-Compliant-v1.5", 229 | "CAD007-O365 Session set Sign-in Frequency for Apps for All users when Modern Auth Clients and Non-Compliant-v1.2", 230 | "GLOBAL - 3020 - SESSION - BYOD Persistence", 231 | "CAD010-RJD Require MFA for device join or registration when Browser and Modern Auth Clients-v1.2", 232 | "CAL002-RSI Require MFA registration from trusted locations only for All users when Browser and Modern Auth Clients-v1.5", 233 | "CAP002-O365 Grant Exchange ActiveSync Clients for All users when Approved App-v1.0", 234 | "CAU009-Management BLOCK Admin Portals for All Users when Browser and Modern Auth Clients-v1.2", 235 | "GLOBAL - 1020 - BLOCK - Device Code Auth Flow", 236 | "GLOBAL - 1060 - BLOCK - Service Accounts (Trusted Locations Excluded) - Remember to add 1 service account per policy", 237 | "GLOBAL - 1080 - BLOCK - Guest Access to Sensitive Apps", 238 | "GLOBAL - 3030 - SESSION - Register Security Info Requirements - v1.2", 239 | "CAD001-O365 Grant macOS access for All users when Modern Auth Clients and Compliant-v1.1", 240 | "CAD002-O365 Grant Windows access for All users when Modern Auth Clients and Compliant-v1.1", 241 | "CAD003-O365 Grant iOS and Android access for All users when Modern Auth Clients and ApprovedApp or Compliant-v1.2", 242 | "CAD011-O365 Grant Linux access for All users when Modern Auth Clients and Compliant-v1.0", 243 | "GLOBAL - 2070 - GRANT - Mobile Device Access Requirements - v1.2", 244 | "CAD014-O365 Require App Protection Policy for Edge on Windows for All users when Browser and Non-Compliant-v1.0" 245 | ) 246 | 247 | # Execute the copy operation 248 | Copy-ConditionalAccessPolicies -SourcePath $sourcePath -BaseDestPath $baseDestPath -ExpectedPolicies $expectedPolicies 249 | -------------------------------------------------------------------------------- /14-Exclude-Include-Admins-Roles-CAPs copy 3.ps1: -------------------------------------------------------------------------------- 1 | Import-module 'C:\code\ConditionalAccessManagement\ConditionalAccessManagement.psm1' 2 | 3 | # Use functions 4 | # Update-ConditionalAccessPolicyGuestTypes 5 | Update-ConditionalAccessPolicyAdminRoles -------------------------------------------------------------------------------- /2-Exclude-EntraGroup-AllConditionalAccessPolicies copy 9.ps1: -------------------------------------------------------------------------------- 1 | 2 | 3 | Start-Transcript -Path "C:\Code\CB\Entra\CNA\ConditionalAccess\Exclude_GroupFromAllCAPoliciesUsingBeta-v8.log" 4 | # Install the Microsoft Graph Beta module if not already installed 5 | # Install-Module Microsoft.Graph.Beta -Scope Allusers -AllowClobber -Force 6 | # Install-Module Microsoft.Graph.Groups -Scope Allusers -AllowClobber -Force 7 | 8 | # Import the Microsoft Graph Beta module 9 | # Import-Module Microsoft.Graph.Beta 10 | 11 | 12 | # Import-Module Microsoft.Graph.Identity.SignIns 13 | 14 | # Disconnect-MgGraph 15 | # Connect to Microsoft Graph 16 | Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess", "Group.ReadWrite.All", "Policy.Read.All", "Application.Read.All" 17 | 18 | # Disconnect-MgGraph 19 | 20 | 21 | # Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess", "Group.ReadWrite.All", "Policy.Read.All", "Application.Read.All" 22 | function New-ConditionalAccessGroup { 23 | param ( 24 | [string]$GroupName 25 | ) 26 | 27 | $groupParams = @{ 28 | DisplayName = $GroupName 29 | MailEnabled = $false 30 | MailNickname = "NotSet" 31 | SecurityEnabled = $true 32 | } 33 | $group = New-MgGroup @groupParams 34 | # Write-Output "Group Created: $($group.DisplayName) with ID: $($group.Id)" 35 | return $group.Id 36 | } 37 | 38 | 39 | function Get-ConditionalAccessPoliciesViaMgGraph { 40 | $uri = "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" 41 | 42 | # Initialize a list for better performance 43 | $allPolicies = [System.Collections.Generic.List[PSObject]]::new() 44 | 45 | do { 46 | # Fetch the policies via Graph API 47 | $response = Invoke-MgGraphRequest -Uri $uri -Method GET -Headers @{"Prefer" = "odata.maxpagesize=999" } 48 | $policies = $response.Value 49 | 50 | # Add the policies to the list 51 | $allPolicies.Add($policies) 52 | 53 | # Check for next link for pagination 54 | $uri = if ($response.'@odata.nextLink') { $response.'@odata.nextLink' } else { $null } 55 | } while ($uri) 56 | 57 | # Convert the list back to an array (optional) 58 | return $allPolicies.ToArray() 59 | } 60 | 61 | 62 | # function Exclude-GroupFromAllCAPoliciesUsingBeta { 63 | # param ( 64 | # [string]$ExcludeGroupId # The ID of the group to be excluded 65 | # ) 66 | 67 | # # Retrieve all Conditional Access Policies using the custom function 68 | # $allPolicies = Get-ConditionalAccessPoliciesViaMgGraph 69 | 70 | # foreach ($policy in $allPolicies) { 71 | # # Check if the group is already excluded 72 | # if ($policy.conditions.users.excludeGroups -contains $ExcludeGroupId) { 73 | # Write-Output "Group '$ExcludeGroupId' is already excluded in Policy: $($policy.displayName)" 74 | # continue 75 | # } 76 | 77 | # # Add the group to the excludeGroups array 78 | # $updatedExcludeGroups = $policy.conditions.users.excludeGroups + $ExcludeGroupId 79 | 80 | # # Prepare the conditions parameter 81 | # $conditions = @{ 82 | # users = @{ 83 | # excludeGroups = $updatedExcludeGroups 84 | # } 85 | # } 86 | 87 | # # Update the Conditional Access Policy using the Beta endpoint 88 | # try { 89 | # Update-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.id -Conditions $conditions 90 | # Write-Output "Updated Policy: $($policy.displayName) to exclude Group '$ExcludeGroupId'" 91 | # } catch { 92 | # Write-Error "Failed to update Policy: $($policy.displayName). Error: $_" 93 | # } 94 | # } 95 | # } 96 | 97 | 98 | 99 | 100 | 101 | function Exclude-GroupFromAllCAPoliciesUsingBeta { 102 | param ( 103 | [Parameter(Mandatory = $true)] 104 | [string]$ExcludeGroupId # The ID of the group to be excluded 105 | ) 106 | 107 | # Ensure a connection to Microsoft Graph 108 | # $graphScopes = "Policy.ReadWrite.ConditionalAccess" 109 | # Connect-MgGraph -Scopes $graphScopes 110 | 111 | # Retrieve all Conditional Access Policies using the custom function 112 | $allPolicies = Get-ConditionalAccessPoliciesViaMgGraph 113 | 114 | foreach ($policy in $allPolicies) { 115 | # Check if the group is already excluded 116 | if ($policy.conditions.users.excludeGroups -contains $ExcludeGroupId) { 117 | Write-Output "Group '$ExcludeGroupId' is already excluded in Policy: $($policy.displayName)" 118 | continue 119 | } 120 | 121 | # Add the group to the excludeGroups array 122 | $updatedExcludeGroups = $policy.conditions.users.excludeGroups + $ExcludeGroupId 123 | 124 | # Prepare the body parameter for Update-MgBetaIdentityConditionalAccessPolicy 125 | $bodyParams = @{ 126 | Conditions = @{ 127 | Users = @{ 128 | ExcludeGroups = $updatedExcludeGroups 129 | } 130 | } 131 | } 132 | 133 | # Update the Conditional Access Policy using the Beta endpoint 134 | try { 135 | Update-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.id -BodyParameter $bodyParams 136 | Write-Output "Updated Policy: $($policy.displayName) to exclude Group '$ExcludeGroupId'" 137 | } 138 | catch { 139 | Write-Error "Failed to update Policy: $($policy.displayName). Error: $_" 140 | } 141 | } 142 | 143 | # Optionally, disconnect from Microsoft Graph after operations are complete 144 | # Disconnect-MgGraph 145 | } 146 | 147 | 148 | 149 | 150 | 151 | $groupId = $null 152 | 153 | 154 | $allconditionalaccesspoliciescount = (Get-ConditionalAccessPoliciesViaMgGraph).Count 155 | $allconditionalaccesspoliciescount 156 | 157 | # Uncomment the following lines to create a new group and add it to Conditional Access Policies 158 | # $groupId = New-ConditionalAccessGroup -GroupName "SG002 - Conditional Access - GLOBAL - DMZ - Exclusion Group" 159 | 160 | 161 | # $groupId = '4ecfb1e1-d76d-464a-866a-203bd77815c2' #CCI 162 | # $groupId = '2b56f107-e156-4ba6-ac5d-0db1e412a1d5' #Bellwoods 163 | # $groupId = '1e83e83f-6b88-4e6e-b979-37ad3c938d7e' #RAC 164 | # $groupId = 'b7f7e66a-a0f8-4113-ade7-987d8bae0cb6' #BCFHT 165 | # $groupId = '7b8fdb31-6ae0-460d-8c4c-afc671f52ecf' #Sandbox 166 | # $groupId = 'eccafc70-52d9-4935-b20b-543507559930' #ICTC 167 | # $groupId = 'f995c07d-5258-4478-ba41-503c9e8bde59' #Antea 168 | # $groupId = 'ef0f9b0f-52a0-4369-a955-aa5703aa8518' #CARMS 169 | # $groupId = '13f371ff-d912-4195-a238-750840cb47d5' #ARH 170 | # $groupId = "05fb21ca-b737-4e48-b557-e40d5feaaa58" #Ambico 171 | # $groupId = "d230864a-3736-4556-b978-fc1a99e624f5" #CNA 172 | # $groupId = "e7ff2f49-96f2-42fb-bcde-053dc9488e6a" #MSFT 173 | $groupId = "7c71e1c5-bd77-4684-9ea9-369baaecd536" #TGB 174 | # $groupId = '' #CPHA 175 | 176 | # Exclude-GroupFromAllCAPolicies -ExcludeGroupId $groupId 177 | Exclude-GroupFromAllCAPoliciesUsingBeta -ExcludeGroupId $groupId 178 | 179 | Stop-Transcript -------------------------------------------------------------------------------- /3-Move-ConditionalAccessPoliciesJSONfiles.ps1: -------------------------------------------------------------------------------- 1 | # Define the path to the CSV file 2 | $csvPath = "D:\Code\CB\Entra\CCI\Graph\export\DeprecatedPolicies-v9-cci.csv" 3 | 4 | # Define the source and destination directories 5 | $sourceDir = "C:\code\caac\Feb192024\CCI\Canada Computing Inc\ConditionalAccess" 6 | $destinationDir = "C:\code\caac\Feb192024\CCI\Canada Computing Inc\ConditionalAccess-Recreated-Modern-Graph-API" 7 | 8 | # Import the CSV file 9 | $csvData = Import-Csv -Path $csvPath 10 | 11 | # Iterate over each row in the CSV 12 | foreach ($row in $csvData) { 13 | # Extract the display name 14 | $displayName = $row.'displayname' 15 | 16 | # Define the source file path based on the display name 17 | $sourceFile = Join-Path -Path $sourceDir -ChildPath "$displayName.json" 18 | 19 | # Define the destination file path 20 | $destinationFile = Join-Path -Path $destinationDir -ChildPath "$displayName.json" 21 | 22 | # Check if the source file exists 23 | if (Test-Path -Path $sourceFile) { 24 | # Move the JSON file from the source to the destination directory 25 | Move-Item -Path $sourceFile -Destination $destinationFile 26 | Write-Host "Moved: $sourceFile to $destinationFile" 27 | } else { 28 | Write-Host "File not found: $sourceFile" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /4-Delete-allConditionalAccessPolicies-v4-CSV.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with the necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.Read.All', 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Confirm before proceeding as this will delete Conditional Access policies specified in the CSV 5 | $confirmation = Read-Host "Are you sure you want to delete Conditional Access policies listed in the CSV? (yes/no)" 6 | if ($confirmation -ne 'yes') { 7 | Write-Output "Operation aborted by the user." 8 | Disconnect-MgGraph 9 | exit 10 | } 11 | 12 | # Import the CSV file containing the policy IDs 13 | # $csvPath = Read-Host "D:\Code\CB\Entra\CCI\Graph\export\DeprecatedPolicies-v6-sandbox.csv" 14 | $csvPath = "D:\Code\CB\Entra\Ladco\Graph\export\DeprecatedPolicies-v9-cci.csv" 15 | $policyIds = Import-Csv -Path $csvPath 16 | 17 | # Iterate through the CSV data and delete each policy by ID 18 | foreach ($policy in $policyIds) { 19 | $policyId = $policy.Id # Assuming the column name in the CSV is 'PolicyId' 20 | try { 21 | # Delete the Conditional Access policy by its ID 22 | Remove-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policyId 23 | Write-Output "Successfully requested deletion of Conditional Access policy with ID: $policyId" 24 | } catch { 25 | Write-Error "Failed to delete Conditional Access policy with ID: $policyId. Error: $_" 26 | } 27 | } 28 | 29 | # Disconnect from Microsoft Graph 30 | # Disconnect-MgGraph 31 | -------------------------------------------------------------------------------- /4.1-Delete-allConditionalAccessPolicies-v4-API copy 4.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Microsoft.Graph.Identity.SignIns, PSWriteHTML, Microsoft.Graph.Identity.DirectoryManagement 2 | 3 | function Connect-GraphWithScope { 4 | [CmdletBinding()] 5 | param() 6 | 7 | $requiredScopes = @( 8 | "Policy.Read.All" 9 | "Policy.ReadWrite.ConditionalAccess" 10 | "Organization.Read.All" 11 | ) 12 | 13 | $currentContext = Get-MgContext 14 | 15 | if ($null -eq $currentContext) { 16 | Write-Host "No existing Graph connection found. Connecting..." -ForegroundColor Yellow 17 | Connect-MgGraph -Scopes $requiredScopes 18 | return 19 | } 20 | 21 | $missingScopes = $requiredScopes | Where-Object { $_ -notin $currentContext.Scopes } 22 | 23 | if ($missingScopes) { 24 | Write-Host "Missing required scopes. Reconnecting with all required scopes..." -ForegroundColor Yellow 25 | Disconnect-MgGraph 26 | Connect-MgGraph -Scopes $requiredScopes 27 | } 28 | } 29 | 30 | function New-ExportPath { 31 | param ( 32 | [string]$BasePath = "C:\Code\CB\Entra\Sandbox\Graph\export", 33 | [string]$FilePrefix = "ConditionalAccessPolicies" 34 | ) 35 | 36 | $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" 37 | $exportPaths = @{ 38 | Directory = $BasePath 39 | Csv = Join-Path -Path $BasePath -ChildPath "$FilePrefix`_$timestamp.csv" 40 | Html = Join-Path -Path $BasePath -ChildPath "$FilePrefix`_$timestamp.html" 41 | } 42 | 43 | if (-not (Test-Path -Path $exportPaths.Directory)) { 44 | New-Item -Path $exportPaths.Directory -ItemType Directory -Force | Out-Null 45 | } 46 | 47 | return $exportPaths 48 | } 49 | 50 | function Export-PolicyData { 51 | param ( 52 | [Parameter(Mandatory)] 53 | [object[]]$Policies, 54 | [Parameter(Mandatory)] 55 | [string]$CsvPath, 56 | [Parameter(Mandatory)] 57 | [string]$HtmlPath, 58 | [Parameter()] 59 | [hashtable]$Metadata 60 | ) 61 | 62 | # Export to CSV 63 | $Policies | Export-Csv -Path $CsvPath -NoTypeInformation 64 | 65 | New-HTML -Title "Conditional Access Policies Report" -FilePath $HtmlPath -ShowHTML { 66 | New-HTMLSection -HeaderText "Deletion Summary" { 67 | New-HTMLPanel { 68 | New-HTMLText -Text @" 69 |

Report Details

70 | 79 | "@ 80 | } 81 | } 82 | 83 | New-HTMLSection -HeaderText "Policy Deletion Results" { 84 | New-HTMLTable -DataTable $Policies -ScrollX -Buttons @('copyHtml5', 'excelHtml5', 'csvHtml5') -SearchBuilder { 85 | New-TableCondition -Name 'Status' -ComparisonType string -Operator eq -Value 'Failed' -BackgroundColor Salmon -Color Black 86 | New-TableCondition -Name 'Status' -ComparisonType string -Operator eq -Value 'Success' -BackgroundColor LightGreen -Color Black 87 | New-TableCondition -Name 'DisplayName' -ComparisonType string -Operator contains -Value '' -BackgroundColor White -Color Black 88 | } 89 | } 90 | } 91 | } 92 | 93 | function Remove-ConditionalAccessPolicies { 94 | [CmdletBinding(SupportsShouldProcess)] 95 | param() 96 | 97 | try { 98 | # Ensure proper Graph connection 99 | Connect-GraphWithScope 100 | 101 | # Get current tenant details 102 | $tenantInfo = Get-MgOrganization 103 | $tenantName = $tenantInfo.DisplayName 104 | $tenantId = $tenantInfo.Id 105 | 106 | Write-Host "Connected to tenant: $tenantName (ID: $tenantId)" -ForegroundColor Yellow 107 | 108 | # Get export paths 109 | $exportPaths = New-ExportPath 110 | 111 | # Retrieve all Conditional Access policies 112 | $policies = Get-MgIdentityConditionalAccessPolicy 113 | $initialPolicyCount = $policies.Count 114 | 115 | if ($initialPolicyCount -eq 0) { 116 | Write-Warning "No Conditional Access policies found in the tenant." 117 | return 118 | } 119 | 120 | # Initialize results tracking 121 | $results = [System.Collections.ArrayList]::new() 122 | 123 | # Create initial backup with all policies 124 | $policies | ForEach-Object { 125 | $null = $results.Add([PSCustomObject]@{ 126 | DisplayName = $_.DisplayName 127 | Id = $_.Id 128 | State = $_.State 129 | Status = "Pending" 130 | ErrorMessage = "" 131 | }) 132 | } 133 | 134 | # Display summary 135 | Write-Host "`nSummary:" -ForegroundColor Cyan 136 | Write-Host "- Tenant: $tenantName" -ForegroundColor Cyan 137 | Write-Host "- Total policies to be deleted: $initialPolicyCount" -ForegroundColor Cyan 138 | Write-Host "- Backup will be saved to: $($exportPaths.Csv)" -ForegroundColor Cyan 139 | Write-Host "- HTML report: $($exportPaths.Html)" -ForegroundColor Cyan 140 | 141 | # Confirm deletion 142 | $confirmMessage = "Are you sure you want to delete all $initialPolicyCount Conditional Access policies from tenant '$tenantName'? (yes/no)" 143 | $confirmation = Read-Host -Prompt $confirmMessage 144 | 145 | if ($confirmation -ne 'yes') { 146 | Write-Warning "Operation aborted by user" 147 | return 148 | } 149 | 150 | # Delete policies and update results 151 | foreach ($policy in $policies) { 152 | if ($PSCmdlet.ShouldProcess($policy.DisplayName, "Delete Conditional Access Policy")) { 153 | try { 154 | Remove-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.Id 155 | $result = $results | Where-Object Id -eq $policy.Id 156 | $result.Status = "Success" 157 | Write-Host "Deleted policy: $($policy.DisplayName)" -ForegroundColor Green 158 | } 159 | catch { 160 | $result = $results | Where-Object Id -eq $policy.Id 161 | $result.Status = "Failed" 162 | $result.ErrorMessage = $_.Exception.Message 163 | Write-Error "Failed to delete policy '$($policy.DisplayName)': $_" 164 | } 165 | } 166 | } 167 | 168 | # Final verification 169 | Start-Sleep -Seconds 5 # Allow time for deletions to process 170 | $remainingPolicies = Get-MgIdentityConditionalAccessPolicy 171 | 172 | # Prepare metadata for report 173 | $metadata = @{ 174 | TenantName = $tenantName 175 | TenantId = $tenantId 176 | TotalPolicies = $initialPolicyCount 177 | SuccessCount = ($results | Where-Object Status -eq "Success").Count 178 | FailureCount = ($results | Where-Object Status -eq "Failed").Count 179 | RemainingPolicies = $remainingPolicies.Count 180 | } 181 | 182 | # Generate reports 183 | Export-PolicyData -Policies $results -CsvPath $exportPaths.Csv -HtmlPath $exportPaths.Html -Metadata $metadata 184 | 185 | # Display final results 186 | Write-Host "`nOperation Complete:" -ForegroundColor Cyan 187 | Write-Host "- Successfully deleted: $($metadata.SuccessCount) policies" -ForegroundColor Green 188 | Write-Host "- Failed to delete: $($metadata.FailureCount) policies" -ForegroundColor $(if ($metadata.FailureCount -gt 0) { 'Red' } else { 'Green' }) 189 | Write-Host "- Remaining policies: $($metadata.RemainingPolicies)" -ForegroundColor Cyan 190 | Write-Host "`nReports generated:" -ForegroundColor Green 191 | Write-Host "CSV Report: $($exportPaths.Csv)" -ForegroundColor Green 192 | Write-Host "HTML Report: $($exportPaths.Html)" -ForegroundColor Green 193 | 194 | if ($metadata.FailureCount -gt 0) { 195 | Write-Host "`nFailed Deletions:" -ForegroundColor Red 196 | $results | Where-Object Status -eq "Failed" | ForEach-Object { 197 | Write-Host "- $($_.DisplayName): $($_.ErrorMessage)" -ForegroundColor Red 198 | } 199 | } 200 | } 201 | catch { 202 | Write-Error "An error occurred: $_" 203 | } 204 | } 205 | 206 | # Run the cleanup 207 | Remove-ConditionalAccessPolicies -------------------------------------------------------------------------------- /5-recreateConditionalAccesspoliciesusingJSON-v7.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Specify the directory containing the JSON files 5 | # $jsonDir = "C:\code\caac\Feb172024\CCI\Entra-Intune-v1\Canada Computing Inc\ConditionalAccess-Recreated-Modern-Graph-API" 6 | $jsonDir = "C:\code\caac\Feb192024\CCI\Canada Computing Inc\ConditionalAccess-Recreated-Modern-Graph-API" 7 | 8 | # Get all JSON files from the directory 9 | $jsonFiles = Get-ChildItem -Path $jsonDir -Filter "*.json" 10 | 11 | foreach ($jsonFile in $jsonFiles) { 12 | # Load the JSON content 13 | $jsonContent = Get-Content -Path $jsonFile.FullName -Raw | ConvertFrom-Json 14 | 15 | # Prepare the policy object for creation 16 | $policyParams = @{ 17 | DisplayName = $jsonContent.displayName + " - Modern API" 18 | State = "disabled" # Ensure the policy is created in the "off" state 19 | Conditions = @{ 20 | Users = @{ 21 | IncludeUsers = @("All") # Specify user object IDs to include 22 | # ExcludeUsers = @("userObjectId3") # Specify user object IDs to exclude 23 | } 24 | Applications = @{ 25 | # IncludeApplications = @("appId1", "appId2") # Specify application IDs to include 26 | IncludeApplications = @("All") # Specify application IDs to include 27 | } 28 | } 29 | GrantControls = @{ 30 | BuiltInControls = @("mfa") # Require MFA 31 | Operator = "OR" 32 | } 33 | } 34 | 35 | # Convert policy object to JSON 36 | $policyJson = $policyParams | ConvertTo-Json -Depth 10 37 | 38 | try { 39 | # Attempt to create the Conditional Access policy 40 | $result = New-MgIdentityConditionalAccessPolicy -BodyParameter $policyJson 41 | Write-Host "Successfully created policy: $($result.DisplayName)" 42 | } catch { 43 | Write-Error "Failed to create policy from file $($jsonFile.Name): $_" 44 | } 45 | } 46 | 47 | # Disconnect from Microsoft Graph 48 | # Disconnect-MgGraph 49 | -------------------------------------------------------------------------------- /6-RemoveCAOrphanedGroup.ps1: -------------------------------------------------------------------------------- 1 | $orphanedGroupId = '614050e3-2fa4-4ab3-ad4e-12ef93d805e3' # The ID of the deleted (orphan) group 2 | 3 | 4 | Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess", "Group.ReadWrite.All", "Policy.Read.All" 5 | 6 | 7 | 8 | function Get-ConditionalAccessPoliciesViaMgGraph { 9 | $uri = "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" 10 | $allPolicies = @() 11 | 12 | do { 13 | $response = Invoke-MgGraphRequest -Uri $uri -Method GET -Headers @{"Prefer"="odata.maxpagesize=999"} 14 | $policies = $response.Value 15 | $allPolicies += $policies 16 | 17 | $uri = if ($response.'@odata.nextLink') { $response.'@odata.nextLink' } else { $null } 18 | } while ($uri) 19 | 20 | return $allPolicies 21 | } 22 | 23 | $allPolicies = Get-ConditionalAccessPoliciesViaMgGraph 24 | 25 | foreach ($policy in $allPolicies) { 26 | if ($policy.conditions.users.excludeGroups -contains $orphanedGroupId) { 27 | # Prepare to update the policy by removing the orphaned group ID 28 | $updatedExcludeGroups = $policy.conditions.users.excludeGroups | Where-Object { $_ -ne $orphanedGroupId } 29 | 30 | # Prepare the updated conditions without the orphaned group ID 31 | $conditions = @{ 32 | users = @{ 33 | excludeGroups = $updatedExcludeGroups 34 | } 35 | } 36 | 37 | # Update the policy 38 | try { 39 | Update-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.id -Conditions $conditions 40 | Write-Output "Removed orphaned group from Policy: $($policy.displayName)" 41 | } catch { 42 | Write-Error "Failed to remove orphaned group from Policy: $($policy.displayName). Error: $_" 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /7-RemoveCAOrphanedUser copy 2.ps1: -------------------------------------------------------------------------------- 1 | function Get-ConditionalAccessPoliciesViaMgGraph { 2 | $uri = "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" 3 | $allPolicies = @() 4 | 5 | do { 6 | $response = Invoke-MgGraphRequest -Uri $uri -Method GET -Headers @{"Prefer" = "odata.maxpagesize=999" } 7 | $policies = $response.Value 8 | $allPolicies += $policies 9 | 10 | $uri = if ($response.'@odata.nextLink') { $response.'@odata.nextLink' } else { $null } 11 | } while ($uri) 12 | 13 | return $allPolicies 14 | } 15 | 16 | 17 | 18 | $allPolicies = Get-ConditionalAccessPoliciesViaMgGraph 19 | 20 | 21 | function Remove-OrphanedUserFromCAPolicy { 22 | param( 23 | [Parameter(Mandatory = $true)] 24 | [string]$orphanedUserId, 25 | [Parameter(Mandatory = $true)] 26 | [object]$policy 27 | ) 28 | 29 | Process { 30 | Write-Verbose "Processing Policy: $($policy.displayName)" 31 | 32 | # Check if the orphaned user is in the excludeUsers list 33 | if ($policy.conditions.users.excludeUsers -contains $orphanedUserId) { 34 | Write-Verbose "Found orphaned user in Policy: $($policy.displayName)" 35 | 36 | # Remove the orphaned user ID from excludeUsers 37 | $updatedExcludeUsers = $policy.conditions.users.excludeUsers | Where-Object { $_ -ne $orphanedUserId } 38 | 39 | # Check if updatedExcludeUsers is empty to determine if we need to pass an empty array 40 | if (-not $updatedExcludeUsers) { 41 | $updatedExcludeUsers = @() 42 | } 43 | 44 | # Prepare the body parameter for Update-MgBetaIdentityConditionalAccessPolicy 45 | $bodyParams = @{ 46 | Conditions = @{ 47 | Users = @{ 48 | ExcludeUsers = $updatedExcludeUsers 49 | } 50 | } 51 | } 52 | 53 | try { 54 | # Update the policy using Update-MgBetaIdentityConditionalAccessPolicy 55 | Update-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.id -BodyParameter $bodyParams 56 | Write-Output "Successfully updated Policy: $($policy.displayName)" 57 | } 58 | catch { 59 | Write-Error "Failed to update Policy: $($policy.displayName). Error: $($_.Exception.Message)" 60 | } 61 | } 62 | else { 63 | Write-Verbose "Orphaned user not found in Policy: $($policy.displayName)" 64 | } 65 | } 66 | } 67 | 68 | 69 | # Connect to Microsoft Graph 70 | $graphScopes = "Policy.ReadWrite.ConditionalAccess", "Group.ReadWrite.All", "Policy.Read.All" 71 | Connect-MgGraph -Scopes $graphScopes -ErrorAction Stop 72 | Write-Verbose "Connected to Microsoft Graph with necessary scopes." 73 | 74 | # Retrieve all Conditional Access Policies 75 | $allPolicies = Get-ConditionalAccessPoliciesViaMgGraph 76 | Write-Verbose "Retrieved all Conditional Access Policies." 77 | 78 | 79 | $orphanedUserId = $null 80 | $orphanedUserId = '6303c7ce-c078-47ce-a1f3-9750d8d3ff68' # Replace this with the actual orphaned user ID 81 | 82 | foreach ($policy in $allPolicies) { 83 | Remove-OrphanedUserFromCAPolicy -orphanedUserId $orphanedUserId -policy $policy -Verbose 84 | } 85 | 86 | # Optionally, disconnect from Microsoft Graph after operations are complete 87 | # Disconnect-MgGraph 88 | # Write-Verbose "Disconnected from Microsoft Graph." 89 | -------------------------------------------------------------------------------- /8-RemoveCAOrphanedobjects-dynamic copy.ps1: -------------------------------------------------------------------------------- 1 | # Function to get all users and groups from Microsoft Graph 2 | function Get-AllUsersAndGroups { 3 | $allUsers = [System.Collections.Generic.List[PSCustomObject]]::new() 4 | $allGroups = [System.Collections.Generic.List[PSCustomObject]]::new() 5 | 6 | # Get all users 7 | $uriUsers = "https://graph.microsoft.com/v1.0/users" 8 | do { 9 | $responseUsers = Invoke-MgGraphRequest -Uri $uriUsers -Method GET -Headers @{"Prefer"="odata.maxpagesize=999"} 10 | $users = [System.Collections.Generic.List[PSCustomObject]]::new() 11 | $responseUsers.value | ForEach-Object { [void]$users.Add($_) } 12 | $allUsers.Add($users) 13 | 14 | $uriUsers = if ($responseUsers.'@odata.nextLink') { $responseUsers.'@odata.nextLink' } else { $null } 15 | } while ($uriUsers) 16 | 17 | # Get all groups 18 | $uriGroups = "https://graph.microsoft.com/v1.0/groups" 19 | do { 20 | $responseGroups = Invoke-MgGraphRequest -Uri $uriGroups -Method GET -Headers @{"Prefer"="odata.maxpagesize=999"} 21 | $groups = [System.Collections.Generic.List[PSCustomObject]]::new() 22 | $responseGroups.value | ForEach-Object { [void]$groups.Add($_) } 23 | $allGroups.Add($groups) 24 | 25 | $uriGroups = if ($responseGroups.'@odata.nextLink') { $responseGroups.'@odata.nextLink' } else { $null } 26 | } while ($uriGroups) 27 | 28 | return [PSCustomObject]@{ Users = $allUsers; Groups = $allGroups } 29 | } 30 | 31 | # Function to get all conditional access policies 32 | function Get-ConditionalAccessPoliciesViaMgGraph { 33 | $allPolicies = [System.Collections.Generic.List[PSCustomObject]]::new() 34 | $uri = "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" 35 | 36 | do { 37 | $response = Invoke-MgGraphRequest -Uri $uri -Method GET -Headers @{"Prefer" = "odata.maxpagesize=999" } 38 | $policies = [System.Collections.Generic.List[PSCustomObject]]::new() 39 | $response.Value | ForEach-Object { [void]$policies.Add($_) } 40 | $allPolicies.Add($policies) 41 | 42 | $uri = if ($response.'@odata.nextLink') { $response.'@odata.nextLink' } else { $null } 43 | } while ($uri) 44 | 45 | return $allPolicies 46 | } 47 | 48 | # Function to remove orphaned users and groups from conditional access policies 49 | function Remove-OrphanedUsersAndGroups { 50 | param( 51 | [Parameter(Mandatory = $true)] 52 | [object]$allEntities, 53 | [Parameter(Mandatory = $true)] 54 | [object]$policy 55 | ) 56 | 57 | Process { 58 | Write-Verbose "Processing Policy: $($policy.displayName)" 59 | 60 | $isUpdated = $false 61 | 62 | # Function to validate if a user or group ID is present in the respective entities list 63 | function Is-Orphaned { 64 | param ( 65 | [string]$id, 66 | [System.Collections.Generic.List[PSCustomObject]]$entities 67 | ) 68 | return (-not ($entities.id -contains $id)) -and ($id -ne "All") 69 | } 70 | 71 | # Remove orphaned users from includeUsers and excludeUsers 72 | if ($policy.conditions.users.includeUsers) { 73 | $orphanedIncludeUsers = $policy.conditions.users.includeUsers | Where-Object { Is-Orphaned -id $_ -entities $allEntities.Users } 74 | if ($orphanedIncludeUsers) { 75 | $updatedIncludeUsers = $policy.conditions.users.includeUsers | Where-Object { -not ($orphanedIncludeUsers -contains $_) } 76 | foreach ($userId in $orphanedIncludeUsers) { 77 | Write-Host "Orphaned user found in includeUsers in Policy: $($policy.displayName). User ID: $userId" -ForegroundColor Yellow 78 | } 79 | $policy.conditions.users.includeUsers = $updatedIncludeUsers 80 | $isUpdated = $true 81 | } 82 | } 83 | 84 | if ($policy.conditions.users.excludeUsers) { 85 | $orphanedExcludeUsers = $policy.conditions.users.excludeUsers | Where-Object { Is-Orphaned -id $_ -entities $allEntities.Users } 86 | if ($orphanedExcludeUsers) { 87 | $updatedExcludeUsers = $policy.conditions.users.excludeUsers | Where-Object { -not ($orphanedExcludeUsers -contains $_) } 88 | foreach ($userId in $orphanedExcludeUsers) { 89 | Write-Host "Orphaned user found in excludeUsers in Policy: $($policy.displayName). User ID: $userId" -ForegroundColor Yellow 90 | } 91 | $policy.conditions.users.excludeUsers = $updatedExcludeUsers 92 | $isUpdated = $true 93 | } 94 | } 95 | 96 | # Remove orphaned groups from includeGroups and excludeGroups 97 | if ($policy.conditions.users.includeGroups) { 98 | $orphanedIncludeGroups = $policy.conditions.users.includeGroups | Where-Object { Is-Orphaned -id $_ -entities $allEntities.Groups } 99 | if ($orphanedIncludeGroups) { 100 | $updatedIncludeGroups = $policy.conditions.users.includeGroups | Where-Object { -not ($orphanedIncludeGroups -contains $_) } 101 | foreach ($groupId in $orphanedIncludeGroups) { 102 | Write-Host "Orphaned group found in includeGroups in Policy: $($policy.displayName). Group ID: $groupId" -ForegroundColor Yellow 103 | } 104 | $policy.conditions.users.includeGroups = $updatedIncludeGroups 105 | $isUpdated = $true 106 | } 107 | } 108 | 109 | if ($policy.conditions.users.excludeGroups) { 110 | $orphanedExcludeGroups = $policy.conditions.users.excludeGroups | Where-Object { Is-Orphaned -id $_ -entities $allEntities.Groups } 111 | if ($orphanedExcludeGroups) { 112 | $updatedExcludeGroups = $policy.conditions.users.excludeGroups | Where-Object { -not ($orphanedExcludeGroups -contains $_) } 113 | foreach ($groupId in $orphanedExcludeGroups) { 114 | Write-Host "Orphaned group found in excludeGroups in Policy: $($policy.displayName). Group ID: $groupId" -ForegroundColor Yellow 115 | } 116 | $policy.conditions.users.excludeGroups = $updatedExcludeGroups 117 | $isUpdated = $true 118 | } 119 | } 120 | 121 | # Update the policy if there were changes 122 | if ($isUpdated) { 123 | try { 124 | Update-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.id -Conditions $policy.conditions 125 | Write-Host "Updated policy: $($policy.displayName)" -ForegroundColor Green 126 | } catch { 127 | Write-Error "Failed to update policy: $($policy.displayName). Error: $_" 128 | } 129 | } else { 130 | Write-Host "No orphaned users or groups found in Policy: $($policy.displayName)" -ForegroundColor Cyan 131 | } 132 | } 133 | } 134 | 135 | # Connect to Microsoft Graph 136 | $graphScopes = "Policy.ReadWrite.ConditionalAccess", "Group.ReadWrite.All", "Policy.Read.All" 137 | Connect-MgGraph -Scopes $graphScopes -ErrorAction Stop 138 | Write-Verbose "Connected to Microsoft Graph with necessary scopes." 139 | 140 | # Retrieve all users and groups 141 | $allEntities = Get-AllUsersAndGroups 142 | Write-Verbose "Retrieved all users and groups." 143 | 144 | # Retrieve all Conditional Access Policies 145 | $allPolicies = Get-ConditionalAccessPoliciesViaMgGraph 146 | Write-Verbose "Retrieved all Conditional Access Policies." 147 | 148 | foreach ($policy in $allPolicies) { 149 | Remove-OrphanedUsersAndGroups -allEntities $allEntities -policy $policy -Verbose 150 | } -------------------------------------------------------------------------------- /9-Conditional Access JSON Converter copy 4.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules PSWriteHTML 2 | 3 | function Convert-CADirectoryToSingleJson { 4 | [CmdletBinding()] 5 | param ( 6 | [Parameter(Mandatory)] 7 | [string]$DirectoryPath, 8 | 9 | [Parameter()] 10 | [string]$OutputPath = "conversion_results.html" 11 | ) 12 | 13 | if (-not (Test-Path -Path $DirectoryPath)) { 14 | Write-Error "Directory not found: $DirectoryPath" 15 | return 16 | } 17 | 18 | $allPolicies = [System.Collections.ArrayList]::new() 19 | $results = [System.Collections.ArrayList]::new() 20 | 21 | $getChildParams = @{ 22 | Path = $DirectoryPath 23 | Filter = "*.json" 24 | } 25 | $jsonFiles = @(Get-ChildItem @getChildParams) 26 | 27 | foreach ($file in $jsonFiles) { 28 | try { 29 | $getContentParams = @{ 30 | Path = $file.FullName 31 | Raw = $true 32 | } 33 | $policy = Get-Content @getContentParams | ConvertFrom-Json 34 | $null = $allPolicies.Add($policy) 35 | 36 | $successResult = [PSCustomObject]@{ 37 | FileName = $file.Name 38 | Status = "Success" 39 | Error = "" 40 | PolicyName = $policy.displayName 41 | } 42 | $null = $results.Add($successResult) 43 | } 44 | catch { 45 | $failureResult = [PSCustomObject]@{ 46 | FileName = $file.Name 47 | Status = "Failed" 48 | Error = $_.Exception.Message 49 | PolicyName = "" 50 | } 51 | $null = $results.Add($failureResult) 52 | } 53 | } 54 | 55 | $combinedJson = @{ 56 | '@odata.context' = 'https://graph.microsoft.com/beta/$metadata#policies/conditionalAccessPolicies' 57 | 'value' = $allPolicies.ToArray() 58 | } 59 | 60 | $convertToJsonParams = @{ 61 | Depth = 20 62 | } 63 | $combinedJson | ConvertTo-Json @convertToJsonParams | Set-Clipboard 64 | 65 | $successCount = ($results | Where-Object Status -eq "Success").Count 66 | $failureCount = ($results | Where-Object Status -eq "Failed").Count 67 | 68 | $metadata = @{ 69 | GeneratedBy = $env:USERNAME 70 | GeneratedOn = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 71 | TotalPolicies = $results.Count 72 | SuccessCount = $successCount 73 | FailureCount = $failureCount 74 | } 75 | 76 | $htmlParams = @{ 77 | Title = "Conditional Access Policy Conversion Report" 78 | FilePath = $OutputPath 79 | ShowHTML = $true 80 | } 81 | 82 | New-HTML @htmlParams { 83 | $sectionParams = @{ 84 | HeaderText = "Conversion Summary" 85 | } 86 | New-HTMLSection @sectionParams { 87 | New-HTMLPanel { 88 | $textParams = @{ 89 | Text = @" 90 |

Report Details

91 | 98 | "@ 99 | } 100 | New-HTMLText @textParams 101 | } 102 | } 103 | 104 | $resultsSectionParams = @{ 105 | HeaderText = "Policy Conversion Results" 106 | } 107 | New-HTMLSection @resultsSectionParams { 108 | $tableParams = @{ 109 | DataTable = $results 110 | ScrollX = $true 111 | Buttons = @('copyHtml5', 'excelHtml5', 'csvHtml5') 112 | SearchBuilder = $true 113 | } 114 | New-HTMLTable @tableParams { 115 | $failedConditionParams = @{ 116 | Name = 'Status' 117 | ComparisonType = 'string' 118 | Operator = 'eq' 119 | Value = 'Failed' 120 | BackgroundColor = 'Salmon' 121 | Color = 'Black' 122 | } 123 | New-TableCondition @failedConditionParams 124 | 125 | $successConditionParams = @{ 126 | Name = 'Status' 127 | ComparisonType = 'string' 128 | Operator = 'eq' 129 | Value = 'Success' 130 | BackgroundColor = 'LightGreen' 131 | Color = 'Black' 132 | } 133 | New-TableCondition @successConditionParams 134 | } 135 | } 136 | } 137 | 138 | $summaryParams = @{ 139 | Object = "`nConversion Summary:" 140 | ForegroundColor = "Cyan" 141 | } 142 | Write-Host @summaryParams 143 | 144 | Write-Host "----------------" 145 | 146 | $successParams = @{ 147 | Object = "Successful conversions: $successCount" 148 | ForegroundColor = "Green" 149 | } 150 | Write-Host @successParams 151 | 152 | $failureColor = if ($failureCount -gt 0) { "Red" } else { "Green" } 153 | $failureParams = @{ 154 | Object = "Failed conversions: $failureCount" 155 | ForegroundColor = $failureColor 156 | } 157 | Write-Host @failureParams 158 | 159 | $clipboardParams = @{ 160 | Object = "`nCombined JSON has been copied to clipboard" 161 | ForegroundColor = "Green" 162 | } 163 | Write-Host @clipboardParams 164 | 165 | $reportParams = @{ 166 | Object = "Report saved to: $OutputPath" 167 | ForegroundColor = "Green" 168 | } 169 | Write-Host @reportParams 170 | } 171 | 172 | 173 | 174 | # Example usage: 175 | # Convert-CADirectoryToSingleJson -DirectoryPath "C:\code\CA\KVS\cabaseline202409\ConditionalAccess" 176 | # Convert-CADirectoryToSingleJson -DirectoryPath "C:\CaaC\SandBox\Dec102024-v2\AO\ConditionalAccess" 177 | Convert-CADirectoryToSingleJson -DirectoryPath "C:\CaaC\SandBox\Dec162024-v3\DC_KVS_Combined\MSFT\ADMINS" -------------------------------------------------------------------------------- /Archive/15-Exclude-Include-Gues-Roles-CAPs copy 10.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Microsoft.Graph.Identity.SignIns, PSWriteHTML 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | # Main execution 12 | Update-ConditionalAccessPolicyGuestTypes -------------------------------------------------------------------------------- /CABaseline2025/AppConfigurationManagedApp/ACP001 - iOSiPadOS - Outlook - Default Signature and External Mailtip.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AppConfigurationManagedApp/ACP001 - iOSiPadOS - Outlook - Default Signature and External Mailtip.json -------------------------------------------------------------------------------- /CABaseline2025/AppConfigurationManagedApp/ACP002 - Android - Outlook - Default Signature and External Mailtip.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AppConfigurationManagedApp/ACP002 - Android - Outlook - Default Signature and External Mailtip.json -------------------------------------------------------------------------------- /CABaseline2025/AppProtection/APP001 - Unmanaged - BYOD - iOSiPadOS - MAM - Require Min iOS version.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AppProtection/APP001 - Unmanaged - BYOD - iOSiPadOS - MAM - Require Min iOS version.json -------------------------------------------------------------------------------- /CABaseline2025/AppProtection/APP002 - Unmanaged - BYOD - Android - MAM - Require Min OS version.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AppProtection/APP002 - Unmanaged - BYOD - Android - MAM - Require Min OS version.json -------------------------------------------------------------------------------- /CABaseline2025/AppProtection/MAM for Edge.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AppProtection/MAM for Edge.json -------------------------------------------------------------------------------- /CABaseline2025/AssignmentFilters/Filter001 - Exclude Library Computers from Filehold Install.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AssignmentFilters/Filter001 - Exclude Library Computers from Filehold Install.json -------------------------------------------------------------------------------- /CABaseline2025/AssignmentFilters/Filter002 - Unmanaged - BYOD - iOSiPad OS Devices.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AssignmentFilters/Filter002 - Unmanaged - BYOD - iOSiPad OS Devices.json -------------------------------------------------------------------------------- /CABaseline2025/AssignmentFilters/Filter003 - Unmanaged - BYOD - Android OS Devices.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AssignmentFilters/Filter003 - Unmanaged - BYOD - Android OS Devices.json -------------------------------------------------------------------------------- /CABaseline2025/AuthenticationStrengths/MS Auth app - WHFB - TAP.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AuthenticationStrengths/MS Auth app - WHFB - TAP.json -------------------------------------------------------------------------------- /CABaseline2025/AuthenticationStrengths/Multifactor authentication.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AuthenticationStrengths/Multifactor authentication.json -------------------------------------------------------------------------------- /CABaseline2025/AuthenticationStrengths/Passwordless MFA.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AuthenticationStrengths/Passwordless MFA.json -------------------------------------------------------------------------------- /CABaseline2025/AuthenticationStrengths/Phishing-resistant MFA.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/AuthenticationStrengths/Phishing-resistant MFA.json -------------------------------------------------------------------------------- /CABaseline2025/CompliancePolicies/Default compliance policy for Android.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/CompliancePolicies/Default compliance policy for Android.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD001-O365 Grant macOS access for All users when Modern Auth Clients and Compliant-v1.1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD001-O365 Grant macOS access for All users when Modern Auth Clients and Compliant-v1.1.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD002-O365 Grant Windows access for All users when Modern Auth Clients and Compliant-v1.1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD002-O365 Grant Windows access for All users when Modern Auth Clients and Compliant-v1.1.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD003-O365 Grant iOS and Android access for All users when Modern Auth Clients and ApprovedApp or Compliant-v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD003-O365 Grant iOS and Android access for All users when Modern Auth Clients and ApprovedApp or Compliant-v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD004-O365 Grant Require MFA for All users when Browser and Non-Compliant-v1.5.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD004-O365 Grant Require MFA for All users when Browser and Non-Compliant-v1.5.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD005-O365 Block access for unsupported device platforms for All users when Modern Auth Clients-v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD005-O365 Block access for unsupported device platforms for All users when Modern Auth Clients-v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD006-O365 Session block download on unmanaged device for All users when Browser and Modern App Clients and Non-Compliant-v1.5.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD006-O365 Session block download on unmanaged device for All users when Browser and Modern App Clients and Non-Compliant-v1.5.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD007-O365 Session set Sign-in Frequency for Apps for All users when Modern Auth Clients and Non-Compliant-v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD007-O365 Session set Sign-in Frequency for Apps for All users when Modern Auth Clients and Non-Compliant-v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD008-All Session set Sign-in Frequency for All users when Browser and Non-Compliant-v1.1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD008-All Session set Sign-in Frequency for All users when Browser and Non-Compliant-v1.1.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD009-All Session disable browser persistence for All users when Browser and Non-Compliant-v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD009-All Session disable browser persistence for All users when Browser and Non-Compliant-v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD010-RJD Require MFA for device join or registration when Browser and Modern Auth Clients-v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD010-RJD Require MFA for device join or registration when Browser and Modern Auth Clients-v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD011-O365 Grant Linux access for All users when Modern Auth Clients and Compliant-v1.0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD011-O365 Grant Linux access for All users when Modern Auth Clients and Compliant-v1.0.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD012-ALL Grant access for Admin users when Browser and Modern Auth Clients and Compliant- Remember to Exclude Trusted locationsv1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD012-ALL Grant access for Admin users when Browser and Modern Auth Clients and Compliant- Remember to Exclude Trusted locationsv1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD014-O365 Require App Protection Policy for Edge on Windows for All users when Browser and Non-Compliant-v1.0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD014-O365 Require App Protection Policy for Edge on Windows for All users when Browser and Non-Compliant-v1.0.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD015-All Grant access for All users when Browser and Modern Auth Clients and Compliant on Windows and macOS- v1.0 .json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD015-All Grant access for All users when Browser and Modern Auth Clients and Compliant on Windows and macOS- v1.0 .json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAD016-EXO_SPO Require token protection when Modern Auth Clients on Windows - v1.1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAD016-EXO_SPO Require token protection when Modern Auth Clients on Windows - v1.1.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAL002-RSI Require MFA registration from trusted locations only for All users when Browser and Modern Auth Clients-v1.5.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAL002-RSI Require MFA registration from trusted locations only for All users when Browser and Modern Auth Clients-v1.5.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAL004-All Block access for Admins from non-trusted locations when Browser and Modern Auth Clients-v1.1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAL004-All Block access for Admins from non-trusted locations when Browser and Modern Auth Clients-v1.1.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAL011-Allow access from Trusted Countries Only v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAL011-Allow access from Trusted Countries Only v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAP001-All Block Legacy Authentication for All users when OtherClients-v1.1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAP001-All Block Legacy Authentication for All users when OtherClients-v1.1.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAP002-O365 Grant Exchange ActiveSync Clients for All users when Approved App-v1.0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAP002-O365 Grant Exchange ActiveSync Clients for All users when Approved App-v1.0.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAU001-All Grant Require MFA for guests when Browser and Modern Auth Clients-v1.0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAU001-All Grant Require MFA for guests when Browser and Modern Auth Clients-v1.0.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAU002-All Grant Require MFA for All users when Browser and Modern Auth Clients-v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAU002-All Grant Require MFA for All users when Browser and Modern Auth Clients-v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAU003-Selected Block unapproved apps for guests when Browser and Modern Auth Clients-v1.0.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAU003-Selected Block unapproved apps for guests when Browser and Modern Auth Clients-v1.0.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAU005-Selected Session route through MDCA for All users when Browser on Compliant-v1.1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAU005-Selected Session route through MDCA for All users when Browser on Compliant-v1.1.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAU008-All Grant Require Phishing-resistant MFA for Admins when Browser and Modern Auth Clients-Test if WHFB work from BYOD-v1.4.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAU008-All Grant Require Phishing-resistant MFA for Admins when Browser and Modern Auth Clients-Test if WHFB work from BYOD-v1.4.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAU009-Management BLOCK Admin Portals for All Users when Browser and Modern Auth Clients-v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAU009-Management BLOCK Admin Portals for All Users when Browser and Modern Auth Clients-v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/CAU013-All Grant Require phishing resistant MFA for All users when Browser and Modern Auth Clients - Keep for Admins initially-v1.1.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/CAU013-All Grant Require phishing resistant MFA for All users when Browser and Modern Auth Clients - Keep for Admins initially-v1.1.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 1020 - BLOCK - Device Code Auth Flow.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 1020 - BLOCK - Device Code Auth Flow.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 1040 - BLOCK - Countries not Allowed - Remember to Update Countries.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 1040 - BLOCK - Countries not Allowed - Remember to Update Countries.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 1060 - BLOCK - Service Accounts (Trusted Locations Excluded) - Remember to add 1 service account per policy.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 1060 - BLOCK - Service Accounts (Trusted Locations Excluded) - Remember to add 1 service account per policy.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 1080 - BLOCK - Guest Access to Sensitive Apps.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 1080 - BLOCK - Guest Access to Sensitive Apps.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 1085 - BLOCK - User Access to Sensitive Apps - v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 1085 - BLOCK - User Access to Sensitive Apps - v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 1090 - BLOCK - High-Med-Risk Sign-Ins - Entra ID P2 - v1.3.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 1090 - BLOCK - High-Med-Risk Sign-Ins - Entra ID P2 - v1.3.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 1100 - BLOCK - High-Med-Risk Users - Entra ID P2 - v1.3.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 1100 - BLOCK - High-Med-Risk Users - Entra ID P2 - v1.3.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 2010 - GRANT - Low-Risk Sign-ins - Entra ID P2 - v1.3.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 2010 - GRANT - Low-Risk Sign-ins - Entra ID P2 - v1.3.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 2020 - GRANT - Low-Risk Users - Entra ID P2 - v1.3.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 2020 - GRANT - Low-Risk Users - Entra ID P2 - v1.3.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 2040 - GRANT - Terms of Use (All users) - Remember to update TOU v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 2040 - GRANT - Terms of Use (All users) - Remember to update TOU v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 2050 - GRANT - MFA for All Users - need to exclude all Admins - v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 2050 - GRANT - MFA for All Users - need to exclude all Admins - v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 2060 - GRANT - Mobile Apps and Desktop Clients - Only for fully Blocking BYOD.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 2060 - GRANT - Mobile Apps and Desktop Clients - Only for fully Blocking BYOD.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 2070 - GRANT - Mobile Device Access Requirements - v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 2070 - GRANT - Mobile Device Access Requirements - v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 3010 - SESSION - ADMINS - Persistence.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 3010 - SESSION - ADMINS - Persistence.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 3020 - SESSION - BYOD Persistence.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 3020 - SESSION - BYOD Persistence.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/GLOBAL - 3030 - SESSION - Register Security Info Requirements - v1.2.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/GLOBAL - 3030 - SESSION - Register Security Info Requirements - v1.2.json -------------------------------------------------------------------------------- /CABaseline2025/ConditionalAccess/OVERRIDE - 0001 - GRANT - Example.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/ConditionalAccess/OVERRIDE - 0001 - GRANT - Example.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD001_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD001_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD002_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD002_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD003_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD003_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD004_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD004_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD005_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD005_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD006_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD006_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD007_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD007_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD008_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD008_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD009_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD009_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD010_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD010_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD012_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD012_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD014_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD014_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD015_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD015_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD015_Include.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD015_Include.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD016_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD016_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAD016_Include.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAD016_Include.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAL002_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAL002_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAL004_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAL004_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAP001_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAP001_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAP002_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAP002_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAU001_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAU001_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAU002_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAU002_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAU003_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAU003_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAU005_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAU005_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAU008_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAU008_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAU009_Exclude.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAU009_Exclude.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_CAU013_Include.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_CAU013_Include.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_ConAcc-Breakglass.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_ConAcc-Breakglass.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/AAD_UA_Update-Ring-02.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/AAD_UA_Update-Ring-02.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/Conditional Access Service Accounts.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/Conditional Access Service Accounts.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/Excluded from Country Block List.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/Excluded from Country Block List.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/Excluded from Device Code Auth Flow Block.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/Excluded from Device Code Auth Flow Block.json -------------------------------------------------------------------------------- /CABaseline2025/Groups/Information Technology and Systems.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/Groups/Information Technology and Systems.json -------------------------------------------------------------------------------- /CABaseline2025/MigrationTable.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/MigrationTable.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/All Compliant Network locations.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/All Compliant Network locations.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/Allowed Countries.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/Allowed Countries.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/CCI - FortiGate VPN SSL.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/CCI - FortiGate VPN SSL.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/CCI JumpBox.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/CCI JumpBox.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/Canada and USA.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/Canada and USA.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/Fake Restrictive Location.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/Fake Restrictive Location.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/HQ - Canada.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/HQ - Canada.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/High-Risk Countries.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/High-Risk Countries.json -------------------------------------------------------------------------------- /CABaseline2025/NamedLocations/Service Accounts Trusted IPs.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/NamedLocations/Service Accounts Trusted IPs.json -------------------------------------------------------------------------------- /CABaseline2025/TermsOfUse/MSFT Terms of Use.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/TermsOfUse/MSFT Terms of Use.json -------------------------------------------------------------------------------- /CABaseline2025/TermsOfUse/Terms of Use.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/TermsOfUse/Terms of Use.json -------------------------------------------------------------------------------- /CABaseline2025/TermsOfUse/file-sample_150kB.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/CABaseline2025/TermsOfUse/file-sample_150kB.pdf -------------------------------------------------------------------------------- /Compliance/Archive/Find-MgGraphPermissions.ps1: -------------------------------------------------------------------------------- 1 | Find-MgGraphPermission audit -------------------------------------------------------------------------------- /Compliance/Archive/GraphCalls.ps1: -------------------------------------------------------------------------------- 1 | # relative v1.0 URI 2 | Invoke-MgGraphRequest -Uri "v1.0/auditLogs/directoryAudits?filter=activityDateTime ge $startDate" -OutputType PSObject 3 | 4 | # absolute beta URI, special (PATCH) request method 5 | Invoke-MgGraphRequest -Method PATCH -Uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" -Body $body 6 | 7 | # relative URI with variable instead of ID 8 | Invoke-MgGraphRequest -Uri "v1.0/groups/$($group.Id)/settings" -Method POST -Body $json -ContentType "application/json" 9 | 10 | # URI defined via positional argument 11 | Invoke-MgGraphRequest -OutputType PSObject "https://graph.microsoft.com/v1.0/devices" 12 | 13 | # non resolvable URI 14 | Invoke-MgGraphRequest -OutputType PSObject -Uri $msGraphPermissionsRequestUri 15 | 16 | # official Mg command (read operation) 17 | Get-MgApplication -ApplicationId "123456" 18 | 19 | # official Mg command (write operation) 20 | Update-MgApplication 21 | 22 | # Invoke-MSGraphRequest 23 | Invoke-MSGraphRequest -Url 'https://graph.microsoft.com/beta/servicePrincipals?$select=id' 24 | 25 | # Invoke-WebRequest 26 | Invoke-WebRequest "https://graph.microsoft.com/v1.0/devices" 27 | 28 | # Invoke-RestMethod 29 | Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/devices" -header $header 30 | 31 | # using Invoke-RestMethod alias 32 | irm -Uri "https://graph.microsoft.com/v1.0/users" -header $header 33 | 34 | # dependant function that has its own Graph API calls 35 | Remove-O365OrphanedMailbox -------------------------------------------------------------------------------- /Compliance/Archive/Invoke-MgGraphRequestwithAccessToken copy 2.ps1: -------------------------------------------------------------------------------- 1 | # Ensure you are authenticated 2 | Connect-MgGraph -Scopes "Directory.Read.All" 3 | 4 | # Fetch organization details using the Graph cmdlet 5 | $organization = Get-MgOrganization 6 | 7 | # Output the organization details 8 | $organization | Format-List 9 | -------------------------------------------------------------------------------- /Compliance/Archive/Logging.ps1: -------------------------------------------------------------------------------- 1 | function Log-FunctionCall { 2 | param ( 3 | [string]$Message, 4 | [string]$Level = 'INFO' 5 | ) 6 | 7 | $callerFunction = (Get-PSCallStack)[1].Command 8 | $formattedMessage = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [$Level] [Function: $callerFunction] $Message" 9 | Write-Host $formattedMessage 10 | } 11 | 12 | function Test-Function { 13 | Log-FunctionCall -Message "This is a test message from the function." 14 | } 15 | 16 | Test-Function 17 | 18 | 19 | 20 | 21 | class Logger { 22 | [void] LogClassCall([string]$Message, [string]$Level = 'INFO') { 23 | $callerFunction = (Get-PSCallStack)[1].Command 24 | $callerClass = $this.GetType().Name 25 | $formattedMessage = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [$Level] [Class: $callerClass] [Function: $callerFunction] $Message" 26 | Write-Host $formattedMessage 27 | } 28 | } 29 | 30 | class TestClass { 31 | [Logger]$logger 32 | 33 | TestClass() { 34 | $this.logger = [Logger]::new() 35 | } 36 | 37 | [void] TestMethod() { 38 | $this.logger.LogClassCall("This is a test message from the class method.", "INFO") 39 | } 40 | } 41 | 42 | $testInstance = [TestClass]::new() 43 | $testInstance.TestMethod() 44 | -------------------------------------------------------------------------------- /Compliance/Archive/Ondrej-Sebela-doitpshway copy 2.ps1: -------------------------------------------------------------------------------- 1 | #the following does not work keeps returning 2 | 3 | 4 | # WARNING: Command's Invoke-MgGraphRequest definition is missing. Skip getting its dependencies 5 | # WARNING: Command's Invoke-MgGraphRequest definition is missing. Skip getting its dependencies 6 | # WARNING: Command's Invoke-MgGraphRequest definition is missing. Skip getting its dependencies 7 | # WARNING: Command's Invoke-MgGraphRequest definition is missing. Skip getting its dependencies 8 | # WARNING: Command's Invoke-MgGraphRequest definition is missing. Skip getting its dependencies 9 | # WARNING: Command's Get-MgApplication definition is missing. Skip getting its dependencies 10 | # WARNING: Command's Update-MgApplication definition is missing. Skip getting its dependencies 11 | # WARNING: Unable to find command 'Invoke-MSGraphRequest' (source: ) details. Skip getting its dependencies 12 | # InvalidOperation: Cannot index into a null array. 13 | # InvalidOperation: Cannot index into a null array. 14 | # InvalidOperation: Cannot index into a null array. 15 | # WARNING: Unable to find command 'Remove-O365OrphanedMailbox' (source: ) details. Skip getting its dependencies 16 | # WARNING: 'Find-MgGraphCommand' was unable to find command ''?! 17 | # WARNING: Be noted that it is impossible to tell whether found permissions for some command are all required, or just some subset of them (for least-privileged access). Consult the Microsoft Graph Permissions Reference documentation to identify the least-privileged permission for your use case :( 18 | 19 | # # Ensure required modules are installed 20 | # Install-Module -Name MSGraphStuff -Scope Allusers -Force -AllowClobber 21 | # Install-Module -Name DependencySearch -Scope Allusers -Force -AllowClobber 22 | # Install-Module -Name Microsoft.Graph.Authentication -Scope Allusers -Force -AllowClobber 23 | # Install-Module -Name Microsoft.Graph.Reports -Scope Allusers -Force -AllowClobber 24 | # Install-Module -Name Microsoft.Graph.Users -Scope Allusers -Force -AllowClobber 25 | 26 | # Load the necessary modules 27 | Import-Module MSGraphStuff 28 | Import-Module DependencySearch 29 | Import-Module Microsoft.Graph.Authentication 30 | Import-Module Microsoft.Graph.Reports 31 | Import-Module Microsoft.Graph.Users 32 | 33 | # Example code that includes the URI we want to check using a recognized command 34 | # Example code that includes a recognized command 35 | # $codeToCheck = @" 36 | # Get-MgUser -UserId 'user@example.com' 37 | # "@ 38 | 39 | # Write the example code to a temporary file 40 | # $tempScriptPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "tempGraphScript.ps1") 41 | # Set-Content -Path $tempScriptPath -Value $codeToCheck 42 | 43 | # Cache available modules to speed up repeated 'Get-CodeGraphPermissionRequirement' function invocations 44 | $availableModules = @(Get-Module -ListAvailable) 45 | 46 | # Get the required permissions for the example code 47 | # $permissions = Get-CodeGraphPermissionRequirement -scriptPath $tempScriptPath -goDeep -availableModules $availableModules -permType "application", "delegated" 48 | $permissions = Get-CodeGraphPermissionRequirement -scriptPath "C:\Code\CB\Entra\ICTC\Entra\Devices\Beta\GraphCalls.ps1" -goDeep -availableModules $availableModules -permType "application", "delegated" 49 | 50 | # Output the permissions 51 | $permissions | Out-GridView 52 | 53 | # Clean up the temporary file 54 | # Remove-Item -Path $tempScriptPath -------------------------------------------------------------------------------- /Compliance/Archive/Ondrej-Sebela-doitpshway copy.ps1: -------------------------------------------------------------------------------- 1 | # # Ensure required modules are installed 2 | Install-Module -Name MSGraphStuff -Scope Allusers -Force -AllowClobber 3 | Install-Module -Name DependencySearch -Scope Allusers -Force -AllowClobber 4 | Install-Module -Name Microsoft.Graph.Authentication -Scope Allusers -Force -AllowClobber 5 | 6 | # Load the necessary modules 7 | Import-Module MSGraphStuff 8 | Import-Module DependencySearch 9 | Import-Module Microsoft.Graph.Authentication 10 | 11 | # Example code that includes the URI we want to check 12 | $codeToCheck = @" 13 | Invoke-MgGraphRequest -Uri 'https://graph.microsoft.com/v1.0/auditLogs/signIns' -Method Get 14 | "@ 15 | 16 | # Write the example code to a temporary file 17 | $tempScriptPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "tempGraphScript.ps1") 18 | Set-Content -Path $tempScriptPath -Value $codeToCheck 19 | 20 | # Cache available modules to speed up repeated 'Get-CodeGraphPermissionRequirement' function invocations 21 | $availableModules = @(Get-Module -ListAvailable) 22 | 23 | # Get the required permissions for the example code 24 | $permissions = Get-CodeGraphPermissionRequirement -scriptPath $tempScriptPath -goDeep -availableModules $availableModules -permType "application", "delegated" 25 | 26 | # Output the permissions 27 | $permissions | Out-GridView 28 | 29 | # Clean up the temporary file 30 | Remove-Item -Path $tempScriptPath 31 | -------------------------------------------------------------------------------- /Compliance/Archive/Ondrej-Sebela-doitpshway.ps1: -------------------------------------------------------------------------------- 1 | # Install MSGraphStuff module from the PowerShell Gallery 2 | Install-Module -Name MSGraphStuff -Scope AllUsers -Force -AllowClobber 3 | 4 | # Example code that includes the URI we want to check 5 | $codeToCheck = @" 6 | Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/auditLogs/signIns' -Method Get 7 | "@ 8 | 9 | # Write the example code to a temporary file 10 | $tempScriptPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "tempGraphScript.ps1") 11 | Set-Content -Path $tempScriptPath -Value $codeToCheck 12 | 13 | # Load the MSGraphStuff module 14 | Import-Module MSGraphStuff 15 | 16 | # Get the required permissions for the example code 17 | $permissions = Get-CodeGraphPermissionRequirement -scriptPath $tempScriptPath -permType "application", "delegated" 18 | 19 | # Output the permissions 20 | $permissions | Out-GridView 21 | 22 | # Clean up the temporary file 23 | Remove-Item -Path $tempScriptPath 24 | -------------------------------------------------------------------------------- /Compliance/Archive/helloworld.psm1: -------------------------------------------------------------------------------- 1 | function Get-Greeting { 2 | param ( 3 | [string]$Name 4 | ) 5 | return "Bonjour, $Name!" 6 | } -------------------------------------------------------------------------------- /Compliance/Archive/test-LINQ-v2.ps1: -------------------------------------------------------------------------------- 1 | # Define the class 2 | class SignInLog { 3 | [string] $userDisplayName 4 | [string] $deviceId 5 | } 6 | 7 | # Path to the JSON file 8 | $JsonFilePath = "C:\log.json" 9 | 10 | # Initialize a list to store the filtered log objects 11 | $logList = [System.Collections.Generic.List[SignInLog]]::new() 12 | 13 | # Open the JSON file and create a JsonTextReader 14 | $reader = [System.IO.StreamReader]::new($JsonFilePath) 15 | $jsonReader = [Newtonsoft.Json.JsonTextReader]::new($reader) 16 | 17 | # Read and process the JSON file incrementally 18 | while ($jsonReader.Read()) { 19 | if ($jsonReader.TokenType -eq [Newtonsoft.Json.JsonToken]::StartObject) { 20 | $jObject = [Newtonsoft.Json.Linq.JObject]::Load($jsonReader) 21 | $userDisplayName = $jObject["userDisplayName"] 22 | $deviceId = $jObject["deviceDetail"]["deviceId"] 23 | 24 | if ($userDisplayName -ne "On-Premises Directory Synchronization Service Account") { 25 | $signInLog = [SignInLog]::new() 26 | $signInLog.userDisplayName = [string]$userDisplayName 27 | $signInLog.deviceId = [string]$deviceId 28 | $logList.Add($signInLog) 29 | } 30 | } 31 | } 32 | 33 | # # Output the filtered logs 34 | # $logList | ForEach-Object { 35 | # Write-Host "User: $($_.userDisplayName), Device ID: $($_.deviceId)" 36 | # } 37 | -------------------------------------------------------------------------------- /Compliance/Archive/test-LINQ-v3.ps1: -------------------------------------------------------------------------------- 1 | # Define the class 2 | class SignInLog { 3 | [string] $userDisplayName 4 | [string] $deviceId 5 | } 6 | 7 | # Path to the JSON file 8 | $JsonFilePath = "C:\log.json" 9 | 10 | # Initialize a list to store the filtered log objects 11 | $logList = [System.Collections.Generic.List[SignInLog]]::new() 12 | 13 | # Open the JSON file and create a JsonDocument 14 | $fileStream = [System.IO.File]::OpenRead($JsonFilePath) 15 | 16 | try { 17 | # Read and process the JSON file incrementally 18 | $jsonDoc = [System.Text.Json.JsonDocument]::Parse($fileStream) 19 | 20 | foreach ($element in $jsonDoc.RootElement.EnumerateArray()) { 21 | $userDisplayName = $element.GetProperty("userDisplayName").GetString() 22 | $deviceId = $element.GetProperty("deviceDetail").GetProperty("deviceId").GetString() 23 | 24 | if ($userDisplayName -ne "On-Premises Directory Synchronization Service Account") { 25 | $signInLog = [SignInLog]::new() 26 | $signInLog.userDisplayName = $userDisplayName 27 | $signInLog.deviceId = $deviceId 28 | $logList.Add($signInLog) 29 | } 30 | } 31 | 32 | # Output the filtered logs 33 | # $logList | ForEach-Object { 34 | # Write-Host "User: $($_.userDisplayName), Device ID: $($_.deviceId)" 35 | # } 36 | } 37 | finally { 38 | # Clean up 39 | $fileStream.Dispose() 40 | } 41 | -------------------------------------------------------------------------------- /Compliance/Archive/test-LINQ.ps1: -------------------------------------------------------------------------------- 1 | # Define the class 2 | class SignInLog { 3 | [string] $userDisplayName 4 | [string] $deviceId 5 | } 6 | 7 | # Path to the JSON file 8 | $JsonFilePath = "C:\log.json" 9 | 10 | # Load the JSON file 11 | $reader = [System.IO.StreamReader]::new($JsonFilePath) 12 | $jarray = [Newtonsoft.Json.Linq.JArray]::Load([NewtonSoft.Json.JsonTextReader]$reader) 13 | 14 | # Filter out specific users and create instances of SignInLog 15 | $filteredLogs = $jarray.SelectTokens('$..[?(@.userDisplayName != ''On-Premises Directory Synchronization Service Account'')]') 16 | 17 | # Initialize a list to store the filtered log objects 18 | $logList = [System.Collections.Generic.List[SignInLog]]::new() 19 | 20 | # Convert filtered JSON tokens to SignInLog objects 21 | foreach ($log in $filteredLogs) { 22 | $userDisplayName = [string]$log.userDisplayName 23 | $deviceId = [string]$log.deviceDetail.deviceId 24 | $signInLog = [SignInLog]::new() 25 | $signInLog.userDisplayName = $userDisplayName 26 | $signInLog.deviceId = $deviceId 27 | $logList.Add($signInLog) 28 | } 29 | 30 | # Output the filtered logs 31 | # $logList | ForEach-Object { 32 | # Write-Host "User: $($_.userDisplayName), Device ID: $($_.deviceId)" 33 | # } 34 | -------------------------------------------------------------------------------- /Compliance/Archive/test-Parallel-v2.ps1: -------------------------------------------------------------------------------- 1 | # Example JSON data 2 | $Json = @( 3 | @{userDisplayName = 'User1'; userPrincipalName = 'user1@example.com'}, 4 | @{userDisplayName = 'On-Premises Directory Synchronization Service Account'; userPrincipalName = 'sync@example.com'}, 5 | @{userDisplayName = 'User2'; userPrincipalName = 'user2@example.com'} 6 | ) 7 | 8 | # Convert the array to JSON and then back to an array of PSCustomObjects to simulate receiving JSON data 9 | $JsonData = $Json | ConvertTo-Json | ConvertFrom-Json 10 | 11 | # Process the JSON data in parallel 12 | $JsonData | ForEach-Object -Parallel { 13 | # Simulate some processing for each user 14 | $user = $_ 15 | $result = [PSCustomObject]@{ 16 | UserDisplayName = $user.userDisplayName 17 | UserPrincipalName = $user.userPrincipalName 18 | ProcessedTime = (Get-Date).ToString() 19 | } 20 | # Output the result 21 | $result 22 | } -ThrottleLimit 4 23 | -------------------------------------------------------------------------------- /Compliance/Archive/test-Parallel.ps1: -------------------------------------------------------------------------------- 1 | # Define a function that uses ForEach-Object -Parallel 2 | function Demo-ParallelScriptRoot { 3 | param ( 4 | [Parameter(Mandatory = $true)] 5 | [string]$ScriptRoot 6 | ) 7 | 8 | # Example array to iterate over 9 | $array = 1..5 10 | 11 | # Use ForEach-Object -Parallel 12 | $array | ForEach-Object -Parallel { 13 | # Use $using: scope to pass $ScriptRoot 14 | $localScriptRoot = $using:ScriptRoot 15 | Write-Output "Script Root in parallel block: $localScriptRoot" 16 | } -ThrottleLimit 2 17 | } 18 | 19 | # Call the function 20 | Demo-ParallelScriptRoot -ScriptRoot $PSScriptRoot 21 | -------------------------------------------------------------------------------- /Compliance/Archive/tests/Async.Logging.PSF.test.ps1: -------------------------------------------------------------------------------- 1 | # Enable asynchronous logging in PSFramework 2 | Set-PSFConfig -FullName PSFramework.Logging.FileSystem.Asynchronous -Value $true -PassThru | Register-PSFConfig 3 | 4 | 5 | # Example of logging a message 6 | Write-PSFMessage -Level 'Debug' -Message "This is a Debug message." 7 | -------------------------------------------------------------------------------- /Compliance/Archive/tests/GetLatestVersion.Choco.test.ps1: -------------------------------------------------------------------------------- 1 | # $mode = $env:EnvironmentMode 2 | 3 | #region FIRING UP MODULE STARTER 4 | ################################################################################################# 5 | # # 6 | # FIRING UP MODULE STARTER # 7 | # # 8 | ################################################################################################# 9 | 10 | 11 | Invoke-Expression (Invoke-RestMethod "https://raw.githubusercontent.com/aollivierre/module-starter/main/Install-EnhancedModuleStarterAO.ps1") 12 | 13 | # Define a hashtable for splatting 14 | $moduleStarterParams = @{ 15 | Mode = 'dev' 16 | SkipPSGalleryModules = $true 17 | SkipCheckandElevate = $true 18 | SkipPowerShell7Install = $true 19 | SkipEnhancedModules = $true 20 | SkipGitRepos = $true 21 | # ExecutionMode = 'Parallel' 22 | } 23 | 24 | # Call the function using the splat 25 | Invoke-ModuleStarter @moduleStarterParams 26 | 27 | #endregion FIRING UP MODULE STARTER 28 | 29 | 30 | # Example usage with pipeline support 31 | # 'GoogleChrome', 'MicrosoftEdge', 'Firefox' | Get-LatestChocoVersion 32 | 33 | 34 | # Example usage 35 | $apps = 'GoogleChrome', 'MicrosoftEdge', 'Firefox' 36 | $apps | Get-LatestChocoVersion -------------------------------------------------------------------------------- /Compliance/Archive/tests/GetLatestVersion.Winget.test.ps1: -------------------------------------------------------------------------------- 1 | # $mode = $env:EnvironmentMode 2 | 3 | #region FIRING UP MODULE STARTER 4 | ################################################################################################# 5 | # # 6 | # FIRING UP MODULE STARTER # 7 | # # 8 | ################################################################################################# 9 | 10 | 11 | # Invoke-Expression (Invoke-RestMethod "https://raw.githubusercontent.com/aollivierre/module-starter/main/Install-EnhancedModuleStarterAO.ps1") 12 | 13 | # Define a hashtable for splatting 14 | # $moduleStarterParams = @{ 15 | # Mode = 'dev' 16 | # SkipPSGalleryModules = $true 17 | # SkipCheckandElevate = $true 18 | # SkipPowerShell7Install = $true 19 | # SkipEnhancedModules = $true 20 | # SkipGitRepos = $true 21 | # # ExecutionMode = 'Parallel' 22 | # } 23 | 24 | # Call the function using the splat 25 | # Invoke-ModuleStarter @moduleStarterParams 26 | 27 | #endregion FIRING UP MODULE STARTER 28 | 29 | 30 | 31 | import-module 'C:\code\Modulesv2\EnhancedModuleStarterAO\EnhancedModuleStarterAO.psm1' -Force 32 | 33 | 34 | # $params = @{ 35 | # id = "7zip.7zip" 36 | # # TargetVersion = "24.8.0.0" 37 | # AcceptNewerVersion = $true 38 | # } 39 | 40 | # $result = Get-LatestWinGetVersion @params 41 | # $result | Format-List 42 | 43 | 44 | 45 | 46 | $params = @{ 47 | id = "Microsoft.PowerShell" 48 | AcceptNewerVersion = $true 49 | } 50 | 51 | $result = Get-LatestWinGetVersion @params 52 | $result | Format-List 53 | 54 | 55 | 56 | # # Example usage: 57 | # $params = @{ 58 | # id = "7zip.7zip" 59 | # TargetVersion = "" 60 | # AcceptNewerVersion = $true 61 | # } 62 | # $latestVersion = Get-LatestWinGetVersion @params 63 | # if ($latestVersion) { 64 | # Write-Host "Latest version installed: $latestVersion" 65 | # } else { 66 | # Write-Host "Latest version is not installed or not found." 67 | # } -------------------------------------------------------------------------------- /Compliance/Archive/tests/validatesoftware.test copy.ps1: -------------------------------------------------------------------------------- 1 | # $mode = $env:EnvironmentMode 2 | 3 | #region FIRING UP MODULE STARTER 4 | ################################################################################################# 5 | # # 6 | # FIRING UP MODULE STARTER # 7 | # # 8 | ################################################################################################# 9 | 10 | 11 | # Invoke-Expression (Invoke-RestMethod "https://raw.githubusercontent.com/aollivierre/module-starter/main/Install-EnhancedModuleStarterAO.ps1") 12 | 13 | # Define a hashtable for splatting 14 | # $moduleStarterParams = @{ 15 | # Mode = 'dev' 16 | # SkipPSGalleryModules = $true 17 | # SkipCheckandElevate = $true 18 | # SkipPowerShell7Install = $true 19 | # SkipEnhancedModules = $true 20 | # SkipGitRepos = $true 21 | # ExecutionMode = 'Parallel' 22 | # } 23 | 24 | # Call the function using the splat 25 | # Invoke-ModuleStarter @moduleStarterParams 26 | 27 | # Define replacements in a hashtable 28 | # $replacements = @{ 29 | # '\$Mode = "dev"' = '$Mode = "dev"' 30 | # '\$SkipPSGalleryModules = \$false' = '$SkipPSGalleryModules = $true' 31 | # '\$SkipCheckandElevate = \$false' = '$SkipCheckandElevate = $true' 32 | # '\$SkipAdminCheck = \$false' = '$SkipAdminCheck = $true' 33 | # '\$SkipPowerShell7Install = \$false' = '$SkipPowerShell7Install = $true' 34 | # '\$SkipModuleDownload = \$false' = '$SkipModuleDownload = $true' 35 | # '\$SkipGitrepos = \$false' = '$SkipGitrepos = $true' 36 | # } 37 | 38 | # # Apply the replacements 39 | # foreach ($pattern in $replacements.Keys) { 40 | # $scriptContent = $scriptContent -replace $pattern, $replacements[$pattern] 41 | # } 42 | 43 | # # Execute the script 44 | # Invoke-Expression $scriptContent 45 | 46 | 47 | 48 | 49 | 50 | 51 | # function Set-ScriptModeToDev { 52 | # # [CmdletBinding()] 53 | # # param ( 54 | # # [Parameter(Mandatory = $true)] 55 | # # [string]$ScriptContent 56 | # # ) 57 | 58 | # $scriptContent = Invoke-RestMethod "https://raw.githubusercontent.com/aollivierre/module-starter/main/Module-Starter.ps1" 59 | 60 | # # Ensure TLS 1.2 is used for all web requests 61 | # [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 62 | 63 | # # Define replacements in a hashtable 64 | # $replacements = @{ 65 | # '\$Mode = "dev"' = '$Mode = "dev"' 66 | # '\$SkipPSGalleryModules = \$false' = '$SkipPSGalleryModules = $true' 67 | # '\$SkipCheckandElevate = \$false' = '$SkipCheckandElevate = $true' 68 | # '\$SkipAdminCheck = \$false' = '$SkipAdminCheck = $true' 69 | # '\$SkipPowerShell7Install = \$false' = '$SkipPowerShell7Install = $true' 70 | # '\$SkipModuleDownload = \$false' = '$SkipModuleDownload = $true' 71 | # '\$SkipGitrepos = \$false' = '$SkipGitrepos = $true' 72 | # } 73 | 74 | # # Apply the replacements 75 | # foreach ($pattern in $replacements.Keys) { 76 | # $ScriptContent = $ScriptContent -replace $pattern, $replacements[$pattern] 77 | # } 78 | 79 | # # Execute the script 80 | # Invoke-Expression $ScriptContent 81 | # } 82 | 83 | # Example usage: 84 | # Set-ScriptModeToDev 85 | 86 | 87 | import-module 'C:\code\Modulesv2\EnhancedModuleStarterAO\EnhancedModuleStarterAO.psm1' -Force 88 | 89 | 90 | 91 | #endregion FIRING UP MODULE STARTER 92 | 93 | 94 | # . "C:\code\IntuneDeviceMigration\DeviceMigration\PSAppDeployToolkit\Toolkit\AppDeployToolkit\AppDeployToolkitMain.ps1" 95 | 96 | # $validationParams = @{ 97 | # SoftwareName = "Git" 98 | # MinVersion = [version]"2.46.0" 99 | # RegistryPath = "HKLM:\SOFTWARE\GitForWindows" 100 | # ExePath = "C:\Program Files\Git\bin\git.exe" 101 | # MaxRetries = 3 # Single retry after installation 102 | # DelayBetweenRetries = 5 103 | # } 104 | 105 | # Validate-SoftwareInstallation @validationParams 106 | 107 | 108 | # $params = @{ 109 | # SoftwareName = '7-Zip' 110 | # MinVersion = [version] "19.0.0.0" 111 | # LatestVersion = [version] "22.1.0.0" 112 | # RegistryPath = 'HKLM:\SOFTWARE\7-Zip' 113 | # ExePath = 'C:\Program Files\7-Zip\7z.exe' 114 | # MaxRetries = 1 115 | # DelayBetweenRetries = 5 116 | # } 117 | 118 | # Validate-SoftwareInstallation @params 119 | 120 | 121 | 122 | 123 | function Check-7ZipInstallation { 124 | param ( 125 | [string]$CustomRegistryPath = "HKLM:\SOFTWARE\7-Zip", 126 | [string]$LogFilePath = "C:\Logs\7ZipCheck.log" 127 | ) 128 | 129 | Begin { 130 | # Initialize log file 131 | $logMessage = "Checking 7-Zip installation..." | Out-String 132 | Write-EnhancedLog -Message $logMessage -Level "INFO" -FilePath $LogFilePath 133 | 134 | # Define registry paths to check 135 | $registryPaths = @( 136 | "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", 137 | "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall", 138 | $CustomRegistryPath 139 | ) 140 | 141 | # Initialize result variable 142 | $sevenZipVersion = $null 143 | } 144 | 145 | Process { 146 | foreach ($registryPath in $registryPaths) { 147 | try { 148 | # Get all installed software in the current registry path 149 | $subkeys = Get-ChildItem -Path $registryPath -ErrorAction Stop 150 | 151 | foreach ($subkey in $subkeys) { 152 | # Check if 7-Zip is installed 153 | $displayName = (Get-ItemProperty -Path $subkey.PSPath -Name DisplayName -ErrorAction SilentlyContinue).DisplayName 154 | if ($displayName -like "*7-Zip*") { 155 | $sevenZipVersion = (Get-ItemProperty -Path $subkey.PSPath -Name DisplayVersion -ErrorAction SilentlyContinue).DisplayVersion 156 | Write-EnhancedLog -Message "7-Zip found in '$registryPath' with version $sevenZipVersion." -Level "INFO" -FilePath $LogFilePath 157 | break 158 | } 159 | } 160 | 161 | if ($sevenZipVersion) { 162 | break 163 | } 164 | } catch { 165 | Write-EnhancedLog -Message "Failed to access registry path: $registryPath. Error: $_" -Level "ERROR" -FilePath $LogFilePath 166 | } 167 | } 168 | } 169 | 170 | End { 171 | if ($sevenZipVersion) { 172 | Write-EnhancedLog -Message "7-Zip version $sevenZipVersion is installed." -Level "NOTICE" -FilePath $LogFilePath 173 | return $true 174 | } else { 175 | Write-EnhancedLog -Message "7-Zip is not installed." -Level "WARNING" -FilePath $LogFilePath 176 | return $false 177 | } 178 | } 179 | } 180 | 181 | # Example usage: 182 | $checkResult = Check-7ZipInstallation -CustomRegistryPath "HKLM:\SOFTWARE\7-Zip" -LogFilePath "C:\Logs\7ZipCheck.log" 183 | 184 | if ($checkResult -eq $false) { 185 | Write-Host "7-Zip is not installed on this machine." -ForegroundColor Red 186 | exit 1 187 | } else { 188 | Write-Host "7-Zip is installed." -ForegroundColor Green 189 | exit 0 190 | } 191 | 192 | 193 | 194 | 195 | # $params = @{ 196 | # SoftwareName = 'notepad++' 197 | # MinVersion = [version] "19.0.0.0" 198 | # LatestVersion = [version] "22.1.0.0" 199 | # # RegistryPath = 'HKLM:\SOFTWARE\7-Zip' 200 | # # ExePath = 'C:\Program Files\7-Zip\7z.exe' 201 | # MaxRetries = 3 202 | # DelayBetweenRetries = 5 203 | # } 204 | 205 | # Validate-SoftwareInstallation @params 206 | -------------------------------------------------------------------------------- /Compliance/Benchmarking/1-Get-Content and ConvertFrom-Json.ps1: -------------------------------------------------------------------------------- 1 | # Method 1: Using Get-Content and ConvertFrom-Json 2 | function Process-Json-GetContent { 3 | param ( 4 | [string]$JsonFilePath 5 | ) 6 | 7 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 8 | 9 | $jsonContent = Get-Content -Path $JsonFilePath -Raw 10 | $jsonData = $jsonContent | ConvertFrom-Json 11 | 12 | # Simulate processing 13 | $jsonData.Count 14 | 15 | $stopwatch.Stop() 16 | Write-Host "Method 1: Get-Content and ConvertFrom-Json took $($stopwatch.Elapsed.TotalMilliseconds) ms" 17 | } 18 | 19 | # Usage 20 | Process-Json-GetContent -JsonFilePath "C:\log.json" -------------------------------------------------------------------------------- /Compliance/Benchmarking/2-System.IO.StreamReader and ConvertFrom-Json.ps1: -------------------------------------------------------------------------------- 1 | # Method 2: Using System.IO.StreamReader and ConvertFrom-Json 2 | function Process-Json-StreamReader { 3 | param ( 4 | [string]$JsonFilePath 5 | ) 6 | 7 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 8 | 9 | $streamReader = [System.IO.StreamReader]::new($JsonFilePath) 10 | $jsonContent = $streamReader.ReadToEnd() 11 | $streamReader.Close() 12 | $jsonData = $jsonContent | ConvertFrom-Json 13 | 14 | # Simulate processing 15 | $jsonData.Count 16 | 17 | $stopwatch.Stop() 18 | Write-Host "Method 2: StreamReader and ConvertFrom-Json took $($stopwatch.Elapsed.TotalMilliseconds) ms" 19 | } 20 | 21 | # Usage 22 | Process-Json-StreamReader -JsonFilePath "C:\log.json" -------------------------------------------------------------------------------- /Compliance/Benchmarking/3-System.Text.Json.JsonDocument.ps1: -------------------------------------------------------------------------------- 1 | # Load System.Text.Json assembly 2 | Add-Type -AssemblyName System.Text.Json 3 | 4 | # Method 3: Using System.Text.Json.JsonDocument 5 | function Process-Json-JsonDocument { 6 | param ( 7 | [string]$JsonFilePath 8 | ) 9 | 10 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 11 | 12 | $fileStream = [System.IO.File]::OpenRead($JsonFilePath) 13 | $jsonDoc = [System.Text.Json.JsonDocument]::Parse($fileStream) 14 | 15 | # Simulate processing 16 | $elementCount = $jsonDoc.RootElement.GetArrayLength() 17 | 18 | $fileStream.Close() 19 | 20 | $stopwatch.Stop() 21 | Write-Host "Method 3: System.Text.Json.JsonDocument took $($stopwatch.Elapsed.TotalMilliseconds) ms" 22 | } 23 | 24 | # Usage 25 | Process-Json-JsonDocument -JsonFilePath "C:\log.json" -------------------------------------------------------------------------------- /Compliance/Benchmarking/4-System.Text.Json.JsonDocument.ps1: -------------------------------------------------------------------------------- 1 | # Load System.Text.Json assembly 2 | Add-Type -AssemblyName System.Text.Json 3 | 4 | # Method 4: Using System.Text.Json.JsonDocument with an Efficient File Open 5 | function Process-Json-JsonDocument { 6 | param ( 7 | [string]$JsonFilePath 8 | ) 9 | 10 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 11 | 12 | # Open the file using FileStream with buffering and SequentialScan 13 | $fileStream = [System.IO.FileStream]::new($JsonFilePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read, 4096, [System.IO.FileOptions]::SequentialScan) 14 | $jsonDoc = [System.Text.Json.JsonDocument]::Parse($fileStream) 15 | 16 | # Simulate processing 17 | $elementCount = $jsonDoc.RootElement.GetArrayLength() 18 | 19 | $fileStream.Close() 20 | 21 | $stopwatch.Stop() 22 | Write-Host "Method 4: System.Text.Json.JsonDocument with system.io.filestream took $($stopwatch.Elapsed.TotalMilliseconds) ms" 23 | } 24 | 25 | # Usage 26 | Process-Json-JsonDocument -JsonFilePath "C:\log.json" -------------------------------------------------------------------------------- /Compliance/Benchmarking/5-compare-json-file-read.ps1: -------------------------------------------------------------------------------- 1 | # Load System.Text.Json assembly 2 | Add-Type -AssemblyName System.Text.Json 3 | 4 | # Method 3: Using System.Text.Json.JsonDocument 5 | function Process-Json-JsonDocument-Method3 { 6 | param ( 7 | [string]$JsonFilePath 8 | ) 9 | 10 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 11 | 12 | $fileStream = [System.IO.File]::OpenRead($JsonFilePath) 13 | $jsonDoc = [System.Text.Json.JsonDocument]::Parse($fileStream) 14 | 15 | # Simulate processing 16 | $elementCount = $jsonDoc.RootElement.GetArrayLength() 17 | 18 | $fileStream.Close() 19 | 20 | $stopwatch.Stop() 21 | return $stopwatch.Elapsed.TotalMilliseconds 22 | } 23 | 24 | # Method 4: Using System.Text.Json.JsonDocument with an Efficient File Open 25 | function Process-Json-JsonDocument-Method4 { 26 | param ( 27 | [string]$JsonFilePath 28 | ) 29 | 30 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 31 | 32 | # Open the file using FileStream with buffering and SequentialScan 33 | $fileStream = [System.IO.FileStream]::new($JsonFilePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read, 4096, [System.IO.FileOptions]::SequentialScan) 34 | $jsonDoc = [System.Text.Json.JsonDocument]::Parse($fileStream) 35 | 36 | # Simulate processing 37 | $elementCount = $jsonDoc.RootElement.GetArrayLength() 38 | 39 | $fileStream.Close() 40 | 41 | $stopwatch.Stop() 42 | return $stopwatch.Elapsed.TotalMilliseconds 43 | } 44 | 45 | # Run each method 100 times and record the elapsed times 46 | $resultsMethod3 = @() 47 | $resultsMethod4 = @() 48 | $JsonFilePath = "C:\log.json" 49 | 50 | for ($i = 0; $i -lt 100; $i++) { 51 | $resultsMethod3 += Process-Json-JsonDocument-Method3 -JsonFilePath $JsonFilePath 52 | $resultsMethod4 += Process-Json-JsonDocument-Method4 -JsonFilePath $JsonFilePath 53 | } 54 | 55 | # Calculate average times 56 | $averageTimeMethod3 = ($resultsMethod3 | Measure-Object -Average).Average 57 | $averageTimeMethod4 = ($resultsMethod4 | Measure-Object -Average).Average 58 | 59 | # Display results 60 | Write-Host "Method 3: Average time using System.Text.Json.JsonDocument took $averageTimeMethod3 ms" 61 | Write-Host "Method 4: Average time using System.Text.Json.JsonDocument with FileStream took $averageTimeMethod4 ms" 62 | 63 | 64 | 65 | 66 | 67 | 68 | # $code = @" 69 | # using System; 70 | # using System.IO; 71 | # using System.Text.Json; 72 | 73 | # public class JsonProcessor 74 | # { 75 | # public static long ProcessJson(string jsonFilePath) 76 | # { 77 | # var stopwatch = System.Diagnostics.Stopwatch.StartNew(); 78 | 79 | # using (FileStream fileStream = new FileStream(jsonFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan)) 80 | # { 81 | # byte[] buffer = new byte[4096]; 82 | # int bytesRead; 83 | # long elementCount = 0; 84 | 85 | # while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0) 86 | # { 87 | # var jsonReader = new Utf8JsonReader(buffer.AsSpan(0, bytesRead), isFinalBlock: bytesRead < buffer.Length, state: default); 88 | 89 | # while (jsonReader.Read()) 90 | # { 91 | # if (jsonReader.TokenType == JsonTokenType.StartObject) 92 | # { 93 | # elementCount++; 94 | # } 95 | # } 96 | # } 97 | 98 | # stopwatch.Stop(); 99 | # Console.WriteLine($"Utf8JsonReader took {stopwatch.Elapsed.TotalMilliseconds} ms, processed {elementCount} elements"); 100 | # return stopwatch.ElapsedMilliseconds; 101 | # } 102 | # } 103 | # } 104 | # "@ 105 | 106 | 107 | 108 | 109 | # # Compile the C# code 110 | # Add-Type -TypeDefinition $code -Language CSharp 111 | 112 | # # Define the PowerShell function to call the C# method 113 | # function Process-Json-Utf8JsonReader { 114 | # param ( 115 | # [string]$JsonFilePath 116 | # ) 117 | 118 | # return [JsonProcessor]::ProcessJson($JsonFilePath) 119 | # } 120 | 121 | # # Run the method 100 times and record the elapsed times 122 | # $resultsMethod5 = @() 123 | # $JsonFilePath = "C:\log.json" 124 | 125 | # for ($i = 0; $i -lt 100; $i++) { 126 | # $resultsMethod5 += Process-Json-Utf8JsonReader -JsonFilePath $JsonFilePath 127 | # } 128 | 129 | # # Calculate average time 130 | # $averageTimeMethod5 = ($resultsMethod5 | Measure-Object -Average).Average 131 | 132 | # # Display results 133 | # Write-Host "Method 5: Average time using System.Text.Json.Utf8JsonReader took $averageTimeMethod5 ms" 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /Compliance/Benchmarking/Test-DataStructures.ps1: -------------------------------------------------------------------------------- 1 | # Helper function to measure execution time 2 | function Measure-ExecutionTime { 3 | param ( 4 | [scriptblock]$Code, 5 | [int]$Iterations = 100 6 | ) 7 | $totalTime = [timespan]::Zero 8 | for ($i = 0; $i -lt $Iterations; $i++) { 9 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 10 | & $Code 11 | $stopwatch.Stop() 12 | $totalTime += $stopwatch.Elapsed 13 | } 14 | return $totalTime.TotalMilliseconds / $Iterations 15 | } 16 | 17 | # Helper function to parse JSON data 18 | function Parse-JsonData { 19 | param ( 20 | [string]$JsonData 21 | ) 22 | $jsonData = $JsonData.Trim() 23 | if ($jsonData.StartsWith('[') -and $jsonData.EndsWith(']')) { 24 | return $jsonData | ConvertFrom-Json 25 | } 26 | elseif ($jsonData.StartsWith('{') -and $jsonData.EndsWith('}')) { 27 | return , $jsonData | ConvertFrom-Json 28 | } 29 | else { 30 | Write-Warning "Invalid JSON data encountered: $jsonData" 31 | return $null 32 | } 33 | } 34 | 35 | # Method 1: Using Array 36 | function Process-SignInLogs-Array { 37 | param ( 38 | [string]$JsonFilePath 39 | ) 40 | $uniqueIds = @() 41 | $lines = Get-Content -Path $JsonFilePath -ReadCount 0 42 | foreach ($line in $lines) { 43 | $logs = Parse-JsonData -JsonData $line 44 | if ($logs) { 45 | foreach ($log in $logs) { 46 | $deviceId = $log.deviceDetail.deviceId 47 | if (-not $uniqueIds.Contains($deviceId)) { 48 | $uniqueIds += $deviceId 49 | } 50 | } 51 | } 52 | } 53 | } 54 | 55 | # Method 2: Using Hashtable 56 | function Process-SignInLogs-Hashtable { 57 | param ( 58 | [string]$JsonFilePath 59 | ) 60 | $uniqueIds = @{} 61 | $lines = Get-Content -Path $JsonFilePath -ReadCount 0 62 | foreach ($line in $lines) { 63 | $logs = Parse-JsonData -JsonData $line 64 | if ($logs) { 65 | foreach ($log in $logs) { 66 | $deviceId = $log.deviceDetail.deviceId 67 | if (-not $uniqueIds.ContainsKey($deviceId)) { 68 | $uniqueIds[$deviceId] = $true 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | # Method 3: Using HashSet 76 | function Process-SignInLogs-HashSet { 77 | param ( 78 | [string]$JsonFilePath 79 | ) 80 | $uniqueIds = [System.Collections.Generic.HashSet[string]]::new() 81 | $lines = Get-Content -Path $JsonFilePath -ReadCount 0 82 | foreach ($line in $lines) { 83 | $logs = Parse-JsonData -JsonData $line 84 | if ($logs) { 85 | foreach ($log in $logs) { 86 | $deviceId = $log.deviceDetail.deviceId 87 | $uniqueIds.Add($deviceId) | Out-Null 88 | } 89 | } 90 | } 91 | } 92 | 93 | # JSON file path 94 | $jsonFilePath = "C:\log.json" 95 | 96 | # Measure execution times 97 | $arrayTime = Measure-ExecutionTime -Code { Process-SignInLogs-Array -JsonFilePath $jsonFilePath } 98 | $hashtableTime = Measure-ExecutionTime -Code { Process-SignInLogs-Hashtable -JsonFilePath $jsonFilePath } 99 | $hashSetTime = Measure-ExecutionTime -Code { Process-SignInLogs-HashSet -JsonFilePath $jsonFilePath } 100 | 101 | # Output results 102 | Write-Host "Average execution time using Array: $arrayTime ms" 103 | Write-Host "Average execution time using Hashtable: $hashtableTime ms" 104 | Write-Host "Average execution time using HashSet: $hashSetTime ms" -------------------------------------------------------------------------------- /Compliance/Benchmarking/test-vscode-debugging.ps1: -------------------------------------------------------------------------------- 1 | function Get-Greeting { 2 | param ( 3 | [string]$Name 4 | ) 5 | return "Hello, $Name!" 6 | } 7 | 8 | # Import the module 9 | Import-Module "$PSScriptRoot\helloworld.psm1" -Force 10 | 11 | # Test the function 12 | $greeting = Get-Greeting -Name "World" 13 | Write-Host $greeting 14 | 15 | $DBG 16 | 17 | # Breakpoint to inspect the variable 18 | $greeting 19 | -------------------------------------------------------------------------------- /Compliance/CustomExports/BYODCompliant.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/Compliance/CustomExports/BYODCompliant.csv -------------------------------------------------------------------------------- /Compliance/CustomExports/CorporateIncompliant.csv: -------------------------------------------------------------------------------- 1 | "DeviceName","UserName","DeviceEntraID","UserEntraID","DeviceOS","OSVersion","DeviceComplianceStatus","DeviceStateInIntune","TrustType","UserLicense","SignInStatus","City","State","CountryOrRegion" 2 | "ICTC-642","Sadik Idriss","2eb123e2-eed7-4b20-86f7-4f4ac8a88733","d3e336a8-fc7a-4188-92a1-7d0c3d906467","Windows10","10.0.19045.5011","Non-Compliant","Absent","Hybrid Azure AD joined","Microsoft 365 Business Premium","Success","Quebec City","Quebec","CA" 3 | "ICTC-622","Reem Fakhouri","61e9e207-6650-4fe3-acd6-91a30437f226","c7fb58ea-321b-4768-8cbf-50077d0179bc","Windows10","","Non-Compliant","Absent","Hybrid Azure AD joined","Microsoft 365 Business Premium","Success","Toronto","Ontario","CA" 4 | "ICTC-581","Mairead Matthews","c55915fc-6fba-422a-9328-394a0bc508ef","027b0c6d-7da4-4b25-8d86-08c338ade181","Windows10","10.0.19045.4170","Non-Compliant","Absent","Hybrid Azure AD joined","Microsoft 365 Business Premium","Success","Vancouver","British Columbia","CA" 5 | "ICTC-571","Dave Murray","c95b0eb5-87e4-49ec-a619-2b6e686e8c72","271e64f6-a1e3-4792-8e7e-3ddf6b97e3b1","Windows10","","Non-Compliant","Absent","Hybrid Azure AD joined","Microsoft 365 Business Premium","Success","Calgary","Alberta","CA" 6 | "ICTC-MGMT","Nijat Mammadov","0bb33864-ff6a-4fb7-8495-4d3d4b84a0ae","66fe21d7-0a19-4988-b5d2-4f6147ee29b2","Windows","10.0.17763.0","Non-Compliant","Absent","Hybrid Azure AD joined","Other","Success","Toronto","Ontario","CA" 7 | -------------------------------------------------------------------------------- /Compliance/CustomExports/Report_Compliant.csv: -------------------------------------------------------------------------------- 1 | "ComplianceStatus","TrustType","DeviceOS","DeviceStateInIntune","Count" 2 | "Compliant","Azure AD joined","Windows","Present","6" 3 | "Compliant","Azure AD joined","Windows10","Present","14" 4 | "Compliant","Hybrid Azure AD joined","Windows","Present","15" 5 | "Compliant","Hybrid Azure AD joined","Windows10","Present","13" 6 | -------------------------------------------------------------------------------- /Compliance/CustomExports/Report_Error.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aollivierre/ConditionalAccess/1b182d291022f8eb3d9d930f5d6fe8f2448280e5/Compliance/CustomExports/Report_Error.csv -------------------------------------------------------------------------------- /Compliance/CustomExports/Report_External.csv: -------------------------------------------------------------------------------- 1 | "DeviceName","UserName","DeviceEntraID","UserEntraID","DeviceOS","OSVersion","DeviceComplianceStatus","DeviceStateInIntune","TrustType","UserLicense","SignInStatus","City","State","CountryOrRegion" 2 | "{PII Removed}","Siddiqui, Ayesha","N/A","21b90bc7-95c1-4988-8b84-c6833fc38699","Windows10","","Non-Compliant","External","Hybrid Azure AD joined","Other","Success","Toronto","Ontario","CA" 3 | -------------------------------------------------------------------------------- /Compliance/CustomExports/Report_NonCompliant.csv: -------------------------------------------------------------------------------- 1 | "ComplianceStatus","TrustType","DeviceOS","DeviceStateInIntune","Count" 2 | "Non-Compliant","","","BYOD","2" 3 | "Non-Compliant","","Android","BYOD","4" 4 | "Non-Compliant","","Ios 16.7.10","BYOD","1" 5 | "Non-Compliant","","Ios 17.3","BYOD","1" 6 | "Non-Compliant","","Ios 17.3.0","BYOD","1" 7 | "Non-Compliant","","Ios 17.5.1","BYOD","1" 8 | "Non-Compliant","","Ios 17.6","BYOD","1" 9 | "Non-Compliant","","Ios 17.6.0","BYOD","1" 10 | "Non-Compliant","","Ios 17.6.1","BYOD","7" 11 | "Non-Compliant","","Ios 17.7","BYOD","2" 12 | "Non-Compliant","","Ios 17.7.0","BYOD","2" 13 | "Non-Compliant","","Ios 18.0","BYOD","3" 14 | "Non-Compliant","","Ios 18.0.0","BYOD","2" 15 | "Non-Compliant","","Ios 18.0.1","BYOD","1" 16 | "Non-Compliant","","MacOs","BYOD","7" 17 | "Non-Compliant","","Windows","BYOD","2" 18 | "Non-Compliant","","Windows10","BYOD","65" 19 | "Non-Compliant","Azure AD registered","Ios 17.6.1","Absent","1" 20 | "Non-Compliant","Azure AD registered","Windows10","Absent","25" 21 | "Non-Compliant","Hybrid Azure AD joined","Windows","Absent","1" 22 | "Non-Compliant","Hybrid Azure AD joined","Windows10","Absent","4" 23 | -------------------------------------------------------------------------------- /Compliance/CustomExports/Report_NonPremiumLicenses.csv: -------------------------------------------------------------------------------- 1 | "DeviceName","UserName","DeviceEntraID","UserEntraID","DeviceOS","OSVersion","DeviceComplianceStatus","DeviceStateInIntune","TrustType","UserLicense","SignInStatus","City","State","CountryOrRegion" 2 | "BYOD","Terence Nascimento (Nova)","N/A","04213b98-7eba-41ab-96e7-0dde304504bb","Windows10","","Non-Compliant","BYOD","","Other","Success","Ottawa","Ontario","CA" 3 | "BYOD","Alexandra Cutean","N/A","0db0e3fe-7dc0-4439-b371-75844eb2966f","Windows10","","Non-Compliant","BYOD","","Other","Success","Squamish","British Columbia","CA" 4 | "{PII Removed}","Siddiqui, Ayesha","N/A","21b90bc7-95c1-4988-8b84-c6833fc38699","Windows10","","Non-Compliant","External","Hybrid Azure AD joined","Other","Success","Toronto","Ontario","CA" 5 | "BYOD","ICTC-CTIC Women in Tech","N/A","481e1fd1-86f2-4a49-9ea7-eacfbff71e7b","Windows10","","Non-Compliant","BYOD","","Other","Success","Ottawa","Ontario","CA" 6 | "BYOD","Terence Nascimento (Nova)","N/A","501e6933-d388-48c2-8ece-2fca572c9a19","Windows10","","Non-Compliant","BYOD","","Other","Success","Ottawa","Ontario","CA" 7 | "BYOD","Magi Reyes (NOVA)","N/A","65012f3d-59d2-4620-a7ea-c7f0c1b9c69c","Windows10","","Non-Compliant","BYOD","","Other","Success","Kitchener","Ontario","CA" 8 | "BYOD","Nijat Mammadov","N/A","66fe21d7-0a19-4988-b5d2-4f6147ee29b2","Windows10","","Non-Compliant","BYOD","","Other","Success","Stittsville","Ontario","CA" 9 | "BYOD","NovaAdmin-John Fawcett","N/A","677d34c0-14f0-4a26-9db6-f21bd7c048c0","Windows10","","Non-Compliant","BYOD","","Other","Success","Toronto","Ontario","CA" 10 | "BYOD","Jainish Acharya","N/A","7d5f579e-11a7-4dfa-8a15-13c585de86da","Windows10","","Non-Compliant","BYOD","","Other","Success","Nepean","Ontario","CA" 11 | "BYOD","No-Reply","N/A","8f29e97e-0f20-40f5-8a9b-24264301d99d","","","Non-Compliant","BYOD","","Other","Success","Barrie","Ontario","CA" 12 | "BYOD","Ann Stephen","N/A","a3925472-e922-4d7e-98f5-8d62bdc9e8c6","Windows10","","Non-Compliant","BYOD","","Other","Success","Ottawa","Ontario","CA" 13 | "BYOD","Abdullah Ollivierre (NOVA)","N/A","bde8ec78-f15e-449a-ae87-63d6f1b512bb","Windows","","Non-Compliant","BYOD","","Other","Success","Winnipeg","Manitoba","CA" 14 | "BYOD","Shakeel Ahmed","N/A","f1580fa8-2db6-41f0-b331-8501de1c3e08","Windows10","","Non-Compliant","BYOD","","Other","Success","Windsor","Ontario","CA" 15 | "BYOD","ICTC Finance","N/A","f7c280af-539b-4ca1-bcd7-8dce889ce935","","","Non-Compliant","BYOD","","Other","Success","Barrie","Ontario","CA" 16 | "BYOD","Abdulahad Shaikh (NOVA)","N/A","fcc23ae1-4167-4d1a-9794-8fb7e279b873","Windows10","","Non-Compliant","BYOD","","Other","Success","Toronto","Ontario","CA" 17 | -------------------------------------------------------------------------------- /Compliance/CustomExports/Report_PIIRemoved.csv: -------------------------------------------------------------------------------- 1 | "DeviceName","UserName","DeviceEntraID","UserEntraID","DeviceOS","OSVersion","DeviceComplianceStatus","DeviceStateInIntune","TrustType","UserLicense","SignInStatus","City","State","CountryOrRegion" 2 | "{PII Removed}","Siddiqui, Ayesha","N/A","21b90bc7-95c1-4988-8b84-c6833fc38699","Windows10","","Non-Compliant","External","Hybrid Azure AD joined","Other","Success","Toronto","Ontario","CA" 3 | -------------------------------------------------------------------------------- /Compliance/CustomExports/Report_Present.csv: -------------------------------------------------------------------------------- 1 | "ComplianceStatus","TrustType","DeviceOS","DeviceStateInIntune","Count" 2 | "Compliant","Azure AD joined","Windows","Present","6" 3 | "Compliant","Azure AD joined","Windows10","Present","14" 4 | "Compliant","Hybrid Azure AD joined","Windows","Present","15" 5 | "Compliant","Hybrid Azure AD joined","Windows10","Present","13" 6 | -------------------------------------------------------------------------------- /Compliance/CustomExports/StructuredReport.csv: -------------------------------------------------------------------------------- 1 | "ComplianceStatus","TrustType","DeviceOS","DeviceStateInIntune","Count" 2 | "Compliant","Azure AD joined","Windows","Present","6" 3 | "Compliant","Azure AD joined","Windows10","Present","14" 4 | "Compliant","Hybrid Azure AD joined","Windows","Present","15" 5 | "Compliant","Hybrid Azure AD joined","Windows10","Present","13" 6 | "Non-Compliant","","","BYOD","2" 7 | "Non-Compliant","","Android","BYOD","4" 8 | "Non-Compliant","","Ios 16.7.10","BYOD","1" 9 | "Non-Compliant","","Ios 17.3","BYOD","1" 10 | "Non-Compliant","","Ios 17.3.0","BYOD","1" 11 | "Non-Compliant","","Ios 17.5.1","BYOD","1" 12 | "Non-Compliant","","Ios 17.6","BYOD","1" 13 | "Non-Compliant","","Ios 17.6.0","BYOD","1" 14 | "Non-Compliant","","Ios 17.6.1","BYOD","7" 15 | "Non-Compliant","","Ios 17.7","BYOD","2" 16 | "Non-Compliant","","Ios 17.7.0","BYOD","2" 17 | "Non-Compliant","","Ios 18.0","BYOD","3" 18 | "Non-Compliant","","Ios 18.0.0","BYOD","2" 19 | "Non-Compliant","","Ios 18.0.1","BYOD","1" 20 | "Non-Compliant","","MacOs","BYOD","7" 21 | "Non-Compliant","","Windows","BYOD","2" 22 | "Non-Compliant","","Windows10","BYOD","65" 23 | "Non-Compliant","Azure AD registered","Ios 17.6.1","Absent","1" 24 | "Non-Compliant","Azure AD registered","Windows10","Absent","25" 25 | "Non-Compliant","Hybrid Azure AD joined","Windows","Absent","1" 26 | "Non-Compliant","Hybrid Azure AD joined","Windows10","Absent","4" 27 | -------------------------------------------------------------------------------- /Compliance/Modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "requiredModules": [ 3 | "Microsoft.Graph.Authentication", 4 | "Microsoft.Graph.Applications", 5 | "Microsoft.Graph.Identity.DirectoryManagement", 6 | "ImportExcel", 7 | "powershell-yaml" , 8 | "PSWriteHTML", 9 | "MSAL.PS", 10 | "IntuneWin32App", 11 | "Microsoft.Graph.Groups", 12 | "SvRooij.ContentPrep.Cmdlet" 13 | ], 14 | "importedModules": [ 15 | "Microsoft.Graph.Identity.DirectoryManagement", 16 | "Microsoft.Graph.Authentication", 17 | "Microsoft.Graph.Identity.DirectoryManagement", 18 | "Microsoft.Graph.Applications", 19 | "ImportExcel", 20 | "powershell-yaml" , 21 | "PSWriteHTML", 22 | "MSAL.PS", 23 | "IntuneWin32App", 24 | "Microsoft.Graph.Groups", 25 | "SvRooij.ContentPrep.Cmdlet" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /Compliance/Readme.md: -------------------------------------------------------------------------------- 1 | Certainly! Here’s a documentation note for future reference, advising on how to maintain and customize the script, specifically focusing on the `Load-SignInLogs`, `Add-Result`, and `Process-DeviceItem` functions: 2 | 3 | --- 4 | 5 | ### **Script Maintenance and Customization Guide** 6 | 7 | #### **1. Customizing the `Load-SignInLogs` Function** 8 | 9 | The `Load-SignInLogs` function is responsible for loading and parsing sign-in logs from a JSON file. This function extracts specific properties from the JSON data and includes them in the `signInLog` object. 10 | 11 | - **When to Update:** 12 | - If you need to include additional properties from the JSON file (e.g., `location`, `clientAppUsed`), you should modify the `Load-SignInLogs` function to capture these properties. 13 | - If certain properties are no longer needed in the report, you can remove them from this function to simplify the `signInLog` object. 14 | 15 | - **How to Update:** 16 | - Locate the section where each property is extracted, for example: 17 | ```powershell 18 | $deviceDetail = [PSCustomObject]@{ 19 | DeviceId = $element.GetProperty("deviceDetail").GetProperty("deviceId").GetString() 20 | DisplayName = $element.GetProperty("deviceDetail").GetProperty("displayName").GetString() 21 | OperatingSystem = $element.GetProperty("deviceDetail").GetProperty("operatingSystem").GetString() 22 | IsCompliant = $element.GetProperty("deviceDetail").GetProperty("isCompliant").GetBoolean() 23 | TrustType = $element.GetProperty("deviceDetail").GetProperty("trustType").GetString() 24 | } 25 | ``` 26 | - Add or remove lines within these blocks to include or exclude properties. 27 | 28 | #### **2. Customizing the `Add-Result` Function** 29 | 30 | The `Add-Result` function constructs a result object that is eventually added to the processing context. This result object is what gets exported in the final report. 31 | 32 | - **When to Update:** 33 | - If you’ve updated the `Load-SignInLogs` function to include new properties, you’ll need to update `Add-Result` to reflect these changes. 34 | - Conversely, if you’ve removed properties from `Load-SignInLogs`, you should also remove the corresponding fields in `Add-Result` to avoid unnecessary data processing. 35 | 36 | - **How to Update:** 37 | - Update the `Add-Result` function by modifying the `[PSCustomObject]` construction block: 38 | ```powershell 39 | $result = [PSCustomObject]@{ 40 | DeviceName = $deviceName 41 | UserName = $Item.UserDisplayName 42 | DeviceEntraID = $DeviceId 43 | UserEntraID = $Item.UserId 44 | DeviceOS = $Item.DeviceDetail.OperatingSystem 45 | OSVersion = $osVersion 46 | DeviceComplianceStatus = $complianceStatus 47 | DeviceStateInIntune = $DeviceState 48 | TrustType = $Item.DeviceDetail.TrustType 49 | UserLicense = $userLicense 50 | SignInStatus = $signInStatus # New property for Sign-In Status 51 | City = $Item.Location.City # New property for City 52 | State = $Item.Location.State # New property for State 53 | CountryOrRegion = $Item.Location.CountryOrRegion # New property for Country/Region 54 | } 55 | ``` 56 | - Add new properties as needed, or remove those no longer required. 57 | 58 | #### **3. Customizing the `Process-DeviceItem` Function** 59 | 60 | The `Process-DeviceItem` function is where logic is applied to decide whether to process a sign-in log entry or skip it based on specific conditions, such as error codes or the presence of specific properties. 61 | 62 | - **When to Update:** 63 | - Update this function when you want to change the conditions under which a sign-in log is processed or skipped. For example, you might want to skip logs with specific error codes or filter logs based on device compliance status. 64 | 65 | - **How to Update:** 66 | - Locate the conditional logic where decisions are made, for example: 67 | ```powershell 68 | if ($Item.Status.ErrorCode -ne 0) { 69 | Write-EnhancedLog -Message "Sign-in attempt failed for user $($Item.UserDisplayName) with ErrorCode: $($Item.Status.ErrorCode) - $($Item.Status.FailureReason)" -Level "WARNING" 70 | return 71 | } 72 | ``` 73 | - Adjust the conditions to reflect your new requirements. 74 | - Modify or add logging statements as necessary to capture the reasons for skipping or processing specific entries. 75 | 76 | #### **Final Note:** 77 | Whenever you update any of these functions, make sure to thoroughly test the script to ensure that the changes work as expected and that all necessary data is being captured or excluded based on the updates. 78 | 79 | --- 80 | 81 | This guide should help maintain the script and ensure that any future changes can be made systematically, without losing track of why those changes are being implemented. -------------------------------------------------------------------------------- /Compliance/combine-allmodules.ps1: -------------------------------------------------------------------------------- 1 | # Define the root path 2 | $rootPath = 'C:\Code\Modules' 3 | $outputFile = Join-Path -Path $rootPath -ChildPath 'CombinedModules.ps1' 4 | 5 | # Initialize the output file 6 | New-Item -Path $outputFile -ItemType File -Force 7 | 8 | # Function to combine files from a directory and its subdirectories 9 | function Combine-AllPS1Files { 10 | param ( 11 | [string]$directory 12 | ) 13 | Get-ChildItem -Path $directory -Filter *.ps1 -Recurse | ForEach-Object { 14 | Get-Content -Path $_.FullName | Add-Content -Path $outputFile 15 | Add-Content -Path $outputFile -Value "`n" # Add a new line for separation 16 | } 17 | } 18 | 19 | # Combine all PS1 files in the root path and its subdirectories 20 | Combine-AllPS1Files -directory $rootPath 21 | 22 | Write-Host "All PS1 files have been combined into $outputFile" 23 | -------------------------------------------------------------------------------- /Compliance/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "PackageName": "PR4B_GetSignInLogs", 3 | "PackageUniqueGUID": "7b34084e-b856-40f5-9a5b-32b3249fb777", 4 | "Version": 1, 5 | "PackageExecutionContext": "SYSTEM", 6 | "RepetitionInterval": "PT60M", 7 | "LoggingDeploymentName": "PR4B_GetSignInLogsCustomlog", 8 | "ScriptMode": "Remediation", 9 | "RunOnDemand": true 10 | } -------------------------------------------------------------------------------- /Compliance/modulesexclusion.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ] 4 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/Delete-allConditionalAccessPolicies-v2.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with the necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.Read.All', 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Confirm before proceeding as this will delete all Conditional Access policies 5 | $confirmation = Read-Host "Are you sure you want to delete ALL Conditional Access policies? (yes/no)" 6 | if ($confirmation -ne 'yes') { 7 | Write-Output "Operation aborted by the user." 8 | Disconnect-MgGraph 9 | exit 10 | } 11 | 12 | # Fetch all Conditional Access policies 13 | $policies = Get-MgIdentityConditionalAccessPolicy 14 | 15 | # Iterate and delete each policy 16 | foreach ($policy in $policies) { 17 | $policyId = $policy.Id 18 | $policyName = $policy.DisplayName 19 | try { 20 | # Assuming there's a cmdlet to remove policies by ID. If not, you may need to use Invoke-MgGraphRequest with the appropriate HTTP method and URI 21 | Remove-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policyId -Force 22 | Write-Output "Successfully deleted Conditional Access policy: $policyName ($policyId)" 23 | } catch { 24 | Write-Error "Failed to delete Conditional Access policy: $policyName ($policyId). Error: $_" 25 | } 26 | } 27 | 28 | # Disconnect from Microsoft Graph 29 | Disconnect-MgGraph 30 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/Delete-allConditionalAccessPolicies-v3.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with the necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.Read.All', 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Confirm before proceeding as this will delete all Conditional Access policies 5 | $confirmation = Read-Host "Are you sure you want to delete ALL Conditional Access policies? (yes/no)" 6 | if ($confirmation -ne 'yes') { 7 | Write-Output "Operation aborted by the user." 8 | Disconnect-MgGraph 9 | exit 10 | } 11 | 12 | # Fetch all Conditional Access policies 13 | $policies = Get-MgIdentityConditionalAccessPolicy 14 | 15 | # Iterate and attempt to delete each policy 16 | foreach ($policy in $policies) { 17 | $policyId = $policy.Id 18 | $policyName = $policy.DisplayName 19 | try { 20 | # Adjusted cmdlet call without the -Force parameter 21 | Remove-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policyId 22 | Write-Output "Successfully requested deletion of Conditional Access policy: $policyName ($policyId)" 23 | } catch { 24 | Write-Error "Failed to delete Conditional Access policy: $policyName ($policyId). Error: $_" 25 | } 26 | } 27 | 28 | 29 | # Disconnect from Microsoft Graph 30 | Disconnect-MgGraph 31 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/Delete-allConditionalAccessPolicies.ps1: -------------------------------------------------------------------------------- 1 | # Install the required modules if not already installed 2 | Install-Module Microsoft.Graph.Authentication -Scope allusers 3 | Install-Module Microsoft.Graph.Identity.SignIns -Scope AllUsers 4 | 5 | # Connect to Microsoft Graph 6 | Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess" 7 | 8 | # Confirm before proceeding as this will delete all Conditional Access policies 9 | $confirmation = Read-Host "Are you sure you want to delete ALL Conditional Access policies? (yes/no)" 10 | if ($confirmation -ne 'yes') { 11 | Write-Output "Operation aborted by the user." 12 | exit 13 | } 14 | 15 | # Fetch all Conditional Access policies 16 | $policies = Get-MgConditionalAccessPolicy 17 | 18 | # Iterate and delete each policy 19 | foreach ($policy in $policies) { 20 | $policyId = $policy.Id 21 | $policyName = $policy.DisplayName 22 | try { 23 | Remove-MgConditionalAccessPolicy -ConditionalAccessPolicyId $policyId -Force 24 | Write-Output "Successfully deleted Conditional Access policy: $policyName ($policyId)" 25 | } catch { 26 | Write-Error "Failed to delete Conditional Access policy: $policyName ($policyId). Error: $_" 27 | } 28 | } 29 | 30 | # Disconnect from Microsoft Graph 31 | Disconnect-MgGraph 32 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/Rename-ConditionalAccessPolicies-All-v2.ps1: -------------------------------------------------------------------------------- 1 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\Main" 2 | $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\PMM\GRANT" 3 | $jsonFiles = Get-ChildItem -Path $jsonFilesDirectory -Filter "*.json" 4 | 5 | foreach ($file in $jsonFiles) { 6 | if (Test-Path $file.FullName) { 7 | $jsonContent = Get-Content -Path $file.FullName | Out-String 8 | $jsonObject = $jsonContent | ConvertFrom-Json 9 | 10 | if ($null -ne $jsonObject.PSObject.Properties.Match('displayName')) { 11 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($file.Name) 12 | $jsonObject.displayName = $fileNameWithoutExtension 13 | $updatedJsonContent = $jsonObject | ConvertTo-Json -Depth 100 14 | $updatedJsonContent | Set-Content -Path $file.FullName 15 | } else { 16 | Write-Host "The file $($file.Name) does not contain a 'displayName' property." 17 | } 18 | } else { 19 | Write-Host "Unable to find or access the file: $($file.FullName)" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/Rename-ConditionalAccessPolicies-All-v3.ps1: -------------------------------------------------------------------------------- 1 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\Main" 2 | $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\PMM\GRANT" 3 | $jsonFiles = Get-ChildItem -Path $jsonFilesDirectory -Filter "*.json" 4 | 5 | foreach ($file in $jsonFiles) { 6 | try { 7 | # Ensure the JSON content is read with the correct encoding, UTF8 is commonly used for JSON files 8 | $jsonContent = Get-Content -Path $file.FullName -Raw -Encoding UTF8 9 | $jsonObject = $jsonContent | ConvertFrom-Json 10 | 11 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($file.Name) 12 | 13 | # Update the displayName property 14 | $jsonObject.displayName = $fileNameWithoutExtension 15 | 16 | $updatedJsonContent = $jsonObject | ConvertTo-Json -Depth 100 -Compress 17 | $updatedJsonContent | Set-Content -Path $file.FullName -Force -Encoding UTF8 18 | } catch { 19 | Write-Host "An error occurred processing $($file.Name): $_" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/Rename-ConditionalAccessPolicies-All-v4.ps1: -------------------------------------------------------------------------------- 1 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\Main" 2 | $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\PMM\GRANT" 3 | $jsonFiles = Get-ChildItem -Path $jsonFilesDirectory -Filter "*.json" 4 | 5 | foreach ($file in $jsonFiles) { 6 | try { 7 | # Read the file content as an array of lines and then join them into a single string 8 | $jsonContentLines = Get-Content -Path $file.FullName -Encoding UTF8 9 | $jsonContent = $jsonContentLines -join "" 10 | $jsonObject = $jsonContent | ConvertFrom-Json 11 | 12 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($file.Name) 13 | 14 | # Update the displayName property 15 | $jsonObject.displayName = $fileNameWithoutExtension 16 | 17 | $updatedJsonContent = $jsonObject | ConvertTo-Json -Depth 100 -Compress 18 | $updatedJsonContent | Set-Content -Path $file.FullName -Force -Encoding UTF8 19 | } catch { 20 | Write-Host "An error occurred processing $($file.Name): $_" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/recreateConditionalAccesspoliciesusingJSON-v2.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Specify the directory containing the JSON files 5 | $jsonDir = "C:\code\caac\Feb172024\CCI\Entra-Intune-v1\Canada Computing Inc\ConditionalAccess-Recreated-Modern-Graph-API" 6 | 7 | # Get all JSON files from the directory 8 | $jsonFiles = Get-ChildItem -Path $jsonDir -Filter "*.json" 9 | 10 | foreach ($jsonFile in $jsonFiles) { 11 | # Load the JSON content 12 | $jsonContent = Get-Content -Path $jsonFile.FullName -Raw | ConvertFrom-Json 13 | 14 | # Prepare the policy object for creation 15 | $policyParams = @{ 16 | DisplayName = $jsonContent.displayName + " - Modern API" 17 | State = $jsonContent.state 18 | Conditions = $jsonContent.conditions 19 | GrantControls = $jsonContent.grantControls 20 | # Include other fields as needed, ensuring they match the expected schema 21 | } 22 | 23 | # Remove any null or deprecated properties to match the expected schema 24 | $policyParams.GetEnumerator() | ForEach-Object { 25 | if ($null -eq $policyParams[$_.Key]) { 26 | $policyParams.Remove($_.Key) 27 | } 28 | } 29 | 30 | # Convert the policy parameters to a JSON object 31 | $policyJson = $policyParams | ConvertTo-Json -Depth 10 32 | 33 | try { 34 | # Create the new Conditional Access policy 35 | $result = New-MgIdentityConditionalAccessPolicy -BodyParameter $policyJson 36 | Write-Host "Successfully created policy: $($result.DisplayName)" 37 | } catch { 38 | Write-Error "Failed to create policy from $($jsonFile.Name): $_" 39 | } 40 | } 41 | 42 | # Disconnect from Microsoft Graph 43 | # Disconnect-MgGraph 44 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/recreateConditionalAccesspoliciesusingJSON-v3.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Define a simple Conditional Access policy 5 | $policyDisplayName = "Sample Policy - Modern API" 6 | $policyState = "enabled" 7 | 8 | # Define conditions for the policy (adjust as needed) 9 | $conditions = @{ 10 | Applications = @{ 11 | IncludeApplications = "All" 12 | } 13 | Users = @{ 14 | IncludeUsers = "All" 15 | } 16 | } 17 | 18 | # Define grant controls for the policy (adjust as needed) 19 | $grantControls = @{ 20 | BuiltInControls = @("mfa") 21 | Operator = "OR" 22 | } 23 | 24 | # Create the policy 25 | try { 26 | $policyParams = @{ 27 | DisplayName = $policyDisplayName 28 | State = $policyState 29 | Conditions = $conditions 30 | GrantControls = $grantControls 31 | } 32 | 33 | $policyJson = $policyParams | ConvertTo-Json -Depth 10 34 | 35 | # Create the Conditional Access policy 36 | $result = New-MgIdentityConditionalAccessPolicy -BodyParameter $policyJson 37 | Write-Host "Successfully created policy: $($result.DisplayName)" 38 | } catch { 39 | Write-Error "Failed to create policy: $_" 40 | } 41 | 42 | # Disconnect from Microsoft Graph 43 | # Disconnect-MgGraph 44 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/recreateConditionalAccesspoliciesusingJSON-v4.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Define a Conditional Access policy with required conditions 5 | $policyDisplayName = "Sample Policy - Modern API" 6 | $policyState = "enabled" 7 | 8 | # Define conditions for the policy, including 'users' and 'applications' 9 | $conditions = @{ 10 | Applications = @{ 11 | IncludeApplications = @("All") # Include all applications 12 | } 13 | Users = @{ 14 | IncludeUsers = @("All") # Include all users 15 | } 16 | } 17 | 18 | # Define grant controls for the policy 19 | $grantControls = @{ 20 | BuiltInControls = @("mfa") # Require MFA 21 | Operator = "OR" 22 | } 23 | 24 | # Construct the policy object 25 | $policyObject = @{ 26 | DisplayName = $policyDisplayName 27 | State = $policyState 28 | Conditions = $conditions 29 | GrantControls = $grantControls 30 | } 31 | 32 | # Convert policy object to JSON 33 | $policyJson = $policyObject | ConvertTo-Json -Depth 10 34 | 35 | try { 36 | # Attempt to create the Conditional Access policy 37 | $result = New-MgIdentityConditionalAccessPolicy -BodyParameter $policyJson 38 | Write-Host "Successfully created policy: $($result.DisplayName)" 39 | } catch { 40 | Write-Error "Failed to create policy: $_" 41 | } 42 | 43 | # Disconnect from Microsoft Graph 44 | # Disconnect-MgGraph 45 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/recreateConditionalAccesspoliciesusingJSON-v5.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Define a Conditional Access policy with required conditions 5 | $policyDisplayName = "Sample Policy - Modern API - v2 - OFF" 6 | $policyState = "disabled" # Set policy to be off (disabled) 7 | 8 | # Define conditions for the policy, including 'users' and 'applications' 9 | $conditions = @{ 10 | Applications = @{ 11 | IncludeApplications = @("All") # Include all applications 12 | } 13 | Users = @{ 14 | IncludeUsers = @("All") # Include all users 15 | } 16 | } 17 | 18 | # Define grant controls for the policy 19 | $grantControls = @{ 20 | BuiltInControls = @("mfa") # Require MFA 21 | Operator = "OR" 22 | } 23 | 24 | # Construct the policy object 25 | $policyObject = @{ 26 | DisplayName = $policyDisplayName 27 | State = $policyState 28 | Conditions = $conditions 29 | GrantControls = $grantControls 30 | } 31 | 32 | # Convert policy object to JSON 33 | $policyJson = $policyObject | ConvertTo-Json -Depth 10 34 | 35 | try { 36 | # Attempt to create the Conditional Access policy in the "off" state 37 | $result = New-MgIdentityConditionalAccessPolicy -BodyParameter $policyJson 38 | Write-Host "Successfully created policy in the 'off' state: $($result.DisplayName)" 39 | } catch { 40 | Write-Error "Failed to create policy: $_" 41 | } 42 | 43 | # Disconnect from Microsoft Graph 44 | Disconnect-MgGraph 45 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/recreateConditionalAccesspoliciesusingJSON-v6.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Specify the directory containing the JSON files 5 | $jsonDir = "C:\code\caac\Feb172024\CCI\Entra-Intune-v1\Canada Computing Inc\ConditionalAccess-Recreated-Modern-Graph-API" 6 | 7 | # Get all JSON files from the directory 8 | $jsonFiles = Get-ChildItem -Path $jsonDir -Filter "*.json" 9 | 10 | foreach ($jsonFile in $jsonFiles) { 11 | # Load the JSON content 12 | $jsonContent = Get-Content -Path $jsonFile.FullName -Raw | ConvertFrom-Json 13 | 14 | # Prepare the policy object for creation 15 | $policyParams = @{ 16 | DisplayName = $jsonContent.displayName + " - Modern API" 17 | State = "disabled" # Ensure the policy is created in the "off" state 18 | # Define other necessary properties for the policy here 19 | # For example, Conditions and GrantControls as per your requirements 20 | # This example uses placeholder values 21 | Conditions = @{ 22 | Applications = @{ 23 | IncludeApplications = @("All") 24 | } 25 | Users = @{ 26 | IncludeUsers = @("All") 27 | } 28 | } 29 | GrantControls = @{ 30 | BuiltInControls = @("block") 31 | Operator = "OR" 32 | } 33 | } 34 | 35 | # Convert policy object to JSON 36 | $policyJson = $policyParams | ConvertTo-Json -Depth 10 37 | 38 | try { 39 | # Attempt to create the Conditional Access policy 40 | $result = New-MgIdentityConditionalAccessPolicy -BodyParameter $policyJson 41 | Write-Host "Successfully created policy: $($result.DisplayName)" 42 | } catch { 43 | Write-Error "Failed to create policy from file $($jsonFile.Name): $_" 44 | } 45 | } 46 | 47 | # Disconnect from Microsoft Graph 48 | # Disconnect-MgGraph 49 | -------------------------------------------------------------------------------- /ConditionalAccess/Archive/recreateConditionalAccesspoliciesusingJSON.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Specify the directory containing the JSON files 5 | $jsonDir = "C:\code\caac\Feb172024\CCI\Entra-Intune-v1\Canada Computing Inc\ConditionalAccess-Recreated-Modern-Graph-API" 6 | 7 | # Get all JSON files from the directory 8 | $jsonFiles = Get-ChildItem -Path $jsonDir -Filter "*.json" 9 | 10 | foreach ($jsonFile in $jsonFiles) { 11 | # Load the JSON content 12 | $jsonContent = Get-Content -Path $jsonFile.FullName -Raw | ConvertFrom-Json 13 | 14 | # Construct a new policy object from the JSON content, ensuring to avoid deprecated attributes 15 | $newPolicy = @{ 16 | DisplayName = $jsonContent.displayName + " - Modern API" 17 | State = $jsonContent.state 18 | Conditions = @{ 19 | Applications = $jsonContent.conditions.applications 20 | Users = $jsonContent.conditions.users 21 | Platforms = $jsonContent.conditions.platforms 22 | Locations = $jsonContent.conditions.locations 23 | ClientAppTypes = $jsonContent.conditions.clientAppTypes 24 | } 25 | GrantControls = $jsonContent.grantControls 26 | SessionControls = $jsonContent.sessionControls 27 | } 28 | 29 | # Convert the new policy object to JSON 30 | $newPolicyJson = $newPolicy | ConvertTo-Json -Depth 10 31 | 32 | try { 33 | # Create the new Conditional Access policy using the Modern API 34 | $result = New-MgIdentityConditionalAccessPolicy -BodyParameter $newPolicyJson 35 | Write-Host "Successfully created policy: $($result.DisplayName)" 36 | } catch { 37 | Write-Error "Failed to create policy from $($jsonFile.Name): $_" 38 | } 39 | } 40 | 41 | # Disconnect from Microsoft Graph 42 | Disconnect-MgGraph 43 | -------------------------------------------------------------------------------- /ConditionalAccess/Conditional Access Policy Name Generator.ps1: -------------------------------------------------------------------------------- 1 | # Functions for policy generation 2 | function New-CAPolicyName { 3 | param ( 4 | [string]$CategoryCode, 5 | [string]$SequenceNumber, 6 | [string]$Scope, 7 | [string]$Action, 8 | [string]$Condition, 9 | [string]$Clients, 10 | [string]$Version 11 | ) 12 | 13 | "CA$CategoryCode$SequenceNumber - $($Scope.ToUpper()) - $($Action.ToUpper()) - $Condition - when - $Clients - v$Version.json" 14 | } 15 | 16 | function Export-CAPolicy { 17 | param ( 18 | [string]$OutputPath = ".\CAPolicies.csv" 19 | ) 20 | 21 | $policies = @( 22 | # Identity & Authentication Policies 23 | @{ 24 | CategoryCode = "CAP" 25 | SequenceNumber = "001" 26 | Scope = "GLOBAL" 27 | Action = "BLOCK" 28 | Condition = "LegacyAuth" 29 | Clients = "AllClients" 30 | Version = "1.0" 31 | } 32 | @{ 33 | CategoryCode = "CAP" 34 | SequenceNumber = "002" 35 | Scope = "GLOBAL" 36 | Action = "BLOCK" 37 | Condition = "DeviceCodeAuth" 38 | Clients = "AllClients" 39 | Version = "1.0" 40 | } 41 | @{ 42 | CategoryCode = "CAU" 43 | SequenceNumber = "001" 44 | Scope = "ADMINS" 45 | Action = "GRANT" 46 | Condition = "RequirePhishingResistantMFA" 47 | Clients = "BrowserModernAuthClients" 48 | Version = "1.0" 49 | } 50 | # Location-Based Access 51 | @{ 52 | CategoryCode = "CAL" 53 | SequenceNumber = "001" 54 | Scope = "GLOBAL" 55 | Action = "BLOCK" 56 | Condition = "NonAllowedCountries" 57 | Clients = "AllClients" 58 | Version = "1.0" 59 | } 60 | # Device-Based Policies 61 | @{ 62 | CategoryCode = "CAD" 63 | SequenceNumber = "001" 64 | Scope = "GLOBAL" 65 | Action = "BLOCK" 66 | Condition = "UnsupportedPlatforms" 67 | Clients = "AllClients" 68 | Version = "1.0" 69 | } 70 | # Risk-Based Policies 71 | @{ 72 | CategoryCode = "CAU" 73 | SequenceNumber = "002" 74 | Scope = "ADMINS" 75 | Action = "BLOCK" 76 | Condition = "AnyRiskLevel" 77 | Clients = "AllClients" 78 | Version = "1.0" 79 | } 80 | # Guest-Specific Policies 81 | @{ 82 | CategoryCode = "CAU" 83 | SequenceNumber = "003" 84 | Scope = "GUESTS" 85 | Action = "BLOCK" 86 | Condition = "SensitiveApps" 87 | Clients = "AllClients" 88 | Version = "1.0" 89 | } 90 | # Break-Glass Policies 91 | @{ 92 | CategoryCode = "CAB" 93 | SequenceNumber = "001" 94 | Scope = "SELECTED" 95 | Action = "GRANT" 96 | Condition = "EmergencyAccess" 97 | Clients = "BrowserModernAuthClients" 98 | Version = "1.0" 99 | } 100 | ) 101 | 102 | $output = foreach ($policy in $policies) { 103 | [PSCustomObject]@{ 104 | PolicyName = New-CAPolicyName @policy 105 | CategoryCode = $policy.CategoryCode 106 | Scope = $policy.Scope 107 | Action = $policy.Action 108 | Condition = $policy.Condition 109 | Clients = $policy.Clients 110 | Version = $policy.Version 111 | } 112 | } 113 | 114 | # Export to CSV 115 | $output | Export-Csv -Path $OutputPath -NoTypeInformation 116 | 117 | # Generate HTML report 118 | $HTMLPath = $OutputPath.Replace('.csv', '.html') 119 | 120 | $metadata = @{ 121 | GeneratedBy = $env:USERNAME 122 | GeneratedOn = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 123 | TotalPolicies = $output.Count 124 | Categories = ($output | Group-Object CategoryCode | ForEach-Object { "$($_.Name): $($_.Count)" }) -join ", " 125 | } 126 | 127 | New-HTML -Title "Conditional Access Policies" -FilePath $HTMLPath -ShowHTML { 128 | New-HTMLSection -HeaderText "Generation Summary" { 129 | New-HTMLPanel { 130 | New-HTMLText -Text @" 131 |

Report Details

132 | 138 | "@ 139 | } 140 | } 141 | 142 | New-HTMLSection -HeaderText "Conditional Access Policies" { 143 | New-HTMLTable -DataTable $output -ScrollX -Buttons @('copyHtml5', 'excelHtml5', 'csvHtml5') -SearchBuilder { 144 | New-TableCondition -Name 'Action' -ComparisonType string -Operator eq -Value 'BLOCK' -BackgroundColor Salmon -Color Black 145 | New-TableCondition -Name 'Action' -ComparisonType string -Operator eq -Value 'GRANT' -BackgroundColor LightGreen -Color Black 146 | New-TableCondition -Name 'Action' -ComparisonType string -Operator eq -Value 'SESSION' -BackgroundColor LightBlue -Color Black 147 | } 148 | } 149 | } 150 | 151 | # Display summary in console 152 | Write-Host "`nPolicy Summary:" -ForegroundColor Cyan 153 | $output | Group-Object CategoryCode | ForEach-Object { 154 | Write-Host "$($_.Name): $($_.Count) policies" 155 | } 156 | 157 | Write-Host "`nOutput files generated:" -ForegroundColor Green 158 | Write-Host "CSV: $OutputPath" 159 | Write-Host "HTML: $HTMLPath" 160 | } 161 | 162 | # Execute the function 163 | Export-CAPolicy -------------------------------------------------------------------------------- /ConditionalAccess/Delete-allConditionalAccessPolicies-v4.ps1: -------------------------------------------------------------------------------- 1 | # Connect to Microsoft Graph with the necessary permissions 2 | Connect-MgGraph -Scopes 'Policy.Read.All', 'Policy.ReadWrite.ConditionalAccess' 3 | 4 | # Confirm before proceeding as this will delete all Conditional Access policies 5 | $confirmation = Read-Host "Are you sure you want to delete ALL Conditional Access policies? (yes/no)" 6 | if ($confirmation -ne 'yes') { 7 | Write-Output "Operation aborted by the user." 8 | Disconnect-MgGraph 9 | exit 10 | } 11 | 12 | 13 | 14 | function Get-ConditionalAccessPoliciesViaMgGraph { 15 | $uri = "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" 16 | $allPolicies = @() 17 | 18 | do { 19 | $response = Invoke-MgGraphRequest -Uri $uri -Method GET -Headers @{"Prefer"="odata.maxpagesize=999"} 20 | $policies = $response.Value 21 | $allPolicies += $policies 22 | 23 | $uri = if ($response.'@odata.nextLink') { $response.'@odata.nextLink' } else { $null } 24 | } while ($uri) 25 | 26 | return $allPolicies 27 | } 28 | 29 | 30 | # $allPolicies = Get-ConditionalAccessPoliciesViaMgGraph 31 | $policies = Get-ConditionalAccessPoliciesViaMgGraph 32 | 33 | # Fetch all Conditional Access policies 34 | # $policies = Get-MgIdentityConditionalAccessPolicy 35 | 36 | # Iterate and attempt to delete each policy 37 | foreach ($policy in $policies) { 38 | $policyId = $policy.Id 39 | $policyName = $policy.DisplayName 40 | try { 41 | # Adjusted cmdlet call without the -Force parameter 42 | Remove-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policyId 43 | Write-Output "Successfully requested deletion of Conditional Access policy: $policyName ($policyId)" 44 | } catch { 45 | Write-Error "Failed to delete Conditional Access policy: $policyName ($policyId). Error: $_" 46 | } 47 | } 48 | 49 | 50 | # Disconnect from Microsoft Graph 51 | # Disconnect-MgGraph 52 | -------------------------------------------------------------------------------- /ConditionalAccess/Rename-ConditionalAccessPolicies-All.ps1: -------------------------------------------------------------------------------- 1 | # Define the directory containing the JSON files 2 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\Main" 3 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\PMM\GRANT" 4 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\SettingsCatalog" 5 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\DeviceConfiguration" 6 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\UpdatePolicies" 7 | # $jsonFilesDirectory = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\AdministrativeTemplates" 8 | 9 | # Get all JSON files in the directory 10 | $jsonFiles = Get-ChildItem -Path $jsonFilesDirectory -Filter "*.json" 11 | 12 | # Iterate over each JSON file 13 | foreach ($file in $jsonFiles) { 14 | # Read the content of the JSON file 15 | $jsonContent = Get-Content -Path $file.FullName | Out-String 16 | 17 | # Convert the JSON content to a PowerShell object 18 | $jsonObject = $jsonContent | ConvertFrom-Json 19 | 20 | # Extract the file name without the extension 21 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($file.Name) 22 | 23 | # Update the displayName property 24 | # $jsonObject.name = $fileNameWithoutExtension 25 | $jsonObject.displayName = $fileNameWithoutExtension 26 | 27 | # Convert the modified object back to JSON 28 | $updatedJsonContent = $jsonObject | ConvertTo-Json -Depth 100 29 | 30 | # Save the updated JSON back to the file, overwriting the original content 31 | $updatedJsonContent | Set-Content -Path $file.FullName 32 | } -------------------------------------------------------------------------------- /ConditionalAccess/Rename-ConditionalAccessPolicies.ps1: -------------------------------------------------------------------------------- 1 | # Define the path to your JSON file 2 | $jsonFilePath = "C:\Code\CaaC\Nova\Feb022024\AOllivierre-Sandbox\Entra-Intune-v2\MSFT\ConditionalAccess\Main\zzz-CA004 - GRANT - ADMINS - MFA - Global Admins with default Auth Strengths.json" 3 | 4 | # Read the content of the JSON file 5 | $jsonContent = Get-Content -Path $jsonFilePath | Out-String 6 | 7 | # Convert the JSON content to a PowerShell object 8 | $jsonObject = $jsonContent | ConvertFrom-Json 9 | 10 | # Extract the file name without the extension 11 | $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($jsonFilePath) 12 | 13 | # Update the displayName property 14 | $jsonObject.displayName = $fileNameWithoutExtension 15 | 16 | # Convert the modified object back to JSON 17 | $updatedJsonContent = $jsonObject | ConvertTo-Json -Depth 100 18 | 19 | # Save the updated JSON back to the file, overwriting the original content 20 | $updatedJsonContent | Set-Content -Path $jsonFilePath 21 | -------------------------------------------------------------------------------- /Module/ConditionalAccess.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | ModuleVersion = '1.0.0' 3 | GUID = New-Guid 4 | Author = 'Your Name' 5 | CompanyName = 'Your Company' 6 | Copyright = '(c) 2025. All rights reserved.' 7 | Description = 'Module for managing Conditional Access Policies with focus on Guest Access' 8 | PowerShellVersion = '5.1' 9 | RequiredModules = @( 10 | 'Microsoft.Graph.Identity.SignIns', 11 | 'PSWriteHTML' 12 | ) 13 | FunctionsToExport = @( 14 | 'Get-ConditionalAccessPoliciesDetails', 15 | 'Export-GuestPolicyReport', 16 | 'Update-ConditionalAccessPolicyGuestTypes' 17 | ) 18 | PrivateData = @{ 19 | PSData = @{ 20 | Tags = @('ConditionalAccess', 'Azure', 'Security', 'Guest') 21 | ProjectUri = '' 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Module/ConditionalAccess.psm1: -------------------------------------------------------------------------------- 1 | # Import all public functions 2 | Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue | 3 | ForEach-Object { . $_.FullName } 4 | 5 | # Import all private functions 6 | Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue | 7 | ForEach-Object { . $_.FullName } 8 | 9 | # Export public functions 10 | Export-ModuleMember -Function (Get-ChildItem -Path $PSScriptRoot\Public\*.ps1).BaseName 11 | -------------------------------------------------------------------------------- /Module/Example/15-Exclude-Include-Gues-Roles-CAPs copy 9.ps1: -------------------------------------------------------------------------------- 1 | Import-module 'C:\code\ConditionalAccess\Module\ConditionalAccess.psm1' 2 | 3 | Update-ConditionalAccessPolicyGuestTypes -------------------------------------------------------------------------------- /Module/Private/Get-GuestUserTypes.ps1: -------------------------------------------------------------------------------- 1 | function Get-GuestUserTypes { 2 | [CmdletBinding()] 3 | param() 4 | 5 | @( 6 | [PSCustomObject]@{ 7 | DisplayName = "Internal guest users" 8 | Id = "internalGuest" 9 | Description = "Guest users within your organization" 10 | Category = "Internal" 11 | }, 12 | [PSCustomObject]@{ 13 | DisplayName = "B2B collaboration guest users" 14 | Id = "b2bCollaborationGuest" 15 | Description = "Users invited to collaborate with your organization" 16 | Category = "B2B" 17 | }, 18 | [PSCustomObject]@{ 19 | DisplayName = "B2B collaboration member users" 20 | Id = "b2bCollaborationMember" 21 | Description = "Members from other organizations" 22 | Category = "B2B" 23 | }, 24 | [PSCustomObject]@{ 25 | DisplayName = "B2B direct connect users" 26 | Id = "b2bDirectConnectUser" 27 | Description = "Users connecting directly from partner organizations" 28 | Category = "B2B" 29 | }, 30 | [PSCustomObject]@{ 31 | DisplayName = "Other external users" 32 | Id = "otherExternalUser" 33 | Description = "All other types of external users" 34 | Category = "External" 35 | }, 36 | [PSCustomObject]@{ 37 | DisplayName = "Service provider users" 38 | Id = "serviceProvider" 39 | Description = "Users from service provider organizations" 40 | Category = "External" 41 | } 42 | ) | Sort-Object Category, DisplayName 43 | } -------------------------------------------------------------------------------- /Module/Private/Show-GuestOperationMenu.ps1: -------------------------------------------------------------------------------- 1 | function Show-GuestOperationMenu { 2 | [CmdletBinding()] 3 | param() 4 | 5 | $menuText = @" 6 | 7 | ====== Conditional Access Policy Guest Operation ====== 8 | 9 | Select an operation: 10 | [I] Include Selected Guest Types 11 | [E] Exclude Selected Guest Types 12 | [C] Cancel Operation 13 | 14 | Enter your choice [I/E/C]: 15 | "@ 16 | 17 | do { 18 | $choice = Read-Host -Prompt $menuText 19 | switch ($choice.ToUpper()) { 20 | 'I' { return 'Include' } 21 | 'E' { return 'Exclude' } 22 | 'C' { return 'Cancel' } 23 | default { 24 | Write-Host "Invalid selection. Please try again." -ForegroundColor Yellow 25 | } 26 | } 27 | } while ($true) 28 | } 29 | -------------------------------------------------------------------------------- /Module/Public/Export-GuestPolicyReport.ps1: -------------------------------------------------------------------------------- 1 | function Export-GuestPolicyReport { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter(Mandatory)] 5 | [object[]]$Results, 6 | 7 | [Parameter(Mandatory)] 8 | [string]$OutputDir, 9 | 10 | [Parameter()] 11 | [string]$ReportName = "GuestPolicy_Update" 12 | ) 13 | 14 | $reportParams = @{ 15 | OutputDir = $OutputDir 16 | ReportName = $ReportName 17 | Results = $Results 18 | Timestamp = Get-Date -Format "yyyyMMdd_HHmmss" 19 | } 20 | 21 | $reportPaths = @{ 22 | HTML = Join-Path $OutputDir "$($ReportName)_$($reportParams.Timestamp).html" 23 | CSV = Join-Path $OutputDir "$($ReportName)_$($reportParams.Timestamp).csv" 24 | } 25 | 26 | # Ensure output directory exists 27 | $null = New-Item -ItemType Directory -Force -Path $OutputDir 28 | 29 | # Export to CSV 30 | $Results | Export-Csv -Path $reportPaths.CSV -NoTypeInformation 31 | 32 | # Generate HTML report 33 | New-HTML -TitleText "Guest Policy Update Report" -FilePath $reportPaths.HTML -ShowHTML { 34 | New-HTMLSection -HeaderText "Policy Update Summary" { 35 | New-HTMLPanel { 36 | New-HTMLText -Text @" 37 |

Update Details

38 | 45 | "@ 46 | } 47 | } 48 | 49 | New-HTMLSection -HeaderText "Updated Policies" { 50 | New-HTMLTable -DataTable $Results -ScrollX { 51 | New-TableCondition -Name 'Status' -ComparisonType string -Operator eq -Value 'Success' -BackgroundColor LightGreen -Color Black 52 | New-TableCondition -Name 'Status' -ComparisonType string -Operator eq -Value 'Failed' -BackgroundColor Salmon -Color Black 53 | } -Buttons @('copyHtml5', 'excelHtml5', 'csvHtml5', 'searchBuilder') 54 | } 55 | } 56 | 57 | Write-Host "`nReports generated:" -ForegroundColor Green 58 | Write-Host "CSV Report: $($reportPaths.CSV)" -ForegroundColor Green 59 | Write-Host "HTML Report: $($reportPaths.HTML)" -ForegroundColor Green 60 | 61 | return $reportPaths 62 | } -------------------------------------------------------------------------------- /Module/Public/Get-ConditionalAccessPoliciesDetails.ps1: -------------------------------------------------------------------------------- 1 | function Get-ConditionalAccessPoliciesDetails { 2 | [CmdletBinding()] 3 | param( 4 | [Parameter()] 5 | [ValidateSet('All', 'Guest', 'AdminRoles')] 6 | [string]$PolicyType = 'All' 7 | ) 8 | 9 | try { 10 | Write-Verbose "Retrieving policies from Microsoft Graph..." 11 | $policies = Get-MgIdentityConditionalAccessPolicy -All 12 | 13 | if (-not $policies) { 14 | Write-Warning "No policies retrieved from Microsoft Graph" 15 | return @() 16 | } 17 | 18 | Write-Verbose "Processing $($policies.Count) policies..." 19 | $formattedPolicies = @(foreach ($policy in $policies) { 20 | Write-Verbose "Processing policy: $($policy.DisplayName)" 21 | 22 | # Extract current version from display name 23 | $version = if ($policy.DisplayName -match '-v(\d+\.\d+)$') { 24 | [decimal]$matches[1] 25 | } else { 26 | 1.0 27 | } 28 | 29 | # Build the admin roles status 30 | $adminRolesStatus = [System.Collections.ArrayList]::new() 31 | if ($PolicyType -in @('All', 'AdminRoles')) { 32 | if ($policy.Conditions.Users.IncludeRoles.Count -gt 0) { 33 | $null = $adminRolesStatus.Add("Include: $($policy.Conditions.Users.IncludeRoles.Count) roles") 34 | } 35 | 36 | if ($policy.Conditions.Users.ExcludeRoles.Count -gt 0) { 37 | $null = $adminRolesStatus.Add("Exclude: $($policy.Conditions.Users.ExcludeRoles.Count) roles") 38 | } 39 | } 40 | 41 | # Build the guest status 42 | $guestStatus = [System.Collections.ArrayList]::new() 43 | if ($PolicyType -in @('All', 'Guest')) { 44 | if ($policy.Conditions.Users.IncludeGuestsOrExternalUsers) { 45 | $null = $guestStatus.Add("Include: Guest/External Users") 46 | } 47 | 48 | if ($policy.Conditions.Users.ExcludeGuestsOrExternalUsers) { 49 | $null = $guestStatus.Add("Exclude: Guest/External Users") 50 | } 51 | } 52 | 53 | # Format status strings 54 | $currentAdminRoles = if ($adminRolesStatus.Count -gt 0) { 55 | $adminRolesStatus -join ' | ' 56 | } else { 57 | "No admin roles configured" 58 | } 59 | 60 | $currentGuestStatus = if ($guestStatus.Count -gt 0) { 61 | $guestStatus -join ' | ' 62 | } else { 63 | "No guest configuration" 64 | } 65 | 66 | # Create output object based on PolicyType 67 | $outputObject = [ordered]@{ 68 | DisplayName = $policy.DisplayName 69 | Id = $policy.Id 70 | State = $policy.State 71 | Version = $version 72 | } 73 | 74 | # Add type-specific properties based on PolicyType 75 | switch ($PolicyType) { 76 | 'All' { 77 | $outputObject['CurrentAdminRoles'] = $currentAdminRoles 78 | $outputObject['CurrentGuestStatus'] = $currentGuestStatus 79 | } 80 | 'Guest' { 81 | $outputObject['CurrentGuestStatus'] = $currentGuestStatus 82 | } 83 | 'AdminRoles' { 84 | $outputObject['CurrentAdminRoles'] = $currentAdminRoles 85 | } 86 | } 87 | 88 | [PSCustomObject]$outputObject 89 | }) 90 | 91 | Write-Verbose "Returning $($formattedPolicies.Count) formatted policies" 92 | return $formattedPolicies 93 | } 94 | catch { 95 | Write-Error "Failed to retrieve or process Conditional Access Policies: $_" 96 | return @() 97 | } 98 | } 99 | 100 | 101 | 102 | # # Get all policy details 103 | # Get-ConditionalAccessPoliciesDetails -PolicyType All 104 | 105 | # # Get only guest-related details 106 | # Get-ConditionalAccessPoliciesDetails -PolicyType Guest 107 | 108 | # # Get only admin role details 109 | # Get-ConditionalAccessPoliciesDetails -PolicyType AdminRoles 110 | 111 | # # With verbose output 112 | # Get-ConditionalAccessPoliciesDetails -PolicyType All -Verbose -------------------------------------------------------------------------------- /Module/Public/Update-ConditionalAccessPolicyGuestTypes.ps1: -------------------------------------------------------------------------------- 1 | 2 | function Update-ConditionalAccessPolicyGuestTypes { 3 | [CmdletBinding()] 4 | param( 5 | [Parameter()] 6 | [string]$OutputPath = ".\Reports" 7 | ) 8 | 9 | try { 10 | # Show welcome message 11 | Write-Host "`nConditional Access Policy Guest Types Update Tool" -ForegroundColor Cyan 12 | Write-Host "=================================================" -ForegroundColor Cyan 13 | 14 | # Get operation type 15 | $operation = Show-GuestOperationMenu 16 | if ($operation -eq 'Cancel') { 17 | Write-Host "`nOperation cancelled by user." -ForegroundColor Yellow 18 | return 19 | } 20 | 21 | Write-Host "`nSelected Operation: $operation" -ForegroundColor Green 22 | 23 | # Get current policies 24 | Write-Host "`nRetrieving current policy information..." -ForegroundColor Cyan 25 | $policies = Get-ConditionalAccessPoliciesDetails 26 | 27 | if (-not $policies) { 28 | Write-Warning "No policies found to process." 29 | return 30 | } 31 | 32 | # Select policies to update 33 | Write-Host "`nSelect policies to update..." -ForegroundColor Cyan 34 | $selectedPolicies = $policies | 35 | Out-GridView -Title "Select Conditional Access Policies to Modify" -PassThru 36 | 37 | if (-not $selectedPolicies) { 38 | Write-Warning "No policies selected for processing." 39 | return 40 | } 41 | 42 | # Select guest types 43 | Write-Host "`nSelect guest types to $($operation.ToLower())..." -ForegroundColor Cyan 44 | $guestTypes = Get-GuestUserTypes 45 | 46 | $selectedGuestTypes = $guestTypes | 47 | Out-GridView -Title "Select Guest Types to $operation" -PassThru 48 | 49 | if (-not $selectedGuestTypes) { 50 | Write-Warning "No guest types selected. Operation cancelled." 51 | return 52 | } 53 | 54 | # Enhanced operation summary 55 | Write-Host "`nOperation Summary:" -ForegroundColor Cyan 56 | Write-Host "==================" -ForegroundColor Cyan 57 | Write-Host "Operation: $operation guest/external users" -ForegroundColor White 58 | Write-Host "`nSelected Policies:" -ForegroundColor White 59 | $selectedPolicies | ForEach-Object { Write-Host "- $($_.DisplayName)" -ForegroundColor Gray } 60 | Write-Host "`nSelected Guest Types:" -ForegroundColor White 61 | $selectedGuestTypes | ForEach-Object { Write-Host "- $($_.DisplayName)" -ForegroundColor Gray } 62 | 63 | $confirm = Read-Host "`nDo you want to proceed? [Y/N]" 64 | if ($confirm -notmatch '^[Yy]$') { 65 | Write-Host "`nOperation cancelled by user." -ForegroundColor Yellow 66 | return 67 | } 68 | 69 | $results = [System.Collections.ArrayList]::new() 70 | 71 | foreach ($policy in $selectedPolicies) { 72 | try { 73 | Write-Host "`nProcessing policy: $($policy.DisplayName)" -ForegroundColor Cyan 74 | 75 | # Create update body 76 | $bodyParams = @{ 77 | conditions = @{ 78 | users = @{ 79 | "$($operation.ToLower())GuestsOrExternalUsers" = @{ 80 | guestOrExternalUserTypes = $selectedGuestTypes.Id -join ',' 81 | externalTenants = @{ 82 | membershipKind = "all" 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | # Update policy 90 | $null = Update-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.Id -BodyParameter $bodyParams 91 | 92 | $null = $results.Add([PSCustomObject]@{ 93 | PolicyName = $policy.DisplayName 94 | PolicyId = $policy.Id 95 | Operation = $operation 96 | GuestTypesUpdated = $selectedGuestTypes.DisplayName -join ', ' 97 | Status = 'Success' 98 | ErrorMessage = '' 99 | }) 100 | 101 | Write-Host "Successfully updated policy: $($policy.DisplayName)" -ForegroundColor Green 102 | } 103 | catch { 104 | $errorMessage = $_.Exception.Message 105 | 106 | $null = $results.Add([PSCustomObject]@{ 107 | PolicyName = $policy.DisplayName 108 | PolicyId = $policy.Id 109 | Operation = $operation 110 | GuestTypesUpdated = '' 111 | Status = 'Failed' 112 | ErrorMessage = $errorMessage 113 | }) 114 | 115 | Write-Warning "Failed to update policy $($policy.DisplayName): $errorMessage" 116 | } 117 | } 118 | 119 | if ($results.Count -gt 0) { 120 | Export-GuestPolicyReport -Results $results -OutputDir $OutputPath 121 | } 122 | 123 | return $results 124 | } 125 | catch { 126 | Write-Error "Operation failed: $_" 127 | } 128 | } -------------------------------------------------------------------------------- /Module/en-US/about_ConditionalAccess.help.txt: -------------------------------------------------------------------------------- 1 | TOPIC 2 | about_ConditionalAccess 3 | 4 | SHORT DESCRIPTION 5 | A PowerShell module for managing Azure AD Conditional Access Policies with focus on Guest Access. 6 | 7 | LONG DESCRIPTION 8 | The ConditionalAccess module provides cmdlets for managing and updating Azure AD Conditional Access 9 | Policies, specifically focusing on guest access configurations. It allows you to: 10 | 11 | - Retrieve details about existing Conditional Access policies 12 | - Update guest access configurations (Include/Exclude) 13 | - Generate detailed reports of policy changes 14 | - Manage different guest user types 15 | 16 | COMMANDS 17 | Get-ConditionalAccessPoliciesDetails 18 | Retrieves and formats details about existing Conditional Access policies 19 | 20 | Export-GuestPolicyReport 21 | Generates HTML and CSV reports for policy updates 22 | 23 | Update-ConditionalAccessPolicyGuestTypes 24 | Updates guest configurations in Conditional Access policies 25 | 26 | EXAMPLES 27 | Get policy details: 28 | Get-ConditionalAccessPoliciesDetails 29 | 30 | Update guest configurations: 31 | Update-ConditionalAccessPolicyGuestTypes -OutputPath "C:\Reports" 32 | 33 | KEYWORDS 34 | - ConditionalAccess 35 | - Azure 36 | - Security 37 | - Guest Access 38 | - Policies 39 | 40 | SEE ALSO 41 | Online version: [Your documentation URL] 42 | Microsoft Graph documentation: https://docs.microsoft.com/graph/api/resources/conditionalaccesspolicy 43 | -------------------------------------------------------------------------------- /Modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "requiredModules": [ 3 | "Microsoft.Graph.Authentication", 4 | "Microsoft.Graph.Applications", 5 | "Microsoft.Graph.Identity.DirectoryManagement", 6 | "Microsoft.Graph.Users", 7 | "Microsoft.Graph.Beta.Identity.SignIns" 8 | ], 9 | "importedModules": [ 10 | "Microsoft.Graph.Identity.DirectoryManagement", 11 | "Microsoft.Graph.Authentication", 12 | "Microsoft.Graph.Identity.DirectoryManagement", 13 | "Microsoft.Graph.Applications", 14 | "Microsoft.Graph.Users", 15 | "Microsoft.Graph.Beta.Identity.SignIns" 16 | ] 17 | } 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Modern Conditional Access Baseline 2025 2 | 3 | This repository contains a comprehensive set of Conditional Access (CA) policies and PowerShell management tools for Microsoft Entra ID (formerly Azure AD), designed to enhance your organization's security posture while maintaining usability. 4 | 5 | ## 🙏 Acknowledgments 6 | 7 | This project builds upon the excellent work of: 8 | - Kenneth van Surksum ([@kennethvs](https://github.com/kennethvs)) - Original CA baseline policies 9 | - Daniel Chronlund ([@DanielChronlund](https://github.com/DanielChronlund)) - DC Toolbox CA implementations 10 | 11 | ## 📋 Prerequisites 12 | 13 | Before implementing these baselines, ensure: 14 | 15 | 1. Security Defaults are disabled in your tenant 16 | 2. Legacy Per-User MFA is disabled for all users (except unlicensed accounts if necessary) 17 | 3. Required licenses are available for your users 18 | 4. Basic familiarity with Conditional Access concepts 19 | 20 | ## 🏗️ Implementation Components 21 | 22 | ### Required Infrastructure 23 | - 42 Entra ID Groups for inclusion/exclusion management 24 | - 44 Conditional Access policies 25 | - Supporting Intune MAM/APP policies 26 | 27 | ### Policy Modes 28 | - Most policies are deployed in "Report-only" mode for impact assessment 29 | - Compliance-check policies are set to "Off" mode initially to prevent unexpected authentication prompts 30 | 31 | ## 🛠️ Recommended Tools 32 | 33 | ### Policy Deployment 34 | - [Intune Management Tool](https://github.com/Micke-K/IntuneManagement) - For importing and managing policies 35 | 36 | ### Policy Visualization 37 | - [IdPowerToys](https://idpowertoys.merill.net/) - For visualizing and understanding policy interactions 38 | 39 | ## 📝 Best Practices 40 | 41 | 1. **Group-Based Assignment** 42 | - Always use groups for inclusions/exclusions instead of direct user assignments 43 | - Enables easier management and automated import via Intune Management Tool 44 | 45 | 2. **Staged Rollout** 46 | - Start with policies in report-only mode 47 | - Use provided PowerShell tools to analyze sign-in logs 48 | - Assess impact before enabling enforcement 49 | 50 | 3. **Policy Management** 51 | - Maintain documentation of policy exceptions 52 | - Regular review of policy effectiveness 53 | - Monitor for policy conflicts 54 | 55 | ## 🚀 Implementation Guide 56 | 57 | 1. Clone this repository 58 | 2. Create required Entra ID groups 59 | 3. Import baseline policies using Intune Management Tool 60 | 4. Review and customize policies for your environment 61 | 5. Use provided PowerShell tools to monitor impact 62 | 6. Gradually enable enforcement based on analysis 63 | 64 | ## 📊 Included Tools 65 | 66 | This repository includes PowerShell scripts for: 67 | - Managing user/group assignments 68 | - Analyzing sign-in logs for report-only policies 69 | - Impact assessment reporting 70 | - Policy compliance monitoring 71 | 72 | ## 🔜 Future Plans 73 | 74 | - Enhanced PowerShell tools for sign-in log analysis 75 | - Automated impact assessment reporting 76 | - Additional compliance templates 77 | - Integration with Microsoft Graph API 78 | - Additional baseline policies for specific scenarios 79 | 80 | ## 📚 Documentation 81 | 82 | Detailed documentation for each component is available in the respective folders: 83 | - `/policies` - Baseline CA policies 84 | - `/scripts` - PowerShell management tools 85 | - `/docs` - Implementation guides and best practices 86 | 87 | ## 🤝 Contributing 88 | 89 | Contributions are welcome! Please read our contributing guidelines before submitting pull requests. 90 | 91 | ## 📄 License 92 | 93 | This project is licensed under the MIT License - see the LICENSE file for details. 94 | 95 | ## 💬 Support 96 | 97 | For issues and feature requests, please use the GitHub issues section. -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "PackageName": "BuildEntraAppRegCertBasedwithGraph", 3 | "PackageUniqueGUID": "7b34084e-b856-40f5-9a5b-32b3249fb777", 4 | "Version": 1, 5 | "PackageExecutionContext": "SYSTEM", 6 | "RepetitionInterval": "PT60M", 7 | "LoggingDeploymentName": "BuildEntraAppRegCertBasedwithGraphCustomlog", 8 | "ScriptMode": "Remediation", 9 | "RunOnDemand": true 10 | } -------------------------------------------------------------------------------- /modulesexclusion.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ] 4 | -------------------------------------------------------------------------------- /scopes.json: -------------------------------------------------------------------------------- 1 | { 2 | "Scopes": [ 3 | "User.Read", 4 | "User.ReadWrite", 5 | "User.ReadBasic.All", 6 | "Mail.Read", 7 | "Mail.ReadWrite", 8 | "Mail.Send", 9 | "Calendars.Read", 10 | "Calendars.ReadWrite", 11 | "Contacts.Read", 12 | "Contacts.ReadWrite", 13 | "Files.Read", 14 | "Files.ReadWrite", 15 | "Sites.Read.All", 16 | "Sites.ReadWrite.All", 17 | "Group.Read.All", 18 | "Group.ReadWrite.All", 19 | "Directory.Read.All", 20 | "Directory.ReadWrite.All", 21 | "Application.Read.All", 22 | "Application.ReadWrite.All", 23 | "Device.Read", 24 | "DeviceManagementApps.Read.All", 25 | "DeviceManagementApps.ReadWrite.All", 26 | "DeviceManagementConfiguration.Read.All", 27 | "DeviceManagementConfiguration.ReadWrite.All", 28 | "Organization.Read.All", 29 | "Organization.ReadWrite.All", 30 | "Policy.Read.All", 31 | "Policy.ReadWrite.ConditionalAccess", 32 | "DeviceManagementApps.ReadWrite.All", 33 | "AppRoleAssignment.ReadWrite.All" 34 | ] 35 | } 36 | --------------------------------------------------------------------------------