30 January 2019

Export AD OU's Users and Groups & Import to test AD with a new domain name

Well this was a fun task, export Active Directory OU's, all users and groups and import everything into a new test active directory with a different domain name.

First export every thing I need:
-OU's:
Get-ADOrganizationalUnit -filter * | select Name,DistinguishedName | Export-csv -path C:\temp\OUexport.csv -NoTypeInformation
-Users: (per specific OU)
Get-ADUser -Filter * -SearchScope OneLevel -SearchBase "OU=Users,DC=domain,DC=lan" -Properties CanonicalName,CN,DisplayName,GivenName,Name,Surname | Export-Csv "C:\Temp\PeopleExport.csv"
Get-ADUser -Filter * -SearchScope OneLevel -SearchBase "OU=External,OU=Users,DC=domain,DC=lan" -Properties CanonicalName,CN,DisplayName,GivenName,Name,Surname | Export-Csv "C:\Temp\ExternalExport.csv"
Get-ADUser -Filter * -SearchScope OneLevel -SearchBase "OU=Regular Accounts,OU=Users,DC=domain,DC=lan" -Properties CanonicalName,CN,DisplayName,GivenName,Name,Surname | Export-Csv "C:\Temp\RegularAccountsExport.csv"
Get-ADUser -Filter * -SearchScope OneLevel -SearchBase "OU=RandomName,OU=External,OU=Users,DC=domain,DC=lan" -Properties CanonicalName,CN,DisplayName,GivenName,Name,Surname | Export-Csv "C:\Temp\RandomNameExternalExport.csv"
-Groups:
Get-ADgroup -filter * | select Name,DistinguishedName,samaccountname,groupcategory,groupscope | Export-csv -path "C:\temp\GroupsExport.csv"
Then copy the .csv's to the new domain controller in C:\Temp.
Go through the files an find and replace the domainname to the new domainname.

You have to do something extra for the Group's.
In Notepad++ search and replace the CN- value for the DistinguishedName value.
It will look like this in the csv file:
"Name","DistinguishedName","samaccountname","groupcategory","groupscope"
"HelpServicesGroup","CN=HelpServicesGroup,DC=NewDomain,DC=local","HelpServicesGroup","Security","DomainLocal"

But it needs to be:
"Name","DistinguishedName","samaccountname","groupcategory","groupscope"
"HelpServicesGroup","DC=NewDomain,DC=local","HelpServicesGroup","Security","DomainLocal"

This is because the CN does not exist yet.
To replace the "CN=*," value use this in notepad++: \CN=.*?,
Where "\CN=" searches for "CN=", "*" searches for everything between "=" and "," and "?," stops the search where the "," is found.

Then import:
-OU's:
#Import AD Module - RSAT must be installed or run from DC
Import-Module ActiveDirectory
#Varibale location for CSV file
$ous = Import-Csv -Path "C:\temp\OUexport.csv"
# For each function to create OU's 
foreach ($ou in $ous)  
{               
# Function Variables
    $ouname = $ou.name
    $oudn = $ou.DistinguishedName
# Function
    New-ADOrganizationalUnit -Name $ouname -Path $oudn  -ManagedBy 'domain admins'
}
-Users:
Import-Csv .\PeopleExport.csv | New-ADUser -Enabled $True -Path 'OU=People,DC=sapgrc,DC=local' -AccountPassword (ConvertTo-SecureString Pass123 -AsPlainText -force)            
Import-Csv .\externenExport.csv | New-ADUser -Enabled $True -Path 'OU=Externen,OU=People,DC=sapgrc,DC=local' -AccountPassword (ConvertTo-SecureString Pass123 -AsPlainText -force)            
Import-Csv .\algemeneaccountsexport.csv | New-ADUser -Enabled $True -Path 'OU=Algemene Accounts,OU=People,DC=sapgrc,DC=local' -AccountPassword (ConvertTo-SecureString Pass123 -AsPlainText -force)            
Import-Csv .\veiexternenExport.csv | New-ADUser -Enabled $True -Path 'OU=VEI,OU=Externen,OU=People,DC=sapgrc,DC=local' -AccountPassword (ConvertTo-SecureString Pass123 -AsPlainText -force)
-Groups:
#Import AD Module - RSAT must be installed or run from DC            
Import-Module ActiveDirectory            
#Import CSV            
$csv = Import-Csv -Path "C:\Temp\GroupsExport.csv"            
#Loop through all items in the CSV            
ForEach ($item In $csv)            
{            
    #Create the group if it doesn't exist            
    $create = New-ADGroup -Path $item.DistinguishedName -SamAccountName $item.SamAccountName -GroupCategory $item.GroupCategory -GroupScope $item.GroupScope -Name $item.Name             
    Write-Host "Group $($item.Name) created!"            
}            


