diff --git a/.codex/skills-index.json b/.codex/skills-index.json index 38de572..c0b36d3 100644 --- a/.codex/skills-index.json +++ b/.codex/skills-index.json @@ -33,7 +33,7 @@ "name": "ms365-tenant-manager", "source": "../../engineering-team/ms365-tenant-manager", "category": "engineering", - "description": "Comprehensive Microsoft 365 tenant administration skill for setup, configuration, user management, security policies, and organizational structure optimization for Global Administrators" + "description": "Microsoft 365 tenant administration for Global Administrators. Automate M365 tenant setup, Office 365 admin tasks, Azure AD user management, Exchange Online configuration, Teams administration, and security policies. Generate PowerShell scripts for bulk operations, Conditional Access policies, license management, and compliance reporting. Use for M365 tenant manager, Office 365 admin, Azure AD users, Global Administrator, tenant configuration, or Microsoft 365 automation." }, { "name": "senior-architect", diff --git a/engineering-team/ms365-tenant-manager/HOW_TO_USE.md b/engineering-team/ms365-tenant-manager/HOW_TO_USE.md deleted file mode 100644 index 1cc50c4..0000000 --- a/engineering-team/ms365-tenant-manager/HOW_TO_USE.md +++ /dev/null @@ -1,233 +0,0 @@ -# How to Use This Skill - -Hey Claude—I just added the "ms365-tenant-manager" skill. Can you help me set up my Microsoft 365 tenant? - -## Example Invocations - -**Example 1: Initial Tenant Setup** -``` -Hey Claude—I just added the "ms365-tenant-manager" skill. Can you create a complete setup guide for a new Microsoft 365 tenant for a 50-person company with security best practices? -``` - -**Example 2: User Provisioning** -``` -Hey Claude—I just added the "ms365-tenant-manager" skill. Can you generate a PowerShell script to create 20 new users from a CSV file and assign appropriate licenses? -``` - -**Example 3: Security Audit** -``` -Hey Claude—I just added the "ms365-tenant-manager" skill. Can you create a security audit script to check MFA status, admin accounts, and inactive users? -``` - -**Example 4: Conditional Access Policy** -``` -Hey Claude—I just added the "ms365-tenant-manager" skill. Can you help me create a Conditional Access policy requiring MFA for all admin accounts? -``` - -**Example 5: User Offboarding** -``` -Hey Claude—I just added the "ms365-tenant-manager" skill. Can you generate a secure offboarding script for user john.doe@company.com that converts their mailbox and removes access? -``` - -**Example 6: License Management** -``` -Hey Claude—I just added the "ms365-tenant-manager" skill. Can you analyze my current license usage and recommend cost optimizations for 100 users? -``` - -**Example 7: DNS Configuration** -``` -Hey Claude—I just added the "ms365-tenant-manager" skill. Can you provide all the DNS records I need to configure for my custom domain acme.com? -``` - -## What to Provide - -Depending on your task, provide: - -### For Tenant Setup: -- Company name and domain -- Number of users -- Industry/compliance requirements (GDPR, HIPAA, etc.) -- Preferred license types - -### For User Management: -- User details (name, email, department, role) -- License requirements -- Group memberships needed -- CSV file (for bulk operations) - -### For Security Tasks: -- Policy requirements (MFA, Conditional Access) -- User/group scope -- Compliance standards to follow - -### For Reporting: -- Report type needed (license usage, security audit, user activity) -- Time period for analysis -- Specific metrics of interest - -## What You'll Get - -Based on your request, you'll receive: - -### Configuration Guides: -- Step-by-step instructions for Admin Center tasks -- Detailed checklists with time estimates -- Screenshots references and navigation paths -- Best practices and security recommendations - -### PowerShell Scripts: -- Ready-to-use automation scripts -- Complete error handling and validation -- Logging and audit trail capabilities -- Dry-run modes for safe testing -- Clear comments and documentation - -### Reports: -- Security posture assessments -- License utilization analysis -- User activity summaries -- Compliance status reports -- CSV exports for further analysis - -### Documentation: -- Configuration change documentation -- Rollback procedures -- Validation checklists -- Troubleshooting guides - -## Common Use Cases - -### 1. New Tenant Setup -**Ask for:** "Complete tenant setup guide for [company size] with [compliance requirements]" - -**You'll get:** -- Phase-by-phase implementation plan -- DNS records configuration -- Security baseline setup -- Service provisioning steps -- PowerShell automation scripts - -### 2. Bulk User Provisioning -**Ask for:** "Script to create [number] users with [license type] from CSV" - -**You'll get:** -- User creation PowerShell script -- License assignment automation -- Group membership configuration -- Validation and error handling -- Results reporting - -### 3. Security Hardening -**Ask for:** "Security audit and hardening recommendations" - -**You'll get:** -- Comprehensive security audit script -- MFA status check -- Admin role review -- Conditional Access policy templates -- Remediation recommendations - -### 4. License Optimization -**Ask for:** "License cost analysis and optimization for [user count]" - -**You'll get:** -- Current license usage breakdown -- Cost optimization recommendations -- Right-sizing suggestions -- Alternative license combinations -- Projected cost savings - -### 5. User Lifecycle Management -**Ask for:** "Onboarding/offboarding process for [role/department]" - -**You'll get:** -- Automated provisioning scripts -- Secure deprovisioning procedures -- Checklist for manual tasks -- Audit trail documentation - -## Prerequisites - -To use the generated PowerShell scripts, ensure you have: - -### Required PowerShell Modules: -```powershell -Install-Module Microsoft.Graph -Scope CurrentUser -Install-Module ExchangeOnlineManagement -Scope CurrentUser -Install-Module MicrosoftTeams -Scope CurrentUser -Install-Module SharePointPnPPowerShellOnline -Scope CurrentUser -``` - -### Required Permissions: -- **Global Administrator** (for full tenant setup) -- **User Administrator** (for user management) -- **Security Administrator** (for security policies) -- **Exchange Administrator** (for mailbox management) - -### System Requirements: -- PowerShell 7.0 or later (recommended) -- Windows PowerShell 5.1 (minimum) -- Internet connection for Microsoft 365 services - -## Safety & Best Practices - -### Before Running Scripts: -1. **Test in non-production first** (if available) -2. **Review scripts thoroughly** - understand what they do -3. **Use -WhatIf parameter** when available for dry-runs -4. **Backup critical data** before making changes -5. **Document changes** for audit trail - -### Security Considerations: -- Never hardcode credentials in scripts -- Use Azure Key Vault for credential management -- Enable logging for all operations -- Review audit logs regularly -- Follow principle of least privilege - -### Compliance: -- Verify scripts meet your compliance requirements -- Document all configuration changes -- Retain audit logs per compliance policies -- Test disaster recovery procedures - -## Troubleshooting - -### Common Issues: - -**"Access Denied" errors:** -- Verify you have appropriate admin role -- Check Conditional Access policies aren't blocking -- Ensure MFA is completed if required - -**PowerShell module errors:** -- Update modules to latest version: `Update-Module -Name Microsoft.Graph` -- Clear PowerShell cache if issues persist -- Reconnect to services - -**License assignment failures:** -- Verify license availability -- Check user's UsageLocation is set -- Ensure no conflicting licenses - -**DNS propagation delays:** -- DNS changes can take 24-48 hours to propagate -- Use `nslookup` to verify record updates -- Test from multiple locations - -## Additional Resources - -- Microsoft 365 Admin Center: https://admin.microsoft.com -- Azure AD Portal: https://aad.portal.azure.com -- Microsoft Graph Explorer: https://developer.microsoft.com/graph/graph-explorer -- PowerShell Gallery: https://www.powershellgallery.com -- Microsoft 365 Roadmap: https://www.microsoft.com/microsoft-365/roadmap - -## Tips for Best Results - -1. **Be specific** about your requirements (user count, compliance needs, industry) -2. **Mention constraints** (budget, timeline, technical limitations) -3. **Specify output format** (step-by-step guide vs. PowerShell script) -4. **Ask for explanations** if you need to understand WHY something is configured -5. **Request alternatives** if you need options to choose from -6. **Clarify urgency** so appropriate testing recommendations are included diff --git a/engineering-team/ms365-tenant-manager/SKILL.md b/engineering-team/ms365-tenant-manager/SKILL.md index 2795e11..e0c51d4 100644 --- a/engineering-team/ms365-tenant-manager/SKILL.md +++ b/engineering-team/ms365-tenant-manager/SKILL.md @@ -1,196 +1,295 @@ --- name: ms365-tenant-manager -description: Comprehensive Microsoft 365 tenant administration skill for setup, configuration, user management, security policies, and organizational structure optimization for Global Administrators +description: Microsoft 365 tenant administration for Global Administrators. Automate M365 tenant setup, Office 365 admin tasks, Azure AD user management, Exchange Online configuration, Teams administration, and security policies. Generate PowerShell scripts for bulk operations, Conditional Access policies, license management, and compliance reporting. Use for M365 tenant manager, Office 365 admin, Azure AD users, Global Administrator, tenant configuration, or Microsoft 365 automation. --- # Microsoft 365 Tenant Manager -This skill provides expert guidance and automation for Microsoft 365 Global Administrators managing tenant setup, configuration, user lifecycle, security policies, and organizational optimization. +Expert guidance and automation for Microsoft 365 Global Administrators managing tenant setup, user lifecycle, security policies, and organizational optimization. -## Capabilities +--- -- **Tenant Setup & Configuration**: Initial tenant setup, domain configuration, DNS records, service provisioning -- **User & Group Management**: User lifecycle (create, modify, disable, delete), group creation, license assignment -- **Security & Compliance**: Conditional Access policies, MFA setup, DLP policies, retention policies, security baselines -- **SharePoint & OneDrive**: Site provisioning, permissions management, storage quotas, sharing policies -- **Teams Administration**: Team creation, policy management, guest access, compliance settings -- **Exchange Online**: Mailbox management, distribution groups, mail flow rules, anti-spam/malware policies -- **License Management**: License allocation, optimization, cost analysis, usage reporting -- **Reporting & Auditing**: Activity reports, audit logs, compliance reporting, usage analytics -- **Automation Scripts**: PowerShell script generation for bulk operations and recurring tasks -- **Best Practices**: Microsoft recommended configurations, security hardening, governance frameworks +## Table of Contents -## Input Requirements +- [Trigger Phrases](#trigger-phrases) +- [Quick Start](#quick-start) +- [Tools](#tools) +- [Workflows](#workflows) +- [Best Practices](#best-practices) +- [Reference Guides](#reference-guides) +- [Limitations](#limitations) -Tenant management tasks require: -- **Action type**: setup, configure, create, modify, delete, report, audit -- **Resource details**: User info, group names, policy settings, service configurations -- **Organizational context**: Company size, industry, compliance requirements (GDPR, HIPAA, etc.) -- **Current state**: Existing configurations, licenses, user count -- **Desired outcome**: Specific goals, requirements, or changes needed +--- -Formats accepted: -- Text descriptions of administrative tasks -- JSON with structured configuration data -- CSV for bulk user/group operations -- Existing PowerShell scripts to review or modify +## Trigger Phrases -## Output Formats +Use this skill when you hear: +- "set up Microsoft 365 tenant" +- "create Office 365 users" +- "configure Azure AD" +- "generate PowerShell script for M365" +- "set up Conditional Access" +- "bulk user provisioning" +- "M365 security audit" +- "license management" +- "Exchange Online configuration" +- "Teams administration" -Results include: -- **Step-by-step instructions**: Detailed guidance for manual configuration via Admin Center -- **PowerShell scripts**: Ready-to-use scripts for automation (with safety checks) -- **Configuration recommendations**: Security and governance best practices -- **Validation checklists**: Pre/post-implementation verification steps -- **Documentation**: Markdown documentation of changes and configurations -- **Rollback procedures**: Instructions to undo changes if needed -- **Compliance reports**: Security posture and compliance status +--- -## How to Use +## Quick Start -"Set up a new Microsoft 365 tenant for a 50-person company with security best practices" -"Create a PowerShell script to provision 100 users from a CSV file with appropriate licenses" -"Configure Conditional Access policy requiring MFA for all admin accounts" -"Generate a report of all inactive users in the past 90 days" -"Set up Teams policies for external collaboration with security controls" +### Generate Security Audit Script -## Scripts +```bash +python scripts/powershell_generator.py --action audit --output audit_script.ps1 +``` -- `tenant_setup.py`: Initial tenant configuration and service provisioning automation -- `user_management.py`: User lifecycle operations and bulk provisioning -- `security_policies.py`: Security policy configuration and compliance checks -- `reporting.py`: Analytics, audit logs, and compliance reporting -- `powershell_generator.py`: Generates PowerShell scripts for Microsoft Graph API and admin modules +### Create Bulk User Provisioning Script + +```bash +python scripts/user_management.py --action provision --csv users.csv --license E3 +``` + +### Configure Conditional Access Policy + +```bash +python scripts/powershell_generator.py --action conditional-access --require-mfa --include-admins +``` + +--- + +## Tools + +### powershell_generator.py + +Generates ready-to-use PowerShell scripts for Microsoft 365 administration. + +**Usage:** + +```bash +# Generate security audit script +python scripts/powershell_generator.py --action audit + +# Generate Conditional Access policy script +python scripts/powershell_generator.py --action conditional-access \ + --policy-name "Require MFA for Admins" \ + --require-mfa \ + --include-users "All" + +# Generate bulk license assignment script +python scripts/powershell_generator.py --action license \ + --csv users.csv \ + --sku "ENTERPRISEPACK" +``` + +**Parameters:** + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `--action` | Yes | Script type: `audit`, `conditional-access`, `license`, `users` | +| `--policy-name` | No | Name for Conditional Access policy | +| `--require-mfa` | No | Require MFA in policy | +| `--include-users` | No | Users to include: `All` or specific UPNs | +| `--csv` | No | CSV file path for bulk operations | +| `--sku` | No | License SKU for assignment | +| `--output` | No | Output file path (default: stdout) | + +**Output:** Complete PowerShell scripts with error handling, logging, and best practices. + +### user_management.py + +Automates user lifecycle operations and bulk provisioning. + +**Usage:** + +```bash +# Provision users from CSV +python scripts/user_management.py --action provision --csv new_users.csv + +# Offboard user securely +python scripts/user_management.py --action offboard --user john.doe@company.com + +# Generate inactive users report +python scripts/user_management.py --action report-inactive --days 90 +``` + +**Parameters:** + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `--action` | Yes | Operation: `provision`, `offboard`, `report-inactive`, `sync` | +| `--csv` | No | CSV file for bulk operations | +| `--user` | No | Single user UPN | +| `--days` | No | Days for inactivity threshold (default: 90) | +| `--license` | No | License SKU to assign | + +### tenant_setup.py + +Initial tenant configuration and service provisioning automation. + +**Usage:** + +```bash +# Generate tenant setup checklist +python scripts/tenant_setup.py --action checklist --company "Acme Inc" --users 50 + +# Generate DNS records configuration +python scripts/tenant_setup.py --action dns --domain acme.com + +# Generate security baseline script +python scripts/tenant_setup.py --action security-baseline +``` + +--- + +## Workflows + +### Workflow 1: New Tenant Setup + +**Step 1: Generate Setup Checklist** + +```bash +python scripts/tenant_setup.py --action checklist --company "Company Name" --users 100 +``` + +**Step 2: Configure DNS Records** + +```bash +python scripts/tenant_setup.py --action dns --domain company.com +``` + +**Step 3: Apply Security Baseline** + +```bash +python scripts/powershell_generator.py --action audit > initial_audit.ps1 +``` + +**Step 4: Provision Users** + +```bash +python scripts/user_management.py --action provision --csv employees.csv --license E3 +``` + +### Workflow 2: Security Hardening + +**Step 1: Run Security Audit** + +```bash +python scripts/powershell_generator.py --action audit --output security_audit.ps1 +``` + +**Step 2: Create MFA Policy** + +```bash +python scripts/powershell_generator.py --action conditional-access \ + --policy-name "Require MFA All Users" \ + --require-mfa \ + --include-users "All" +``` + +**Step 3: Review Results** + +Execute generated scripts and review CSV reports in output directory. + +### Workflow 3: User Offboarding + +**Step 1: Generate Offboarding Script** + +```bash +python scripts/user_management.py --action offboard --user departing.user@company.com +``` + +**Step 2: Execute Script with -WhatIf** + +```powershell +.\offboard_user.ps1 -WhatIf +``` + +**Step 3: Execute for Real** + +```powershell +.\offboard_user.ps1 -Confirm:$false +``` + +--- ## Best Practices ### Tenant Setup -1. **Enable MFA first** - Before adding users, enforce multi-factor authentication -2. **Configure named locations** - Define trusted IP ranges for Conditional Access -3. **Set up privileged access** - Use separate admin accounts, enable PIM (Privileged Identity Management) -4. **Domain verification** - Add and verify custom domains before bulk user creation -5. **Baseline security** - Apply Microsoft Secure Score recommendations immediately -### User Management -1. **License assignment** - Use group-based licensing for scalability -2. **Naming conventions** - Establish consistent user principal names (UPNs) and display names -3. **Lifecycle management** - Implement automated onboarding/offboarding workflows -4. **Guest access** - Enable only when necessary, set expiration policies -5. **Shared mailboxes** - Use for department emails instead of assigning licenses +1. Enable MFA before adding users +2. Configure named locations for Conditional Access +3. Use separate admin accounts with PIM +4. Verify custom domains before bulk user creation +5. Apply Microsoft Secure Score recommendations -### Security & Compliance -1. **Zero Trust approach** - Verify explicitly, use least privilege access, assume breach -2. **Conditional Access** - Start with report-only mode, then enforce gradually -3. **Data Loss Prevention** - Define sensitive information types, test policies before enforcement -4. **Retention policies** - Balance compliance requirements with storage costs -5. **Regular audits** - Review permissions, licenses, and security settings quarterly +### Security Operations -### SharePoint & Teams -1. **Site provisioning** - Use templates and governance policies -2. **External sharing** - Restrict to specific domains, require authentication -3. **Storage management** - Set quotas, enable auto-cleanup of old content -4. **Teams templates** - Create standardized team structures for consistency -5. **Guest lifecycle** - Set expiration and regular recertification +1. Start Conditional Access policies in report-only mode +2. Use `-WhatIf` parameter before executing scripts +3. Never hardcode credentials in scripts +4. Enable audit logging for all operations +5. Regular quarterly security reviews ### PowerShell Automation -1. **Use Microsoft Graph** - Prefer Graph API over legacy MSOnline modules -2. **Error handling** - Include try/catch blocks and validation checks -3. **Dry-run mode** - Test scripts with -WhatIf before executing -4. **Logging** - Capture all operations for audit trails -5. **Credential management** - Use Azure Key Vault or managed identities, never hardcode -## Common Tasks +1. Prefer Microsoft Graph over legacy MSOnline modules +2. Include try/catch blocks for error handling +3. Implement logging for audit trails +4. Use Azure Key Vault for credential management +5. Test in non-production tenant first -### Initial Tenant Setup -- Configure company branding -- Add and verify custom domains -- Set up DNS records (MX, SPF, DKIM, DMARC) -- Enable required services (Teams, SharePoint, Exchange) -- Create organizational structure (departments, locations) -- Set default user settings and policies +--- -### User Onboarding -- Create user accounts (single or bulk) -- Assign appropriate licenses -- Add to security and distribution groups -- Configure mailbox and OneDrive -- Set up multi-factor authentication -- Provision Teams access +## Reference Guides -### Security Hardening -- Enable Security Defaults or Conditional Access -- Configure MFA enforcement -- Set up admin role assignments -- Enable audit logging -- Configure anti-phishing policies -- Set up DLP and retention policies +### When to Use Each Reference -### Reporting & Monitoring -- Active users and license utilization -- Security incidents and alerts -- Mailbox usage and storage -- SharePoint site activity -- Teams usage and adoption -- Compliance and audit logs +**references/powershell-templates.md** + +- Ready-to-use script templates +- Conditional Access policy examples +- Bulk user provisioning scripts +- Security audit scripts + +**references/security-policies.md** + +- Conditional Access configuration +- MFA enforcement strategies +- DLP and retention policies +- Security baseline settings + +**references/troubleshooting.md** + +- Common error resolutions +- PowerShell module issues +- Permission troubleshooting +- DNS propagation problems + +--- ## Limitations -- **Permissions required**: Global Administrator or specific role-based permissions -- **API rate limits**: Microsoft Graph API has throttling limits for bulk operations -- **License dependencies**: Some features require specific license tiers (E3, E5) -- **Delegation constraints**: Some tasks cannot be delegated to service principals -- **Regional variations**: Compliance features may vary by geographic region -- **Hybrid scenarios**: On-premises Active Directory integration requires additional configuration -- **Third-party integrations**: External apps may require separate authentication and permissions -- **PowerShell prerequisites**: Requires appropriate modules installed (Microsoft.Graph, ExchangeOnlineManagement, etc.) +| Constraint | Impact | +|------------|--------| +| Global Admin required | Full tenant setup needs highest privilege | +| API rate limits | Bulk operations may be throttled | +| License dependencies | E3/E5 required for advanced features | +| Hybrid scenarios | On-premises AD needs additional configuration | +| PowerShell prerequisites | Microsoft.Graph module required | -## Security Considerations +### Required PowerShell Modules -### Authentication -- Never store credentials in scripts or configuration files -- Use Azure Key Vault for credential management -- Implement certificate-based authentication for automation -- Enable Conditional Access for admin accounts -- Use Privileged Identity Management (PIM) for JIT access +```powershell +Install-Module Microsoft.Graph -Scope CurrentUser +Install-Module ExchangeOnlineManagement -Scope CurrentUser +Install-Module MicrosoftTeams -Scope CurrentUser +``` -### Authorization -- Follow principle of least privilege -- Use custom admin roles instead of Global Admin when possible -- Regularly review and audit admin role assignments -- Enable PIM for temporary elevated access -- Separate user accounts from admin accounts +### Required Permissions -### Compliance -- Enable audit logging for all activities -- Retain logs according to compliance requirements -- Configure data residency for regulated industries -- Implement information barriers where needed -- Regular compliance assessments and reporting - -## PowerShell Modules Required - -To execute generated scripts, ensure these modules are installed: -- `Microsoft.Graph` (recommended, modern Graph API) -- `ExchangeOnlineManagement` (Exchange Online management) -- `MicrosoftTeams` (Teams administration) -- `SharePointPnPPowerShellOnline` (SharePoint management) -- `AzureAD` or `AzureADPreview` (Azure AD management - being deprecated) -- `MSOnline` (Legacy, being deprecated - avoid when possible) - -## Updates & Maintenance - -- Microsoft 365 features and APIs evolve rapidly -- Review Microsoft 365 Roadmap regularly for upcoming changes -- Test scripts in non-production tenant before production deployment -- Subscribe to Microsoft 365 Admin Center message center for updates -- Keep PowerShell modules updated to latest versions -- Regular security baseline reviews (quarterly recommended) - -## Helpful Resources - -- **Microsoft 365 Admin Center**: https://admin.microsoft.com -- **Microsoft Graph Explorer**: https://developer.microsoft.com/graph/graph-explorer -- **PowerShell Gallery**: https://www.powershellgallery.com -- **Microsoft Secure Score**: Security posture assessment in Admin Center -- **Microsoft 365 Compliance Center**: https://compliance.microsoft.com -- **Azure AD Conditional Access**: Identity and access management policies +- **Global Administrator** - Full tenant setup +- **User Administrator** - User management +- **Security Administrator** - Security policies +- **Exchange Administrator** - Mailbox management diff --git a/engineering-team/ms365-tenant-manager/__pycache__/powershell_generator.cpython-313.pyc b/engineering-team/ms365-tenant-manager/__pycache__/powershell_generator.cpython-313.pyc deleted file mode 100644 index d0e3c8b..0000000 Binary files a/engineering-team/ms365-tenant-manager/__pycache__/powershell_generator.cpython-313.pyc and /dev/null differ diff --git a/engineering-team/ms365-tenant-manager/__pycache__/tenant_setup.cpython-313.pyc b/engineering-team/ms365-tenant-manager/__pycache__/tenant_setup.cpython-313.pyc deleted file mode 100644 index 89e505c..0000000 Binary files a/engineering-team/ms365-tenant-manager/__pycache__/tenant_setup.cpython-313.pyc and /dev/null differ diff --git a/engineering-team/ms365-tenant-manager/__pycache__/user_management.cpython-313.pyc b/engineering-team/ms365-tenant-manager/__pycache__/user_management.cpython-313.pyc deleted file mode 100644 index de844f1..0000000 Binary files a/engineering-team/ms365-tenant-manager/__pycache__/user_management.cpython-313.pyc and /dev/null differ diff --git a/engineering-team/ms365-tenant-manager/references/powershell-templates.md b/engineering-team/ms365-tenant-manager/references/powershell-templates.md new file mode 100644 index 0000000..55735ff --- /dev/null +++ b/engineering-team/ms365-tenant-manager/references/powershell-templates.md @@ -0,0 +1,704 @@ +# PowerShell Script Templates + +Ready-to-use PowerShell scripts for Microsoft 365 administration with error handling and best practices. + +--- + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Security Audit Script](#security-audit-script) +- [Conditional Access Policy](#conditional-access-policy) +- [Bulk User Provisioning](#bulk-user-provisioning) +- [User Offboarding](#user-offboarding) +- [License Management](#license-management) +- [DNS Records Configuration](#dns-records-configuration) + +--- + +## Prerequisites + +Install required modules before running scripts: + +```powershell +# Install Microsoft Graph module (recommended) +Install-Module Microsoft.Graph -Scope CurrentUser -Force + +# Install Exchange Online module +Install-Module ExchangeOnlineManagement -Scope CurrentUser -Force + +# Install Teams module +Install-Module MicrosoftTeams -Scope CurrentUser -Force + +# Verify installations +Get-InstalledModule Microsoft.Graph, ExchangeOnlineManagement, MicrosoftTeams +``` + +--- + +## Security Audit Script + +Comprehensive security audit for MFA status, admin accounts, inactive users, and permissions. + +```powershell +<# +.SYNOPSIS + Microsoft 365 Security Audit Report + +.DESCRIPTION + Performs comprehensive security audit and generates CSV reports. + Checks: MFA status, admin accounts, inactive users, guest access, licenses + +.OUTPUTS + CSV reports in SecurityAudit_[timestamp] directory +#> + +#Requires -Modules Microsoft.Graph, ExchangeOnlineManagement + +param( + [int]$InactiveDays = 90, + [string]$OutputPath = "." +) + +# Connect to services +Connect-MgGraph -Scopes "Directory.Read.All", "User.Read.All", "AuditLog.Read.All" +Connect-ExchangeOnline + +$timestamp = Get-Date -Format "yyyyMMdd_HHmmss" +$reportPath = Join-Path $OutputPath "SecurityAudit_$timestamp" +New-Item -ItemType Directory -Path $reportPath -Force | Out-Null + +Write-Host "Starting Security Audit..." -ForegroundColor Cyan + +# 1. MFA Status Check +Write-Host "[1/5] Checking MFA status..." -ForegroundColor Yellow + +$users = Get-MgUser -All -Property Id,DisplayName,UserPrincipalName,AccountEnabled +$mfaReport = @() + +foreach ($user in $users) { + $authMethods = Get-MgUserAuthenticationMethod -UserId $user.Id -ErrorAction SilentlyContinue + $hasMFA = ($authMethods | Where-Object { $_.AdditionalProperties.'@odata.type' -ne '#microsoft.graph.passwordAuthenticationMethod' }).Count -gt 0 + + $mfaReport += [PSCustomObject]@{ + UserPrincipalName = $user.UserPrincipalName + DisplayName = $user.DisplayName + AccountEnabled = $user.AccountEnabled + MFAEnabled = $hasMFA + AuthMethodsCount = $authMethods.Count + } +} + +$mfaReport | Export-Csv -Path "$reportPath/MFA_Status.csv" -NoTypeInformation +$usersWithoutMFA = ($mfaReport | Where-Object { -not $_.MFAEnabled -and $_.AccountEnabled }).Count +Write-Host " Users without MFA: $usersWithoutMFA" -ForegroundColor $(if($usersWithoutMFA -gt 0){'Red'}else{'Green'}) + +# 2. Admin Roles Audit +Write-Host "[2/5] Auditing admin roles..." -ForegroundColor Yellow + +$adminRoles = Get-MgDirectoryRole -All +$adminReport = @() + +foreach ($role in $adminRoles) { + $members = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -All + foreach ($member in $members) { + $memberUser = Get-MgUser -UserId $member.Id -ErrorAction SilentlyContinue + if ($memberUser) { + $adminReport += [PSCustomObject]@{ + UserPrincipalName = $memberUser.UserPrincipalName + DisplayName = $memberUser.DisplayName + Role = $role.DisplayName + AccountEnabled = $memberUser.AccountEnabled + } + } + } +} + +$adminReport | Export-Csv -Path "$reportPath/Admin_Roles.csv" -NoTypeInformation +Write-Host " Admin assignments: $($adminReport.Count)" -ForegroundColor Cyan + +# 3. Inactive Users +Write-Host "[3/5] Finding inactive users ($InactiveDays+ days)..." -ForegroundColor Yellow + +$inactiveDate = (Get-Date).AddDays(-$InactiveDays) +$inactiveUsers = Get-MgUser -All -Property Id,DisplayName,UserPrincipalName,SignInActivity,AccountEnabled | + Where-Object { + $_.AccountEnabled -and + $_.SignInActivity.LastSignInDateTime -and + $_.SignInActivity.LastSignInDateTime -lt $inactiveDate + } | + Select-Object UserPrincipalName, DisplayName, + @{N='LastSignIn';E={$_.SignInActivity.LastSignInDateTime}}, + @{N='DaysSinceSignIn';E={((Get-Date) - $_.SignInActivity.LastSignInDateTime).Days}} + +$inactiveUsers | Export-Csv -Path "$reportPath/Inactive_Users.csv" -NoTypeInformation +Write-Host " Inactive users: $($inactiveUsers.Count)" -ForegroundColor $(if($inactiveUsers.Count -gt 0){'Yellow'}else{'Green'}) + +# 4. Guest Users +Write-Host "[4/5] Reviewing guest access..." -ForegroundColor Yellow + +$guestUsers = Get-MgUser -Filter "userType eq 'Guest'" -All -Property UserPrincipalName,DisplayName,AccountEnabled,CreatedDateTime +$guestUsers | Select-Object UserPrincipalName, DisplayName, AccountEnabled, CreatedDateTime | + Export-Csv -Path "$reportPath/Guest_Users.csv" -NoTypeInformation +Write-Host " Guest users: $($guestUsers.Count)" -ForegroundColor Cyan + +# 5. License Usage +Write-Host "[5/5] Analyzing licenses..." -ForegroundColor Yellow + +$licenses = Get-MgSubscribedSku -All +$licenseReport = foreach ($lic in $licenses) { + [PSCustomObject]@{ + ProductName = $lic.SkuPartNumber + TotalLicenses = $lic.PrepaidUnits.Enabled + AssignedLicenses = $lic.ConsumedUnits + AvailableLicenses = $lic.PrepaidUnits.Enabled - $lic.ConsumedUnits + Utilization = [math]::Round(($lic.ConsumedUnits / [math]::Max($lic.PrepaidUnits.Enabled, 1)) * 100, 1) + } +} + +$licenseReport | Export-Csv -Path "$reportPath/License_Usage.csv" -NoTypeInformation +Write-Host " License SKUs: $($licenses.Count)" -ForegroundColor Cyan + +# Summary +Write-Host "`n=== Security Audit Summary ===" -ForegroundColor Green +Write-Host "Total Users: $($users.Count)" +Write-Host "Users without MFA: $usersWithoutMFA $(if($usersWithoutMFA -gt 0){'[ACTION REQUIRED]'})" +Write-Host "Inactive Users: $($inactiveUsers.Count)" +Write-Host "Guest Users: $($guestUsers.Count)" +Write-Host "Admin Assignments: $($adminReport.Count)" +Write-Host "`nReports saved to: $reportPath" -ForegroundColor Green + +# Disconnect +Disconnect-MgGraph +Disconnect-ExchangeOnline -Confirm:$false +``` + +--- + +## Conditional Access Policy + +Create Conditional Access policy requiring MFA for administrators. + +```powershell +<# +.SYNOPSIS + Create Conditional Access Policy for MFA + +.DESCRIPTION + Creates a Conditional Access policy requiring MFA. + Policy is created in report-only mode for safe testing. + +.PARAMETER PolicyName + Name for the policy + +.PARAMETER IncludeAllUsers + Apply to all users (default: false, admins only) +#> + +#Requires -Modules Microsoft.Graph + +param( + [string]$PolicyName = "Require MFA for Administrators", + [switch]$IncludeAllUsers, + [switch]$Enforce +) + +Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess", "Directory.Read.All" + +# Get admin role IDs +$adminRoles = @( + "62e90394-69f5-4237-9190-012177145e10" # Global Administrator + "194ae4cb-b126-40b2-bd5b-6091b380977d" # Security Administrator + "f28a1f50-f6e7-4571-818b-6a12f2af6b6c" # SharePoint Administrator + "29232cdf-9323-42fd-ade2-1d097af3e4de" # Exchange Administrator + "fe930be7-5e62-47db-91af-98c3a49a38b1" # User Administrator +) + +# Build conditions +$conditions = @{ + Users = @{ + IncludeRoles = if ($IncludeAllUsers) { $null } else { $adminRoles } + IncludeUsers = if ($IncludeAllUsers) { @("All") } else { $null } + ExcludeUsers = @("GuestsOrExternalUsers") + } + Applications = @{ + IncludeApplications = @("All") + } + ClientAppTypes = @("browser", "mobileAppsAndDesktopClients") +} + +# Remove null entries +if ($IncludeAllUsers) { + $conditions.Users.Remove("IncludeRoles") +} else { + $conditions.Users.Remove("IncludeUsers") +} + +$grantControls = @{ + BuiltInControls = @("mfa") + Operator = "OR" +} + +$state = if ($Enforce) { "enabled" } else { "enabledForReportingButNotEnforced" } + +$policyParams = @{ + DisplayName = $PolicyName + State = $state + Conditions = $conditions + GrantControls = $grantControls +} + +try { + $policy = New-MgIdentityConditionalAccessPolicy -BodyParameter $policyParams + Write-Host "Policy created successfully" -ForegroundColor Green + Write-Host " Name: $($policy.DisplayName)" + Write-Host " ID: $($policy.Id)" + Write-Host " State: $state" + + if (-not $Enforce) { + Write-Host "`nPolicy is in REPORT-ONLY mode." -ForegroundColor Yellow + Write-Host "Monitor sign-in logs before enforcing." + Write-Host "To enforce: Update policy state to 'enabled' in Azure AD portal" + } +} catch { + Write-Host "Error creating policy: $_" -ForegroundColor Red +} + +Disconnect-MgGraph +``` + +--- + +## Bulk User Provisioning + +Create users from CSV with license assignment. + +```powershell +<# +.SYNOPSIS + Bulk User Provisioning from CSV + +.DESCRIPTION + Creates users from CSV file with automatic license assignment. + +.PARAMETER CsvPath + Path to CSV file with columns: DisplayName, UserPrincipalName, Department, JobTitle + +.PARAMETER LicenseSku + License SKU to assign (e.g., ENTERPRISEPACK for E3) + +.PARAMETER Password + Initial password (auto-generated if not provided) +#> + +#Requires -Modules Microsoft.Graph + +param( + [Parameter(Mandatory)] + [string]$CsvPath, + + [string]$LicenseSku = "ENTERPRISEPACK", + + [string]$Password, + + [switch]$WhatIf +) + +Connect-MgGraph -Scopes "User.ReadWrite.All", "Directory.ReadWrite.All" + +# Validate CSV +if (-not (Test-Path $CsvPath)) { + Write-Host "CSV file not found: $CsvPath" -ForegroundColor Red + exit 1 +} + +$users = Import-Csv $CsvPath +Write-Host "Found $($users.Count) users in CSV" -ForegroundColor Cyan + +# Get license SKU ID +$license = Get-MgSubscribedSku -All | Where-Object { $_.SkuPartNumber -eq $LicenseSku } +if (-not $license) { + Write-Host "License SKU not found: $LicenseSku" -ForegroundColor Red + Write-Host "Available SKUs:" + Get-MgSubscribedSku -All | ForEach-Object { Write-Host " $($_.SkuPartNumber)" } + exit 1 +} + +$results = @() +$successCount = 0 +$errorCount = 0 + +foreach ($user in $users) { + $upn = $user.UserPrincipalName + + if ($WhatIf) { + Write-Host "[WhatIf] Would create: $upn" -ForegroundColor Yellow + continue + } + + # Generate password if not provided + $userPassword = if ($Password) { $Password } else { + -join ((65..90) + (97..122) + (48..57) + (33,35,36,37) | Get-Random -Count 16 | ForEach-Object { [char]$_ }) + } + + $userParams = @{ + DisplayName = $user.DisplayName + UserPrincipalName = $upn + MailNickname = $upn.Split("@")[0] + AccountEnabled = $true + Department = $user.Department + JobTitle = $user.JobTitle + UsageLocation = "US" # Required for license assignment + PasswordProfile = @{ + Password = $userPassword + ForceChangePasswordNextSignIn = $true + ForceChangePasswordNextSignInWithMfa = $true + } + } + + try { + # Create user + $newUser = New-MgUser -BodyParameter $userParams + Write-Host "Created: $upn" -ForegroundColor Green + + # Assign license + $licenseParams = @{ + AddLicenses = @(@{ SkuId = $license.SkuId }) + RemoveLicenses = @() + } + Set-MgUserLicense -UserId $newUser.Id -BodyParameter $licenseParams + Write-Host " License assigned: $LicenseSku" -ForegroundColor Cyan + + $successCount++ + $results += [PSCustomObject]@{ + UserPrincipalName = $upn + Status = "Success" + Password = $userPassword + Message = "Created and licensed" + } + } catch { + Write-Host "Error for $upn : $_" -ForegroundColor Red + $errorCount++ + $results += [PSCustomObject]@{ + UserPrincipalName = $upn + Status = "Failed" + Password = "" + Message = $_.Exception.Message + } + } +} + +# Export results +if (-not $WhatIf) { + $resultsPath = "UserProvisioning_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" + $results | Export-Csv -Path $resultsPath -NoTypeInformation + Write-Host "`nResults saved to: $resultsPath" -ForegroundColor Green + Write-Host "Success: $successCount | Errors: $errorCount" +} + +Disconnect-MgGraph +``` + +**CSV Format:** + +```csv +DisplayName,UserPrincipalName,Department,JobTitle +John Smith,john.smith@contoso.com,Engineering,Developer +Jane Doe,jane.doe@contoso.com,Marketing,Manager +``` + +--- + +## User Offboarding + +Secure user offboarding with mailbox conversion and access removal. + +```powershell +<# +.SYNOPSIS + Secure User Offboarding + +.DESCRIPTION + Performs secure offboarding: disables account, revokes sessions, + converts mailbox to shared, removes licenses, sets forwarding. + +.PARAMETER UserPrincipalName + UPN of user to offboard + +.PARAMETER ForwardTo + Email to forward messages to (optional) + +.PARAMETER RetainMailbox + Keep mailbox as shared (default: true) +#> + +#Requires -Modules Microsoft.Graph, ExchangeOnlineManagement + +param( + [Parameter(Mandatory)] + [string]$UserPrincipalName, + + [string]$ForwardTo, + + [switch]$RetainMailbox = $true, + + [switch]$WhatIf +) + +Connect-MgGraph -Scopes "User.ReadWrite.All", "Directory.ReadWrite.All" +Connect-ExchangeOnline + +Write-Host "Starting offboarding for: $UserPrincipalName" -ForegroundColor Cyan + +$user = Get-MgUser -UserId $UserPrincipalName -ErrorAction SilentlyContinue +if (-not $user) { + Write-Host "User not found: $UserPrincipalName" -ForegroundColor Red + exit 1 +} + +$actions = @() + +# 1. Disable account +if (-not $WhatIf) { + Update-MgUser -UserId $user.Id -AccountEnabled:$false +} +$actions += "Disabled account" +Write-Host "[1/6] Account disabled" -ForegroundColor Green + +# 2. Revoke all sessions +if (-not $WhatIf) { + Revoke-MgUserSignInSession -UserId $user.Id +} +$actions += "Revoked all sessions" +Write-Host "[2/6] Sessions revoked" -ForegroundColor Green + +# 3. Reset password +$newPassword = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 32 | ForEach-Object { [char]$_ }) +if (-not $WhatIf) { + $passwordProfile = @{ + Password = $newPassword + ForceChangePasswordNextSignIn = $true + } + Update-MgUser -UserId $user.Id -PasswordProfile $passwordProfile +} +$actions += "Reset password" +Write-Host "[3/6] Password reset" -ForegroundColor Green + +# 4. Remove from groups +$groups = Get-MgUserMemberOf -UserId $user.Id -All +$groupCount = 0 +foreach ($group in $groups) { + if ($group.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.group') { + if (-not $WhatIf) { + Remove-MgGroupMemberByRef -GroupId $group.Id -DirectoryObjectId $user.Id -ErrorAction SilentlyContinue + } + $groupCount++ + } +} +$actions += "Removed from $groupCount groups" +Write-Host "[4/6] Removed from $groupCount groups" -ForegroundColor Green + +# 5. Convert mailbox to shared (if retaining) +if ($RetainMailbox) { + if (-not $WhatIf) { + Set-Mailbox -Identity $UserPrincipalName -Type Shared + } + $actions += "Converted mailbox to shared" + Write-Host "[5/6] Mailbox converted to shared" -ForegroundColor Green + + # Set forwarding if specified + if ($ForwardTo) { + if (-not $WhatIf) { + Set-Mailbox -Identity $UserPrincipalName -ForwardingAddress $ForwardTo + } + $actions += "Mail forwarding set to $ForwardTo" + Write-Host " Forwarding to: $ForwardTo" -ForegroundColor Cyan + } +} else { + Write-Host "[5/6] Mailbox retention skipped" -ForegroundColor Yellow +} + +# 6. Remove licenses +$licenses = Get-MgUserLicenseDetail -UserId $user.Id +if ($licenses -and -not $WhatIf) { + $licenseParams = @{ + AddLicenses = @() + RemoveLicenses = $licenses.SkuId + } + Set-MgUserLicense -UserId $user.Id -BodyParameter $licenseParams +} +$actions += "Removed $($licenses.Count) licenses" +Write-Host "[6/6] Removed $($licenses.Count) licenses" -ForegroundColor Green + +# Summary +Write-Host "`n=== Offboarding Complete ===" -ForegroundColor Green +Write-Host "User: $UserPrincipalName" +Write-Host "Actions taken:" +$actions | ForEach-Object { Write-Host " - $_" } + +if ($WhatIf) { + Write-Host "`n[WhatIf] No changes were made" -ForegroundColor Yellow +} + +Disconnect-MgGraph +Disconnect-ExchangeOnline -Confirm:$false +``` + +--- + +## License Management + +Analyze license usage and optimize allocation. + +```powershell +<# +.SYNOPSIS + License Usage Analysis and Optimization + +.DESCRIPTION + Analyzes current license usage and identifies optimization opportunities. +#> + +#Requires -Modules Microsoft.Graph + +Connect-MgGraph -Scopes "Directory.Read.All", "User.Read.All" + +Write-Host "Analyzing License Usage..." -ForegroundColor Cyan + +$licenses = Get-MgSubscribedSku -All + +$report = foreach ($lic in $licenses) { + $available = $lic.PrepaidUnits.Enabled - $lic.ConsumedUnits + $utilization = [math]::Round(($lic.ConsumedUnits / [math]::Max($lic.PrepaidUnits.Enabled, 1)) * 100, 1) + + [PSCustomObject]@{ + ProductName = $lic.SkuPartNumber + Total = $lic.PrepaidUnits.Enabled + Assigned = $lic.ConsumedUnits + Available = $available + Utilization = "$utilization%" + Status = if ($utilization -gt 90) { "Critical" } + elseif ($utilization -gt 75) { "Warning" } + elseif ($utilization -lt 50) { "Underutilized" } + else { "Healthy" } + } +} + +$report | Format-Table -AutoSize + +# Find users with unused licenses +Write-Host "`nChecking for inactive licensed users..." -ForegroundColor Yellow + +$inactiveDate = (Get-Date).AddDays(-90) +$inactiveLicensed = Get-MgUser -All -Property Id,DisplayName,UserPrincipalName,SignInActivity,AssignedLicenses | + Where-Object { + $_.AssignedLicenses.Count -gt 0 -and + $_.SignInActivity.LastSignInDateTime -and + $_.SignInActivity.LastSignInDateTime -lt $inactiveDate + } | + Select-Object DisplayName, UserPrincipalName, + @{N='LastSignIn';E={$_.SignInActivity.LastSignInDateTime}}, + @{N='LicenseCount';E={$_.AssignedLicenses.Count}} + +if ($inactiveLicensed) { + Write-Host "Found $($inactiveLicensed.Count) inactive users with licenses:" -ForegroundColor Yellow + $inactiveLicensed | Format-Table -AutoSize +} else { + Write-Host "No inactive licensed users found" -ForegroundColor Green +} + +# Export +$report | Export-Csv -Path "LicenseAnalysis_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation + +Disconnect-MgGraph +``` + +--- + +## DNS Records Configuration + +Generate DNS records for custom domain setup. + +```powershell +<# +.SYNOPSIS + Generate DNS Records for Microsoft 365 + +.DESCRIPTION + Outputs required DNS records for custom domain verification and services. + +.PARAMETER Domain + Custom domain name +#> + +param( + [Parameter(Mandatory)] + [string]$Domain +) + +Write-Host "DNS Records for: $Domain" -ForegroundColor Cyan +Write-Host "=" * 60 + +Write-Host "`n### MX Record (Email)" -ForegroundColor Yellow +Write-Host "Type: MX" +Write-Host "Host: @" +Write-Host "Points to: $Domain.mail.protection.outlook.com" +Write-Host "Priority: 0" + +Write-Host "`n### SPF Record (Email Authentication)" -ForegroundColor Yellow +Write-Host "Type: TXT" +Write-Host "Host: @" +Write-Host "Value: v=spf1 include:spf.protection.outlook.com -all" + +Write-Host "`n### Autodiscover (Outlook Configuration)" -ForegroundColor Yellow +Write-Host "Type: CNAME" +Write-Host "Host: autodiscover" +Write-Host "Points to: autodiscover.outlook.com" + +Write-Host "`n### DKIM Records (Email Signing)" -ForegroundColor Yellow +$domainKey = $Domain.Replace(".", "-") +Write-Host "Type: CNAME" +Write-Host "Host: selector1._domainkey" +Write-Host "Points to: selector1-$domainKey._domainkey.{tenant}.onmicrosoft.com" +Write-Host "" +Write-Host "Type: CNAME" +Write-Host "Host: selector2._domainkey" +Write-Host "Points to: selector2-$domainKey._domainkey.{tenant}.onmicrosoft.com" + +Write-Host "`n### DMARC Record (Email Policy)" -ForegroundColor Yellow +Write-Host "Type: TXT" +Write-Host "Host: _dmarc" +Write-Host "Value: v=DMARC1; p=quarantine; rua=mailto:dmarc@$Domain" + +Write-Host "`n### Teams/Skype Records" -ForegroundColor Yellow +Write-Host "Type: CNAME" +Write-Host "Host: sip" +Write-Host "Points to: sipdir.online.lync.com" +Write-Host "" +Write-Host "Type: CNAME" +Write-Host "Host: lyncdiscover" +Write-Host "Points to: webdir.online.lync.com" +Write-Host "" +Write-Host "Type: SRV" +Write-Host "Service: _sip._tls" +Write-Host "Port: 443" +Write-Host "Target: sipdir.online.lync.com" +Write-Host "" +Write-Host "Type: SRV" +Write-Host "Service: _sipfederationtls._tcp" +Write-Host "Port: 5061" +Write-Host "Target: sipfed.online.lync.com" + +Write-Host "`n### MDM Enrollment (Intune)" -ForegroundColor Yellow +Write-Host "Type: CNAME" +Write-Host "Host: enterpriseregistration" +Write-Host "Points to: enterpriseregistration.windows.net" +Write-Host "" +Write-Host "Type: CNAME" +Write-Host "Host: enterpriseenrollment" +Write-Host "Points to: enterpriseenrollment.manage.microsoft.com" + +Write-Host "`n" + "=" * 60 -ForegroundColor Cyan +Write-Host "Verify DNS propagation: nslookup -type=mx $Domain" +Write-Host "Note: DNS changes may take 24-48 hours to propagate" +``` diff --git a/engineering-team/ms365-tenant-manager/references/security-policies.md b/engineering-team/ms365-tenant-manager/references/security-policies.md new file mode 100644 index 0000000..7140c61 --- /dev/null +++ b/engineering-team/ms365-tenant-manager/references/security-policies.md @@ -0,0 +1,357 @@ +# Security Policies Reference + +Comprehensive security configuration guide for Microsoft 365 tenants covering Conditional Access, MFA, DLP, and security baselines. + +--- + +## Table of Contents + +- [Conditional Access Policies](#conditional-access-policies) +- [Multi-Factor Authentication](#multi-factor-authentication) +- [Data Loss Prevention](#data-loss-prevention) +- [Security Baselines](#security-baselines) +- [Admin Role Security](#admin-role-security) +- [Guest Access Controls](#guest-access-controls) + +--- + +## Conditional Access Policies + +### Policy Architecture + +| Policy Type | Target Users | Applications | Grant Control | +|-------------|-------------|--------------|---------------| +| Admin MFA | Admin roles | All apps | Require MFA | +| User MFA | All users | All apps | Require MFA | +| Device Compliance | All users | Office 365 | Compliant device | +| Location-Based | All users | All apps | Block non-trusted | +| Legacy Auth Block | All users | All apps | Block | + +### Recommended Policies + +#### 1. Require MFA for Administrators + +**Scope:** Global Admin, Security Admin, Exchange Admin, SharePoint Admin, User Admin + +**Settings:** +- Include: Directory roles (admin roles) +- Exclude: Emergency access accounts +- Grant: Require MFA +- Session: Sign-in frequency 4 hours + +#### 2. Require MFA for All Users + +**Scope:** All users + +**Settings:** +- Include: All users +- Exclude: Emergency access accounts, service accounts +- Conditions: All cloud apps +- Grant: Require MFA +- Session: Persistent browser session disabled + +#### 3. Block Legacy Authentication + +**Scope:** All users + +**Settings:** +- Include: All users +- Conditions: Exchange ActiveSync, Other clients +- Grant: Block access + +**Why:** Legacy protocols (POP, IMAP, SMTP AUTH) cannot enforce MFA. + +#### 4. Require Compliant Devices + +**Scope:** All users accessing sensitive data + +**Settings:** +- Include: All users +- Applications: Office 365, SharePoint, Exchange +- Grant: Require device compliance OR Hybrid Azure AD joined +- Platforms: Windows, macOS, iOS, Android + +#### 5. Block Access from Untrusted Locations + +**Scope:** High-risk operations + +**Settings:** +- Include: All users +- Applications: Azure Management, Microsoft Graph +- Conditions: Exclude named locations (corporate IPs) +- Grant: Block access + +### Named Locations Configuration + +| Location Name | Type | IP Ranges | +|--------------|------|-----------| +| Corporate HQ | IP ranges | 203.0.113.0/24 | +| VPN Exit Points | IP ranges | 198.51.100.0/24 | +| Trusted Countries | Countries | US, CA, GB | +| Blocked Countries | Countries | (high-risk regions) | + +### Policy Deployment Strategy + +1. **Report-Only Mode (Week 1-2)** + - Enable policies in report-only + - Monitor sign-in logs for impact + - Identify false positives + +2. **Pilot Group (Week 3-4)** + - Enable for IT staff first + - Address issues before broad rollout + - Document exceptions needed + +3. **Gradual Rollout (Week 5-8)** + - Enable by department + - Provide user communication + - Monitor help desk tickets + +4. **Full Enforcement** + - Enable for all users + - Maintain exception process + - Quarterly policy review + +--- + +## Multi-Factor Authentication + +### MFA Methods (Strength Ranking) + +| Method | Security Level | User Experience | +|--------|---------------|-----------------| +| FIDO2 Security Keys | Highest | Excellent | +| Windows Hello | Highest | Excellent | +| Microsoft Authenticator (Passwordless) | High | Good | +| Microsoft Authenticator (Push) | High | Good | +| OATH Hardware Token | High | Fair | +| SMS/Voice | Medium | Good | +| Email OTP | Low | Fair | + +### Recommended Configuration + +**For Administrators:** +- Require phishing-resistant MFA (FIDO2, Windows Hello) +- Disable SMS/Voice as backup +- Enforce re-authentication every 4 hours + +**For Standard Users:** +- Require Microsoft Authenticator +- Allow SMS as backup (temporary) +- Session lifetime: 90 days with risk-based re-auth + +**For External/Guest Users:** +- Require MFA from home tenant +- Fall back to email OTP if needed + +### MFA Registration Campaign + +``` +Phase 1: Communication (Week 1) +- Announce MFA requirement +- Provide registration instructions +- Set deadline for registration + +Phase 2: Registration (Week 2-3) +- Open registration portal +- IT support available +- Track registration progress + +Phase 3: Enforcement (Week 4) +- Enable MFA requirement +- Grace period for stragglers +- Block unregistered after deadline +``` + +--- + +## Data Loss Prevention + +### Sensitive Information Types + +| Category | Examples | Action | +|----------|----------|--------| +| Financial | Credit card, Bank account | Block external sharing | +| PII | SSN, Passport, Driver's license | Require justification | +| Health | Medical records, Insurance | Block and notify | +| Credentials | Passwords, API keys | Block all sharing | + +### DLP Policy Templates + +#### Financial Data Protection + +**Scope:** Exchange, SharePoint, OneDrive, Teams + +**Rules:** +1. Credit card numbers (Luhn validated) +2. Bank account numbers +3. SWIFT codes + +**Actions:** +- Block external sharing +- Encrypt email to external recipients +- Notify compliance team + +#### PII Protection + +**Scope:** All Microsoft 365 locations + +**Rules:** +1. Social Security Numbers +2. Passport numbers +3. Driver's license numbers + +**Actions:** +- Warn user before sharing +- Require business justification +- Log all incidents + +#### Healthcare (HIPAA) + +**Scope:** Exchange, SharePoint, Teams + +**Rules:** +1. Medical record numbers +2. Health insurance IDs +3. Drug names with patient info + +**Actions:** +- Block external sharing +- Apply encryption +- Retain for 7 years + +### DLP Deployment + +1. **Audit Mode First** + - Enable policies in test mode + - Review matched content + - Tune false positives + +2. **User Tips** + - Enable policy tips in apps + - Educate before enforcing + - Provide override option with justification + +3. **Enforcement** + - Block high-risk content + - Warn for medium-risk + - Log everything + +--- + +## Security Baselines + +### Microsoft Secure Score Targets + +| Category | Target Score | Key Actions | +|----------|-------------|-------------| +| Identity | 80%+ | MFA, Conditional Access, PIM | +| Data | 70%+ | DLP, Sensitivity labels, Encryption | +| Device | 75%+ | Compliance policies, Defender | +| Apps | 70%+ | OAuth app review, Admin consent | + +### Priority Security Settings + +#### Identity (Do First) + +- [ ] Enable Security Defaults OR Conditional Access +- [ ] Require MFA for all admins +- [ ] Block legacy authentication +- [ ] Enable self-service password reset +- [ ] Configure password protection (banned passwords) + +#### Data Protection + +- [ ] Enable sensitivity labels +- [ ] Configure DLP policies +- [ ] Enable audit logging +- [ ] Set retention policies +- [ ] Configure information barriers (if needed) + +#### Device Security + +- [ ] Require device compliance +- [ ] Enable Microsoft Defender for Endpoint +- [ ] Configure BitLocker requirements +- [ ] Set application protection policies +- [ ] Enable Windows Autopilot + +#### Application Security + +- [ ] Review OAuth app permissions +- [ ] Configure admin consent workflow +- [ ] Block risky OAuth apps +- [ ] Enable app governance +- [ ] Configure MCAS policies + +--- + +## Admin Role Security + +### Privileged Identity Management (PIM) + +**Configuration:** +- Require approval for Global Admin activation +- Maximum activation: 8 hours +- Require MFA at activation +- Require justification +- Send notification to security team + +### Role Assignment Best Practices + +| Role | Assignment Type | Approval Required | +|------|-----------------|-------------------| +| Global Admin | Eligible only | Yes | +| Security Admin | Eligible only | Yes | +| User Admin | Eligible | No | +| Help Desk Admin | Permanent (limited) | No | + +### Emergency Access Accounts + +**Configuration:** +- 2 cloud-only accounts +- Excluded from ALL Conditional Access +- No MFA (break-glass scenario) +- Monitored via alerts +- Passwords in secure vault +- Test quarterly + +**Naming:** `emergency-access-01@tenant.onmicrosoft.com` + +--- + +## Guest Access Controls + +### Guest Invitation Settings + +| Setting | Recommended Value | +|---------|------------------| +| Guest invite restrictions | Admins and users in guest inviter role | +| Enable guest self-service sign-up | No | +| Enable email one-time passcode | Yes | +| Collaboration restrictions | Allow invitations only to specified domains | + +### Guest Access Review + +**Frequency:** Quarterly + +**Scope:** +- All guest users +- Group memberships +- Application access + +**Actions:** +- Remove inactive guests (90+ days) +- Revoke unnecessary permissions +- Require re-certification + +### B2B Collaboration Settings + +**Allowed Domains:** +- Partners: `partner1.com`, `partner2.com` +- Block all others for sensitive resources + +**Guest Permissions:** +- Limited directory browsing +- Cannot enumerate users +- Cannot invite other guests diff --git a/engineering-team/ms365-tenant-manager/references/troubleshooting.md b/engineering-team/ms365-tenant-manager/references/troubleshooting.md new file mode 100644 index 0000000..8973c6d --- /dev/null +++ b/engineering-team/ms365-tenant-manager/references/troubleshooting.md @@ -0,0 +1,411 @@ +# Troubleshooting Guide + +Common issues and solutions for Microsoft 365 tenant administration. + +--- + +## Table of Contents + +- [Authentication Errors](#authentication-errors) +- [PowerShell Module Issues](#powershell-module-issues) +- [Permission Problems](#permission-problems) +- [License Assignment Failures](#license-assignment-failures) +- [DNS and Domain Issues](#dns-and-domain-issues) +- [Conditional Access Lockouts](#conditional-access-lockouts) +- [Mailbox Issues](#mailbox-issues) + +--- + +## Authentication Errors + +### "AADSTS50076: MFA Required" + +**Cause:** User requires MFA but hasn't completed it. + +**Solutions:** +1. Complete MFA registration at https://aka.ms/mfasetup +2. Use interactive authentication: + ```powershell + Connect-MgGraph -Scopes "User.Read.All" -UseDeviceAuthentication + ``` +3. Check Conditional Access policies excluding the user + +### "AADSTS65001: User hasn't consented" + +**Cause:** Application requires permissions user hasn't granted. + +**Solutions:** +1. Grant admin consent in Azure AD portal +2. Use admin account for initial consent: + ```powershell + Connect-MgGraph -Scopes "User.ReadWrite.All" -ContextScope Process + ``` +3. Add application to enterprise applications with pre-consent + +### "AADSTS700016: Application not found" + +**Cause:** App registration missing or incorrect tenant. + +**Solutions:** +1. Verify app ID in Azure AD > App registrations +2. Check multi-tenant setting if cross-tenant +3. Re-register application if needed + +### "Access Denied" Despite Admin Role + +**Causes:** +- PIM role not activated +- Role assignment pending +- Conditional Access blocking + +**Solutions:** +1. Activate PIM role: + - Go to Azure AD > Privileged Identity Management + - Activate required role +2. Wait 5-10 minutes for role propagation +3. Check Conditional Access policies in report-only mode + +--- + +## PowerShell Module Issues + +### Module Not Found + +**Error:** `The term 'Connect-MgGraph' is not recognized` + +**Solutions:** +```powershell +# Install module +Install-Module Microsoft.Graph -Scope CurrentUser -Force + +# If already installed, import explicitly +Import-Module Microsoft.Graph + +# Check installation +Get-InstalledModule Microsoft.Graph +``` + +### Module Version Conflicts + +**Error:** `Assembly with same name already loaded` + +**Solutions:** +```powershell +# Remove all versions +Get-Module Microsoft.Graph* | Remove-Module -Force + +# Clear cache +Remove-Item "$env:USERPROFILE\.local\share\powershell\*" -Recurse -Force + +# Reinstall +Install-Module Microsoft.Graph -Force -AllowClobber +``` + +### Exchange Online Connection Failures + +**Error:** `Connecting to remote server failed` + +**Solutions:** +```powershell +# Use modern authentication +Connect-ExchangeOnline -UserPrincipalName admin@tenant.com + +# If MFA issues, use device code +Connect-ExchangeOnline -Device + +# Check WinRM service +Get-Service WinRM | Start-Service +``` + +### Graph API Throttling + +**Error:** `429 Too Many Requests` + +**Solutions:** +1. Implement retry logic: + ```powershell + $retryCount = 0 + $maxRetries = 3 + do { + try { + $result = Get-MgUser -All + break + } catch { + if ($_.Exception.Response.StatusCode -eq 429) { + $retryAfter = $_.Exception.Response.Headers['Retry-After'] + Start-Sleep -Seconds ([int]$retryAfter + 5) + $retryCount++ + } else { throw } + } + } while ($retryCount -lt $maxRetries) + ``` +2. Reduce batch sizes +3. Use delta queries for incremental updates + +--- + +## Permission Problems + +### Insufficient Privileges for User Creation + +**Error:** `Insufficient privileges to complete the operation` + +**Required Permissions:** +- User Administrator role +- OR User.ReadWrite.All Graph permission + +**Solutions:** +1. Verify role assignment: + ```powershell + Get-MgDirectoryRoleMember -DirectoryRoleId (Get-MgDirectoryRole -Filter "displayName eq 'User Administrator'").Id + ``` +2. Request role assignment or PIM activation +3. Use service principal with appropriate permissions + +### Cannot Modify Another Admin + +**Error:** `Cannot update privileged user` + +**Cause:** Attempting to modify user with equal or higher privileges. + +**Solutions:** +1. Use account with higher privilege level +2. Global Admin required to modify other Global Admins +3. Remove target's admin role first (if appropriate) + +### Application Permission vs Delegated + +**Issue:** Script works interactively but fails in automation + +**Solution:** Use application permissions for automation: +```powershell +# Application authentication (daemon/service) +$clientId = "app-id" +$tenantId = "tenant-id" +$clientSecret = ConvertTo-SecureString "secret" -AsPlainText -Force +$credential = New-Object System.Management.Automation.PSCredential($clientId, $clientSecret) + +Connect-MgGraph -ClientSecretCredential $credential -TenantId $tenantId +``` + +--- + +## License Assignment Failures + +### "Usage location must be specified" + +**Error:** `License assignment failed because UsageLocation is not set` + +**Solution:** +```powershell +# Set usage location before license assignment +Update-MgUser -UserId user@tenant.com -UsageLocation "US" + +# Then assign license +$license = @{ + AddLicenses = @(@{SkuId = "sku-id"}) + RemoveLicenses = @() +} +Set-MgUserLicense -UserId user@tenant.com -BodyParameter $license +``` + +### "No available licenses" + +**Error:** `License quota exceeded` + +**Solutions:** +1. Check available licenses: + ```powershell + Get-MgSubscribedSku | Select-Object SkuPartNumber, + @{N='Available';E={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}} + ``` +2. Remove licenses from inactive users +3. Purchase additional licenses + +### Conflicting Service Plans + +**Error:** `Conflicting service plans` + +**Cause:** User has license with overlapping services. + +**Solution:** +```powershell +# Check current licenses +Get-MgUserLicenseDetail -UserId user@tenant.com | + Select-Object SkuPartNumber, @{N='Plans';E={$_.ServicePlans.ServicePlanName}} + +# Remove conflicting license first +$remove = @{ + AddLicenses = @() + RemoveLicenses = @("conflicting-sku-id") +} +Set-MgUserLicense -UserId user@tenant.com -BodyParameter $remove + +# Then add new license +``` + +--- + +## DNS and Domain Issues + +### Domain Verification Failing + +**Error:** `Domain verification record not found` + +**Solutions:** +1. Verify TXT record: + ```bash + nslookup -type=TXT domain.com + ``` +2. Check for typos in record value +3. Wait 24-48 hours for propagation +4. Try alternate verification (MX record) + +### MX Record Not Resolving + +**Error:** `Mail flow disrupted` + +**Diagnostic:** +```bash +nslookup -type=MX domain.com +# Should return: domain.com.mail.protection.outlook.com +``` + +**Solutions:** +1. Verify MX record points to `domain.com.mail.protection.outlook.com` +2. Priority should be 0 or lowest number +3. Remove conflicting MX records + +### SPF Record Issues + +**Error:** `SPF validation failed` + +**Correct SPF:** +``` +v=spf1 include:spf.protection.outlook.com -all +``` + +**Common Mistakes:** +- Multiple SPF records (only one allowed) +- Missing `-all` or using `~all` +- Too many DNS lookups (max 10) + +**Check:** +```bash +nslookup -type=TXT domain.com | findstr spf +``` + +--- + +## Conditional Access Lockouts + +### Locked Out by MFA Policy + +**Symptoms:** Cannot sign in, MFA loop + +**Immediate Actions:** +1. Use emergency access account +2. Sign in from trusted location/device +3. Contact admin to temporarily exclude user + +**Resolution:** +```powershell +# Add user to CA exclusion group +$group = Get-MgGroup -Filter "displayName eq 'CA-Excluded-Users'" +New-MgGroupMember -GroupId $group.Id -DirectoryObjectId (Get-MgUser -UserId user@tenant.com).Id +``` + +### Policy Conflicts + +**Symptoms:** Unexpected blocks, inconsistent behavior + +**Diagnostic:** +1. Check sign-in logs: Azure AD > Sign-in logs +2. Filter by user, check "Conditional Access" tab +3. Review which policies applied/failed + +**Resolution:** +1. Review all policies in report-only mode +2. Check for conflicting conditions +3. Ensure proper policy ordering + +### Break-Glass Procedure + +**When to use:** Complete admin lockout + +**Steps:** +1. Sign in with emergency access account +2. Go to Azure AD > Security > Conditional Access +3. Set all policies to "Report-only" +4. Diagnose and fix root cause +5. Re-enable policies gradually + +--- + +## Mailbox Issues + +### Mailbox Not Provisioning + +**Error:** `Mailbox doesn't exist` + +**Causes:** +- License not assigned +- License assignment pending +- User created without Exchange license + +**Solutions:** +1. Verify license: + ```powershell + Get-MgUserLicenseDetail -UserId user@tenant.com + ``` +2. Wait 5-10 minutes after license assignment +3. Force mailbox provisioning: + ```powershell + # Reassign license + Set-MgUserLicense -UserId user@tenant.com -BodyParameter @{ + RemoveLicenses = @("sku-id") + AddLicenses = @() + } + Start-Sleep -Seconds 60 + Set-MgUserLicense -UserId user@tenant.com -BodyParameter @{ + AddLicenses = @(@{SkuId = "sku-id"}) + RemoveLicenses = @() + } + ``` + +### Mailbox Size Limit + +**Error:** `Mailbox quota exceeded` + +**Solutions:** +```powershell +# Check current quota +Get-Mailbox user@tenant.com | Select-Object ProhibitSendQuota, ProhibitSendReceiveQuota + +# Increase quota (if license allows) +Set-Mailbox user@tenant.com -ProhibitSendQuota 99GB -ProhibitSendReceiveQuota 100GB + +# Or enable archive +Enable-Mailbox user@tenant.com -Archive +``` + +### Mail Flow Issues + +**Diagnostic:** +```powershell +# Test mail flow +Test-Mailflow -TargetEmailAddress external@gmail.com + +# Check mail flow rules +Get-TransportRule | Where-Object {$_.State -eq 'Enabled'} | Select-Object Name, Priority, Conditions + +# Check connectors +Get-InboundConnector +Get-OutboundConnector +``` + +**Common Fixes:** +1. Check transport rules for blocks +2. Verify connector configuration +3. Check ATP/spam policies +4. Review quarantine for false positives diff --git a/engineering-team/ms365-tenant-manager/powershell_generator.py b/engineering-team/ms365-tenant-manager/scripts/powershell_generator.py similarity index 100% rename from engineering-team/ms365-tenant-manager/powershell_generator.py rename to engineering-team/ms365-tenant-manager/scripts/powershell_generator.py diff --git a/engineering-team/ms365-tenant-manager/tenant_setup.py b/engineering-team/ms365-tenant-manager/scripts/tenant_setup.py similarity index 100% rename from engineering-team/ms365-tenant-manager/tenant_setup.py rename to engineering-team/ms365-tenant-manager/scripts/tenant_setup.py diff --git a/engineering-team/ms365-tenant-manager/user_management.py b/engineering-team/ms365-tenant-manager/scripts/user_management.py similarity index 100% rename from engineering-team/ms365-tenant-manager/user_management.py rename to engineering-team/ms365-tenant-manager/scripts/user_management.py