An automated PowerShell script for Entra ID that creates enterprise-grade Conditional Access policies to provide significantly improved security over Microsoft's basic "Security Defaults".
Who is this for? Organizations that are currently using Security Defaults or have only basic Conditional Access policies in place and want to quickly level up their security posture.
Important Note: While these policies provide strong baseline security, they are not bulletproof. Conditional Access policies should always be tailored to your organization's specific needs, risk tolerance, and operational requirements.
For additional Microsoft 365 security improvements, check out Easy Wins Email Defense.
- AZ-BetterSecDefaults.ps1 - Main script that creates all policies
- AZ-BetterSecDefaults-Checker.ps1 - Optional validation script to check for risky sign-ins
Before running this script, ensure you have:
- β Entra ID Premium P2 License (script will check and exit if not found)
- β Security Defaults DISABLED (script will automatically disable if enabled)
- β Microsoft Graph PowerShell Module installed
- β Global Administrator credentials for your tenant
- β Your WAN IP address in CIDR format (e.g., 203.0.113.0/24)
This script automatically creates 7 Conditional Access policies. All policies and named locations are checked for existence before creation to prevent duplicates.
Prompts you for trusted location IP in CIDR format. Creates policy that requires MFA or hybrid join for any login coming from any network NOT in the "trusted" named location.
Best Practice: This satisfies the best practice of enforcing multi-factor authentication for all users while providing a practical exception for corporate networks with compliant devices.
Blocks logins to all apps from outside of the United States. Excludes global admin role.
Best Practice: This helps organizations satisfy compliance requirements for data sovereignty and geographic access restrictions, reducing the attack surface by limiting access to expected geographic regions.
Blocks all logins from MacOS devices. Excludes global admin role.
Best Practice: This enforces platform standardization best practices and helps organizations maintain a Windows-only environment for security, compliance, and management consistency.
Blocks all logins from Linux devices. Excludes global admin role.
Best Practice: This supports endpoint security best practices by preventing authentication from potentially unmanaged or non-compliant Linux systems that may not meet organizational security standards.
Blocks legacy authentication protocols (Exchange ActiveSync and other legacy clients) unless originating from a trusted location.
Best Practice: This satisfies the critical best practice of eliminating legacy authentication methods that bypass modern security controls like MFA and are frequently exploited in attacks.
Downloads and processes IP lists for known VPN providers (10,000+ IPs) and Tor exit nodes, creating named locations and blocking authentication attempts from these sources. Excludes global admin role.
Best Practice: This addresses the best practice of blocking anonymization services that are commonly used by threat actors to mask their true origin and evade geographic restrictions.
Technical Details: This policy automatically downloads current threat intelligence feeds from:
- X4BNet VPN IP List - 10,000+ known VPN provider IPs
- SecOps-Institute Tor Exit Nodes - Current Tor exit node IPs
The script intelligently chunks these IPs into multiple named locations (800 IPs per location) to work within Azure's limits.
Creates sign-in risk policy that blocks medium and high-risk sign-in attempts identified by Azure AD Identity Protection. Excludes global admin role.
Best Practice: This implements the best practice of risk-based conditional access, leveraging Microsoft's threat intelligence to automatically block suspicious authentication attempts in real-time.
- Download AZ-BetterSecDefaults.ps1
- Open PowerShell as Administrator
- Run the script:
.\AZ-BetterSecDefaults.ps1
The script will prompt you for:
- Azure Tenant ID - Your organization's Entra ID tenant identifier
- Authentication - You'll authenticate with Global Administrator credentials
- Trusted Location IP - Your corporate WAN IP address in CIDR format (e.g.,
203.0.113.0/24)
The script will then:
- β Verify your Entra ID P2 license
- β Disable Security Defaults if enabled
- β Create the "Trusted" named location with your IP
- β Download threat intelligence IP lists
- β Create all 7 Conditional Access policies
- β Display a summary of created/existing policies
The AZ-BetterSecDefaults-Checker.ps1 script validates your environment by checking for risky sign-in activity that your new policies will prevent.
It searches the last 14 days of sign-in logs for:
- β Successful logins from outside the USA
- β Successful logins from MacOS devices
- β Successful logins from Linux devices
- β Successful logins using legacy authentication
Run this before implementing the policies to:
- Identify legitimate use cases you may need to accommodate
- Validate which policies are most relevant for your environment
- Gather data to justify the policy implementation to stakeholders
- Ensure you won't inadvertently block legitimate users
.\AZ-BetterSecDefaults-Checker.ps1- Test in Report-Only Mode - Consider manually setting policies to "Report-Only" initially to monitor impact
- Review Exclusions - Global Administrators are excluded from most policies - consider if this is appropriate for your org
- Geographic Restrictions - The USA-only policy may not be suitable for global organizations
- Platform Restrictions - Ensure MacOS/Linux blocks align with your environment
- Legacy Auth - Verify no critical applications rely on legacy authentication before blocking
- Monitor Sign-In Logs - Watch for blocked users who may need exceptions
- Create Break-Glass Accounts - Ensure emergency access accounts exist and are properly excluded
- Document Exceptions - Maintain a record of any policy exceptions created
- Regular Reviews - Periodically review policies to ensure they remain aligned with your needs
"NamedLocation with id does not exist"
- Ensure you're running the latest version of the script
- Named locations may take a few moments to propagate in Azure AD
Policies already exist
- The script safely skips existing policies - this is expected behavior if re-running
VPN/TOR IP list download fails
- Check your internet connectivity
- Verify you can access GitHub from your network
- The script requires outbound HTTPS access
Contributions are welcome! Please feel free to submit issues or pull requests.
- VPN IP List: X4BNet/lists_vpn
- Tor Exit Nodes: SecOps-Institute/Tor-IP-Addresses
This project is provided as-is for educational and security improvement purposes. Use at your own risk and always test in a non-production environment first.
Created by @biffalo
Questions or suggestions? Open an issue or reach out via GitHub!