And there you have it.

22 January 2019

The content cannot be displayed in a frame - Exchange On-Premises - Exchange Online - Exchange Hybrid

After setting up your Hybrid Exchange connection and logging in to the Exchange Control Panel trying to move your first mailbox to Exchange Online you need to login to Office365.

When you click the login button on the popup you receive the following error:
Now this is fairly easy to fix, just add the url https://outlook.office365.com to the trusted sites in Internet Explorer.
But then this:
The option is greyed out.

There are 2 ways to get around this, one through the registry and one through a group policy:
Add the following to a textfile and paste in:
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMapKey]
"https://outlook.office365.com"="2"
Save as a .reg and execute.

This can also be stored in the HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMapKey.

The check if the settings are present run in PowerShell:

$(get-item "HKCU:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMapKey").property            
            
$(get-item "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMapKey").property            

The group policy goes like this:
  • Start -> type gpedit.msc -> hit Enter
  • navigate to Computer Configuration -> Administrative Templates -> Windows Components -> Internet Explorer -> Internet Control Panel -> Security Page
  • in the right-hand panel, double-click on the Site to Zone Assignment List option, then click Show...
  • trusted sites are the ones with 2 in the Value column (1 = Intranet, 3 = Internet, 4 = Restricted)
If that doesn't work (that option is set to "Not Configured" or the list is empty), try the same, except instead of Computer Configuration, start with User Configuration.












04 January 2019

Connect to all Azure & Office 365 services in one PowerShell window

We've all been there, when running some commandlets from Exchange online suddenly you need to switch to Sharepoint, AzureAD or Skype Online.

With this handy script you can connect to all services at once.
I personally always use the Exchange Online PowerShell module for this, as it will be updated when starting it so you always have the latest commandlets for Exchange Online.

There are some requirements that have to be met before hand:

  • .Net 4.5
  • Windows Management Framework 3.0 or 4.0
  • 64-bit version of Windows OS
Installed modules:
  • Azure Active Directory V2 module
  • SharePoint Online module
  • Skype for Business Online module
Execution policy needs to be at least "Remote Signed"

In the past I have created a script that installs all these requirements at once:
I try to keep this updated, so if anything fails leave me a comment.


Then you can run the lines below and connect to all the services in one PowerShell window.
Mind you, this is all for MFA enabled accounts.

# Azure Active Directory            
Connect-MsolService            
# SharePoint Online            
Connect-SPOService -Url https://tenant-admin.sharepoint.com            
# Skype for Business Online            
Import-Module SkypeOnlineConnector            
$sfboSession = New-CsOnlineSession -UserName "username@domain.com" -OverrideAdminDomain tenant.onmicrosoft.com            
Import-PSSession $sfboSession            
# Exchange Online            
Connect-Exopssession -UserPrincipalName username@domain.com            
# Microsoft Teams            
Connect-MicrosoftTeams            
# AzureAD            
Connect-AzureAD

03 January 2019

Enable audit logging on all mailboxes in your tenant - Optimize your SecureScore

If you want to achieve the highest Secure Score number you will be advised to enable mailbox auditing by the SecureScore actions list.
If you follow the link provided in the article you will land on a Github page that has a script to enable auditing on all mailboxes in a tenant.
But it was missing one type of mailbox, the SchedulingMailbox.
I added the missing mailbox type in the command below, now it works as it should.

First login to your tenant with global admin rights or Exchange Online admin privileges:
Connect-EXOPSSession
Check how your settings are now:
Get-Mailbox -ResultSize Unlimited | Select Name, AuditEnabled, AuditLogAgeLimit | Out-Gridview
Then turn on audit logging on all mailboxes:
Get-Mailbox -ResultSize Unlimited -Filter {RecipientTypeDetails -eq "UserMailbox" -or RecipientTypeDetails -eq "SharedMailbox" -or 
RecipientTypeDetails -eq "RoomMailbox" -or RecipientTypeDetails -eq "DiscoveryMailbox" -or RecipientTypeDetails -eq "SchedulingMailbox"}
 | Set-Mailbox -AuditEnabled $true -AuditLogAgeLimit 180 -AuditAdmin Update, MoveToDeletedItems, SoftDelete, HardDelete, SendAs, 
