├── EXOPrimaryEmailDomains └── EXOPrimaryEmailDomains.ps1 ├── .gitattributes ├── LICENSE ├── Get-ImmutableID └── Get-ImmutableID.ps1 ├── Connect-ComplianceCenter └── Function-ConnectComplianceCenter.ps1 ├── Test-FederatedDomainProof └── Test-FederatedDomainProof.ps1 ├── Connect-EXOnline └── Functions-ConnectDisconnect.ps1 ├── CompareOnPremisesToCloud └── CompareOnPremisesToCloud.ps1 └── CompareCloudToOnPremises └── CompareCloudToOnPremises.ps1 /EXOPrimaryEmailDomains/EXOPrimaryEmailDomains.ps1: -------------------------------------------------------------------------------- 1 | $mailboxes = Get-Mailbox -ResultSize Unlimited | select PrimarySmtpAddress 2 | 3 | $domains = @() 4 | 5 | foreach ($mailbox in $mailboxes) 6 | { 7 | $domain = $mailbox.PrimarySmtpAddress.Split("@")[1] 8 | 9 | $domains += $domain 10 | } 11 | 12 | $domains | Group-Object | Select name,count 13 | 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Paul Cunningham 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Get-ImmutableID/Get-ImmutableID.ps1: -------------------------------------------------------------------------------- 1 | #Get-ImmutableID.ps1 2 | #Written By: Paul Cunningham 3 | # 4 | #Change Log 5 | #V1.0, 9/1/2015 - Initial version 6 | # 7 | #.SYNOPSIS 8 | #Calculates the immutable ID of an on-premises Active Directory user object. 9 | # 10 | #.EXAMPLE 11 | #.\Get-ImmutableID.ps1 user1@domain.com 12 | # 13 | 14 | #................................... 15 | # Static Variables 16 | #................................... 17 | 18 | 19 | 20 | #................................... 21 | # Functions 22 | #................................... 23 | 24 | 25 | 26 | #................................... 27 | # Script 28 | #................................... 29 | 30 | [CmdletBinding()] 31 | Param( 32 | [Parameter(Mandatory=$True,Position=1)] 33 | [string]$UserName 34 | ) 35 | 36 | try 37 | { 38 | Import-Module ActiveDirectory -ErrorAction STOP 39 | $user = Get-ADUser $UserName -ErrorAction STOP 40 | $guid = [GUID]($user).ObjectGUID 41 | $bytearray = $guid.ToByteArray() 42 | 43 | $immutableID = [system.convert]::ToBase64String($bytearray) 44 | 45 | Write-Host "User: $UserName" 46 | Write-Host "ImmutableID: $immutableID" 47 | 48 | } 49 | catch 50 | { 51 | Write-Warning $_.Exception.Message 52 | EXIT 53 | } 54 | 55 | -------------------------------------------------------------------------------- /Connect-ComplianceCenter/Function-ConnectComplianceCenter.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | These functions can be added to your PowerShell profile to allow you to 3 | quickly and easily connect to the Office 365 Compliance Center. 4 | 5 | For more info on how they are used see: 6 | http://exchangeserverpro.com/powershell-function-connect-office-365-compliance-center/ 7 | http://exchangeserverpro.com/create-powershell-profile 8 | 9 | Written by: Paul Cunningham 10 | 11 | Find me on: 12 | 13 | * My Blog: https://paulcunningham.me 14 | * Twitter: https://twitter.com/paulcunningham 15 | * LinkedIn: https://au.linkedin.com/in/cunninghamp/ 16 | * Github: https://github.com/cunninghamp 17 | 18 | Change Log: 19 | V1.00, 8/7/2014 - Initial version 20 | #> 21 | 22 | # This function will prompt for authentication and connect to the Office 365 Compliance Center 23 | Function Connect-ComplianceCenter { 24 | 25 | $URL = "https://ps.compliance.protection.outlook.com/powershell-liveid/" 26 | 27 | $Credentials = Get-Credential -Message "Enter your Office 365 admin credentials" 28 | 29 | $EXOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $URL -Credential $Credentials -Authentication Basic -AllowRedirection -Name "Compliance Center" 30 | 31 | Import-PSSession $EXOSession 32 | 33 | } 34 | 35 | #This function will disconnect the PS Session "Compliance Center". This may 36 | #leave other PS Sessions open to Office 365 if others have been created. 37 | Function Disconnect-ComplianceCenter { 38 | 39 | Remove-PSSession -Name "Compliance" 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Test-FederatedDomainProof/Test-FederatedDomainProof.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Test-FederatedDomainProof.ps1 - Test the federated domain proof TXT record exists in DNS. 4 | 5 | .DESCRIPTION 6 | This PowerShell script checks DNS for the TXT record containing the federated domain 7 | proof string that must be created when setting up a Hybrid Exchange/Office 365 configuration. 8 | The script must be run from within the Exchange organization that you are testing. In other 9 | words, you can't test Org A's federated domain proof record from Org B. 10 | 11 | .OUTPUTS 12 | Results are output to the console. 13 | 14 | .PARAMETER Domain 15 | The domain name to check. 16 | 17 | .EXAMPLE 18 | .\Test-FederatedDomainProof.ps1 -Domain exchangeserverpro.net 19 | 20 | .NOTES 21 | Written by: Paul Cunningham 22 | 23 | Find me on: 24 | 25 | * My Blog: https://paulcunningham.me 26 | * Twitter: https://twitter.com/paulcunningham 27 | * LinkedIn: https://au.linkedin.com/in/cunninghamp/ 28 | * Github: https://github.com/cunninghamp 29 | 30 | Change Log 31 | V1.00, 10/08/2015 - Initial version 32 | #> 33 | 34 | #requires -version 2 35 | 36 | param ( 37 | [Parameter(Mandatory=$true)] 38 | [string]$Domain 39 | ) 40 | 41 | 42 | #................................... 43 | # Script 44 | #................................... 45 | 46 | 47 | #Add Exchange 2010 snapin if not already loaded in the PowerShell session 48 | if (Test-Path $env:ExchangeInstallPath\bin\RemoteExchange.ps1) 49 | { 50 | . $env:ExchangeInstallPath\bin\RemoteExchange.ps1 51 | Connect-ExchangeServer -auto -AllowClobber 52 | } 53 | else 54 | { 55 | Write-Warning "Exchange Server management tools are not installed on this computer." 56 | EXIT 57 | } 58 | 59 | Write-Host "Get federated domain proof for domain $domain" 60 | 61 | $proof = (Get-FederatedDomainProof -DomainName $domain).Proof 62 | 63 | Write-Host "Proof: $proof" 64 | 65 | Write-Host "Lookup TXT records for domain $domain" 66 | try { 67 | 68 | $txts = @(Resolve-DnsName -Name $domain -Type TXT -Server 8.8.8.8 -ErrorAction STOP).Strings 69 | 70 | Write-Host "TXT records:" 71 | $txts 72 | } 73 | catch 74 | { 75 | Write-Warning $_.Exception.Message 76 | EXIT 77 | } 78 | 79 | Write-Host "Compare proof to TXT records" 80 | 81 | if ($txts -contains $proof) 82 | { 83 | Write-Host -ForegroundColor Green "Proof found in TXT records." 84 | } 85 | else 86 | { 87 | Write-Host -ForegroundColor Red "Proof not found in TXT records." 88 | } 89 | 90 | 91 | #................................... 92 | # Finished 93 | #................................... 94 | -------------------------------------------------------------------------------- /Connect-EXOnline/Functions-ConnectDisconnect.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | These functions can be added to your PowerShell profile to allow you to 3 | quickly and easily connect to Exchange Online (Office 365). 4 | 5 | For more info on how they are used see: 6 | http://exchangeserverpro.com/powershell-function-connect-office-365/ 7 | http://exchangeserverpro.com/create-powershell-profile 8 | 9 | Written by: Paul Cunningham 10 | 11 | Find me on: 12 | 13 | * My Blog: https://paulcunningham.me 14 | * Twitter: https://twitter.com/paulcunningham 15 | * LinkedIn: https://au.linkedin.com/in/cunninghamp/ 16 | * Github: https://github.com/cunninghamp 17 | 18 | Change Log: 19 | V1.00, 14/10/2014 - Initial version 20 | V1.01, 22/05/2016 - Updated with new PowerShell endpoint URL 21 | V1.02, 27/09/2016 - Connect-EXOnline updated with new functionality for using stored credentials 22 | #> 23 | 24 | Function Connect-EXOnline { 25 | 26 | <# 27 | .SYNOPSIS 28 | Connect-EXOnline.ps1 - Connect to Exchange Online 29 | 30 | .DESCRIPTION 31 | This function will connect to Exchange Online using PowerShell. 32 | 33 | .PARAMETER UseCredential 34 | Uses a stored credential on the computer for authenticating with 35 | Exchange Online. For more information on using stored credentials 36 | refer to 37 | 38 | .PARAMETER Prefix 39 | Prefixes the Exchange Online cmdlets with the value that you specify 40 | (such as "Cloud")so that they can be used alongside the on-premises 41 | Exchange cmdlets of the same name. 42 | 43 | .EXAMPLE 44 | Connect-EXOnline 45 | Prompts for authentication and connects to Exchange Online. 46 | 47 | .EXAMPLE 48 | Connect-EXOnline -UseCredential admin@tenant.onmicrosoft.com 49 | Uses the stored credential for admin@tenant.onmicrosoft.com to connect 50 | to Exchange Online. 51 | 52 | .EXAMPLE 53 | Connect-EXOnline -UseCredential admin@tenant.onmicrosoft.com -Prefix EXO 54 | Uses the stored credential for admin@tenant.onmicrosoft.com to connect 55 | to Exchange Online, and prefixes the cmdlets with "EXO", for example 56 | Get-EXOMailbox instead of Get-Mailbox. 57 | 58 | .NOTES 59 | Written by: Paul Cunningham 60 | 61 | Find me on: 62 | 63 | * My Blog: http://paulcunningham.me 64 | * Twitter: https://twitter.com/paulcunningham 65 | * LinkedIn: http://au.linkedin.com/in/cunninghamp/ 66 | * Github: https://github.com/cunninghamp 67 | 68 | For more Office 365 tips, tricks and news 69 | check out Practical 365. 70 | 71 | * Website: https://practical365.com 72 | * Twitter: https://twitter.com/practical365 73 | #> 74 | 75 | param( 76 | [Parameter(Mandatory=$false)] 77 | [string]$UseCredential, 78 | 79 | [Parameter(Mandatory=$false)] 80 | [string]$Prefix 81 | ) 82 | 83 | $URL = "https://outlook.office365.com/powershell-liveid/" 84 | 85 | if ($UseCredential) { 86 | $Credentials = Get-StoredCredential -UserName $UseCredential 87 | } 88 | else { 89 | $Credentials = Get-Credential -Message "Enter your Office 365 admin credentials" 90 | } 91 | 92 | $EXOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $URL -Credential $Credentials -Authentication Basic -AllowRedirection -Name "Exchange Online" 93 | 94 | if ($Prefix) { 95 | Import-PSSession $EXOSession -Prefix $Prefix 96 | } 97 | else { 98 | Import-PSSession $EXOSession 99 | } 100 | } 101 | 102 | #This function will disconnect the PS Session "Exchange Online". This may 103 | #leave other PS Sessions open to EXO if others have been created. 104 | Function Disconnect-EXOnline { 105 | 106 | Remove-PSSession -Name "Exchange Online" 107 | 108 | } 109 | -------------------------------------------------------------------------------- /CompareOnPremisesToCloud/CompareOnPremisesToCloud.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | CompareOnPremisesToCloud.ps1 4 | #> 5 | 6 | #requires -version 2 7 | 8 | [CmdletBinding()] 9 | param ( 10 | 11 | [Parameter( Mandatory=$false)] 12 | [string]$ADWSserver 13 | 14 | ) 15 | 16 | 17 | #................................... 18 | # Variables 19 | #................................... 20 | 21 | $scriptname = "CompareOnPremisesToCloud.ps1" 22 | $now = Get-Date 23 | 24 | $myDir = Split-Path -Parent $MyInvocation.MyCommand.Path 25 | $logfile = "$myDir\$scriptname.log" 26 | 27 | $report = @() 28 | 29 | #................................... 30 | # Logfile Strings 31 | #................................... 32 | 33 | $logstring0 = "=====================================" 34 | $logstring1 = " $scriptname" 35 | 36 | 37 | #................................... 38 | # Initialization Strings 39 | #................................... 40 | 41 | $initstring0 = "Initializing..." 42 | 43 | 44 | #................................... 45 | # Functions 46 | #................................... 47 | 48 | 49 | # This function will prompt for authentication and connect to Exchange Online 50 | Function Connect-EXOnline { 51 | 52 | $URL = "https://ps.outlook.com/powershell" 53 | 54 | $Credentials = Get-Credential 55 | 56 | $EXOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $URL -Credential $Credentials -Authentication Basic -AllowRedirection -Name "Exchange Online" 57 | 58 | Import-PSSession $EXOSession -Prefix EXO 59 | 60 | } 61 | 62 | #This function will disconnect the PS Session "Exchange Online". This may 63 | #leave other PS Sessions open to EXO if others have been created. 64 | Function Disconnect-EXOnline { 65 | 66 | Remove-PSSession -Name "Exchange Online" 67 | 68 | } 69 | 70 | 71 | #................................... 72 | # Initialize 73 | #................................... 74 | 75 | try { 76 | Import-Module ActiveDirectory -ErrorAction STOP 77 | } 78 | catch { 79 | Write-Warning $_.Exception.Message 80 | EXIT 81 | } 82 | 83 | 84 | #................................... 85 | # Script 86 | #................................... 87 | 88 | Write-Host "Connecting to Exchange Online..." 89 | 90 | Connect-EXOnline 91 | 92 | Write-Host "Retrieving mailbox list from Exchange Online" 93 | $cloudusers = Get-EXOUser 94 | 95 | Write-Host "Retrieving user accounts list from Active Directory" 96 | if ($ADWSserver) 97 | { 98 | $onpremusers = Get-ADUser -Filter * -Properties * -Server $ADWSserver 99 | } 100 | else 101 | { 102 | $onpremusers = Get-ADUser -Filter * -Properties * 103 | } 104 | 105 | foreach ($onpremuser in $onpremusers) 106 | { 107 | 108 | Write-Host "Processing: $onpremuser" 109 | $reportObj = New-Object PSObject 110 | $reportObj | Add-Member NoteProperty -Name "Name" -Value $onpremuser.Name 111 | $reportObj | Add-Member NoteProperty -Name "SamAccountName" -Value $onpremuser.SamAccountName 112 | $reportObj | Add-Member NoteProperty -Name "UPN" -Value $onpremuser.UserPrincipalName 113 | $reportObj | Add-Member NoteProperty -Name "Email Address" -Value $onpremuser.EmailAddress 114 | $reportObj | Add-Member NoteProperty -Name "Target Address" -Value $onpremuser.targetAddress 115 | 116 | $clouduser = $null 117 | 118 | $clouduser = $cloudusers | Where {$_.UserPrincipalName -eq $onpremuser.UserPrincipalName} 119 | 120 | if ($clouduser) 121 | { 122 | $reportObj | Add-Member NoteProperty -Name "Cloud Name" -Value $clouduser.Name 123 | $reportObj | Add-Member NoteProperty -Name "Cloud UPN" -Value $clouduser.UserPrincipalName 124 | $reportObj | Add-Member NoteProperty -Name "Cloud Email Address" -Value $clouduser.WindowsEmailAddress 125 | } 126 | else 127 | { 128 | $reportObj | Add-Member NoteProperty -Name "Cloud Name" -Value "Not matched" 129 | $reportObj | Add-Member NoteProperty -Name "Cloud UPN" -Value "Not matched" 130 | $reportObj | Add-Member NoteProperty -Name "Cloud Email Address" -Value "Not matched" 131 | } 132 | 133 | $report +=$reportObj 134 | 135 | } 136 | 137 | Write-Host "Disconnecting from Exchange Online" 138 | Disconnect-EXOnline 139 | 140 | Write-Host "Writing report to CSV file" 141 | $report | Export-CSV -NoTypeInformation CompareOnPremisestoCloud-Report.csv 142 | 143 | #................................... 144 | # End 145 | #................................... 146 | 147 | Write-Host "Finished." 148 | 149 | -------------------------------------------------------------------------------- /CompareCloudToOnPremises/CompareCloudToOnPremises.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | CompareCloudToOnPremises.ps1 4 | #> 5 | 6 | #requires -version 2 7 | 8 | [CmdletBinding()] 9 | param ( 10 | 11 | [Parameter( Mandatory=$false)] 12 | [string]$ADWSserver 13 | 14 | ) 15 | 16 | 17 | #................................... 18 | # Variables 19 | #................................... 20 | 21 | $scriptname = "CompareCloudToOnPremises.ps1" 22 | $now = Get-Date 23 | 24 | $myDir = Split-Path -Parent $MyInvocation.MyCommand.Path 25 | $logfile = "$myDir\$scriptname.log" 26 | 27 | $report = @() 28 | 29 | #................................... 30 | # Logfile Strings 31 | #................................... 32 | 33 | $logstring0 = "=====================================" 34 | $logstring1 = " $scriptname" 35 | 36 | 37 | #................................... 38 | # Initialization Strings 39 | #................................... 40 | 41 | $initstring0 = "Initializing..." 42 | 43 | 44 | #................................... 45 | # Functions 46 | #................................... 47 | 48 | 49 | # This function will prompt for authentication and connect to Exchange Online 50 | Function Connect-EXOnline { 51 | 52 | $URL = "https://ps.outlook.com/powershell" 53 | 54 | $Credentials = Get-Credential 55 | 56 | $EXOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $URL -Credential $Credentials -Authentication Basic -AllowRedirection -Name "Exchange Online" 57 | 58 | Import-PSSession $EXOSession -Prefix EXO 59 | 60 | } 61 | 62 | #This function will disconnect the PS Session "Exchange Online". This may 63 | #leave other PS Sessions open to EXO if others have been created. 64 | Function Disconnect-EXOnline { 65 | 66 | Remove-PSSession -Name "Exchange Online" 67 | 68 | } 69 | 70 | 71 | #................................... 72 | # Initialize 73 | #................................... 74 | 75 | try { 76 | Import-Module ActiveDirectory -ErrorAction STOP 77 | } 78 | catch { 79 | Write-Warning $_.Exception.Message 80 | EXIT 81 | } 82 | 83 | 84 | #................................... 85 | # Script 86 | #................................... 87 | 88 | Write-Host "Connecting to Exchange Online..." 89 | 90 | Connect-EXOnline 91 | 92 | Write-Host "Retrieving mailbox list from Exchange Online" 93 | $cloudusers = Get-EXOUser 94 | 95 | Write-Host "Retrieving user accounts list from Active Directory" 96 | 97 | if ($ADWSserver) 98 | { 99 | $onpremusers = Get-ADUser -Filter * -Properties * -Server $ADWSserver 100 | } 101 | else 102 | { 103 | $onpremusers = Get-ADUser -Filter * -Properties * 104 | } 105 | 106 | foreach ($clouduser in $cloudusers) 107 | { 108 | 109 | Write-Host "Processing: $clouduser" 110 | $reportObj = New-Object PSObject 111 | $reportObj | Add-Member NoteProperty -Name "Name" -Value $clouduser.Name 112 | $reportObj | Add-Member NoteProperty -Name "UPN" -Value $clouduser.UserPrincipalName 113 | $reportObj | Add-Member NoteProperty -Name "Email Address" -Value $clouduser.WindowsEmailAddress 114 | 115 | 116 | $onpremuser = $null 117 | 118 | $onpremuser = $onpremusers | Where {$_.UserPrincipalName -eq $clouduser.UserPrincipalName} 119 | 120 | if ($onpremuser) 121 | { 122 | $reportObj | Add-Member NoteProperty -Name "On-Prem Name" -Value $onpremuser.Name 123 | $reportObj | Add-Member NoteProperty -Name "On_Prem UPN" -Value $onpremuser.UserPrincipalName 124 | $reportObj | Add-Member NoteProperty -Name "SamAccountName" -Value $onpremuser.SamAccountName 125 | $reportObj | Add-Member NoteProperty -Name "On-Prem Email Address" -Value $onpremuser.EmailAddress 126 | $reportObj | Add-Member NoteProperty -Name "Target Address" -Value $onpremuser.targetAddress 127 | } 128 | else 129 | { 130 | $reportObj | Add-Member NoteProperty -Name "On-Prem Name" -Value "No match" 131 | $reportObj | Add-Member NoteProperty -Name "On_Prem UPN" -Value "No match" 132 | $reportObj | Add-Member NoteProperty -Name "SamAccountName" -Value "No match" 133 | $reportObj | Add-Member NoteProperty -Name "On-Prem Email Address" -Value "No match" 134 | $reportObj | Add-Member NoteProperty -Name "Target Address" -Value "No match" 135 | } 136 | 137 | $report +=$reportObj 138 | 139 | } 140 | 141 | Write-Host "Disconnecting from Exchange Online" 142 | Disconnect-EXOnline 143 | 144 | Write-Host "Writing report to CSV file" 145 | $report | Export-CSV -NoTypeInformation CompareCloudToOnPremises-Report.csv 146 | 147 | #................................... 148 | # End 149 | #................................... 150 | 151 | Write-Host "Finished." 152 | 153 | --------------------------------------------------------------------------------