├── Azure AD ├── Baseline-ConditionalAccessPolicies.ps1 ├── Disable-MfaForLicensedUsers.ps1 ├── Enable-GroupsCreationForAllUsers.ps1 ├── Enable-MfaForLicensedUsers.ps1 ├── Enable-SensitivityLabelsForGroups.ps1 ├── Install-BaselineCAPolicies.ps1 ├── Install-DataProtectionCAPolicies.ps1 ├── Install-GuestCAPolicies.ps1 ├── Install-ITPMBaselineCAPolicies.ps1 ├── Limit-GroupsCreation.ps1 ├── Readme.md └── Set-GroupExpirationPolicy.ps1 ├── Compliance ├── Enable-SensitivityLabelsForGroups.ps1 ├── Install-DataRetentionPolicies.ps1 ├── Install-EmailRetentionPolicy.ps1 ├── Install-SensitivityLabels.ps1 ├── Install-TeamsRetentionPolicies.ps1 ├── Limit-GroupsCreation.ps1 └── readme.md ├── DataProtectionScripts.zip ├── Exchange Online ├── Advanced-TenantConfig.ps1 ├── Block-ConsumerStorageOWA.ps1 ├── Block-UnmanagedDownload.ps1 ├── Configure-Auditing.ps1 ├── Customize-MessageEncryption.ps1 ├── Disable-Forwarding.ps1 ├── Disable-SharedMbxSignOn.ps1 ├── Install-EXOCustomProtection.ps1 ├── Install-EXOStandardProtection.ps1 ├── README.md ├── Set-DeletedItemsRetention.ps1 ├── Setup-ArchiveLegalHold.ps1 └── Setup-DKIM.ps1 ├── Incident Response ├── Export-ActivityByIPAddress.ps1 ├── Export-ActivityByUser.ps1 ├── Export-PrivilegedUserActions.ps1 ├── Export-PrivilegedUserSignIn.ps1 ├── Export-SignInByIPAddress.ps1 ├── Export-SignInByUser.ps1 ├── Install-AzureADProtectionAlerts.ps1 ├── ReadMe.md ├── Remediate-CompromisedUser.ps1 ├── Start-AzureADIRCollection.ps1 ├── Start-UnifiedAuditLogIRCollection.ps1 └── permissiontable.csv ├── LICENSE ├── Microsoft 365 Setup Guide.onepkg ├── README.md ├── Setup Intune ├── Export-ADMX.ps1 ├── Export-AppConfiguration.ps1 ├── Export-AppProtection.ps1 ├── Export-Applications.ps1 ├── Export-Compliance.ps1 ├── Export-DeviceConfiguration.ps1 ├── Export-EndpointSecurity.ps1 ├── Get-DeviceEnrollmentRestrictions.ps1 ├── Import-AppConfiguration.ps1 ├── Import-AppProtection.ps1 ├── Import-Applications.ps1 ├── Import-Compliance.ps1 ├── Import-DeviceConfiguration.ps1 ├── Import-EndpointSecurity.ps1 ├── Install-BYODMobileDeviceProfiles.ps1 ├── Install-MamAndMdmPolicies.ps1 ├── OLD_Import-MAMPolicy.ps1 ├── OLD_Setup-Intune.ps1 ├── README.md ├── Set-DeviceEnrollmentRestrictions.ps1 ├── Set-MDMAuthority.ps1 └── Setup-Intune.ps1 ├── ThreatDefenseScripts.zip ├── Windows 10 ├── Install-EndpointSecuritySample.ps1 ├── Install-LegacyProfiles.ps1 ├── Install-OneDriveProfile.ps1 ├── Install-Windows10SecurityProfiles.ps1 ├── Install-WindowsSecurityProfiles.ps1 ├── JSON │ ├── Export-AppConfiguration.ps1 │ ├── Export-AppProtection.ps1 │ ├── Export-Compliance.ps1 │ ├── Export-DeviceConfiguration.ps1 │ ├── Export-EndpointSecurity.ps1 │ ├── Export-SoftwareUpdates.ps1 │ ├── Import-AppConfiguration.ps1 │ ├── Import-AppProtection.ps1 │ ├── Import-Compliance.ps1 │ ├── Import-DeviceConfiguration.ps1 │ ├── Import-EndpointSecurity.ps1 │ ├── Win10-ADMX │ │ └── OneDriveClientConfig.json │ ├── Win10-Apps │ │ ├── ChromiumEdge.json │ │ ├── Office32.json │ │ └── Office64.json │ ├── Win10-Compliance │ │ ├── [ITPM Baseline] Windows 10_ Delayed.json │ │ └── [ITPM Baseline] Windows 10_ Immediate.json │ ├── Win10-DeviceConfig │ │ ├── [ITPM Corporate] Windows 10_ Allow Autopilot Reset.json │ │ ├── [ITPM Corporate] Windows 10_ Disable first sign-in animation.json │ │ ├── [ITPM Corporate] Windows 10_ MDMWinsOverGP.json │ │ ├── [ITPM Legacy] Windows 10_ Baseline Device Restrictions.json │ │ └── [ITPM Legacy] Windows 10_ Baseline Endpoint Protection.json │ ├── Win10-EndpointSecurity │ │ ├── [ITPM Corporate] ASR Rules Audit.json │ │ ├── [ITPM Corporate] ASR Rules Enable.json │ │ ├── [ITPM Corporate] BitLocker silent enablement.json │ │ ├── [ITPM Corporate] BitLocker with removable drive protection.json │ │ ├── [ITPM Corporate] Defender Antivirus.json │ │ ├── [ITPM Corporate] Optional_ Block removable storage.json │ │ ├── [ITPM Corporate] Windows Firewall.json │ │ ├── [ITPM Corporate] Windows Hello for Business.json │ │ ├── [ITPM Corporate] Windows Security Center.json │ │ ├── [ITPM Enterprise] SmartLocker Audit.json │ │ ├── [ITPM Enterprise] SmartLocker Enable.json │ │ └── [ITPM Enterprise] Windows Credential Guard.json │ ├── Win10-SecurityBaselines │ │ ├── [ITPM Corporate] Edge Chromium baseline.json │ │ └── [ITPM Corporate] Modified security baseline.json │ ├── Win10-Update │ │ ├── [ITPM Corporate] Default Update Ring.json │ │ └── [ITPM Corporate] Delayed Update Ring.json │ ├── Win10-WIP │ │ ├── [ITPM Optional] WIP-MAM without enrollment.json │ │ └── [ITPM Optional] WIP-MDM with enrollment.json │ └── readme.md └── readme.md ├── ZeroTrustScripts.zip └── mggraph-samples ├── Install-SmbAdmxConfigs.ps1 ├── Install-SmbAppProtectionPolicies.ps1 ├── Install-SmbCompliancePolicies.ps1 ├── Install-SmbConditionalAccessPolicies.ps1 ├── Install-SmbDeviceConfigs.ps1 ├── Install-SmbDeviceFilters.ps1 ├── Install-SmbSecurityProfile.ps1 └── Install-SmbSettingsCatalogBaselines.ps1 /Azure AD/Disable-MfaForLicensedUsers.ps1: -------------------------------------------------------------------------------- 1 | 2 | <################################################################################################## 3 | # 4 | .SYNOPSIS 5 | Disable MFA on all licensed user accounts (per-user MFA) 6 | Use this when you want to switch from per-user MFA to Conditional Access for MFA 7 | Conditional Access requires Azure AD Premium P1/P2, EM+S E3/E5 or M365B/E3/35 8 | 9 | You have to connect to Azure AD using Connect-MsolService before running this script: 10 | https://docs.microsoft.com/en-us/powershell/module/msonline/connect-msolservice?view=azureadps-1.0 11 | 12 | Source of script: https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-userstates 13 | 14 | .NOTES 15 | FileName: Disable-MfaForLicensedUsers.ps1 16 | Author: Alex Fields, ITProMentor.com 17 | Created: 02-01-2020 18 | Revised: 02-01-2020 19 | Version: 1.0 20 | 21 | #> 22 | ################################################################################################### 23 | 24 | 25 | 26 | ## To disable only for a specific user: 27 | ## Set-MsolUser -UserPrincipalName user@domain.com -StrongAuthenticationRequirements @() 28 | ## To disable for all users: 29 | ## Get-Msoluser -all | Where-Object {$_.IsLicensed -eq $true} | Set-MsolUser -StrongAuthenticationRequirements @() 30 | 31 | ## Find out who is registered for MFA: 32 | ## Get-Msoluser -all | Where-Object {$_.StrongAuthenticationMethods -like "*"} # Sets the MFA requirement state 33 | function Set-MfaState { 34 | 35 | [CmdletBinding()] 36 | param( 37 | [Parameter(ValueFromPipelineByPropertyName=$True)] 38 | $ObjectId, 39 | [Parameter(ValueFromPipelineByPropertyName=$True)] 40 | $UserPrincipalName, 41 | [ValidateSet("Disabled","Enabled","Enforced")] 42 | $State 43 | ) 44 | 45 | Process { 46 | Write-Verbose ("Setting MFA state for user '{0}' to '{1}'." -f $ObjectId, $State) 47 | $Requirements = @() 48 | if ($State -ne "Disabled") { 49 | $Requirement = 50 | [Microsoft.Online.Administration.StrongAuthenticationRequirement]::new() 51 | $Requirement.RelyingParty = "*" 52 | $Requirement.State = $State 53 | $Requirements += $Requirement 54 | } 55 | 56 | Set-MsolUser -ObjectId $ObjectId -UserPrincipalName $UserPrincipalName ` 57 | -StrongAuthenticationRequirements $Requirements 58 | } 59 | } 60 | 61 | # Disable MFA for all users 62 | Get-MsolUser -All | Set-MfaState -State Disabled # After this has been run, create a Conditional Access policy to replace per-user MFA: # Azure AD > Security > Conditional Access > New policy # Name it GRANT - MFA for users # Select Users and groups > All users (and Exclude any emergency access accounts, other exceptions) # Select Cloud apps and actions > All cloud apps # Do NOT select any Conditions (e.g. unless you want to exclude trusted locations) # Select Access Controls > Grant > Require Multi-factor authentication # Save and enable the policy -------------------------------------------------------------------------------- /Azure AD/Enable-GroupsCreationForAllUsers.ps1: -------------------------------------------------------------------------------- 1 | 2 | <################################################################################################## 3 | # 4 | .SYNOPSIS 5 | This will re-enable creating Microsoft 365 Groups for all users 6 | 7 | You must have the Preview version of the Azure AD PowerShell module: 8 | Uninstall-Module AzureAD 9 | Install-Module AzureADPreview 10 | 11 | Source of script: 12 | https://docs.microsoft.com/en-us/microsoft-365/admin/create-groups/manage-creation-of-groups?view=o365-worldwide 13 | 14 | .NOTES 15 | FileName: Enable-GroupsCreationForAllUsers.ps1 16 | Author: Alex Fields, ITProMentor.com 17 | Created: February 2020 18 | Revised: April 2021 19 | 20 | #> 21 | ################################################################################################### 22 | 23 | Import-Module AzureADPreview -Force 24 | 25 | $GroupName = "" 26 | $AllowGroupCreation = "True" 27 | 28 | 29 | $CheckForGroup = Get-AzureADGroup -All $true | Where-Object DisplayName -eq $GroupName 30 | 31 | if ($CheckForGroup -eq $null -or $CheckForGroup -eq "") { 32 | New-AzureADGroup -DisplayName $GroupName -SecurityEnabled $true -MailEnabled $false -MailNickName sg-GroupCreators 33 | 34 | $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id 35 | if(!$settingsObjectID) 36 | { 37 | $template = Get-AzureADDirectorySettingTemplate | Where-object {$_.displayname -eq "group.unified"} 38 | $settingsCopy = $template.CreateDirectorySetting() 39 | New-AzureADDirectorySetting -DirectorySetting $settingsCopy 40 | $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id 41 | } 42 | 43 | $settingsCopy = Get-AzureADDirectorySetting -Id $settingsObjectID 44 | $settingsCopy["EnableGroupCreation"] = $AllowGroupCreation 45 | 46 | if($GroupName) 47 | { 48 | $settingsCopy["GroupCreationAllowedGroupId"] = (Get-AzureADGroup -SearchString $GroupName).objectid 49 | } else { 50 | $settingsCopy["GroupCreationAllowedGroupId"] = $GroupName 51 | } 52 | Set-AzureADDirectorySetting -Id $settingsObjectID -DirectorySetting $settingsCopy 53 | 54 | (Get-AzureADDirectorySetting -Id $settingsObjectID).Values 55 | 56 | Write-Host 57 | Write-Host "Please add users to the new Security group to enable Groups creation." -ForegroundColor Yellow 58 | Write-Host 59 | Write-Host "Script completed." -ForegroundColor Green 60 | 61 | 62 | } else { 63 | 64 | Write-Host "Security group for Group Creators already exists; no changes will be made." -ForegroundColor Red 65 | Write-Host 66 | Write-Host "Exiting script." -ForegroundColor Red 67 | Write-Host 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /Azure AD/Enable-MfaForLicensedUsers.ps1: -------------------------------------------------------------------------------- 1 | 2 | <################################################################################################## 3 | # 4 | .SYNOPSIS 5 | Enable MFA on all licensed user accounts (per-user MFA) 6 | This method works on all versions of Azure AD / Office 365 7 | If you want to switch from per-user MFA to Conditional Access, see: Disable-MfaForLicensedUsers.ps1 8 | 9 | You have to connect to Azure AD using Connect-MsolService before running this script: 10 | https://docs.microsoft.com/en-us/powershell/module/msonline/connect-msolservice?view=azureadps-1.0 11 | 12 | Source of script: https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-userstates 13 | 14 | .NOTES 15 | FileName: Enable-MfaForLicensedUsers.ps1 16 | Author: Alex Fields, ITProMentor.com 17 | Created: 02-01-2020 18 | Revised: 02-01-2020 19 | Version: 1.0 20 | 21 | #> 22 | ################################################################################################### 23 | 24 | 25 | 26 | $st = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement 27 | $st.RelyingParty = "*" 28 | $st.State = "Enabled" 29 | $sta = @($st) 30 | 31 | Get-Msoluser -all | Where-Object {$_.IsLicensed -eq $true} | Set-MsolUser -StrongAuthenticationRequirements $sta 32 | 33 | ## To disable for a specific user: 34 | ## Set-MsolUser -UserPrincipalName user@domain.com -StrongAuthenticationRequirements @() 35 | ## To disable for all users: 36 | ## Get-Msoluser -all | Where-Object {$_.IsLicensed -eq $true} | Set-MsolUser -StrongAuthenticationRequirements @() 37 | 38 | ## Find out who is registered for MFA: 39 | ## Get-Msoluser -all | Where-Object {$_.StrongAuthenticationMethods -like "*"} -------------------------------------------------------------------------------- /Azure AD/Enable-SensitivityLabelsForGroups.ps1: -------------------------------------------------------------------------------- 1 | <################################################################################################## 2 | # 3 | .SYNOPSIS 4 | This script will enable Sensitivity labels for Groups and Sites: 5 | 6 | .PREREQUISITES 7 | 1. You must install the AzureADPreview PowerShell module (Install-AzureADPreview) 8 | 2. You will also require the Exchange Online V2 module (Install-Module -Name ExchangeOnlineManagement) 9 | 10 | .DETAILS 11 | FileName: Enable-SensitivityLabelsForGroups.ps1 12 | Author: Alex Fields, ITProMentor.com 13 | Created: November 2020 14 | Updated: April 2021 15 | 16 | .NOTES 17 | You will be prompted twice since you must authenticate against both Azure AD and Exchange Online 18 | 19 | #> 20 | ################################################################################################### 21 | 22 | 23 | ## Import the AzureADPreview module 24 | Import-Module AzureADPreview 25 | 26 | ## Connect to Azure AD 27 | Connect-AzureAD 28 | 29 | ## Import the Exchange Online V2 module 30 | Import-Module ExchangeOnlineManagement 31 | 32 | ## Connect to the Security & Compliance center with the EXO V2 module 33 | Connect-IPPSSession 34 | 35 | ## Get the Template ID for Group.Unified 36 | $TemplateId = (Get-AzureADDirectorySettingTemplate | where { $_.DisplayName -eq "Group.Unified" }).Id 37 | $Template = Get-AzureADDirectorySettingTemplate | where -Property Id -Value $TemplateId -EQ 38 | 39 | 40 | ## Create a new settings object based on the template 41 | $Setting = $Template.CreateDirectorySetting() 42 | 43 | ## Enable the unified lables feature for groups 44 | $Setting["EnableMIPLabels"] = "True" 45 | 46 | ## Apply the setting 47 | New-AzureADDirectorySetting -DirectorySetting $Setting 48 | 49 | ## Note: Read the settings for this new object out with the following: 50 | $Setting.Values 51 | 52 | ## Run the following to allow Sensitivity labels to be used with Groups: 53 | Execute-AzureAdLabelSync 54 | 55 | 56 | ## End of script -------------------------------------------------------------------------------- /Azure AD/Install-DataProtectionCAPolicies.ps1: -------------------------------------------------------------------------------- 1 | <################################################################################################## 2 | # 3 | .SYNOPSIS 4 | This script will create the following Data Protection Conditional Access policies in your tenant: 5 | 6 | 1. CA201: Office 365: Require managed apps on iOS & Android (MAM) 7 | 2. CA202: Office 365: Require compliant device for iOS & Android (MDM) 8 | 3. CA203: Office 365: Require compliant device for desktop apps on Windows & macOS 9 | 4. CA204: Office 365: Prevent web downloads on unmanaged devices 10 | 11 | .NOTES 12 | 1. You may need to disable the 'Security defaults' first. See https://aka.ms/securitydefaults 13 | 2. None of the policies created by this script will be enabled by default. 14 | 3. Before enabling policies, you should notify end users about the expected impacts 15 | 4. Be sure to populate the security group 'sg-Exclude from CA' with at least one admin account for emergency access 16 | 5. To install the Azure AD Preview PowerShell module use: Install-Module AzureADPreview -AllowClobber 17 | 18 | .DETAILS 19 | FileName: Install-DataProtectionCAPolicies.ps1 20 | Author: Alex Fields, ITProMentor.com 21 | Created: June 2021 22 | Updated: January 2022 23 | 24 | #> 25 | ################################################################################################### 26 | 27 | Import-Module AzureADPreview 28 | Connect-AzureAD 29 | 30 | ## Check for the existence of the "Exclude from CA" security group, and create the group if it does not exist 31 | 32 | $ExcludeCAGroupName = "sgu-Exclude From CA" 33 | $ExcludeCAGroup = Get-AzureADGroup -All $true | Where-Object DisplayName -eq $ExcludeCAGroupName 34 | 35 | if ($ExcludeCAGroup -eq $null -or $ExcludeCAGroup -eq "") { 36 | New-AzureADGroup -DisplayName $ExcludeCAGroupName -SecurityEnabled $true -MailEnabled $false -MailNickName sgu-ExcludeFromCA 37 | $ExcludeCAGroup = Get-AzureADGroup -All $true | Where-Object DisplayName -eq $ExcludeCAGroupName 38 | } 39 | else { 40 | Write-Host "Exclude from CA group already exists" 41 | } 42 | 43 | 44 | ######################################################## 45 | ## 1. 46 | ## CA201: Require managed apps on iOS & Android (MAM) 47 | 48 | ## This policy enables MAM enforcement for iOS and Android devices 49 | ## MAM NOTES: 50 | ## 1. End-users will not be able to access company data from built-in browser or mail apps for iOS or Android; they must use approved apps (e.g. Outlook, Edge) 51 | ## 2. You must also deploy App protection policies in Microsoft Endpoint Manager for this policy to be most effective 52 | ## 2. Android and iOS users must have the Authenticator app configured, and Android users must also download the Company Portal app 53 | 54 | $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet 55 | $conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition 56 | $conditions.Applications.IncludeApplications = "Office365" 57 | $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition 58 | $conditions.Users.IncludeUsers = "All" 59 | $conditions.Users.ExcludeUsers = "GuestsOrExternalUsers" 60 | $conditions.Users.ExcludeGroups = $ExcludeCAGroup.ObjectId 61 | $conditions.Platforms = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition 62 | $conditions.Platforms.IncludePlatforms = @('Android', 'IOS') 63 | $controls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls 64 | $controls._Operator = "OR" 65 | $controls.BuiltInControls = @('ApprovedApplication', 'CompliantApplication') 66 | 67 | New-AzureADMSConditionalAccessPolicy -DisplayName "CA201: O365: Require managed apps on iOS & Android (MAM)" -State "Disabled" -Conditions $conditions -GrantControls $controls 68 | 69 | ######################################################## 70 | ## 2. 71 | ## CA202: Require compliant device for mobile apps on iOS & Android (MDM) 72 | 73 | ## [OPTIONAL POLICY] Enforces MDM compliance for client app access on iOS and Android devices (i.e. Company-owned devices) 74 | ## MDM NOTES: 75 | ## 1. For iOS: Configure Apple enrollment certificate, and optionally connect Apple Business Manager (company-owned) 76 | ## 2. For Android: Link your Managed Google Play account, and optionally configure corporate-owned dedicated or fully managed devices 77 | ## 3. Personal devices: Both iOS and Android users should download the Authenticator app, and the Company Portal app to sign-in 78 | 79 | $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet 80 | $conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition 81 | $conditions.Applications.IncludeApplications = "Office365" 82 | $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition 83 | $conditions.Users.IncludeUsers = "All" 84 | $conditions.Users.ExcludeUsers = "GuestsOrExternalUsers" 85 | $conditions.Users.ExcludeGroups = $ExcludeCAGroup.ObjectId 86 | $conditions.Platforms = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition 87 | $conditions.Platforms.IncludePlatforms = @('Android', 'IOS') 88 | $conditions.ClientAppTypes = @('MobileAppsAndDesktopClients') 89 | $controls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls 90 | $controls._Operator = "OR" 91 | $controls.BuiltInControls = @('CompliantDevice') 92 | 93 | New-AzureADMSConditionalAccessPolicy -DisplayName "CA202: O365: Require compliant device for mobile apps on iOS & Android (MDM)" -State "Disabled" -Conditions $conditions -GrantControls $controls 94 | 95 | ######################################################## 96 | ## 3. 97 | ## CA203: Require compliant device for desktop clients on Windows & macOS 98 | 99 | ## This policy enforces device compliance (or Hybrid Azure AD join) for these platforms: Windows, macOS 100 | ## NOTES: 101 | ## 1. End-users must enroll their devices with Intune before enabling this policy 102 | ## 2. Azure AD joined or Hybrid Joined devices will be managed without taking additional action 103 | ## 3. Users with personal devices should use the Company Portal app to enroll 104 | ## 4. This policy blocks unmanaged device access from desktop client apps (e.g. Outlook, OneDrive, etc.) 105 | ## 5. Optionally, you may add 'Browser' to the ClientAppTypes condition in lieu of the block web downloads policy (SESSION policy) 106 | 107 | $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet 108 | $conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition 109 | $conditions.Applications.IncludeApplications = "Office365" 110 | $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition 111 | $conditions.Users.IncludeUsers = "All" 112 | $conditions.Users.ExcludeUsers = "GuestsOrExternalUsers" 113 | $conditions.Users.ExcludeGroups = $ExcludeCAGroup.ObjectId 114 | $conditions.Platforms = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition 115 | $conditions.Platforms.IncludePlatforms = @('Windows', 'macOS') 116 | $conditions.ClientAppTypes = @('MobileAppsAndDesktopClients') 117 | $controls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls 118 | $controls._Operator = "OR" 119 | $controls.BuiltInControls = @('DomainJoinedDevice', 'CompliantDevice') 120 | 121 | New-AzureADMSConditionalAccessPolicy -DisplayName "CA203: O365: Require compliant device for desktop clients on Windows and macOS" -State "Disabled" -Conditions $conditions -GrantControls $controls 122 | 123 | ######################################################## 124 | ## 4. 125 | ## CA204: Prevent web downloads on unmanaged devices 126 | 127 | ## [OPTIONAL POLICY] This policy prevents web downloads from unmanaged devices and unmanaged web browsers 128 | ## Policy NOTES: 129 | ## 1. You must take additional action in Exchange Online and SharePoint Online to complete the set up for this policy to take effect 130 | ## 2. See my Conditional Access Best Practices guide for more details on those additional steps 131 | ## 3. Unmanaged browsers (e.g. Firefox) will also be impacted by this policy, even on managed devices 132 | ## 4. End users should be advised to use Edge (Chromium version) with Office 365 133 | 134 | $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet 135 | $conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition 136 | $conditions.Applications.IncludeApplications = "Office365" 137 | $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition 138 | $conditions.Users.IncludeUsers = "All" 139 | $conditions.Users.ExcludeUsers = "GuestsOrExternalUsers" 140 | $conditions.Users.ExcludeGroups = $ExcludeCAGroup.ObjectId 141 | $conditions.ClientAppTypes = @('Browser') 142 | $controls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSessionControls 143 | $controls.ApplicationEnforcedRestrictions = $true 144 | 145 | New-AzureADMSConditionalAccessPolicy -DisplayName "CA204: O365: Prevent web downloads on unmanaged devices" -State "Disabled" -Conditions $conditions -SessionControls $controls 146 | 147 | ######################################################## 148 | 149 | Write-Host "Script completed" -ForegroundColor Cyan 150 | 151 | -------------------------------------------------------------------------------- /Azure AD/Install-GuestCAPolicies.ps1: -------------------------------------------------------------------------------- 1 | <################################################################################################## 2 | #NOTE: This script is legacy, the latest complete baseline is Install-ITPMBaselineCAPolicies.ps1 3 | .SYNOPSIS 4 | This script will create the following optional Conditional Access policies in your tenant: 5 | 6 | 1. CA301: Block guest access to unsupported apps 7 | 2. CA302: Require MFA for guests and external users 8 | 9 | .NOTES 10 | 1. You may need to disable the 'Security defaults' first. See https://aka.ms/securitydefaults 11 | 2. None of the policies created by this script will be enabled by default. 12 | 3. Before enabling policies, you should notify end users about the expected impacts 13 | 4. Be sure to populate the security group 'sg-Exclude from CA' with at least one admin account for emergency access 14 | 15 | .HOW-TO 16 | 1. To install the Azure AD Preview PowerShell module use: Install-Module AzureADPreview -AllowClobber 17 | 2. Run .\Install-GuestCAPolicies.ps1 18 | 19 | .DETAILS 20 | FileName: Install-GuestCAPolicies.ps1 21 | Author: Alex Fields, ITProMentor.com 22 | Created: June 2021 23 | Updated: January 2022 24 | 25 | #> 26 | ################################################################################################### 27 | 28 | 29 | 30 | ## Check for the existence of the "Exclude from CA" security group, and create the group if it does not exist 31 | 32 | $ExcludeCAGroupName = "sgu-Exclude From CA" 33 | $ExcludeCAGroup = Get-AzureADGroup -All $true | Where-Object DisplayName -eq $ExcludeCAGroupName 34 | 35 | if ($ExcludeCAGroup -eq $null -or $ExcludeCAGroup -eq "") { 36 | New-AzureADGroup -DisplayName $ExcludeCAGroupName -SecurityEnabled $true -MailEnabled $false -MailNickName sg-ExcludeFromCA 37 | $ExcludeCAGroup = Get-AzureADGroup -All $true | Where-Object DisplayName -eq $ExcludeCAGroupName 38 | } 39 | else { 40 | Write-Host "Exclude from CA group already exists" 41 | } 42 | 43 | 44 | ######################################################## 45 | ## 1. 46 | ## CA301: Block guest access to unsupported apps 47 | ## This policy blocks guest access to all cloud apps except Office 365 48 | 49 | $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet 50 | $conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition 51 | $conditions.Applications.IncludeApplications = "All" 52 | $conditions.Applications.ExcludeApplications = "Office365" 53 | $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition 54 | $conditions.Users.IncludeUsers = "GuestsOrExternalUsers" 55 | $conditions.Users.ExcludeGroups = $ExcludeCAGroup.ObjectId 56 | $controls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls 57 | $controls._Operator = "OR" 58 | $controls.BuiltInControls = "Block" 59 | 60 | New-AzureADMSConditionalAccessPolicy -DisplayName "CA301: Block guest access to unsupported apps" -State "Disabled" -Conditions $conditions -GrantControls $controls 61 | 62 | ######################################################## 63 | ## 2. 64 | ## CA302: Require MFA for guests and external users 65 | ## This policy requires Multi-factor Authentication for guests 66 | 67 | $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet 68 | $conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition 69 | $conditions.Applications.IncludeApplications = "All" 70 | $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition 71 | $conditions.Users.IncludeUsers = "GuestsOrExternalUsers" 72 | $conditions.Users.ExcludeGroups = $ExcludeCAGroup.ObjectId 73 | $conditions.ClientAppTypes = @('Browser', 'MobileAppsAndDesktopClients') 74 | $controls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls 75 | $controls._Operator = "OR" 76 | $controls.BuiltInControls = "MFA" 77 | 78 | New-AzureADMSConditionalAccessPolicy -DisplayName "CA302: Require MFA for guests and external users" -State "Disabled" -Conditions $conditions -GrantControls $controls 79 | 80 | 81 | ######################################################## 82 | 83 | Write-Host "Script completed" -ForegroundColor Cyan 84 | -------------------------------------------------------------------------------- /Azure AD/Limit-GroupsCreation.ps1: -------------------------------------------------------------------------------- 1 | 2 | <################################################################################################## 3 | # 4 | .SYNOPSIS 5 | Define a security group using the variable $GroupName 6 | This will limit the privilege for creating Office 365 Groups to the specified security group 7 | 8 | You must have the Preview version of the Azure AD PowerShell module: 9 | Uninstall-Module AzureAD 10 | Install-Module AzureADPreview 11 | 12 | Source of script: 13 | https://docs.microsoft.com/en-us/microsoft-365/admin/create-groups/manage-creation-of-groups?view=o365-worldwide 14 | 15 | .NOTES 16 | FileName: Limit-GroupsCreation.ps1 17 | Author: Alex Fields, ITProMentor.com 18 | Created: February 2020 19 | Revised: April 2021 20 | 21 | #> 22 | ################################################################################################### 23 | 24 | Import-Module AzureADPreview -Force 25 | 26 | $GroupName = "sg-Group Creators" 27 | $AllowGroupCreation = "False" 28 | 29 | 30 | $CheckForGroup = Get-AzureADGroup -All $true | Where-Object DisplayName -eq $GroupName 31 | 32 | if ($CheckForGroup -eq $null -or $CheckForGroup -eq "") { 33 | New-AzureADGroup -DisplayName $GroupName -SecurityEnabled $true -MailEnabled $false -MailNickName sg-GroupCreators 34 | 35 | $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id 36 | if(!$settingsObjectID) 37 | { 38 | $template = Get-AzureADDirectorySettingTemplate | Where-object {$_.displayname -eq "group.unified"} 39 | $settingsCopy = $template.CreateDirectorySetting() 40 | New-AzureADDirectorySetting -DirectorySetting $settingsCopy 41 | $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id 42 | } 43 | 44 | $settingsCopy = Get-AzureADDirectorySetting -Id $settingsObjectID 45 | $settingsCopy["EnableGroupCreation"] = $AllowGroupCreation 46 | 47 | if($GroupName) 48 | { 49 | $settingsCopy["GroupCreationAllowedGroupId"] = (Get-AzureADGroup -SearchString $GroupName).objectid 50 | } else { 51 | $settingsCopy["GroupCreationAllowedGroupId"] = $GroupName 52 | } 53 | Set-AzureADDirectorySetting -Id $settingsObjectID -DirectorySetting $settingsCopy 54 | 55 | (Get-AzureADDirectorySetting -Id $settingsObjectID).Values 56 | 57 | Write-Host 58 | Write-Host "Please add users to the new Security group to enable Groups creation." -ForegroundColor Yellow 59 | Write-Host 60 | Write-Host "Script completed." -ForegroundColor Green 61 | 62 | 63 | } else { 64 | 65 | Write-Host "Security group for Group Creators already exists; no changes will be made." -ForegroundColor Red 66 | Write-Host 67 | Write-Host "Exiting script." -ForegroundColor Red 68 | Write-Host 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /Azure AD/Readme.md: -------------------------------------------------------------------------------- 1 | ## Azure AD scripts 2 | 3 | NOTE: ALL SCRIPTS IN THIS DIRECTORY ARE OBSOLETE AND NO LONGER UPDATED. 4 | FOR THE LATEST, PLEASE SEE: https://github.com/vanvfields/Microsoft-365/tree/master/mggraph-samples 5 | -------------------------------------------------------------------------------- /Azure AD/Set-GroupExpirationPolicy.ps1: -------------------------------------------------------------------------------- 1 | 2 | <################################################################################################## 3 | # 4 | .SYNOPSIS 5 | This script checks for and sets the Microsoft 365 Groups expiration policy. 6 | If the policy already exists the script will exit without making changes. 7 | 8 | You have to connect to Azure AD using Connect-AzureAD before running this script: 9 | https://docs.microsoft.com/en-us/powershell/azure/active-directory/install-adv2?view=azureadps-2.0 10 | 11 | Source of script: 12 | https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/groups-lifecycle#powershell-examples 13 | 14 | .NOTES 15 | FileName: Set-GroupExpirationPolicy.ps1 16 | Author: Alex Fields, ITProMentor.com 17 | Created: April 2021 18 | Revised: April 2021 19 | 20 | #> 21 | ################################################################################################### 22 | 23 | 24 | ## Check for Group expiration policy 25 | $CheckPolicy = Get-AzureADMSGroupLifecyclePolicy 26 | 27 | if ($CheckPolicy -eq $null -or $CheckPolicy -eq "") { 28 | 29 | Write-Host 30 | Write-Host "No expiration policy found." -ForegroundColor Yellow 31 | Write-Host 32 | $EmailNotification = Read-Host "Enter the email address for orphaned Group notifications" 33 | Write-Host 34 | $GroupLifetime = Read-Host "Enter the desired lifetime for inactive Groups (in days)" 35 | Write-Host 36 | New-AzureADMSGroupLifecyclePolicy -GroupLifetimeInDays $GroupLifetime -ManagedGroupTypes All -AlternateNotificationEmails $EmailNotification 37 | Write-Host 38 | Write-Host "Script complete" -ForegroundColor Green 39 | Write-Host 40 | } 41 | 42 | else { 43 | 44 | Write-Host 45 | Write-Host "Group expiration policy already exists; no changes will be made." -ForegroundColor Red 46 | Write-Host 47 | $CheckPolicy 48 | Write-Host 49 | Write-Host "Script complete" -ForegroundColor Green 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Compliance/Enable-SensitivityLabelsForGroups.ps1: -------------------------------------------------------------------------------- 1 | <################################################################################################## 2 | # 3 | .SYNOPSIS 4 | This script will enable Sensitivity labels for Groups and Sites: 5 | 6 | .PREREQUISITES 7 | 1. You must install the AzureADPreview PowerShell module (Install-AzureADPreview) 8 | 2. You will also require the Exchange Online V2 module (Install-Module -Name ExchangeOnlineManagement) 9 | 10 | .DETAILS 11 | FileName: Enable-SensitivityLabelsForGroups.ps1 12 | Author: Alex Fields, ITProMentor.com 13 | Created: November 2020 14 | Updated: April 2021 15 | 16 | .NOTES 17 | You will be prompted twice since you must authenticate against both Azure AD and Exchange Online 18 | 19 | #> 20 | ################################################################################################### 21 | 22 | 23 | ## Import the AzureADPreview module 24 | Import-Module AzureADPreview 25 | 26 | ## Connect to Azure AD 27 | Connect-AzureAD 28 | 29 | ## Import the Exchange Online V2 module 30 | Import-Module ExchangeOnlineManagement 31 | 32 | ## Connect to the Security & Compliance center with the EXO V2 module 33 | Connect-IPPSSession 34 | 35 | ## Get the Template ID for Group.Unified 36 | $TemplateId = (Get-AzureADDirectorySettingTemplate | where { $_.DisplayName -eq "Group.Unified" }).Id 37 | $Template = Get-AzureADDirectorySettingTemplate | where -Property Id -Value $TemplateId -EQ 38 | 39 | 40 | ## Create a new settings object based on the template 41 | $Setting = $Template.CreateDirectorySetting() 42 | 43 | ## Enable the unified lables feature for groups 44 | $Setting["EnableMIPLabels"] = "True" 45 | 46 | ## Apply the setting 47 | New-AzureADDirectorySetting -DirectorySetting $Setting 48 | 49 | ## Note: Read the settings for this new object out with the following: 50 | $Setting.Values 51 | 52 | ## Run the following to allow Sensitivity labels to be used with Groups: 53 | Execute-AzureAdLabelSync 54 | 55 | 56 | ## End of script -------------------------------------------------------------------------------- /Compliance/Install-DataRetentionPolicies.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Use this script to deploy a blanket retention policy as described in the Data Protection Starter Kit. 4 | You should be familiar with the regulations and policies applicable to your organization before running this script. 5 | Script provided as-is, use at your own risk. 6 | 7 | .NOTES 8 | 1. You must have the ExchangeOnlineManagement PowerShell module installed in order to run this script. 9 | 2. Connect to the Security & Compliance center using Connect-IPPSSession 10 | 11 | .DETAILS 12 | FileName: Install-DataRetentionPolicies.ps1 13 | Author: Alex Fields, ITProMentor.com 14 | Created: September 2021 15 | Updated: September 2021 16 | 17 | #> 18 | 19 | 20 | #Connect-IPPSSession 21 | 22 | Write-Host 23 | $AskDate = Read-Host "Will your retention policies be based on (1) Date created or (2) Date last modified? Type 1 or 2 and press Enter" 24 | 25 | if ($AskDate -eq "1") { 26 | $ExpirationDateOption = "CreationAgeInDays" 27 | Write-Host 28 | Write-Host "Warning: Retention policies created by this script will be based on date created!" -ForegroundColor Yellow 29 | } elseif ($AskDate -eq "2") { 30 | $ExpirationDateOption = "ModificationAgeInDays" 31 | Write-Host 32 | Write-Host "Warning: Retention policies created by this script will be based on date last modified!" -ForegroundColor Yellow 33 | } else { 34 | Write-Host 35 | Write-Host "Input not recognized. Defaulting to date last modified." -ForegroundColor Yellow 36 | $ExpirationDateOption = "ModificationAgeInDays" 37 | Write-Host 38 | Write-Host "Warning: Retention policies created by this script will be based on date last modified!" -ForegroundColor Yellow 39 | } 40 | 41 | Write-Host 42 | $AskEnable = Read-Host "Do you want the policies to be enabled upon creation? Type Y or N and press Enter" 43 | 44 | if ($AskEnable -eq "y") { 45 | $Enabled = $true 46 | Write-Host 47 | Write-Host "Warning: The policies you create next will be enabled and enforced." -ForegroundColor Yellow 48 | } else { 49 | $Enabled = $false 50 | Write-Host 51 | Write-Host "Warning: The policies you create next will be disabled and will not take effect until you enable them." -ForegroundColor Yellow 52 | } 53 | 54 | Write-Host 55 | $Answer = Read-Host "Do you want to deploy the default User retention policy for Email and OneDrive data? Type Y or N and press Enter" 56 | 57 | if ($Answer -eq "y") { 58 | Write-Host 59 | $Years = Read-Host "Retain Email and OneDrive data for how many years? Enter a value between 1 and 10 and press Enter" 60 | $Duration = 365*$Years 61 | 62 | Write-Host 63 | $AskAction = Read-Host "Do you want to (1) Keep, (2) Keep and Delete, or (3) just Delete? Enter 1, 2, or 3 and press Enter" 64 | if ($AskAction -eq "1") { 65 | 66 | New-RetentionCompliancePolicy -Name "User data retention policy" -ExchangeLocation All -OneDriveLocation All -Enabled $Enabled 67 | New-RetentionComplianceRule -Name "User data retention rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction Keep -Policy "User data retention policy" 68 | Write-Host 69 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 70 | 71 | } elseif ($AskAction -eq "2") { 72 | 73 | New-RetentionCompliancePolicy -Name "User data retention policy" -ExchangeLocation All -OneDriveLocation All -Enabled $Enabled 74 | New-RetentionComplianceRule -Name "User data retention rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction KeepAndDelete -Policy "User data retention policy" 75 | Write-Host 76 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 77 | 78 | } elseif ($AskAction -eq "3") { 79 | 80 | New-RetentionCompliancePolicy -Name "User data deletion policy" -ExchangeLocation All -OneDriveLocation All -Enabled $Enabled 81 | New-RetentionComplianceRule -Name "User data deletion rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction Delete -Policy "User data deletion policy" 82 | Write-Host 83 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 84 | 85 | } else { 86 | Write-Host 87 | Write-Host "Invalid input, no policy will be created." -ForegroundColor Yellow 88 | } 89 | 90 | 91 | } else { 92 | Write-Host 93 | Write-Host "The default User data retention policy will not be deployed." -ForegroundColor Yellow 94 | 95 | } 96 | 97 | Write-Host 98 | $Answer = Read-Host "Do you want to deploy the default Company data retention policy? Type Y or N and press Enter" 99 | 100 | if ($Answer -eq "y") { 101 | Write-Host 102 | $Years = Read-Host "Retain SharePoint and Groups data for how many years? Enter a value between 1 and 10 and press Enter" 103 | 104 | $Duration = 365*$Years 105 | 106 | Write-Host 107 | $AskAction = Read-Host "Do you want to (1) Keep, (2) Keep and Delete, or (3) just Delete? Enter 1, 2, or 3 and press Enter" 108 | 109 | if ($AskAction -eq "1") { 110 | 111 | New-RetentionCompliancePolicy -Name "Company data retention policy" -SharePointLocation All -ModernGroupLocation All -Enabled $Enabled 112 | New-RetentionComplianceRule -Name "Company data retention rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction Keep -Policy "Company data retention policy" 113 | Write-Host 114 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 115 | 116 | } elseif ($AskAction -eq "2") { 117 | 118 | New-RetentionCompliancePolicy -Name "Company data retention policy" -SharePointLocation All -ModernGroupLocation All -Enabled $Enabled 119 | New-RetentionComplianceRule -Name "Company data retention rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction KeepAndDelete -Policy "Company data retention policy" 120 | Write-Host 121 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 122 | 123 | } elseif ($AskAction -eq "3") { 124 | 125 | New-RetentionCompliancePolicy -Name "Company data deletion policy" -SharePointLocation All -ModernGroupLocation All -Enabled $Enabled 126 | New-RetentionComplianceRule -Name "Company data deletion rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction Delete -Policy "Company data deletion policy" 127 | Write-Host 128 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 129 | 130 | } else { 131 | Write-Host 132 | Write-Host "Invalid input, no policy will be created." -ForegroundColor Yellow 133 | 134 | } 135 | 136 | 137 | } else { 138 | Write-Host 139 | Write-Host "The default Company data retention policy will not be deployed." -ForegroundColor Yellow 140 | 141 | } 142 | 143 | Write-Host 144 | Write-Host "Script completed" -ForegroundColor Cyan -------------------------------------------------------------------------------- /Compliance/Install-EmailRetentionPolicy.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Use this script to deploy a blanket retention policy as described in the Data Protection Starter Kit. 4 | You should be familiar with the regulations and policies applicable to your organization before running this script. 5 | Script provided as-is, use at your own risk. 6 | 7 | .NOTES 8 | 1. You must have the ExchangeOnlineManagement PowerShell module installed in order to run this script. 9 | 2. Connect to the Security & Compliance center using Connect-IPPSSession 10 | 11 | .DETAILS 12 | FileName: Install-EmailRetentionPolicy.ps1 13 | Author: Alex Fields, ITProMentor.com 14 | Created: September 2021 15 | Updated: February 2022 16 | 17 | #> 18 | 19 | #Import-Module ExchangeOnlineManagement 20 | #Connect-IPPSSession 21 | 22 | Write-Host 23 | $AskDate = Read-Host "Will your retention policy be based on (1) Date created or (2) Date last modified? Type 1 or 2 and press Enter" 24 | 25 | if ($AskDate -eq "1") { 26 | $ExpirationDateOption = "CreationAgeInDays" 27 | Write-Host 28 | Write-Host "Warning: Retention policies created by this script will be based on date created!" -ForegroundColor Yellow 29 | } elseif ($AskDate -eq "2") { 30 | $ExpirationDateOption = "ModificationAgeInDays" 31 | Write-Host 32 | Write-Host "Warning: Retention policies created by this script will be based on date last modified!" -ForegroundColor Yellow 33 | } else { 34 | Write-Host 35 | Write-Host "Input not recognized. Defaulting to date last modified." -ForegroundColor Yellow 36 | $ExpirationDateOption = "ModificationAgeInDays" 37 | Write-Host 38 | Write-Host "Warning: Retention policies created by this script will be based on date last modified!" -ForegroundColor Yellow 39 | } 40 | 41 | Write-Host 42 | $AskEnable = Read-Host "Do you want the policy to be enabled upon creation? Type Y or N and press Enter" 43 | 44 | if ($AskEnable -eq "y") { 45 | $Enabled = $true 46 | Write-Host 47 | Write-Host "Warning: The policy you create next will be enabled and enforced." -ForegroundColor Yellow 48 | } else { 49 | $Enabled = $false 50 | Write-Host 51 | Write-Host "Warning: The policy you create next will be disabled and will not take effect until you enable them." -ForegroundColor Yellow 52 | } 53 | 54 | 55 | Write-Host 56 | $Years = Read-Host "Retain Email data for how many years? Enter a value between 1 and 10 and press Enter" 57 | $Duration = 365*$Years 58 | 59 | Write-Host 60 | $AskAction = Read-Host "Do you want to (1) Keep, (2) Keep and Delete, or (3) just Delete? Enter 1, 2, or 3 and press Enter" 61 | if ($AskAction -eq "1") { 62 | 63 | New-RetentionCompliancePolicy -Name "Email retention policy" -ExchangeLocation All -Enabled $Enabled 64 | New-RetentionComplianceRule -Name "Email retention rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction Keep -Policy "Email retention policy" 65 | Write-Host 66 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 67 | 68 | } elseif ($AskAction -eq "2") { 69 | 70 | New-RetentionCompliancePolicy -Name "Email retention policy" -ExchangeLocation All -Enabled $Enabled 71 | New-RetentionComplianceRule -Name "Email retention rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction KeepAndDelete -Policy "Email retention policy" 72 | Write-Host 73 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 74 | 75 | } elseif ($AskAction -eq "3") { 76 | 77 | New-RetentionCompliancePolicy -Name "Email deletion policy" -ExchangeLocation All -Enabled $Enabled 78 | New-RetentionComplianceRule -Name "Email deletion rule" -RetentionDuration $Duration -RetentionDurationDisplayHint Years -ExpirationDateOption $ExpirationDateOption -RetentionComplianceAction Delete -Policy "Email deletion policy" 79 | Write-Host 80 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 81 | 82 | } -------------------------------------------------------------------------------- /Compliance/Install-SensitivityLabels.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Use this script to deploy Sensitivity Labels from the Data Protection Starter Kit: 4 | - Non-Business: Use to identify personal data 5 | - Public: Use to identify data explicitly approved for public consumption 6 | - General: Use to identify data that can be shared as needed for business purposes. 7 | - Confidential: Category of labels to identify sensitive data 8 | -Anyone (Not Protected): Use to identify sensitive data which can be shared with approved external parties 9 | -External (Protected): Use to identify and protect sensitive data which can be shared with approved external parties 10 | -Internal (Protected): Use to identify and protect sensitive data which can only be shared internally 11 | -Recipients Only (Protected): Use to encrypt email messges in Outlook with Do Not Forward permissions (recipients cannot forward, copy, or print) 12 | 13 | .NOTES 14 | 1. You must have the AzureADPreview PowerShell module installed in order to run this script. 15 | 2. You must have the ExchangeOnlineManagement PowerShell module installed in order to run this script. 16 | 3. You must enable Sensitivity labels for Groups and Sites in order to run this script. 17 | 4. Reference: https://docs.microsoft.com/en-us/microsoft-365/compliance/sensitivity-labels-teams-groups-sites 18 | 19 | .DETAILS 20 | FileName: Install-SensitivityLabels.ps1 21 | Author: Alex Fields, ITProMentor.com 22 | Created: May 2021 23 | Updated: May 2021 24 | 25 | #> 26 | 27 | 28 | Import-Module AzureADPreview 29 | Connect-AzureAD 30 | 31 | Import-Module ExchangeOnlineManagement 32 | Connect-IPPSSession 33 | 34 | 35 | $CheckLabels = Get-LabelPolicy 36 | 37 | if (!$CheckLabels) { 38 | 39 | ## Install the Non-Business label 40 | $NonBusinessParam=@{ 41 | 'Name' = 'Non-Business'; 42 | 'DisplayName' = 'Non-Business'; 43 | 'Tooltip' = 'Use this classification to identify personal, non-corporate data. This label does not imply privacy.' 44 | } 45 | 46 | New-Label @NonBusinessParam 47 | 48 | ## Install the Public label 49 | $PublicParam=@{ 50 | 'Name' = 'Public'; 51 | 'DisplayName' = 'Public'; 52 | 'Tooltip' = 'Use this classification to identify data that is explicitly approved for general public consumption.'; 53 | 'SiteAndGroupProtectionEnabled' = $true; 54 | 'SiteAndGroupProtectionPrivacy' = 'Public'; 55 | 'SiteAndGroupProtectionAllowAccessToGuestUsers' = $true; 56 | 'SiteAndGroupProtectionAllowEmailFromGuestUsers' = $true; 57 | #'SiteExternalSharingControlType' = "ExternalUserAndGuestSharing"; 58 | 'Comment' = ' ' 59 | } 60 | 61 | New-Label @PublicParam 62 | 63 | ## Install the General label 64 | $GeneralParam=@{ 65 | 'Name' = 'General'; 66 | 'DisplayName' = 'General'; 67 | 'Tooltip' = 'Use this label to identify data that belongs to the Organization, but which may be shared as needed.'; 68 | 'SiteAndGroupProtectionEnabled' = $true; 69 | 'SiteAndGroupProtectionAllowAccessToGuestUsers' = $true; 70 | 'SiteAndGroupProtectionAllowEmailFromGuestUsers' = $true; 71 | #'SiteExternalSharingControlType' = "ExternalUserSharingOnly"; 72 | 'Comment' = ' ' 73 | } 74 | 75 | New-Label @GeneralParam 76 | 77 | ## Install the Confidential label 78 | $ConfidentialParam=@{ 79 | 'Name' = 'Confidential'; 80 | 'DisplayName' = 'Confidential'; 81 | 'Tooltip' = 'Use this classification to identify and protect data which is sensitive, and which should be shared more carefully.'; 82 | 'SiteAndGroupProtectionEnabled' = $true; 83 | 'SiteAndGroupProtectionPrivacy' = 'Private'; 84 | 'SiteAndGroupProtectionAllowAccessToGuestUsers' = $false; 85 | 'SiteAndGroupProtectionAllowEmailFromGuestUsers' = $false; 86 | #'SiteExternalSharingControlType' = "Disabled"; 87 | 'Comment' = ' ' 88 | } 89 | 90 | New-Label @ConfidentialParam 91 | 92 | ## Install sub-labels for Confidential 93 | 94 | ## Install the Anyone (Not Protected) label (No encryption is applied) 95 | 96 | $AnyoneParam=@{ 97 | 'Name' = 'Anyone'; 98 | 'DisplayName' = 'Anyone (Not Protected)'; 99 | 'Tooltip' = 'Use this classification to identify Confidential data that can be shared with approved parties outside the Organization; no encryption is applied.'; 100 | 'ParentID' = 'Confidential'; 101 | 'EncryptionEnabled' = $false; 102 | 'EncryptionProtectionType' = 'RemoveProtection'; 103 | 'ApplyContentMarkingHeaderEnabled' = $true; 104 | 'ApplyContentMarkingHeaderAlignment' = 'Left'; 105 | 'ApplyContentMarkingHeaderText' = 'Confidential (Not Protected)' 106 | } 107 | 108 | New-Label @AnyoneParam 109 | 110 | 111 | ## Install the External (Protected) label 112 | 113 | $RightsDefinition = "VIEW,VIEWRIGHTSDATA,DOCEDIT,EDIT,PRINT,EXTRACT,REPLY,REPLYALL,FORWARD,OBJMODEL" 114 | 115 | $ExternalParam=@{ 116 | 'Name' = 'External'; 117 | 'DisplayName' = 'External (Protected)'; 118 | 'Tooltip' = 'Use this classification to identify and protect Confidential data that can be shared with approved parties outside the Organization.'; 119 | 'ParentID' = 'Confidential'; 120 | 'EncryptionEnabled' = $true; 121 | 'EncryptionProtectionType' = 'Template'; 122 | 'EncryptionRightsDefinitions' = "AuthenticatedUsers"+":"+$RightsDefinition; 123 | 'EncryptionContentExpiredOnDateInDaysOrNever' = 'Never'; 124 | 'EncryptionOfflineAccessDays' = '30'; 125 | 'ApplyContentMarkingHeaderEnabled' = $true; 126 | 'ApplyContentMarkingHeaderAlignment' = 'Left'; 127 | 'ApplyContentMarkingHeaderText' = 'Confidential (External)' 128 | } 129 | 130 | New-Label @ExternalParam 131 | 132 | ## Install the Internal label (Encryption with Co-author permissions for all users in the domain) 133 | 134 | $TenantDomain = (Get-AzureADDomain | Where-Object {$_.isInitial}).name 135 | $RightsDefinition = "VIEW,VIEWRIGHTSDATA,DOCEDIT,EDIT,PRINT,EXTRACT,REPLY,REPLYALL,FORWARD,OBJMODEL" 136 | 137 | $InternalParam=@{ 138 | 'Name' = 'Internal'; 139 | 'DisplayName' = 'Internal (Protected)'; 140 | 'Tooltip' = 'Use this classification to identify and protect Confidential data that should not be shared outside the Organization.'; 141 | 'ParentID' = 'Confidential'; 142 | 'EncryptionEnabled' = $true; 143 | 'EncryptionProtectionType' = 'Template'; 144 | 'EncryptionRightsDefinitions' = $TenantDomain+":"+$RightsDefinition; 145 | 'EncryptionContentExpiredOnDateInDaysOrNever' = 'Never'; 146 | 'EncryptionOfflineAccessDays' = '30'; 147 | 'ApplyContentMarkingHeaderEnabled' = $true; 148 | 'ApplyContentMarkingHeaderAlignment' = 'Left'; 149 | 'ApplyContentMarkingHeaderText' = 'Confidential (Internal)' 150 | 151 | } 152 | 153 | New-Label @InternalParam 154 | 155 | 156 | ## Install the Recipients Only label (Applies Do Not Forward template in Outlook) 157 | $DNFParam=@{ 158 | 'Name' = 'Recipients Only'; 159 | 'DisplayName' = 'Recipients Only (Protected)'; 160 | 'Tooltip' = 'Use this classification to protect Confidential messages in Outlook. Recipients cannot forward, copy, or print the message.'; 161 | 'ParentID' = 'Confidential'; 162 | 'EncryptionEnabled' = $true; 163 | 'EncryptionProtectionType' = 'UserDefined'; 164 | 'EncryptionDoNotForward' = $true 165 | } 166 | 167 | New-Label @DNFParam 168 | 169 | 170 | Write-Host 171 | Write-Host "The default labels have been installed." -ForegroundColor Cyan 172 | Write-Host 173 | $Publish = Read-Host "Do you want to publish the labels to all users? Type Y or N and press Enter" 174 | 175 | if ($Publish = 'y') { 176 | 177 | 178 | ## Install a label policy to publish the labels 179 | 180 | 181 | $PolicyJSON = @" 182 | 183 | { 184 | "requiredowngradejustification": true, 185 | "mandatory": false, 186 | "siteandgroupmandatory": false, 187 | "siteandgroupdefaultlabelid": "" 188 | } 189 | 190 | "@ 191 | 192 | 193 | New-LabelPolicy -Name "Default classification labels" -Labels "Non-Business","Public","General","Confidential","Anyone","External","Internal","Recipients Only" -ExchangeLocation All -Settings $PolicyJSON 194 | Write-Host 195 | Write-Host 'Default labels have been added and published to all users in the tenant.' -ForegroundColor Cyan 196 | Write-Host 197 | Write-Host 'Script completed' -ForegroundColor Cyan 198 | Write-Host 199 | } 200 | 201 | else { 202 | 203 | Write-Host 204 | Write-Host "Labels will not be published at this time. You must publish labels before they can be applied to content." -ForegroundColor Yellow 205 | 206 | } 207 | 208 | } 209 | 210 | else { 211 | Write-Host 212 | Write-Host 'Labels are already deployed in this organization. No changes have been made.' -ForegroundColor Yellow 213 | Write-Host 214 | Write-Host 'Script completed' -ForegroundColor Cyan 215 | Write-Host 216 | } 217 | 218 | 219 | <# 220 | .NOTES 221 | At the time of writing this script, the external sharing settings for sites are not functioning correctly when deployed via PowerShell. 222 | 223 | Therefore I have commented out the parameters for now, until Microsoft fixes it. 224 | 225 | It should be as follows: 226 | 227 | SiteExternalSharingControlType: 228 | Anonymous/Anyone links = ExternalUserAndGuestSharing 229 | New and existing guests = ExternalUserSharingOnly 230 | Existing guests only = ExistingExternalUserSharingOnly 231 | Only in the organization = Disabled 232 | 233 | 234 | #> -------------------------------------------------------------------------------- /Compliance/Install-TeamsRetentionPolicies.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Use this script to deploy a blanket retention policy as described in the Data Protection Starter Kit. 4 | You should be familiar with the regulations and policies applicable to your organization before running this script. 5 | Script provided as-is, use at your own risk. 6 | 7 | .NOTES 8 | 1. You must have the ExchangeOnlineManagement PowerShell module installed in order to run this script. 9 | 2. Connect to the Security & Compliance center using Connect-IPPSSession 10 | 11 | .DETAILS 12 | FileName: Install-TeamsRetentionPolicies.ps1 13 | Author: Alex Fields, ITProMentor.com 14 | Created: September 2021 15 | Updated: September 2021 16 | 17 | #> 18 | 19 | 20 | #Connect-IPPSSession 21 | 22 | Write-Host 23 | $AskEnable = Read-Host "Do you want the policies to be enabled upon creation? Type Y or N and press Enter" 24 | 25 | if ($AskEnable -eq "y") { 26 | $Enabled = $true 27 | Write-Host 28 | Write-Host "Warning: The policies you create next will be enabled and enforced." -ForegroundColor Yellow 29 | } else { 30 | $Enabled = $false 31 | Write-Host 32 | Write-Host "Warning: The policies you create next will be disabled and will not take effect until you enable them." -ForegroundColor Yellow 33 | } 34 | 35 | Write-Host 36 | $Answer = Read-Host "Do you want to deploy the default retention policy for Teams chats? Type Y or N and press Enter" 37 | 38 | if ($Answer -eq "y") { 39 | Write-Host 40 | $Days = Read-Host "Retain Teams chat messages for how many days? Enter a value up to 3650 and press Enter" 41 | 42 | Write-Host 43 | $AskAction = Read-Host "Do you want to (1) Keep, (2) Keep and Delete, or (3) just Delete? Enter 1, 2, or 3 and press Enter" 44 | if ($AskAction -eq "1") { 45 | 46 | New-RetentionCompliancePolicy -Name "Teams chats retention policy" -TeamsChatLocation All -Enabled $Enabled 47 | New-RetentionComplianceRule -Name "Teams chats retention rule" -RetentionDuration $Days -RetentionComplianceAction Keep -Policy "Teams chats retention policy" 48 | Write-Host 49 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 50 | 51 | } elseif ($AskAction -eq "2") { 52 | 53 | New-RetentionCompliancePolicy -Name "Teams chats retention policy" -TeamsChatLocation All -Enabled $Enabled 54 | New-RetentionComplianceRule -Name "Teams chats retention rule" -RetentionDuration $Days -RetentionComplianceAction KeepAndDelete -Policy "Teams chats retention policy" 55 | Write-Host 56 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 57 | 58 | } elseif ($AskAction -eq "3") { 59 | 60 | New-RetentionCompliancePolicy -Name "Teams chats deletion policy" -TeamsChatLocation All -Enabled $Enabled 61 | New-RetentionComplianceRule -Name "Teams chats deletion rule" -RetentionDuration $Days -RetentionComplianceAction Delete -Policy "Teams chats deletion policy" 62 | Write-Host 63 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 64 | 65 | } else { 66 | Write-Host 67 | Write-Host "Invalid input, no policy will be created." -ForegroundColor Yellow 68 | } 69 | 70 | 71 | } else { 72 | Write-Host 73 | Write-Host "The default Teams chats policy will not be deployed." -ForegroundColor Yellow 74 | 75 | } 76 | 77 | Write-Host 78 | $Answer = Read-Host "Do you want to deploy the default Teams channels retention policy? Type Y or N and press Enter" 79 | 80 | if ($Answer -eq "y") { 81 | Write-Host 82 | $Days = Read-Host "Retain Teams channel messages for how many days? Enter a value up to 3650 and press Enter" 83 | 84 | Write-Host 85 | $AskAction = Read-Host "Do you want to (1) Keep, (2) Keep and Delete, or (3) just Delete? Enter 1, 2, or 3 and press Enter" 86 | 87 | if ($AskAction -eq "1") { 88 | 89 | New-RetentionCompliancePolicy -Name "Teams channels retention policy" -TeamsChannelLocation All -Enabled $Enabled 90 | New-RetentionComplianceRule -Name "Teams channels retention rule" -RetentionDuration $Days -RetentionComplianceAction Keep -Policy "Teams channels retention policy" 91 | Write-Host 92 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 93 | 94 | } elseif ($AskAction -eq "2") { 95 | 96 | New-RetentionCompliancePolicy -Name "Teams channels retention policy" -TeamsChannelLocation All -Enabled $Enabled 97 | New-RetentionComplianceRule -Name "Teams channels retention rule" -RetentionDuration $Days -RetentionComplianceAction KeepAndDelete -Policy "Teams channels retention policy" 98 | Write-Host 99 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 100 | 101 | } elseif ($AskAction -eq "3") { 102 | 103 | New-RetentionCompliancePolicy -Name "Teams channels deletion policy" -TeamsChannelLocation All -Enabled $Enabled 104 | New-RetentionComplianceRule -Name "Teams channels deletion rule" -RetentionDuration $Days -RetentionComplianceAction Delete -Policy "Teams channels deletion policy" 105 | Write-Host 106 | Write-Host "The policy has been created. Once enabled, it can take up to 24 hours to take effect." -ForegroundColor Green 107 | 108 | } else { 109 | Write-Host 110 | Write-Host "Invalid input, no policy will be created." -ForegroundColor Yellow 111 | 112 | } 113 | 114 | 115 | } else { 116 | Write-Host 117 | Write-Host "The default Teams channels policy will not be deployed." -ForegroundColor Yellow 118 | 119 | } 120 | 121 | Write-Host 122 | Write-Host "Script completed" -ForegroundColor Cyan -------------------------------------------------------------------------------- /Compliance/Limit-GroupsCreation.ps1: -------------------------------------------------------------------------------- 1 | 2 | <################################################################################################## 3 | # 4 | .SYNOPSIS 5 | Define a security group using the variable $GroupName 6 | This will limit the privilege for creating Microsoft 365 Groups to the specified security group 7 | 8 | You must have the Preview version of the Azure AD PowerShell module: 9 | Uninstall-Module AzureAD 10 | Install-Module AzureADPreview 11 | 12 | Source of script: 13 | https://docs.microsoft.com/en-us/microsoft-365/admin/create-groups/manage-creation-of-groups?view=o365-worldwide 14 | 15 | .NOTES 16 | FileName: Limit-GroupsCreation.ps1 17 | Author: Alex Fields, ITProMentor.com 18 | Created: February 2020 19 | Revised: April 2021 20 | 21 | #> 22 | ################################################################################################### 23 | 24 | Import-Module AzureADPreview -Force 25 | 26 | $GroupName = "sg-Group Creators" 27 | $AllowGroupCreation = "False" 28 | 29 | 30 | $CheckForGroup = Get-AzureADGroup -All $true | Where-Object DisplayName -eq $GroupName 31 | 32 | if ($CheckForGroup -eq $null -or $CheckForGroup -eq "") { 33 | New-AzureADGroup -DisplayName $GroupName -SecurityEnabled $true -MailEnabled $false -MailNickName sg-GroupCreators 34 | 35 | $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id 36 | if(!$settingsObjectID) 37 | { 38 | $template = Get-AzureADDirectorySettingTemplate | Where-object {$_.displayname -eq "group.unified"} 39 | $settingsCopy = $template.CreateDirectorySetting() 40 | New-AzureADDirectorySetting -DirectorySetting $settingsCopy 41 | $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id 42 | } 43 | 44 | $settingsCopy = Get-AzureADDirectorySetting -Id $settingsObjectID 45 | $settingsCopy["EnableGroupCreation"] = $AllowGroupCreation 46 | 47 | if($GroupName) 48 | { 49 | $settingsCopy["GroupCreationAllowedGroupId"] = (Get-AzureADGroup -SearchString $GroupName).objectid 50 | } else { 51 | $settingsCopy["GroupCreationAllowedGroupId"] = $GroupName 52 | } 53 | Set-AzureADDirectorySetting -Id $settingsObjectID -DirectorySetting $settingsCopy 54 | 55 | (Get-AzureADDirectorySetting -Id $settingsObjectID).Values 56 | 57 | Write-Host 58 | Write-Host "Please add users to the new Security group to enable Groups creation." -ForegroundColor Yellow 59 | Write-Host 60 | Write-Host "Script completed." -ForegroundColor Green 61 | 62 | 63 | } else { 64 | 65 | Write-Host "Security group for Group Creators already exists; no changes will be made." -ForegroundColor Red 66 | Write-Host 67 | Write-Host "Exiting script." -ForegroundColor Red 68 | Write-Host 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /Compliance/readme.md: -------------------------------------------------------------------------------- 1 | ## Compliance 2 | 3 | These scripts help organizations govern their data using features like Sensitivity labels and Retention policies. 4 |
Enable-SensitivityLabelsForGroups.ps1 - This script will turn on the Groups features for Sensitivity labels 5 |
Install-SensitivityLabels.ps1 - Run this script to import the default sensitivity labels covered in my Data Protection Toolkit 6 |
Install-DataRetentionPolicies.ps1 - Create policies to retain user data (Email and OneDrive) as well as Company data (SharePoint and Groups) 7 |
Install-TeamsRetentionPolicies.ps1 - Create policies for Teams chat and channel messages 8 | -------------------------------------------------------------------------------- /DataProtectionScripts.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vanvfields/Microsoft-365/6be47eaa43899b34594c9c02c3dfd46d765c4d6f/DataProtectionScripts.zip -------------------------------------------------------------------------------- /Exchange Online/Block-ConsumerStorageOWA.ps1: -------------------------------------------------------------------------------- 1 | ## Script by Alex Fields, ITProMentor.com 2 | ## Description: 3 | ## This script will block the ability for users to connect to Consumer cloud storage locations via OWA 4 | ## Prerequisites: 5 | ## The tenant will require any Exchange Online plan 6 | ## Connect to Exchange Online via PowerShell using MFA: 7 | ## https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps 8 | ## WARNING: Script provided as-is. Author is not responsible for its use and application. Use at your own risk. 9 | 10 | $MessageColor = "cyan" 11 | $AssessmentColor = "magenta" 12 | 13 | $OwaPolicy = Get-OwaMailboxPolicy -Identity OwaMailboxPolicy-Default 14 | if ($OwaPolicy.AdditionalStorageProvidersAvailable) { 15 | Write-Host 16 | Write-Host -ForegroundColor $AssessmentColor "Connecting consumer storage locations like GoogleDrive and OneDrive (personal) are currently enabled by the default OWA policy" 17 | Write-Host 18 | $Answer = Read-Host "Do you want to block outside storage locations like GoogleDrive or consumer OneDrive in the default OWA policy? Type Y or N and press Enter to continue" 19 | if ($Answer -eq 'y'-or $Answer -eq 'yes') { 20 | Get-OwaMailboxPolicy | Set-OwaMailboxPolicy -AdditionalStorageProvidersAvailable $False 21 | Write-Host 22 | Write-Host -ForegroundColor $MessageColor "Consumer storage locations like GoogleDrive and OneDrive (personal) are now disabled" 23 | } Else { 24 | Write-Host 25 | Write-Host -ForegroundColor $AssessmentColor "Consumer storage locations like GoogleDrive and OneDrive (personal) have not been disabled" 26 | } 27 | } Else { 28 | Write-Host 29 | Write-Host -ForegroundColor $MessageColor "Consumer storage locations like GoogleDrive and OneDrive (personal) are already disabled" 30 | } 31 | -------------------------------------------------------------------------------- /Exchange Online/Block-UnmanagedDownload.ps1: -------------------------------------------------------------------------------- 1 | ## Script by Alex Fields, ITProMentor.com 2 | ## Description: 3 | ## This script will block attachment downloads on unmanaged devices 4 | ## Prerequisites: 5 | ## The tenant will require any Exchange Online plan and Azure AD Premium P1 or Microsoft 365 Business 6 | ## Connect to Exchange Online via PowerShell using MFA: 7 | ## https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps 8 | ## WARNING: Script provided as-is. Author is not responsible for its use and application. Use at your own risk. 9 | 10 | $MessageColor = "cyan" 11 | $AssessmentColor = "magenta" 12 | 13 | $OwaPolicy = Get-OwaMailboxPolicy -Identity OwaMailboxPolicy-Default 14 | if ($OwaPolicy.ConditionalAccessPolicy -eq 'Off') { 15 | Write-Host 16 | Write-Host -ForegroundColor $AssessmentColor "Attachment download is currently enabled for unmanaged devices by the default OWA policy" 17 | Write-Host 18 | $Answer = Read-Host "Do you want to disable attachment download on unmanaged devices? Type Y or N and press Enter to continue" 19 | if ($Answer -eq 'y'-or $Answer -eq 'yes') { 20 | Get-OwaMailboxPolicy | Set-OwaMailboxPolicy -ConditionalAccessPolicy ReadOnly 21 | Write-Host 22 | Write-Host -ForegroundColor $MessageColor "Attachment download on unmanaged devices is now disabled; please be sure to create a corresponding Conditional Access policy in Azure AD" 23 | } Else { 24 | Write-Host 25 | Write-Host -ForegroundColor $AssessmentColor "Attachment download on unamanged devices has not been disabled" 26 | } 27 | } Else { 28 | Write-Host 29 | Write-Host -ForegroundColor $MessageColor "Attachment download on unmanaged devices is already disabled; please be sure there is a corresponding Conditional Access policy present in Azure AD" 30 | } 31 | 32 | 33 | ## NOTE: You must implement this policy in conjunction with a corresponding Conditional access policy in Azure AD 34 | ## As of today this process cannot be scripted (in a supported way) as Conditional Access is not exposed via the Graph API 35 | ## To create the policy from Azure AD > Conditional Access: 36 | ## Name the policy "Block attachment download in OWA on unmanaged devices" 37 | ## Target the appropriate user groups (or All users) 38 | ## Target Exchange Online 39 | ## Use the Session Control called "Enforce app restricitons" 40 | ## Save and enable the policy 41 | 42 | -------------------------------------------------------------------------------- /Exchange Online/Configure-Auditing.ps1: -------------------------------------------------------------------------------- 1 | ## Script by Alex Fields, ITProMentor.com 2 | ## Description: 3 | ## This script configures auditing for Exchange Online 4 | ## Reference: https://docs.microsoft.com/en-us/exchange/policy-and-compliance/mailbox-audit-logging/enable-or-disable?view=exchserver-2019 5 | ## Prerequisites: 6 | ## The tenant will need any Exchange Online plan 7 | ## Connect to Exchange Online via PowerShell using MFA: https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/clconnect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps 8 | ## WARNING: Script provided as-is. Author is not responsible for its use and application. Use at your own risk. 9 | 10 | $MessageColor = "cyan" 11 | $AssessmentColor = "magenta" 12 | 13 | ## Enable Unified Audit Log Search: 14 | $AuditLogConfig = Get-AdminAuditLogConfig 15 | if ($AuditLogConfig.UnifiedAuditLogIngestionEnabled) { 16 | Write-Host 17 | Write-Host -ForegroundColor $MessageColor "Unified Audit Log Search is already enabled" 18 | } else { 19 | Write-Host 20 | Write-Host -ForegroundColor $AssessmentColor "Unified Audit Log is not enabled" 21 | Write-Host 22 | $Answer = Read-Host "Do you want to enable the Unified Audit Log now? Type Y or N and press Enter to continue" 23 | if ($Answer -eq 'y' -or $Answer -eq 'yes') { 24 | Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true 25 | Write-Host 26 | Write-Host -ForegroundColor $MessageColor "Unified Audit Log Search is now enabled" 27 | } else { 28 | Write-Host 29 | Write-Host -ForegroundColor $AssessmentColor "Unified Audit Log will not be enabled" 30 | } 31 | } 32 | 33 | ## Prompt for the audit log age limit on all mailboxes: 34 | Write-Host 35 | $Answer = Read-Host "Do you want to set the audit log age limit and enable all auditing actions on all mailboxes? Type Y or N and press Enter to continue" 36 | if ($Answer -eq 'y' -or $Answer -eq 'yes') { 37 | Write-Host 38 | $AuditLogAgeLimit = Read-Host "Enter the new audit log age limit in days (or press Enter to continue without making changes)" 39 | if ($AuditLogAgeLimit -eq $null -or $AuditLogAgeLimit -eq "" -or $AuditLogAgeLimit -eq 'n' -or $AuditLogAgeLimit -eq 'no'){ 40 | Write-Host 41 | Write-Host -ForegroundColor $AssessmentColor "The audit log age limit and audit actions will not be modified" 42 | } else { 43 | Get-Mailbox -ResultSize Unlimited | Set-Mailbox -AuditEnabled $true -AuditLogAgeLimit $AuditLogAgeLimit 44 | Write-Host 45 | Write-Host -ForegroundColor $MessageColor "The new audit log age limit has been set for all mailboxes" 46 | ## Enable all mailbox auditing actions 47 | Get-Mailbox -ResultSize Unlimited | Set-Mailbox -AuditAdmin @{Add="Copy","Create","FolderBind","HardDelete","MessageBind","Move","MoveToDeletedItems","SendAs","SendOnBehalf","SoftDelete","Update","UpdateFolderPermissions","UpdateInboxRules","UpdateCalendarDelegation"} 48 | Get-Mailbox -ResultSize Unlimited | Set-Mailbox –AuditDelegate @{Add="Create","FolderBind","HardDelete","Move","MoveToDeletedItems","SendAs","SendOnBehalf","SoftDelete","Update","UpdateFolderPermissions","UpdateInboxRules"} 49 | Get-Mailbox -ResultSize Unlimited | Set-Mailbox –AuditOwner @{Add="Create","HardDelete","Move","Mailboxlogin","MoveToDeletedItems","SoftDelete","Update","UpdateFolderPermissions","UpdateInboxRules","UpdateCalendarDelegation"} 50 | Write-Host 51 | Write-host -ForegroundColor $MessageColor "All auditing actions are now enabled on all mailboxes" 52 | } 53 | 54 | } else { 55 | Write-Host 56 | Write-Host -ForegroundColor $AssessmentColor "The audit log age limit and audit actions will not be modified" 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Exchange Online/Customize-MessageEncryption.ps1: -------------------------------------------------------------------------------- 1 | <################################################################################################## 2 | # 3 | .SYNOPSIS 4 | Customize aspects of the OME encryption experience. 5 | 6 | Connect to Exchange Online via PowerShell using MFA: 7 | https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps 8 | 9 | .NOTES 10 | FileName: Customize-MessageEncryption.ps1 11 | Author: Alex Fields, ITProMentor.com 12 | Created: April 2021 13 | Revised: February 2023 14 | 15 | 16 | #> 17 | ################################################################################################### 18 | ## NOTE: If the script errors out, you may need to set your execution policy. 19 | ## You may also need to run: Enable-OrganizationCustomization 20 | ## Please define these variables before running this script: 21 | $MessageColor = "Green" 22 | $AssessmentColor = "Yellow" 23 | ################################################################################################### 24 | 25 | 26 | ################################################# 27 | ## ENABLE ENCRYPT IN OWA 28 | ## SUBSCRIPTIONS: O365E3/E5, M365B/E3/E5, EM+SE3/E5 29 | ################################################# 30 | 31 | $IRMConfig = Get-IRMConfiguration 32 | if (!$IRMConfig.SimplifiedClientAccessEnabled) { 33 | Write-Host 34 | Write-Host -ForegroundColor $AssessmentColor "The 'Encrypt' option is not available in OWA" 35 | Write-Host 36 | $Answer = Read-Host "Enable the 'Encrypt' option in Outlook Web Access now? Type Y or N and press Enter to continue" 37 | if ($Answer -eq 'y' -or $Answer -eq 'yes') { 38 | Set-IRMConfiguration -SimplifiedClientAccessEnabled $true 39 | Write-Host 40 | Write-Host -ForegroundColor $MessageColor "The 'Encrypt' option for Outlook on the web has been enabled" 41 | } else { 42 | Write-Host 43 | Write-Host -ForegroundColor $AssessmentColor "The 'Encrypt' option for Outlook on the Web will not be enabled" 44 | } 45 | } else { 46 | Write-Host 47 | Write-Host -ForegroundColor $MessageColor "The 'Encrypt' option for Outlook on the web is already enabled" 48 | } 49 | 50 | 51 | ################################################# 52 | ## ENCRYPT PDF ATTACHMENTS 53 | ## SUBSCRIPTIONS: O365E3/E5, M365B/E3/E5, EM+SE3/E5 54 | ################################################# 55 | if (!$IRMConfig.EnablePdfEncryption) { 56 | Write-Host 57 | Write-Host -ForegroundColor $AssessmentColor "PDF attachments are not encrypted by OME" 58 | Write-Host 59 | $Answer = Read-Host "Do you want to enable encryption of PDF attachments in OME protected messages? Type Y or N and press Enter to continue" 60 | if ($Answer -eq 'y' -or $Answer -eq 'yes') { 61 | Set-IRMConfiguration -EnablePdfEncryption $true 62 | Write-Host 63 | Write-Host -ForegroundColor $MessageColor "PDF attachments will now be encrypted by OME" 64 | } else { 65 | Write-Host 66 | Write-Host -ForegroundColor $AssessmentColor "PDF attachments will not be encrypted by OME" 67 | } 68 | } else { 69 | Write-Host 70 | Write-Host -ForegroundColor $MessageColor "PDF attachments are already being encrypted by OME" 71 | } 72 | 73 | 74 | ################################################# 75 | ## AUTO-DECRYPT ENCRYPTED ATTACHMENTS 76 | ## SUBSCRIPTIONS: O365E3/E5, M365B/E3/E5, EM+SE3/E5 77 | ################################################# 78 | Write-Host 79 | if (!$IRMConfig.DecryptAttachmentForEncryptOnly) { 80 | Write-Host 81 | Write-Host -ForegroundColor $AssessmentColor "Attachments are encrypted by default upon download" 82 | Write-Host 83 | $Answer = Read-Host "Do you want to enable attachments to be decrypted on download? Type Y or N and press Enter to continue" 84 | if ($Answer -eq 'y' -or $Answer -eq 'yes') { 85 | Set-IRMConfiguration -DecryptAttachmentForEncryptOnly $true 86 | Write-Host 87 | Write-Host -ForegroundColor $MessageColor "Attachments will now be automatically decrypted on download" 88 | } else { 89 | Write-Host 90 | Write-Host -ForegroundColor $AssessmentColor "Attachments will remain encrypted on download" 91 | } 92 | } else { 93 | Write-Host 94 | Write-Host -ForegroundColor $MessageColor "Attachments are automatically decrypted on download" 95 | } 96 | 97 | 98 | ################################################# 99 | ## JOURNAL REPORT DECRYPTION 100 | ## SUBSCRIPTIONS: O365E3/E5, M365B/E3/E5, EM+SE3/E5 101 | ################################################# 102 | Write-Host 103 | if (!$IRMConfig.JournalReportDecryptionEnabled) { 104 | Write-Host 105 | Write-Host -ForegroundColor $AssessmentColor "Journal reports of OME protected messages are currently not decrypted" 106 | Write-Host 107 | $Answer = Read-Host "Do you want to enable decrypted journal reports for OME protected messages? Type Y or N and press Enter to continue" 108 | if ($Answer -eq 'y' -or $Answer -eq 'yes') { 109 | Set-IRMConfiguration -JournalReportDecryptionEnabled $true 110 | Write-Host 111 | Write-Host -ForegroundColor $MessageColor "Journal reports will now be decrypted" 112 | } else { 113 | Write-Host 114 | Write-Host -ForegroundColor $AssessmentColor "Journal reports will remain encrypted" 115 | } 116 | } else { 117 | Write-Host 118 | Write-Host -ForegroundColor $MessageColor "Journal reports of OME messages are already being decrypted, no changes have been made" 119 | } 120 | 121 | 122 | -------------------------------------------------------------------------------- /Exchange Online/Disable-Forwarding.ps1: -------------------------------------------------------------------------------- 1 | ## Script by Alex Fields, ITProMentor.com 2 | ## Description: 3 | ## This script disables auto-forwarding 4 | ## Prerequisites: 5 | ## The tenant will need to include licensing for any Exchange Online Plan 6 | ## Connect to Exchange Online via PowerShell using MFA: 7 | ## https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps 8 | ## WARNING: Script provided as-is. Author is not responsible for its use and application. Use at your own risk. 9 | 10 | $MessageColor = "cyan" 11 | $AssessmentColor = "magenta" 12 | 13 | ## Disable external domain forwarding (globally disable auto-forwarding on the default remote domain): 14 | 15 | $RemoteDomainDefault = Get-RemoteDomain Default 16 | 17 | if ($RemoteDomainDefault.AutoForwardEnabled) { 18 | Write-Host 19 | Write-Host -ForegroundColor $AssessmentColor "Auto-forwarding to remote domains is currently allowed." 20 | Write-Host 21 | $Answer = Read-Host "Do you want to block auto-forwarding to remote domains? Type Y or N and press Enter to continue" 22 | if ($Answer -eq 'y' -or $Answer -eq 'yes') { 23 | Set-RemoteDomain Default -AutoForwardEnabled $false 24 | Write-Host 25 | Write-Host -ForegroundColor $MessageColor "Auto-forwarding to remote domains is now disabled" 26 | } else { 27 | Write-Host 28 | Write-Host -ForegroundColor $AssessmentColor "Auto-forwarding to remote domains will not be disabled"} 29 | } else { 30 | Write-Host 31 | Write-Host -ForegroundColor $MessageColor "Auto-forwarding to remote domains is already disabled" 32 | } 33 | 34 | Write-Host 35 | $Answer = Read-Host "Do you want to export to CSV a list of mailboxes that might be impacted by disabling auto-forward to remote domains? Type Y or N and press Enter to continue" 36 | if ($Answer -eq 'y' -or $Answer -eq 'yes') { 37 | ## Collect existing mailbox forwarding into CSV files at C:\temp\DomainName-MailboxForwarding.csv and DomainName-InboxRules.csv 38 | Write-Host 39 | Write-Host -ForegroundColor $AssessmentColor "Exporting known mailbox forwarders and inbox rules that auto-forward" 40 | $DefaultDomainName = Get-AcceptedDomain | Where-Object Default -EQ True 41 | Get-Mailbox -ResultSize Unlimited -Filter {(RecipientTypeDetails -ne "DiscoveryMailbox") -and ((ForwardingSmtpAddress -ne $null) -or (ForwardingAddress -ne $null))} | Select Identity,ForwardingSmtpAddress,ForwardingAddress | Export-Csv c:\temp\$DefaultDomainName-MailboxForwarding.csv -append 42 | foreach ($a in (Get-Mailbox -ResultSize Unlimited |select PrimarySMTPAddress)) {Get-InboxRule -Mailbox $a.PrimarySMTPAddress | ?{($_.ForwardTo -ne $null) -or ($_.ForwardAsAttachmentTo -ne $null) -or ($_.DeleteMessage -eq $true) -or ($_.RedirectTo -ne $null)} |select Name,Identity,ForwardTo,ForwardAsAttachmentTo, RedirectTo, DeleteMessage | Export-Csv c:\temp\$DefaultDomainName-InboxRules.csv -append } 43 | Write-Host 44 | Write-Host -ForegroundColor $AssessmentColor "After running this script, check the CSV files under C:\temp for a list of mail users who may be affected by disabling the ability to auto-forward messages to external domains" 45 | Write-Host 46 | } else { 47 | Write-Host 48 | Write-Host -ForegroundColor $MessageColor "Run the script again if you wish to export auto-forwarding mailboxes and inbox rules" 49 | Write-Host 50 | } 51 | 52 | 53 | ## End of script 54 | 55 | 56 | ## The rest of this script is optional, and commented out (use if you deem appropriate) 57 | ## Remove any existing mailbox forwarding rules that are in place: 58 | ## Get-Mailbox | Set-Mailbox -ForwardingAddress $null -ForwardingSmtpAddress $null 59 | 60 | ## DENY AUTO-FORWARDING FROM MAILBOX RULES VIA TRANSPORT RULE 61 | ## Creates a transport rule which will deny auto forwarding rules to external domains and reject the message with a notification to end-users 62 | ## $TransportRuleName = "External Forward Block" 63 | ## $rejectMessageText = "Mail forwarding to external domains is not permitted. If you have questions, please contact support." 64 | ## $ExternalForwardRule = Get-TransportRule | Where-Object {$_.Identity -contains $TransportRuleName} 65 | ## if (!$ExternalForwardRule) { 66 | ## Write-Output "External Forward Block rule not found, creating rule..." 67 | ## New-TransportRule -name $TransportRuleName -Priority 1 -SentToScope NotInOrganization -FromScope InOrganization -MessageTypeMatches AutoForward -RejectMessageEnhancedStatusCode 5.7.1 -RejectMessageReasonText $rejectMessageText 68 | ## } else {Write-Output "External forward block rule already exists."} 69 | 70 | ## Remove the ability for users to setup forwarding via the OWA portal 71 | ## Creates a new RBAC Role Assignment Policy 72 | ## $RoleName = "DenyForwarding" 73 | ## $DenyForwardRole = Get-ManagementRole | Where-Object {$_.Name -contains $RoleName} 74 | ## if (!$DenyForwardRole) { 75 | ## Write-Output "DenyForwarding role not found, creating role..." 76 | ## New-ManagementRole -Parent MyBaseOptions -Name $RoleName 77 | ## Set-ManagementRoleEntry DenyForwarding\Set-Mailbox -RemoveParameter -Parameters DeliverToMailboxAndForward,ForwardingAddress,ForwardingSmtpAddress 78 | ## New-RoleAssignmentPolicy -Name DenyForwardingRoleAssignmentPolicy -Roles DenyForwarding,MyContactInformation,MyRetentionPolicies,MyMailSubscriptions,MyTextMessaging,MyVoiceMail,MyDistributionGroupMembership,MyDistributionGroups,MyProfileInformation,MyTeamMailboxes,"My ReadWriteMailbox Apps","My Marketplace Apps","My Custom Apps" 79 | ## Set-RoleAssignmentPolicy -Identity DenyForwardingRoleAssignmentPolicy -IsDefault -Confirm:$false 80 | ## } else {Write-Output "DenyForwarding role already exists."} 81 | -------------------------------------------------------------------------------- /Exchange Online/Disable-SharedMbxSignOn.ps1: -------------------------------------------------------------------------------- 1 | ## Script by Alex Fields, ITProMentor.com 2 | ## Use this script to block sign-in for shared mailboxes 3 | ## You must connect to Exchange Online and Azure AD using Connect-EXOPSSession and Connect-MsolService before running this script 4 | ## https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps 5 | ## https://docs.microsoft.com/en-us/powershell/module/msonline/connect-msolservice?view=azureadps-1.0 6 | ## WARNING: Script provided as-is. Author is not responsible for its use and application. Use at your own risk. 7 | 8 | 9 | $SharedMailboxes = Get-Mailbox -ResultSize Unlimited -Filter {RecipientTypeDetails -Eq "SharedMailbox"} 10 | 11 | Foreach ($user in $SharedMailboxes) { 12 | 13 | Set-MsolUser -UserPrincipalName $user.UserPrincipalName -BlockCredential $true 14 | 15 | } 16 | 17 | 18 | ## End of script 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Exchange Online/README.md: -------------------------------------------------------------------------------- 1 |
• Install-EXOStandardProtection.ps1: This script will configure your default EOP and MDO settings to match the Standard protection template 6 |
• Advanced-TenantConfig.ps1: For customization of Exchange Online including many of the settings featured in other scripts: 7 |
• Block-UnmanagedDownload.ps1 : This script configures the "Read-Only" Conditonal Access policy (additional config required) 8 |
• Block-ConsumerStorageOWA.ps1 : This script disables 3rd party consumer storage locations in OWA 9 |
• Configure-Auditing.ps1 : This script enables and helps you configure audit log age, etc. 10 |
• Disable-Forwarding.ps1: This script will disable auto-forwarding and also output csv of existing forwarders to C:\temp 11 |
• Disable-SharedMbxSignOn.ps1 : This script disables sign-in for shared mailboxes 12 |
• Set-DeletedItemsRetention.ps1 : This script sets the deleted items retention value to max = 30 days (instead of default = 14) 13 |
• Setup-DKIM.ps1 : This script helps with configuring DKIM; use: .\Setup-DKIM.ps1 -Domain "yourdomainhere.com" 14 | 15 | 16 |
Be sure to read the comments and review each script. You are responsible for your own implementation, use at your own risk. 17 |
These scripts follow the guide published at: https://www.itpromentor.com/email-security-checklist/ 18 |
19 |
--------------------------------------------------------------------------------
/Exchange Online/Set-DeletedItemsRetention.ps1:
--------------------------------------------------------------------------------
1 | ## Script by Alex Fields, ITProMentor.com
2 | ## Description:
3 | ## This script will max out the retention period for deleted items in all Exchange Online mailboxes (the maximum configurable value is 30 days)
4 | ## Prerequisites:
5 | ## The tenant will require any Exchange Online plan
6 | ## Connect to Exchange Online via PowerShell using MFA:
7 | ## https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps
8 | ## WARNING: Script provided as-is. Author is not responsible for its use and application. Use at your own risk.
9 |
10 | $MessageColor = "cyan"
11 | $AssessmentColor = "magenta"
12 |
13 | Write-Host
14 | $CurrentRetention = (Get-Mailbox -ResultSize Unlimited).RetainDeletedItemsFor
15 | Write-Host -ForegroundColor $AssessmentColor "Current retention limit (in days and number of mailboxes):"
16 | $CurrentRetention | group | select name, count | ft
17 | Write-Host
18 | $Answer = Read-Host "By default Exchange Online retains deleted items for 14 days; would you like to enforce the maximum allowed value of 30 days for all mailboxes? Type Y or N and press Enter to continue"
19 | if ($Answer -eq 'y' -or $Answer -eq 'yes') {
20 | Get-Mailbox -ResultSize Unlimited | Set-Mailbox -RetainDeletedItemsFor 30
21 | Get-MailboxPlan | Set-MailboxPlan -RetainDeletedItemsFor 30
22 | Write-Host
23 | Write-Host -ForegroundColor $MessageColor "Deleted items will be retained for the maximum of 30 days for all mailboxes"
24 | } else {
25 | Write-Host
26 | Write-Host -ForegroundColor $AssessmentColor "The deleted items retention value has not been modified on any mailboxes"
27 | }
28 |
29 |
30 | ## End of script
31 |
--------------------------------------------------------------------------------
/Exchange Online/Setup-ArchiveLegalHold.ps1:
--------------------------------------------------------------------------------
1 | ## Script by Alex Fields, ITProMentor.com
2 | ## Description:
3 | ## This script can be used to enable the archive mailbox, and/or litigation hold
4 | ## Prerequisites:
5 | ## Exchange Online plan 2 or the Exchange Online Archiving add-on
6 | ## Connect to Exchange Online via PowerShell using MFA:
7 | ## https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps
8 | ## WARNING: Script provided as-is. Author is not responsible for its use and application. Use at your own risk.
9 |
10 | $MessageColor = "cyan"
11 | $AssessmentColor = "magenta"
12 |
13 |
14 | Write-Host
15 | $Answer = Read-Host "Do you want to configure Archiving and Litigation Hold features? NOTE: Requires Exchange Online Plan 2 or Exchange Online Archiving add-on; type Y or N and press Enter to Continue"
16 | if($Answer -eq 'y' -or $Answer -eq 'yes') {
17 |
18 | ## Check whether the auto-expanding archive feature is enabled, and if not, enable it
19 | $OrgConfig = Get-OrganizationConfig
20 | if ($OrgConfig.AutoExpandingArchiveEnabled) {
21 | Write-Host
22 | Write-Host -ForegroundColor $MessageColor "The Auto Expanding Archive feature is already enabled"
23 | } else {
24 | Set-OrganizationConfig -AutoExpandingArchive
25 | Write-Host
26 | Write-Host -ForegroundColor $MessageColor "The Auto Expanding Archive feature is now enabled"
27 | }
28 |
29 | ## Prompt whether or not to enable the Archive mailbox for all users
30 | Write-Host
31 | $ArchiveAnswer = Read-Host "Do you want to enable the Archive mailbox for all user mailboxes? NOTE: Works against cloud-only accounts; does not work against AD synchronized accounts. Type Y or N and press Enter to continue"
32 | if ($ArchiveAnswer -eq 'y'-or $ArchiveAnswer -eq 'yes') {
33 | Get-Mailbox -ResultSize Unlimited -Filter {ArchiveStatus -Eq "None" -AND RecipientTypeDetails -eq "UserMailbox"} | Enable-Mailbox -Archive
34 | Write-Host
35 | Write-Host -ForegroundColor $MessageColor "The Archive mailbox has been enabled for all user mailboxes"
36 | } Else {
37 | Write-Host
38 | Write-Host -ForegroundColor $AssessmentColor "The Archive mailbox will not be enabled for all user mailboxes"
39 | }
40 |
41 | ## Prompt whether or not to enable Litigation Hold for all mailboxes
42 | Write-Host
43 | $LegalHoldAnswer = Read-Host "Do you want to enable Litigation Hold for all mailboxes? Type Y or N and press Enter to continue"
44 | if ($LegalHoldAnswer -eq 'y' -or $LegalHoldAnswer -eq 'yes') {
45 | Get-Mailbox -ResultSize Unlimited -Filter {LitigationHoldEnabled -Eq "False" -AND RecipientTypeDetails -ne "DiscoveryMailbox"} | Set-Mailbox -LitigationHoldEnabled $True
46 | Write-Host
47 | Write-Host -ForegroundColor $MessageColor "Litigation Hold has been enabled for all mailboxes"
48 | } Else {
49 | Write-Host
50 | Write-Host -ForegroundColor $AssessmentColor "Litigation Hold will not be enabled for all mailboxes"
51 | }
52 |
53 | } Else {
54 | Write-Host
55 | Write-Host -ForegroundColor $AssessmentColor "Archiving and Litigation Hold will not be configured"
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/Exchange Online/Setup-DKIM.ps1:
--------------------------------------------------------------------------------
1 | ## Script by Alex Fields, ITProMentor.com
2 | ## Description:
3 | ## This script can be used to help configure DKIM for Office 365
4 | ## Use: .\Setup-DKIM.ps1 -DomainName "yourdomainhere.com"
5 | ## If you do not specify the DomainName variable, the script will prompt you for it
6 | ## Prerequisites:
7 | ## The tenant will require any Exchange Online plan
8 | ## Connect to Exchange Online via PowerShell using MFA:
9 | ## https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell?view=exchange-ps
10 | ## WARNING: Script provided as-is. Author is not responsible for its use and application. Use at your own risk.
11 |
12 |
13 | $MessageColor = "cyan"
14 | $AssessmentColor = "magenta"
15 |
16 | Param(
17 | $DomainName
18 | )
19 |
20 | if($DomainName -eq $null -or $DomainName -eq ""){
21 | Write-Host
22 | $DomainName = Read-Host -Prompt "Please specify the domain name"
23 | Write-Host
24 | }
25 |
26 |
27 | ## This line will return the CNAME record values for the specified domain name (Points to):
28 | Write-Host -ForegroundColor $MessageColor "Enter the (Points to) CNAME values in DNS for selector1._domainkey and selector2._domainkey:"
29 | Write-Host
30 |
31 | Get-DkimSigningConfig $DomainName | fl Domain,*cname
32 |
33 | ## Pause the script to allow time for entering DKIM records
34 | Write-Host
35 | Read-Host -Prompt "Enter the DKIM records, have a coffee and wait for several minutes while DNS propogates, and then press Enter to continue..."
36 | Write-Host
37 | ## This line will attempt to activate the DKIM service (CNAME records must be already be populated in DNS)
38 |
39 | ##If DKIM exists but not already enabled, enable it
40 | if (((get-dkimsigningconfig -identity $domainname -ErrorAction silent).enabled) -eq $False) {set-dkimsigningconfig -identity $domainname -enabled $true}
41 | ##If it doesn't exist - create new config
42 | if (!(get-dkimsigningconfig -identity $domainname -erroraction silent)) {New-DkimSigningConfig -DomainName $DomainName -Enabled $true}
43 | Write-Host
44 |
45 | ## End of script
46 |
47 |
--------------------------------------------------------------------------------
/Incident Response/Export-ActivityByIPAddress.ps1:
--------------------------------------------------------------------------------
1 | <##################################################################################################
2 | #
3 | .SYNOPSIS
4 | 1. This script exports data from the Unified Audit Log for a specified IP address
5 | 2. You can set the Output Path using the variable $OutputPath, or just run the script and it will prompt
6 | 3. You must have the ExchangeOnlineManagement PowerShell module installed in order to use this script, i.e.:
7 |
8 | Install-Module ExchangeOnlineManagement
9 | Connect-ExchangeOnline
10 |
11 | .NOTES
12 | FileName: Export-ActivitybyIPAddress.ps1
13 | Author: Alex Fields
14 | Created: June 2021
15 | Revised: June 2021
16 |
17 | #>
18 | ###################################################################################################
19 | <#
20 | ## Import module and Connect to Exchange Online
21 | Import-Module ExchangeOnlineManagement
22 | Connect-ExchangeOnline
23 | #>
24 |
25 | ## Define variables
26 | $OutputPath = ""
27 | $DaysAgo = "90"
28 |
29 | $CheckLog= (Get-AdminAuditLogConfig).UnifiedAuditLogIngestionEnabled
30 |
31 | if (!$CheckLog) {
32 | Write-Host "The Unified Audit Log is not enabled in this tenant. You cannot export activities." -ForegroundColor Cyan
33 |
34 | } else {
35 |
36 | ## If OutputPath variable is not defined, prompt for it
37 | if (!$OutputPath) {
38 | Write-Host
39 | $OutputPath = Read-Host 'Enter the output path, e.g. C:\IROutput'
40 | }
41 |
42 | ## If OutputPath does not exist, create it
43 | $CheckOutputPath = Get-Item $OutputPath -ErrorAction SilentlyContinue
44 | if (!$CheckOutputPath) {
45 | Write-Host
46 | Write-Host "Output path does not exist, so the directory will be created." -ForegroundColor Yellow
47 | mkdir $OutputPath
48 | }
49 |
50 | ## Set Start and End Dates
51 | $StartDate = (Get-Date).AddDays(-$DaysAgo)
52 | $EndDate = Get-Date
53 |
54 | ## Get Primary Domain Name (used in naming output files)
55 | $PrimaryDomain = Get-AcceptedDomain | Where-Object Default -eq $true
56 | $DomainName = $PrimaryDomain.DomainName
57 |
58 |
59 | $CheckSubDir = Get-Item $OutputPath\$DomainName -ErrorAction SilentlyContinue
60 | if (!$CheckSubDir) {
61 | Write-Host
62 | Write-Host "Domain sub-directory does not exist, so the sub-directory will be created." -ForegroundColor Yellow
63 | mkdir $OutputPath\$DomainName
64 | }
65 |
66 | $IPAddress = Read-Host "Enter the IP address of interest"
67 | $History = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -IPAddresses $IPAddress -SessionCommand ReturnLargeSet
68 |
69 | if (!$History) {
70 | Write-Host
71 | Write-Host "There are no activities in the audit log for the time period specified" -ForegroundColor Cyan
72 | Write-Host
73 | } else {
74 |
75 | ## Output the events to CSV
76 | $History | Out-GridView
77 | $History | Export-Csv -Path $OutputPath\$DomainName\$IPAddress-AuditLogDetail.csv
78 | Write-Host
79 | Write-Host "See IP address activities in the OutputPath" -ForegroundColor Yellow
80 | Write-Host
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/Incident Response/Export-ActivityByUser.ps1:
--------------------------------------------------------------------------------
1 | <##################################################################################################
2 | #
3 | .SYNOPSIS
4 | 1. This script exports data from the Unified Audit Log for a specified user
5 | 2. You can set the Output Path using the variable $OutputPath, or just run the script and it will prompt
6 | 3. You must have the ExchangeOnlineManagement PowerShell module installed in order to use this script, i.e.:
7 |
8 | Install-Module ExchangeOnlineManagement
9 | Connect-ExchangeOnline
10 |
11 | .NOTES
12 | FileName: Export-ActivityByUser.ps1
13 | Author: Alex Fields
14 | Created: June 2021
15 | Revised: June 2021
16 |
17 | #>
18 | ###################################################################################################
19 | <#
20 | ## Import module and Connect to Exchange Online
21 | Import-Module ExchangeOnlineManagement
22 | Connect-ExchangeOnline
23 | #>
24 | #############################################################
25 | ## Gather the parameters
26 | ## You may set the parameters in the script or enter by prompt
27 |
28 | ## Define variables
29 | $OutputPath = ""
30 | $DaysAgo = "90"
31 |
32 | $CheckLog= (Get-AdminAuditLogConfig).UnifiedAuditLogIngestionEnabled
33 |
34 | if (!$CheckLog) {
35 | Write-Host "The Unified Audit Log is not enabled in this tenant. You cannot export activities." -ForegroundColor Cyan
36 | Write-Host
37 | } else {
38 |
39 |
40 | ## If OutputPath variable is not defined, prompt for it
41 | if (!$OutputPath) {
42 | Write-Host
43 | $OutputPath = Read-Host 'Enter the output path, e.g. C:\IROutput'
44 | }
45 |
46 | ## If OutputPath does not exist, create it
47 | $CheckOutputPath = Get-Item $OutputPath -ErrorAction SilentlyContinue
48 | if (!$CheckOutputPath) {
49 | Write-Host
50 | Write-Host "Output path does not exist, so the directory will be created." -ForegroundColor Yellow
51 | mkdir $OutputPath
52 | }
53 |
54 | ## Set Start and End Dates
55 | $StartDate = (Get-Date).AddDays(-$DaysAgo)
56 | $EndDate = Get-Date
57 |
58 | ## Get Primary Domain Name (used in naming output files)
59 | $PrimaryDomain = Get-AcceptedDomain | Where-Object Default -eq $true
60 | $DomainName = $PrimaryDomain.DomainName
61 |
62 | $CheckSubDir = Get-Item $OutputPath\$DomainName -ErrorAction SilentlyContinue
63 | if (!$CheckSubDir) {
64 | Write-Host
65 | Write-Host "Domain sub-directory does not exist, so the sub-directory will be created." -ForegroundColor Yellow
66 | mkdir $OutputPath\$DomainName
67 | }
68 |
69 | $User = Read-Host "Enter the user's primary email address (UPN)"
70 | $History = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -UserIds $User -SessionCommand ReturnLargeSet
71 |
72 | if (!$History) {
73 | Write-Host
74 | Write-Host "There are no activities in the audit log for the time period specified" -ForegroundColor Cyan
75 | Write-Host
76 | } else {
77 |
78 | ## Output the events to CSV
79 | $History | Out-GridView
80 | $History | Export-Csv -Path $OutputPath\$DomainName\$User-AuditLogActivities.csv
81 | Write-Host
82 | Write-Host "See user activities in the OutputPath" -ForegroundColor Yellow
83 | Write-Host
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/Incident Response/Export-PrivilegedUserActions.ps1:
--------------------------------------------------------------------------------
1 | <##################################################################################################
2 | #
3 | .SYNOPSIS
4 | 1. This script exports several data points from the Azure AD Incident Response PowerShell module
5 | 2. You can set the Output Path using the variable $OutputPath, or just run the script and it will prompt
6 | 3. Specify the primary $DomainName associated with the tenant in order to run the script, or it will prompt
7 | 4. You must have the AzureADIncidentResponse PowerShell module installed in order to use this script, i.e.:
8 |
9 | Install-Module AzureADIncidentResponse
10 |
11 |
12 | .NOTES
13 | FileName: Export-PrivilegedUserActions.ps1
14 | Author: Alex Fields
15 | Created: June 2021
16 | Revised: June 2021
17 |
18 | #>
19 | ###################################################################################################
20 | <#
21 | Import-Module AzureAD
22 | Import-Module AzureADIncidentResponse
23 | #>
24 | #############################################################
25 | ## Gather the parameters
26 | ## You may set the parameters in the script or enter by prompt
27 |
28 | $DomainName = ""
29 | $OutputPath = ""
30 |
31 | ## If the OutputPath variable is undefined, prompt for input
32 | if (!$OutputPath) {
33 | Write-Host
34 | $OutputPath = Read-Host 'Enter the output path, e.g. C:\IROutput'
35 | }
36 |
37 | ## If the output path does not exist, then create it
38 | $CheckOutputPath = Get-Item $OutputPath -ErrorAction SilentlyContinue
39 | if (!$CheckOutputPath) {
40 | Write-Host
41 | Write-Host "Output path does not exist, so the directory will be created." -ForegroundColor Yellow
42 | mkdir $OutputPath
43 | }
44 |
45 | ## If the DomainName variable is undefined, prompt for input
46 | if ($DomainName -eq "") {
47 | Write-Host
48 | $DomainName = Read-Host 'Enter the primary domain name associated with the tenant'
49 | }
50 |
51 |
52 | $CheckSubDir = Get-Item $OutputPath\$DomainName -ErrorAction SilentlyContinue
53 | if (!$CheckSubDir) {
54 | Write-Host
55 | Write-Host "Domain sub-directory does not exist, so the sub-directory will be created." -ForegroundColor Yellow
56 | mkdir $OutputPath\$DomainName
57 | }
58 |
59 |
60 | #############################################################
61 | ## Get the tenant ID and connect to Azure AD
62 | $TenantID = Get-AzureADIRTenantId -DomainName $DomainName
63 | Connect-AzureADIR -TenantId $TenantID
64 | #############################################################
65 |
66 | $PrivUsers = Get-AzureADIRPrivilegedRoleAssignment -TenantId $TenantID | Where-Object RoleMemberObjectType -EQ User
67 |
68 | foreach ($User in $PrivUsers) {
69 |
70 | $DisplayToID = Get-AzureADIRDisplayNameToObjectId -DisplayName $User.RoleMemberName -ObjectType User
71 |
72 | $RoleMemberEmail = $User.RoleMemberMail
73 |
74 | $AuditDetail = Get-AzureADIRAuditActivity -TenantId $TenantID -InitiatedByUser $DisplayToID.ObjectId
75 |
76 | if (!$AuditDetail) {
77 | Write-Host
78 | } else {
79 |
80 | $AuditDetail | Export-Csv $OutputPath\$DomainName\$RoleMemberEmail-AADActivityDetail.csv
81 |
82 | }
83 |
84 | }
85 |
86 | Write-Host
87 | Write-Host "See the output in the domain subdirectory." -ForegroundColor Cyan
88 | Write-Host
--------------------------------------------------------------------------------
/Incident Response/Export-PrivilegedUserSignIn.ps1:
--------------------------------------------------------------------------------
1 | <##################################################################################################
2 | #
3 | .SYNOPSIS
4 | 1. This script exports several data points from the Azure AD Incident Response PowerShell module
5 | 2. You can set the Output Path using the variable $OutputPath, or just run the script and it will prompt
6 | 3. Specify the primary $DomainName associated with the tenant in order to run the script, or it will prompt
7 | 4. You must have the AzureADIncidentResponse PowerShell module installed in order to use this script, i.e.:
8 |
9 | Install-Module AzureADIncidentResponse
10 |
11 |
12 | .NOTES
13 | FileName: Export-PrivilegedUserSignIn.ps1
14 | Author: Alex Fields
15 | Created: June 2021
16 | Revised: June 2021
17 |
18 | #>
19 | ###################################################################################################
20 | <#
21 | Import-Module AzureAD
22 | Import-Module AzureADIncidentResponse
23 | #>
24 | #############################################################
25 | ## Gather the parameters
26 | ## You may set the parameters in the script or enter by prompt
27 |
28 | $DomainName = ""
29 | $OutputPath = ""
30 |
31 | ## If the OutputPath variable is undefined, prompt for input
32 | if (!$OutputPath) {
33 | Write-Host
34 | $OutputPath = Read-Host 'Enter the output path, e.g. C:\IROutput'
35 | }
36 |
37 | ## If the output path does not exist, then create it
38 | $CheckOutputPath = Get-Item $OutputPath -ErrorAction SilentlyContinue
39 | if (!$CheckOutputPath) {
40 | Write-Host
41 | Write-Host "Output path does not exist, so the directory will be created." -ForegroundColor Yellow
42 | mkdir $OutputPath
43 | }
44 |
45 | ## If the DomainName variable is undefined, prompt for input
46 | if ($DomainName -eq "") {
47 | Write-Host
48 | $DomainName = Read-Host 'Enter the primary domain name associated with the tenant'
49 | }
50 |
51 | $CheckSubDir = Get-Item $OutputPath\$DomainName -ErrorAction SilentlyContinue
52 | if (!$CheckSubDir) {
53 | Write-Host
54 | Write-Host "Domain sub-directory does not exist, so the sub-directory will be created." -ForegroundColor Yellow
55 | mkdir $OutputPath\$DomainName
56 | }
57 |
58 | #############################################################
59 | ## Get the tenant ID and connect to Azure AD
60 | $TenantID = Get-AzureADIRTenantId -DomainName $DomainName
61 | Connect-AzureADIR -TenantId $TenantID
62 | #############################################################
63 |
64 | $PrivUsers = Get-AzureADIRPrivilegedRoleAssignment -TenantId $TenantID | Where-Object RoleMemberObjectType -EQ User
65 |
66 | foreach ($User in $PrivUsers) {
67 |
68 | $DisplayToID = Get-AzureADIRDisplayNameToObjectId -DisplayName $User.RoleMemberName -ObjectType User
69 |
70 | $RoleMemberEmail = $User.RoleMemberMail
71 |
72 | $SignInDetail = Get-AzureADIRSignInDetail -TenantId $TenantID -UserId $DisplayToID.ObjectId
73 |
74 | if (!$SignInDetail) {
75 | Write-Host
76 | } else {
77 |
78 | $SignInDetail | Export-Csv $OutputPath\$DomainName\$RoleMemberEmail-SignInDetail.csv
79 |
80 | }
81 |
82 | }
83 |
84 | Write-Host
85 | Write-Host "See the output in the domain subdirectory." -ForegroundColor Cyan
86 | Write-Host
--------------------------------------------------------------------------------
/Incident Response/Export-SignInByIPAddress.ps1:
--------------------------------------------------------------------------------
1 | <##################################################################################################
2 | #
3 | .SYNOPSIS
4 | 1. This script exports several data points from the Azure AD Incident Response PowerShell module
5 | 2. You can set the Output Path using the variable $OutputPath, or just run the script and it will prompt
6 | 3. Specify the primary $DomainName associated with the tenant in order to run the script, or it will prompt
7 | 4. You must have the AzureADIncidentResponse PowerShell module installed in order to use this script, i.e.:
8 |
9 | Install-Module AzureADIncidentResponse
10 |
11 |
12 | .NOTES
13 | FileName: Export-SignInByIPAddress.ps1
14 | Author: Alex Fields
15 | Created: June 2021
16 | Revised: June 2021
17 |
18 | #>
19 | ###################################################################################################
20 | <#
21 | Import-Module AzureAD
22 | Import-Module AzureADIncidentResponse
23 | #>
24 | #############################################################
25 | ## Gather the parameters
26 | ## You may set the parameters in the script or enter by prompt
27 |
28 | $DomainName = ""
29 | $OutputPath = ""
30 |
31 | ## If the OutputPath variable is undefined, prompt for input
32 | if (!$OutputPath) {
33 | Write-Host
34 | $OutputPath = Read-Host 'Enter the output path, e.g. C:\IROutput'
35 | }
36 |
37 | ## If the output path does not exist, then create it
38 | $CheckOutputPath = Get-Item $OutputPath -ErrorAction SilentlyContinue
39 | if (!$CheckOutputPath) {
40 | Write-Host
41 | Write-Host "Output path does not exist, so the directory will be created." -ForegroundColor Yellow
42 | mkdir $OutputPath
43 | }
44 |
45 | ## If the DomainName variable is undefined, prompt for input
46 | if ($DomainName -eq "") {
47 | Write-Host
48 | $DomainName = Read-Host 'Enter the primary domain name associated with the tenant'
49 | }
50 |
51 | $CheckSubDir = Get-Item $OutputPath\$DomainName -ErrorAction SilentlyContinue
52 | if (!$CheckSubDir) {
53 | Write-Host
54 | Write-Host "Domain sub-directory does not exist, so the sub-directory will be created." -ForegroundColor Yellow
55 | mkdir $OutputPath\$DomainName
56 | }
57 |
58 | #############################################################
59 | ## Get tenant ID and connect to Azure AD
60 | $TenantID = Get-AzureADIRTenantId -DomainName $DomainName
61 | Connect-AzureADIR -TenantId $TenantID
62 | #############################################################
63 |
64 | $IPAddress = Read-Host "Enter the interesting IP Address"
65 |
66 | $SignInDetail = Get-AzureADIRSignInDetail -TenantId $TenantID -IpAddress $IPAddress
67 |
68 | if (!$SignInDetail) {
69 | Write-Host
70 | } else {
71 |
72 | $SignInDetail | Out-GridView
73 | $SignInDetail | Export-Csv $OutputPath\$DomainName\$IPAddress-SignInDetail.csv
74 |
75 | }
76 |
77 |
78 |
--------------------------------------------------------------------------------
/Incident Response/Export-SignInByUser.ps1:
--------------------------------------------------------------------------------
1 | <##################################################################################################
2 | #
3 | .SYNOPSIS
4 | 1. This script exports several data points from the Azure AD Incident Response PowerShell module
5 | 2. You can set the Output Path using the variable $OutputPath, or just run the script and it will prompt
6 | 3. Specify the primary $DomainName associated with the tenant in order to run the script, or it will prompt
7 | 4. You must have the AzureADIncidentResponse PowerShell module installed in order to use this script, i.e.:
8 |
9 | Install-Module AzureADIncidentResponse
10 |
11 |
12 | .NOTES
13 | FileName: Export-SignInByUser.ps1
14 | Author: Alex Fields
15 | Created: June 2021
16 | Revised: June 2021
17 |
18 | #>
19 | ###################################################################################################
20 | <#
21 | Import-Module AzureAD
22 | Import-Module AzureADIncidentResponse
23 | #>
24 | #############################################################
25 | ## Gather the parameters and set the working directory
26 | ## You may set the parameters in the script or enter by prompt
27 |
28 | $DomainName = ""
29 | $OutputPath = ""
30 |
31 | ## If the OutputPath variable is undefined, prompt for input
32 | if (!$OutputPath) {
33 | Write-Host
34 | $OutputPath = Read-Host 'Enter the output path, e.g. C:\IROutput'
35 | }
36 |
37 | ## If the output path does not exist, then create it
38 | $CheckOutputPath = Get-Item $OutputPath -ErrorAction SilentlyContinue
39 | if (!$CheckOutputPath) {
40 | Write-Host
41 | Write-Host "Output path does not exist, so the directory will be created." -ForegroundColor Yellow
42 | mkdir $OutputPath
43 | }
44 |
45 | ## If the DomainName variable is undefined, prompt for input
46 | if ($DomainName -eq "") {
47 | Write-Host
48 | $DomainName = Read-Host 'Enter the primary domain name associated with the tenant'
49 | }
50 |
51 | $CheckSubDir = Get-Item $OutputPath\$DomainName -ErrorAction SilentlyContinue
52 | if (!$CheckSubDir) {
53 | Write-Host
54 | Write-Host "Domain sub-directory does not exist, so the sub-directory will be created." -ForegroundColor Yellow
55 | mkdir $OutputPath\$DomainName
56 | }
57 |
58 | #############################################################
59 | ## Get the tenant ID and connect to Azure AD
60 | $TenantID = Get-AzureADIRTenantId -DomainName $DomainName
61 | Connect-AzureADIR -TenantId $TenantID
62 |
63 | #############################################################
64 |
65 | $User = Read-Host "Enter the user's primary email address (UPN)"
66 |
67 | $DisplayName = (Get-AzureADUser -ObjectId $User).DisplayName
68 |
69 | $DisplayToID = Get-AzureADIRDisplayNameToObjectId -DisplayName $DisplayName -ObjectType User
70 |
71 | $SignInDetail = Get-AzureADIRSignInDetail -TenantId $TenantID -UserId $DisplayToID.ObjectId
72 |
73 | if (!$SignInDetail) {
74 | Write-Host
75 | } else {
76 |
77 | $SignInDetail | Out-GridView
78 | $SignInDetail | Export-Csv $OutputPath\$DomainName\$User-SignInDetail.csv
79 |
80 | }
81 |
82 |
83 |
--------------------------------------------------------------------------------
/Incident Response/ReadMe.md:
--------------------------------------------------------------------------------
1 | ## Incident Response Scripts
2 |
3 | I have found these scripts to be useful during Incident Response in Microsoft 365.
4 |
5 | 1) Start-AzureADIRCollection.ps1: Use this script to begin a collection of data against a tenant. You must have the AzureADIncidentResponse module installed.
6 |
7 | 2) Start-UnifiedAuditLogIRCollection.ps1: Use this script to get interesting events exported from the Unified Audit Log. You must have the ExchangeOnlineManagement module installed.
8 |
9 | 3) Export-PrivilegedUserSignIn.ps1: Use this script to investigate the sign-in activities from privileged user accounts. You must have the AzureADIncidentResponse module installed.
10 |
11 | 4) Export-PrivilegedUserActions.ps1: Use this script to investigate the Azure AD audit log for activities performed by privileged users. You must have the AzureADIncidentResponse module installed.
12 |
13 | 5) Export-SignInByUser.ps1: Use this script to get available sign-in data for the specified username. You must have the AzureADIncidentResponse module installed.
14 |
15 | 6) Export-SignInByIpAddress.ps1: Use this script to get available sign-in data for the specified IP address. You must have the AzureADIncidentResponse module installed.
16 |
17 | 7) Export-ActivityByUser.ps1: Use this script to get activities from the Unified audit log for the specified username. You must have the ExchangeOnlineManagement module installed.
18 |
19 | 8) Export-ActivityByIpAddress.ps1: Use this script to get available sign-in data for the specified IP address. You must have the ExchangeOnlineManagement module installed.
20 |
21 | 9) Install-AzureADProtectionAlerts.ps1: Use this script to import alert policies for Azure AD monitoring. You must have the ExchangeOnlineManagement module installed.
22 |
23 | 10) Remediate-CompromisedUser.ps1: Use this script to disable and revoke access, and/or reset a user's password and re-enable access. You must have the AzureAD module installed. There is also an option to reset all admin passwords at once, excluding breakglass and current user account (this option requires the AzureADIncidentResponse module).
24 |
25 |
--------------------------------------------------------------------------------
/Incident Response/Remediate-CompromisedUser.ps1:
--------------------------------------------------------------------------------
1 | <##################################################################################################
2 | #
3 | .SYNOPSIS
4 |
5 | WARNING: Make sure you understand what you're doing before running this script!
6 |
7 | 1. This script will disable and revoke all refresh tokens for the specified user account
8 | 2. You will also reset the password and optionally re-enable the account
9 | 3. There is also an option to reset all admin passwords to random complex GUIDs (this requires the AzureADIncidentResponse module)
10 | 4. You must connect to Azure AD before running this script, i.e.:
11 |
12 | Connect-AzureAD
13 |
14 | .NOTES
15 | FileName: Remediate-CompromisedUser.ps1
16 | Author: Alex Fields
17 | Created: June 2021
18 | Revised: June 2021
19 |
20 | #>
21 | ###################################################################################################
22 |
23 | Import-Module AzureAD
24 |
25 | Write-Host "Do you want to disable an account or reset and re-enable an account?" -ForegroundColor Cyan
26 | Write-Host " 1. Disable an account" -ForegroundColor Cyan
27 | Write-Host " 2. Reset password and re-enable an account" -ForegroundColor Cyan
28 | Write-Host " 3. Panic button: Reset all my admin accounts NOW!" -ForegroundColor Cyan
29 |
30 | $Choice = Read-Host "Type your selection: 1, 2, or 3 and press Enter"
31 |
32 | if ($Choice -eq "1") {
33 | #Get the Username and ObjectID
34 | $UserEmail = Read-Host "Enter the user's primary email address (UPN)"
35 | $User = Get-AzureADUser -ObjectId $UserEmail
36 |
37 | #Disable the user's account and revoke all refresh tokens
38 | Write-Host
39 | Write-Host "Disabling the user's account and revoking all refresh tokens..." -ForegroundColor Yellow
40 | Set-AzureADUser -ObjectId $UserEmail -AccountEnabled $false
41 | Revoke-AzureADUserAllRefreshToken -ObjectId $UserEmail
42 |
43 | #Disable the user's registered devices
44 | Write-Host
45 | Write-Host "Optional: Do you want to disable the user's registered devices?" -ForegroundColor Cyan
46 | Write-Host
47 | $Answer = Read-Host "Type Y or N and press Enter."
48 |
49 | if ($Answer -eq "y") {
50 | Write-Host
51 | Write-Host "Disabling the user's registered devices..." -ForegroundColor Yellow
52 | Get-AzureADUserRegisteredDevice -ObjectId $UserEmail | Set-AzureADDevice -AccountEnabled $false
53 | } else {
54 | Write-Host
55 | Write-Host "The user's registered devices will not be disabled." -ForegroundColor Cyan
56 | }
57 | }
58 |
59 | if ($Choice -eq "2") {
60 | #Get the Username and ObjectID
61 | $UserEmail = Read-Host "Enter the user's primary email address (UPN)"
62 | $User = Get-AzureADUser -ObjectId $UserEmail
63 |
64 | #Change the password quickly to a random string (guid)
65 | Write-Host
66 | Write-Host "Changing the user's password to a random string..." -ForegroundColor Yellow
67 | Write-Host
68 | Set-AzureADUserPassword -ObjectId $User.ObjectId -Password (ConvertTo-SecureString (New-Guid).Guid -AsPlainText -Force)
69 |
70 | #Change the password a second time to a string of your choosing:
71 | Write-Host "You may now change the user's password to a value of your choosing." -ForegroundColor Yellow
72 | Write-Host
73 | $GetPassword = Read-Host "Enter the new password"
74 | $Password = ConvertTo-SecureString $GetPassword -AsPlainText -Force
75 | Set-AzureADUserPassword -ObjectId $User.ObjectId -Password $Password -ForceChangePasswordNextLogin $true
76 | Write-Host
77 |
78 | $Answer = Read-Host "Do you want to re-enable the user's account now? Type Y or N and press ENTER"
79 | Write-Host
80 |
81 | if ($Answer -eq "y") {
82 | Set-AzureADUser -ObjectId $UserEmail -AccountEnabled $true
83 | Write-Host "User's account has been re-enabled. User must change password on next login." -ForegroundColor Yellow
84 | Write-Host
85 | } else
86 | {
87 | Write-Host "No further action will be taken. Account is still disabled." -ForegroundColor Yellow
88 | Write-Host
89 | }
90 |
91 | #Enable the user's registered devices
92 | Write-Host "Optional: Do you want to re-enable the user's registered devices?" -ForegroundColor Cyan
93 | Write-Host
94 | $Answer = Read-Host "Type Y or N and press Enter."
95 |
96 | if ($Answer -eq "y") {
97 | Write-Host
98 | Write-Host "Re-enabling the user's registered devices..." -ForegroundColor Yellow
99 | Get-AzureADUserRegisteredDevice -ObjectId $UserEmail | Set-AzureADDevice -AccountEnabled $true
100 | } else {
101 | Write-Host
102 | Write-Host "The user's registered devices will not be re-enabled." -ForegroundColor Cyan
103 | }
104 |
105 |
106 | }
107 |
108 | if ($Choice -eq "3") {
109 | ## Credit for this section goes to Daniel Chronlund's DCToolBox PowerShell module.
110 | Write-Host
111 | Write-Host "You must have the Azure AD Incident Response module installed to use this option." -ForegroundColor Cyan
112 | Import-Module AzureADIncidentResponse -ErrorAction Stop
113 | Write-Host
114 | Write-Host "Warning: You are about to reset all of your admin passwords to randomly generated GUIDs." -ForegroundColor Yellow
115 | Write-Host "You may specify one other 'breakglass' account besides the current account to exclude from this process." -ForegroundColor Yellow
116 | Write-Host "Are you sure you want to continue?" -ForegroundColor Yellow
117 | $Answer = Read-Host "Type Y or N and press Enter to continue"
118 |
119 | if ($Answer -eq "y") {
120 | #############################################################
121 | ## Get the tenant ID and connect to Azure AD
122 | $Domain = Get-AzureADDomain | where-object IsDefault -eq $true
123 | $TenantID = Get-AzureADIRTenantId -DomainName $Domain.Name
124 | Connect-AzureADIR -TenantId $TenantID
125 | #############################################################
126 |
127 | ## Get the current user running PowerShell against Azure AD.
128 | Write-Host
129 | Write-Host "Getting the current Azure AD user to exclude from the reset process." -ForegroundColor Cyan
130 | $CurrentUser = (Get-AzureADCurrentSessionInfo).Account.Id
131 |
132 | ## Get the additional breakglass user:
133 | Write-Host "Specify one additional Azure AD breakglass account below." -ForegroundColor Cyan
134 | $BreakGlassUser = Read-Host "Enter the UPN of your breakglass account and press Enter to continue"
135 |
136 | Write-Host
137 | Write-Host "Getting Azure AD privileged users" -ForegroundColor Cyan
138 | $PrivUsers = Get-AzureADIRPrivilegedRoleAssignment -TenantId $TenantID | Where-Object RoleMemberObjectType -EQ User
139 |
140 | ## Loop through admins and set new complex passwords (using generated GUIDs).
141 | foreach ($User in $PrivUsers) {
142 | if ($User.RoleMemberUPN -notin $BreakGlassUser -and $User.RoleMemberUPN -ne $CurrentUser) {
143 | Write-Host "Setting new password and revoking current tokens for $($User.RoleMemberUPN)..." -ForegroundColor Yellow
144 | Revoke-AzureADUserAllRefreshToken -ObjectId $User.RoleMemberUPN
145 | Set-AzureADUserPassword -ObjectId $User.RoleMemberUPN -Password (ConvertTo-SecureString (New-Guid).Guid -AsPlainText -Force)
146 | Set-AzureADUserPassword -ObjectId $User.RoleMemberUPN -Password (ConvertTo-SecureString (New-Guid).Guid -AsPlainText -Force)
147 | } else {
148 | Write-Host "Skipping $($User.RoleMemberUPN)!" -ForegroundColor Cyan
149 | }
150 | }
151 | Write-Host
152 | Write-Host "Admin passwords have been changed." -ForegroundColor Cyan
153 | Write-Host "Note: You must manually reset the passwords again and help the users get back into their accounts." -ForegroundColor Yellow
154 | Write-Host "All admin users are advised to check their MFA methods at https://aka.ms/mysecurityinfo after regaining access." -ForegroundColor Yellow
155 | } else {
156 | Write-Host
157 | Write-Host "Exiting script. No changes have been made." -ForegroundColor Cyan
158 | }
159 | }
160 |
161 | Write-Host
162 | Write-Host "Script complete" -ForegroundColor Cyan
163 | Write-Host
--------------------------------------------------------------------------------
/Incident Response/Start-AzureADIRCollection.ps1:
--------------------------------------------------------------------------------
1 | <##################################################################################################
2 | #
3 | .SYNOPSIS
4 | 1. This script exports several data points from the Azure AD Incident Response PowerShell module
5 | 2. You can set the Output Path using the variable $OutputPath, or just run the script and it will prompt
6 | 3. Specify the primary $DomainName associated with the tenant in order to run the script, or it will prompt
7 | 4. See additional examples of the AzureADIR functions in the comments at the end of the script
8 | 5. You must have the AzureADIncidentResponse PowerShell module installed in order to use this script, i.e.:
9 |
10 | Install-Module AzureADIncidentResponse
11 |
12 |
13 | .NOTES
14 | FileName: Start-AzureADIRCollection.ps1
15 | Author: Alex Fields
16 | Created: June 2021
17 | Revised: June 2021
18 |
19 | #>
20 | ###################################################################################################
21 |
22 | Import-Module AzureAD
23 | Import-Module AzureADIncidentResponse
24 |
25 | #############################################################
26 | ## Gather the parameters
27 | ## You may set the parameters in the script or enter by prompt
28 |
29 | $DomainName = ""
30 | $OutputPath = ""
31 |
32 |
33 | ## If the OutputPath variable is undefined, prompt for input
34 | if (!$OutputPath) {
35 | Write-Host
36 | $OutputPath = Read-Host 'Enter the output path, e.g. C:\IROutput'
37 | }
38 |
39 | ## If the output path does not exist, then create it
40 | $CheckOutputPath = Get-Item $OutputPath -ErrorAction SilentlyContinue
41 | if (!$CheckOutputPath) {
42 | Write-Host
43 | Write-Host "Output path does not exist, so the directory will be created." -ForegroundColor Yellow
44 | mkdir $OutputPath
45 | }
46 |
47 | ## If the DomainName variable is undefined, prompt for input
48 | if ($DomainName -eq "") {
49 | Write-Host
50 | $DomainName = Read-Host 'Enter the primary domain name associated with the tenant'
51 | }
52 |
53 | $CheckSubDir = Get-Item $OutputPath\$DomainName -ErrorAction SilentlyContinue
54 | if (!$CheckSubDir) {
55 | Write-Host
56 | Write-Host "Domain sub-directory does not exist, so the sub-directory will be created." -ForegroundColor Yellow
57 | mkdir $OutputPath\$DomainName
58 | }
59 |
60 | ## Change directory to the OutputPath
61 | cd $OutputPath\$DomainName
62 |
63 | #############################################################
64 | ## Get the tenant ID and connect to Azure AD
65 | $TenantID = Get-AzureADIRTenantId -DomainName $DomainName
66 | Connect-AzureADIR -TenantId $TenantID
67 | #############################################################
68 |
69 | ## Get a current list of Azure AD Privileged role assignments
70 | Get-AzureADIRPrivilegedRoleAssignment -TenantId $TenantID -CsvOutput
71 |
72 | ## Gets two lists of applications with assigned permissions: delegated (user) permissions and application permissions
73 | Get-AzureADIRPermission -TenantId $TenantID -CsvOutput
74 |
75 | ## Get a current list of Azure AD users and make recommendations on how to improve their MFA stance
76 | Get-AzureADIRMfaAuthMethodAnalysis -TenantId $TenantID -LocationInfo -CsvOutput
77 |
78 | ## Gets the last interactive sign-in activity for all users in the tenant
79 | Get-AzureADIRUserLastSignInActivity -TenantId $TenantID -All -GuestInfo -CsvOutput
80 |
81 |
82 | ## Get a list of Azure AD users with MFA usage location and phone number
83 | $PhoneToLocationCheck = Get-AzureADIRMfaPhoneToLocationCheck -TenantId $TenantID
84 | if (!$PhoneToLocationCheck) {
85 | Write-Host "There is no data returned for the function Get-AzureADIRMfaPhoneToLocationCheck" -ForegroundColor Cyan
86 | } else {
87 | Get-AzureADIRMfaPhoneToLocationCheck -TenantId $TenantID -CsvOutput
88 | }
89 |
90 | ## Gets user risk dismissals for the target tenant
91 | $UserRiskDismissCheck = Get-AzureADIRDismissedUserRisk -TenantId $TenantID
92 | if (!$UserRiskDismissCheck) {
93 | Write-Host "There is no data returned for the function Get-AzureADIRDismissedUserRisk" -ForegroundColor Cyan
94 | } else {
95 | Get-AzureADIRDismissedUserRisk -TenantId $TenantID -CsvOutput
96 | }
97 |
98 | ## Gets Self-service password reset usage history for the target tenant
99 | $SsprHistoryCheck = Get-AzureADIRSsprUsageHistory -TenantId $TenantID
100 | if (!$SsprHistoryCheck) {
101 | Write-Host "There is no data returned for the function Get-AzureADIRSsprUsageHistory" -ForegroundColor Cyan
102 | } else {
103 | Get-AzureADIRSsprUsageHistory -TenantId $TenantID -CsvOutput
104 | }
105 |
106 | ## Get Azure AD Conditional Access policies
107 | $CAPolicy = Get-AzureADIRConditionalAccessPolicy -TenantId $TenantID
108 | if (!$CAPolicy) {
109 | Write-Host "There is no data returned for the function Get-AzureADIRConditionalAccessPolicy" -ForegroundColor Cyan
110 | } else {
111 | Get-AzureADIRConditionalAccessPolicy -TenantId $TenantID -All -XmlOutput
112 | }
113 |
114 | ######################################################################
115 | Write-Host "Please review the files in your output directory" -ForegroundColor Cyan
116 | Write-Host
117 | Write-Host "Script completed." -ForegroundColor Cyan
118 | Write-Host
119 |
120 | <#
121 | #############################################################
122 | ## More Examples; I encourage you to use and explore the various AzureADIR functions
123 |
124 | #############################################################
125 | ## Collect Azure AD Audit logs by category
126 |
127 | Get-AzureADIRAuditActivity -TenantId $TenantID -Category "DirectoryManagement" | Out-GridView
128 |
129 | Get-AzureADIRAuditActivity -TenantId $TenantID -Category "UserManagement" | Out-GridView
130 |
131 | Get-AzureADIRAuditActivity -TenantId $TenantID -Category "RoleManagement" | Out-GridView
132 |
133 | Get-AzureADIRAuditActivity -TenantId $TenantID -Category "ApplicationManagement" | Out-GridView
134 |
135 |
136 | #############################################################
137 | ## Collect Azure AD Audit logs for specific activities
138 |
139 | ## Gets new MFA method registrations
140 | Get-AzureADIRAuditActivity -TenantId $TenantID -ActivityDisplayName "User registered security info" | Out-GridView
141 |
142 | ## Gets newly added applications
143 | Get-AzureADIRAuditActivity -TenantId $TenantID -ActivityDisplayName ("Add application") | Out-GridView
144 |
145 | ## Gets a list of newly added application permissions
146 | Get-AzureADIRAuditActivity -TenantId $TenantID -ActivityDisplayName ("Add app role assignment to service principal") | Out-GridView
147 |
148 | ## Gets a list of newly added delegated user permissions
149 | Get-AzureADIRAuditActivity -TenantId $TenantID -ActivityDisplayName ("Add delegated permission grant") | Out-GridView
150 |
151 | ## Gets a list of newly consented application permissions
152 | Get-AzureADIRAuditActivity -TenantId $TenantID -ActivityDisplayName ("Consent to application") | Out-GridView
153 |
154 | #############################################################
155 | ## Gets stale user accounts not signed in within last 30 days (including guests)
156 | Get-AzureADIRUserLastSignInActivity -TenantId $TenantID -StaleThreshold 30 -GuestInfo | Export-Csv -Path $OutputPath\$DomainName\AADLog_StaleAccountsLastSignIn.csv
157 |
158 | #############################################################
159 |
160 |
161 |
162 | #>
--------------------------------------------------------------------------------
/Incident Response/permissiontable.csv:
--------------------------------------------------------------------------------
1 | Type,Permission,Risk,Reason
2 | Delegated,Mail.ReadBasic,Medium,DataExfiltration
3 | Delegated,Mail,High,Phishing
4 | Delegated,Contacts,High,Phishing
5 | Delegated,MailboxSettings,High,Phishing
6 | Delegated,People,High,Phishing
7 | Delegated,Files,High,Phishing
8 | Delegated,Notes,High,Phishing
9 | Delegated,Directory.AccessAsUser.All,High,Phishing
10 | Delegated,user_impersonation,High,Phishing
11 | Delegated,Application.ReadWrite.All,High,BroadImpact
12 | Delegated,Directory.ReadWrite.All,High,BroadImpact
13 | Delegated,Domain.ReadWrite.All,High,BroadImpact
14 | Delegated,EduRoster.ReadWrite.All,High,BroadImpact
15 | Delegated,Group.ReadWrite.All,High,BroadImpact
16 | Delegated,Member.Read.Hidden,High,BroadImpact
17 | Delegated,RoleManagement.ReadWrite.Directory,High,BroadImpact
18 | Delegated,User.ReadWrite.All,High,BroadImpact
19 | Delegated,User.ManageCreds.All,High,BroadImpact
20 | Application,Mail,High,Phishing
21 | Application,Contacts,High,Phishing
22 | Application,MailboxSettings,High,Phishing
23 | Application,People,High,Phishing
24 | Application,Files,High,Phishing
25 | Application,Notes,High,Phishing
26 | Application,Directory.AccessAsUser.All,High,Phishing
27 | Application,user_impersonation,High,Phishing
28 | Application,Application.ReadWrite.All,High,BroadImpact
29 | Application,Directory.ReadWrite.All,High,BroadImpact
30 | Application,Domain.ReadWrite.All,High,BroadImpact
31 | Application,EduRoster.ReadWrite.All,High,BroadImpact
32 | Application,Group.ReadWrite.All,High,BroadImpact
33 | Application,Member.Read.Hidden,High,BroadImpact
34 | Application,RoleManagement.ReadWrite.Directory,High,BroadImpact
35 | Application,User.ReadWrite.All,High,BroadImpact
36 | Application,User.ManageCreds.All,High,BroadImpact
37 | Delegated,User.Read,Low,Common pattern
38 | Delegated,User.ReadBasic.All,Low,Common pattern
39 | Delegated,open_id,Low,Common pattern
40 | Delegated,email,Low,Common pattern
41 | Delegated,profile,Low,Common pattern
42 | Delegated,offline_access,Low,Common pattern when used with other low permissions
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to