SendOnBehalf, Create, UpdateFolderPermission -AuditDelegate Update, SoftDelete, HardDelete, SendAs, Create, UpdateFolderPermissions, 
MoveToDeletedItems, SendOnBehalf -AuditOwner UpdateFolderPermission, MailboxLogin, Create, SoftDelete, HardDelete, Update, MoveToDeletedItems
Check again to be sure all mailboxes are enabled for audit logging:
Get-Mailbox -ResultSize Unlimited | Select Name, AuditEnabled, AuditLogAgeLimit | Out-Gridview


27 December 2018

Save disk space - Compact - NTFS compress your folders

In the ever ongoing search for disk space on Exchange servers it is possible to compress certain folders with NTFS compression.
You could do this through the file explorer and click yourself silly, or you can turn to PowerShell.
Actually it's just an old command prompt program, but we'll use it in PowerShell.

Now first things first:

DO NOT USE THIS ON YOUR MAILBOXDATABASES!!!

This may seem like a no brainer but I don't want to hear that someone used it because I didn't warn them.
The only thing you can safely use this for is on log files, temp files, etl files and blg files.
If you've read my previous blog post about cleaning up certain logging folders used by exchange (which can be found here:
https://vanbrenk.blogspot.com/2018/02/clean-iis-log-files-blg-and-etl-files.html)

Here are the directories you can compress safely:
As always with scripts/code found on the internet, test it yourself on a test environment.

.\compact.exe /C /S /A /I "C:\Program Files\Microsoft\Exchange Server\V15\Logging\*"                        
.\compact.exe /C /S /A /I "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Search\Ceres\Diagnostics\ETLTraces\*"                        
.\compact.exe /C /S /A /I "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Search\Ceres\Diagnostics\Logs\*"                        
.\compact.exe /C /S /A /I "C:\Program Files\Microsoft\Exchange Server\V15\FIP-FS\Data\ProgramLogArchive\*"                        
.\compact.exe /C /S /A /I "C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\FrontEnd\Connectivity\*"                        
.\compact.exe /C /S /A /I "C:\Windows\System32\LogFiles\HTTPERR\*"

14 December 2018

Get-CsWebTicket : Failed to logon with given credentials. Make sure correct user name and password provided.

When trying to login to Skype Online through PowerShell or the Skype for Business control panel you receive the following error:
The WinRM client cannot process the request. Basic authentication is currently disabled in the client configuration. Change the client configuration and try the request again.

Or this one:

Get-CsWebTicket : Failed to logon with given credentials. Make sure correct user name and password provided.

Then the search begins, and brought me to this:
View the current winrm settings to check whether "basic authentication" has been disabled or not.
winrm get winrm/config/client/auth
Auth
    Basic = true [Source="GPO"]
    Digest = true [Source="GPO"]
    Kerberos = true
    Negotiate = true
    Certificate = true
    CredSSP = false

For me it was set with a GPO.
Trying to set it with this:

winrm set config/client/auth/ @{basic="true"}

Error: Invalid use of command line. Type "winrm -?" for help.
That didn't go as planned.
The tried to set it in the registry with this:
Open regedit as admin and go to:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WinRM\Client

Simply change the DWORD from 0 to 1 and then restart the PowerShell console

Well that's nice but no solution.

Then searched for the other error, the one with the Get-CSWebTicket error.
Which led me to this:
Since Skype for Business Control Panel don’t support two-step verification we will need to to set up an “app password” for our Office 365 admin account that has MFA enabled.

Oh, really...and yes I just enabled the force MFA option policy in Azure: "Baseline policy: Require MFA for admins (Preview)".

Created an app password an pasted it in my SkypeOnline PowerShell module and voila I was in once again.

27 November 2018

PowerShell One liners (continuous work in progress)

If you know a nice one liner that should be on here drop me a line.
Install the latest PowerShellGet version:
Install-Module PowerShellGet -Force
Find the number of users that connect through OWA:
"C:\Program Files (x86)\Log Parser 2.2\logparser.exe" "SELECT cs-username, Count(*) AS OWAHits from \\sr-xxxxx\d$\IISLogs\W3SVC1\u_ex*.log
 WHERE cs-uri-stem LIKE '/OWA/' AND cs-username IS NOT NULL GROUP BY cs-username ORDER BY OWAHits Desc" -rtp:-1
Find all soft deleted mailboxes
Get-MailboxDatabase | Get-MailboxStatistics | Where { $_.DisconnectReason -eq "SoftDeleted" } | Format-Table DisplayName,Database,DisconnectDate
Permanently delete soft deleted mailboxes
Remove-StoreMailbox -Database MBX02 -Identity "John Doe" -MailboxState SoftDeleted
Delete all soft deleted mailboxes per database
Get-MailboxStatistics -Database MBX02 | where {$_.DisconnectReason -eq "SoftDeleted"} | ForEach
 {Remove-StoreMailbox -Database $_.Database -Identity $_.MailboxGuid -MailboxState SoftDeleted}
Update the Offline Addressbook and the Global Addressbook
Get-OfflineAddressBook | Update-OfflineAddressBook
Get-GlobalAddressList | Update-GlobalAddressList
Update Windows Defender manually:
"%programfiles%\windows defender\mpcmdrun.exe" -signatureupdate -http
Search for IMAP enabled mailboxes:
Get-CASMailbox -ResultSize unlimited | where {$_.ImapEnabled -eq $true} | FL name | out-file C:\temp\imapenabled.txt
Enable Remote Desktop locally:
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 1
Or including the firewall rule:
(Get-WmiObject Win32_TerminalServiceSetting -Namespace root\cimv2\TerminalServices).SetAllowTsConnections(1,1) | Out-Null
(Get-WmiObject -Class "Win32_TSGeneralSetting" -Namespace root\cimv2\TerminalServices 
-Filter "TerminalName='RDP-tcp'").SetUserAuthenticationRequired(0) | Out-Null
Get-NetFirewallRule -DisplayName "Remote Desktop*" | Set-NetFirewallRule -enabled true
Add a user to blocked senders
Set-MailboxJunkEmailConfiguration -Identity "UserName" –BlockedSendersandDomains @{Add="somebody@domain.com"}
Check if set correctly
Get-MailboxJunkEmailConfiguration -Identity "UserName" | FL BlockedSendersandDomains
To Remove a user from blocked senders
Set-MailboxJunkEmailConfiguration -Identity "UserName" –BlockedSendersandDomains @{Remove="somebody@domain.com"}
Delete the file "desktop.ini" from 2 directories deep:
get-childitem -path \\domain.lan\sharename\users\home\*\* -force -filter "desktop.ini" | foreach ($_) {remove-item $_.fullname -force 
-verbose 4>> c:\temp\desktopiniresults.txt}
Set UPN to match Mail Address for Office365 use:
Get-User -OrganizationalUnit "domain.com/OUName" -ResultSize unlimited | Where { -Not [string]::IsNullOrEmpty($_.WindowsEmailAddress) } | 
ForEach { Set-User -Identity $_.Guid.ToString() -UserPrincipalName $_.WindowsEmailAddress.ToString() }
Allow Windows 10 PC in workgroup to manage Hyper-v server:
winrm quickconfig -force
winrm set winrm/config/client ‘@{TrustedHosts=”Name of the Server”}’
Enable protocol logging for IMAP
Set-ImapSettings -Server "CAS01" -ProtocolLogEnabled $true
Disable protocol logging for IMAP
Set-ImapSettings -Server "CAS01" -ProtocolLogEnabled $false
Recreate the Sharedwebconfig.config files for Exchange 2013:
cd %ExchangeInstallPath%\bin
DependentAssemblyGenerator.exe -exchangePath "%ExchangeInstallPath%bin" -exchangePath "%ExchangeInstallPath%ClientAccess" 
-configFile "%ExchangeInstallPath%ClientAccess\SharedWebConfig.config"
DependentAssemblyGenerator.exe -exchangePath "%ExchangeInstallPath%bin" -exchangePath "%ExchangeInstallPath%FrontEnd\HttpProxy" 
-configFile "%ExchangeInstallPath%FrontEnd\HttpProxy\SharedWebConfig.config"
Get the list of network profiles on the system.
Get-NetConnectionProfile
Change the network interface to private, use the network interface index number from the previous command.
Set-NetConnectionProfile -InterfaceIndex 10 -NetworkCategory Private
Get Exchange build number:
Get-ExchangeServer | Format-List Name, Edition, AdminDisplayVersion
Get Exchange Schema version:
"Exchange Schema Version = " + ([ADSI]("LDAP://CN=ms-Exch-Schema-Version-Pt," + ([ADSI]"LDAP://RootDSE").schemaNamingContext)).rangeUpper
Set Default Addressbook Policy and Retention Policy for all mailboxes at once:
Get-Mailbox -ResultSize unlimited | Set-mailbox -AddressBookPolicy "Your AddressBookPolicy" -RetentionPolicy "Your - Default Policy"
Quickly add the Exchange PowerShell module to a regular PowerShell console:
Add-PSSnapin *exchange*
Add multiple aliasses at once:
Set-Mailbox "UserName" -EmailAddresses @{add="UserName01@domain.com","UserName02@domain.com","UserName03@domain.com","UserName04@domain.com",
"UserName05@domain.com","UserName06@domain.com","UserName07@domain.com","UserName08@domain.com","UserName09@domain.com","UserName10@domain.com",
"UserName11@domain.com","UserName12@domain.com","UserName13@domain.com","UserName14@domain.com","UserName15@domain.com","UserName16@domain.com",
"UserName17@domain.com","UserName18@domain.com","UserName19@domain.com","UserName20@domain.com"}
List all mailboxes that have a forwarding address
Get-mailbox -Resultsize Unlimited | select DisplayName,ForwardingAddress | where {$_.ForwardingAddress -ne $Null}
Send Output to Clipboard with PowerShell
Get-EventLog application -Newest 1 | clip
Find specific Help articles with Powershell
Get-Help about_
press tab to cycle through the matches
Find white space (Available new mailbox space) in all databases
Get-MailboxDatabase -Status | sort name | select name,@{Name='DB Size (Gb)';
Expression={$_.DatabaseSize.ToGb()}},@{Name='Available New Mbx Space Gb)';
Expression={$_.AvailableNewMailboxSpace.ToGb()}}
Create Powershell profile
New-Item -path $profile -type file –force
Edit the newly created profile in the following location
C:\Users\Username\Documents\WindowsPowerShell
Load all Powershell available modules at once:
Get-Module -ListAvailable | Import-Module
Turn off shutdown tracker for Windows server
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Reliability"
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Reliability" -Name ShutdownReasonOn -Value 0
Combine multiple files into one;
Get-ChildItem -filter "c:\temp\*.html" | % { Get-Content $_ -ReadCount 0 | Add-Content "c:\temp\combined_files.html" }
Or:
Get-Content -path c:\temp\eventlogs\*.html | Add-Content -Path C:\temp\Eventlogs\combined.html
Get users with imap enabled:
Get-CASMailbox -ResultSize unlimited | Where-Object {$_.imapenabled -eq "true"} | fl name,imapenabled
Get empty AD groups and email the output;
$body=Get-ADGroup -Filter * -Properties Members | where {-not $_.members} | select Name
Send-MailMessage -smtpserver smtp.domain.lan -subject
 "Empty groups" -to "user1@domain.com,user2@domain.com" -from "user@domain.com" -Body ( $Body | out-string )
Set send on behalf of rights;
Set-Mailbox UserMailbox -GrantSendOnBehalfTo UserWhoSends
View who has which permissions on a user mailbox;

Get-MailboxFolderPermission -Identity "alias:\postvak in" | fl 
(for Dutch)

Get-MailboxFolderPermission -Identity "alias:\inbox" | fl 
(for English)

View who has which permissions on a user calendar;

Get-MailboxFolderPermission -Identity alias:\agenda | fl 
(for Dutch)
Get-MailboxFolderPermission -Identity alias:\calendar | fl 
(for English)

Remove user rights on a mailbox/folder for an other user:
Remove-MailboxFolderPermission -Identity username1:\agenda -User username2
Add user rights on a mailbox/folder for an other user:
Add-MailboxFolderPermission -Identity username1:\agenda -AccessRights Publishingeditor -User username2
MAPI encryption enabled or disabled; (for Outlook 2003 clients)

Get-RpcClientAccess | fl encryp*,server
View blocked ActiveSync devices, in "Blocked" state for longer than a month;

Get-ActiveSync Device | Where {$_.DeviceAccessState -eq "blocked"} | Select DeviceModel | ft -auto
Delete "Blocked" activesync devices, in "Blocked" state for longer than a month;

Get-ActiveSync Device | Where {$_.DeviceAccessState -eq "Quarantined" -and $_.FirstSyncTime
 -lt (Get-Date).AddMonths(-1)} | Remove-ActiveSyncDevice

Delete all ActiveSync devices with DeviceAccessState "Blocked";

Get-ActiveSyncDevice | Where {$_.DeviceAccessState -eq "Blocked"} | 
Remove-ActiveSyncDevice

To retrieve all Exchange-related events:


Get-EventLog Application | Where { $_.Source -Ilike “*Exchange*” } 

07 November 2018

Unable to remove shared mailbox from Outlook profile

As a postmaster or Exchange admin you periodically need to open other users mailboxes to move stuff, restore stuff, add or adjust stuff and so on.

After a while you have a long list of attached mailboxes that you don't need anymore.
And sometimes those mailboxes won't disconnect properly.

How do you get rid of them when the mailboxes are still listed in your folder panel though the mailbox but not listed in Account Settings/Change/More settings/Advanced?

You can view the following attribute in ADUC:

Search for the (shared) mailbox you want to remove, right-click the (shared) mailbox, in the Attribute Editor, double click the msExchDelegateListLink attribute, check if your account is listed there. You can remove your account from the msExchDelegateListLink attribute to clear Automapping.
Restart Outlook and check if the shared mailbox is removed.

30 October 2018

Enable Office365 MFA per user or all users - Search for users with MFA disabled

Enabling all users for MFA is relatively easy with PowerShell, and how to's are found all over the web.
But enabling MFA for one user is a bit more difficult.
Here's how to do it:

Enable MFA per user
#Create the StrongAuthenticationRequirement object and insert required settings
$mf= New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$mf.RelyingParty = "*"
$mfa = @($mf)
#Enable MFA for a user
Set-MsolUser -UserPrincipalName userprinciplename@domain.com -StrongAuthenticationRequirements $mfa


#Enable MFA for all users (use with CAUTION!)
Get-MsolUser -All | Set-MsolUser -StrongAuthenticationRequirements $mfa

Check the settings
$User = Get-msoluser -UserPrincipalName 'user@domain.com' | Select-Object -ExpandProperty StrongAuthenticationRequirements
$User.State

#List All users and MFA status :            
Connect-MsolService            
            
$Result=@()             
$users = Get-MsolUser -All            
$users | ForEach-Object {            
$user = $_            
if ($user.StrongAuthenticationRequirements.State -ne $null){            
$mfaStatus = $user.StrongAuthenticationRequirements.State            
}else{            
$mfaStatus = "Disabled" }            
               
$Result += New-Object PSObject -property @{             
UserName = $user.DisplayName            
UserPrincipalName = $user.UserPrincipalName            
MFAStatus = $mfaStatus            
}            
}            
$Result | Select UserName,UserPrincipalName,MFAStatus            
            
#List only MFA enabled users :            
Connect-MsolService            
            
$Result=@()             
$users = Get-MsolUser -All            
$users | ForEach-Object {            
$user = $_            
if ($user.StrongAuthenticationRequirements.State -ne $null){            
$mfaStatus = $user.StrongAuthenticationRequirements.State            
}else{            
$mfaStatus = "Disabled" }            
               
$Result += New-Object PSObject -property @{             
UserName = $user.DisplayName            
UserPrincipalName = $user.UserPrincipalName            
MFAStatus = $mfaStatus            
}            
}             
$Result | Where-Object {$_.MFAStatus -ne "Disabled"}            
            
#List only MFA disabled users :            
Connect-MsolService            
            
$Result=@()             
$users = Get-MsolUser -All            
$users | ForEach-Object {            
$user = $_            
if ($user.StrongAuthenticationRequirements.State -ne $null){            
$mfaStatus = $user.StrongAuthenticationRequirements.State            
}else{            
$mfaStatus = "Disabled" }            
               
$Result += New-Object PSObject -property @{             
UserName = $user.DisplayName            
UserPrincipalName = $user.UserPrincipalName            
MFAStatus = $mfaStatus            
}            
}            
$Result | Where-Object {$_.MFAStatus -eq "Disabled"}            
            
#Export 365 users MFA status to CSV file :            
Connect-MsolService            
            
$Result=@()             
$users = Get-MsolUser -All            
$users | ForEach-Object {            
$user = $_            
if ($user.StrongAuthenticationRequirements.State -ne $null){            
$mfaStatus = $user.StrongAuthenticationRequirements.State            
}else{            
$mfaStatus = "Disabled" }            
               
$Result += New-Object PSObject -property @{             
UserName = $user.DisplayName            
UserPrincipalName = $user.UserPrincipalName            
MFAStatus = $mfaStatus            
}            
}            
$Result | Select UserName,UserPrincipalName,MFAStatus | Export-CSV "C:\Temp\O365-Users-MFA-Status.csv" -NoTypeInformation -Encoding UTF8            
            
#Create the StrongAuthenticationRequirement object and insert required settings            
$mf= New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement            
$mf.RelyingParty = "*"            
$mfa = @($mf)            
            
#Enable all disabled users for MFA :            
Connect-MsolService            
            
$Result=@()             
$users = Get-MsolUser -All            
$users | ForEach-Object {            
$user = $_            
if ($user.StrongAuthenticationRequirements.State -ne $null){            
$mfaStatus = $user.StrongAuthenticationRequirements.State            
}else{            
$mfaStatus = "Disabled" }            
               
$Result += New-Object PSObject -property @{             
UserName = $user.DisplayName            
UserPrincipalName = $user.UserPrincipalName            
MFAStatus = $mfaStatus            
}            
}            
$Result | Where-Object {$_.MFAStatus -eq "Disabled"} | Set-MsolUser -StrongAuthenticationRequirements $mfa

Identify users who have registered for MFA and count the number of users.
$Registered = Get-MsolUser -All | where {$_.StrongAuthenticationMethods -ne $null} | Select-Object -Property UserPrincipalName            
$registered            
$registered.count

Identify users who have not registered for MFA and count the number of users.
$NotRegistered = Get-MsolUser -All | where {$_.StrongAuthenticationMethods.Count -eq 0} | Select-Object -Property UserPrincipalName            
$NotRegistered            
$NotRegistered.count

Bulk enable for multiple users in csv file
Enable for multiple users
function Set-MFAUsers {            
    param (            
        [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]            
        [ValidateScript( {Test-Path $_})]              
        [Alias('FullName')]            
        [String] $Path,            
                    
        [ValidateSet('Enabled','Enforced')]            
        [String] $State = 'Enabled'            
    )            
            
    # Set MFA object            
    $MFASetting = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement -Property @{            
        RelyingParty = "*"            
        State        = $State            
    }            
                
    # Get user list            
    $Users = Get-Content -Path $Path -ReadCount -1            
            
    foreach ($user in $users)             
    {            
         $SetUser = @{            
            UserPrincipalName                = $user            
            StrongAuthenticationRequirements = $MFASetting             
            ErrorAction                      = 'Stop'              
        }            
            
        Try {            
            # Set MFA            
            Set-MsolUser @SetUser            
                        
            # Post Check            
            $ThisUser = Get-msoluser -UserPrincipalName $User |             
                Select-Object -ExpandProperty StrongAuthenticationRequirements            
            
            if ($ThisUser.State -eq $SetUser.StrongAuthenticationRequirements.State) {            
                Write-Host "[SUCCESS] UPN: $user" -ForegroundColor Green            
            }            
            else {            
                Write-Host "[FAILED ] UPN: $user" -ForegroundColor Red            
            }            
        }            
        Catch {            
             Write-Warning -Message $_.Exception.Message            
        }               
    }             
}            
            
Get-ChildItem C:\temp\MFA_Users.txt | Set-MFAUsers -State Enforced

19 October 2018

Exchange 2013 and 2016 - Create Edge subscription

I keep forgetting this:

This is for Exchange 2010, 2013 and 2016 and probaly 2019 but I didn't check this.

Create a new subscription file on the Edge server:
New-EdgeSubscription -FileName C:\Temp\Servername-Edge.xml

Copy the file to a mailbox server and import using this command:
New-EdgeSubscription -FileData ([byte[]]$(Get-Content -Path "C:\Temp\Servername-Edge.xml" -Encoding Byte -ReadCount 0)) -Site "Sitename"