Monday, March 23, 2020

Migrate to cloud authentication in batches

I am excited about this feature that has been released by Microsoft as that will assist many organizations that want to switch over form their federation application such as secuareauth, PING, ADFS and others to Cloud authentication.

  •  password hash synchronization (sync) + seamless single sign-on (SSO)
or
  • pass-through authentication + seamless SSO
Previously organizations have to do a hard cut-over, which to most of us that are managing office 365 is a big NO as there can be issues which we are not aware-of and possibility of repercussions.
With the staged roll-out we can avoid this as it can work in parallel with your current federation provider.

Note: Only Modern authentication is supported with cloud authentication staged roll out, classic authentication will fail back to your federation provider.

Below are the steps you need to follow in order to Enable staged Roll-out:

You have to choose first one of the methods either password hash or pass-through authentication.
We have enabled the password hash sync for our customer.



Next step is to enable Seamless SSO for your domain.(this needs to be done from you Azure AD connect server)

Import module AzureADSSO.psd1 located  under C:\Program Files\Microsoft Azure Active Directory Connect folder.

Import-Module .\AzureADSSO.psd1  (run this in powershell after switching to above location as administrator)



Next command is New-AzureADSSOAuthenticationContext which will launch the browser window where you need to add Global Admin credentials.

Run Get-AzureADSSOStatus | ConvertFrom-Json to check the status of the domains on which this feature is enabled.

Now type $creds = Get-Credential and provide domain administrator credentials.

Next action is to Enable SSO in your forest/domain  Enable-AzureADSSOForest -OnPremCredentials $creds

This will create the AZUREADSSOACC computer account in onpremise for SSO.

---------------------------Now you have to work on GPO ----------------------------------------------------------
ADD https://autologon.microsoftazuread-sso.com to selected or all users intranet zone settings.
Also, enable the policy setting Allow updates to status bar via script.
We pushed it to all users as we will control it later via AD group.
For complete instruction of GPO follow the link 
--------------------------------------------------------------------------------------------------------------------------

Once both the above steps are completed you need to logon to https://portal.azure.com/

Azure Active Directory --> Azure AD Connect




Click Enable staged roll-out for managed users sign-in

Turn On Seamless SSO and Passwordhash



ADD the security group for which you want to Enable this.

Recommendations from Microsoft:
  • No more than 200 users members in the group for the first time.
  • Try to use cloud only group so replication wait time does not occur (not mandatory)


Please also enable conditional access for this group, for our customer we blocked basic authentication and allowed MFA for trusted devices.

Require MFA for All users conditional access settings:






Similarly you need to block Classic authentication for this group so make one more conditional access policy.

Under conditions select the other clients and under grants block access.



Now when you will login your login will not go to your federation provider if you are member of that group but will use passwordhash and SSO (in case of trusted clients)

Non Trusted device screenshot:





Thanks for reading …

Tech Wizard

https://techwizard.cloud

https://www.syscloudpro.com/

PowerShell Cheat Book

Monday, March 16, 2020

End of Exchange Online Classic Authentication

As most of you admins are already aware that Microsoft is killing Basic authentication for Exchange Online services for PowerShell, EWS, POP, IMAP and EAS.

SMTP authentication is still supported.(changes will not affect it)



Microsoft already released the Exchange online MFA Powershell  previously but it lacked the capability to be used in scripts.

https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/mfa-connect-to-exchange-online-powershell

Microsoft has now released the version 2 of the module which they call as EXO v2.

https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/exchange-online-powershell-v2/exchange-online-powershell-v2

You can install it from PowerShell gallery 

https://www.powershellgallery.com/packages/ExchangeOnlineManagement

Install-Module -Name ExchangeOnlineManagement

This new module solves the issue for automated scripts and works seamlessly.

For all those admins/users that use my scripts that call Exchange online, you can install this module and then just update the LaunchEOL function code inside the script as below:

I will be updating my ALL in one office 365 connect in upcoming post.

############################If using a script that use password from file#####################
Function LaunchEOL {
param
(
$Credential
)
Import-Module ExchangeOnlineManagement -Prefix "EOL" -Verbose
Connect-ExchangeOnline -Prefix "EOL" -Credential $Credential
}
Function RemoveEOL {
$Session = Get-PSSession | where {$_.ComputerName -like "outlook.office365.com"}
Remove-PSSession $Session
}
#####################################################################################

######################If using a script that prompts for Credentials#####################
Function LaunchEOL {
Import-Module ExchangeOnlineManagement -Prefix "EOL" -Verbose
Connect-ExchangeOnline -Prefix "EOL"
}
Function RemoveEOL {
$Session = Get-PSSession | where {$_.ComputerName -like "outlook.office365.com"}
Remove-PSSession $Session
}
#####################################################################################

See above in bold you can easily  pass user-credentials to this module. (Connect-ExchangeOnline -Prefix "EOL" -Credential $Credential)

Lets connect now to Exchange Online from my machine after installing the v2 module.



This module has some updated list of cmdlets (older ones still works with the module)  which by default fetches fewer properties  and you need to use the keyword -Properties to get other attributes.

Example:

Older cmdlet

get-mailbox User| Select litigationholdenabled,LitigationHoldDuration,RecipientTypeDetails,PersistedCapabilities,RetentionHoldEnabled,RetentionPolicy,UserPrincipalName,Name

Newer cmdlet

get-exomailbox user -Properties litigationholdenabled,LitigationHoldDuration,RecipientTypeDetails,PersistedCapabilities,RetentionHoldEnabled,RetentionPolicy

If you will not use properties then values will not be displayed.



Start updating your scripts and automation else you will find your self in great trouble once Microsoft blocks it.

You can check Azure AD Signin report to see how you are connecting.

Before using this module: (Classic Auth)


After utilizing this module: (See below it is now REST API based Powershell) - ModernAuth  - Client APP changed from other clients to Mobile Apps and Desktop clients.



Thanks for reading ...

Tech Wizard

https://techwizard.cloud

https://www.syscloudpro.com/

PowerShell Cheat Book

Saturday, March 7, 2020

Bulk Enable Teams Only Mode

Sharing this PowerShell Spell that will assist you in bulk migrating the users to Teams Only mode.
Below are the requirements from our customer:
  • Script should read userprincipalname from text file.
  • Enable these users to Teams Only Mode.
  • Option to Disable as well so that they can be changed back to ISlands mode if required.
  • Report and Log of success and failures.
  • ADD users to the AD group on Enable operation.
  • Remove users to the AD group on Disable operation.
Download the Script from below link and execute it.

https://gallery.technet.microsoft.com/scriptcenter/Bulk-Enable-Teams-Only-Mode-9f666906



It will ask for Userlist which will have userprincipalnames for example:

user1@labtest.com
user2@labtest.com
user3@labtest.com
user4@labtest.com

You need to enter the operation: Enable for upgrading the user to Teams Only Mode and  Disable for changing back users to ISlands mode.

Enter the onmicrosoft domain for example: labtest.onmicrosoft.com.

AD group name so that when enable operation is selected, user is added as member to that group and if Disable operation is selected, user is removed from membership (This is customer specific requirement, you can modify the code if you do not require this step)

Report will be saved in Report folder which will show success and error.

Logs folder will contain logs for the whole operation so you can track the changes done by the script.


PowerShell
<#     
    .NOTES 
    =========================================================================== 
    Created with:     ISE 
    Created on:       3/4/2020 1:46 PM 
    Created by:       Vikas Sukhija 
    Organization:      
    Filename:         BulkProcessingTeamsOnlyMode.ps1 
    =========================================================================== 
    .DESCRIPTION 
    This script will bulk add or remove users to teams only mode 
#> 
param ( 
  [string]$Userlist = $(Read-Host "Enter the text file path that contains userprincipalnames"), 
  [string]$Operation = $(Read-Host "Type Enable for Enabling Teams Only mode and Disable for Island mode"), 
  [string]$domain = $(Read-Host "Type Onmicrosoft Domain"), 
  [string]$group = $(Read-Host "Type AD group that you want to use") 
) 
 
function Write-Log 
{ 
  [CmdletBinding()] 
  param 
  ( 
    [Parameter(Mandatory = $true,ParameterSetName = 'Create')] 
    [array]$Name, 
    [Parameter(Mandatory = $true,ParameterSetName = 'Create')] 
    [string]$Ext, 
    [Parameter(Mandatory = $true,ParameterSetName = 'Create')] 
    [string]$folder, 
     
    [Parameter(ParameterSetName = 'Create',Position = 0)][switch]$Create, 
     
    [Parameter(Mandatory = $true,ParameterSetName = 'Message')] 
    [String]$Message, 
    [Parameter(Mandatory = $true,ParameterSetName = 'Message')] 
    [String]$path, 
    [Parameter(Mandatory = $false,ParameterSetName = 'Message')] 
    [ValidateSet('Information','Warning','Error')] 
    [string]$Severity = 'Information', 
     
    [Parameter(ParameterSetName = 'Message',Position = 0)][Switch]$MSG 
  ) 
  switch ($PsCmdlet.ParameterSetName) { 
    "Create" 
    { 
      $log = @() 
      $date1 = Get-Date -Format d 
      $date1 = $date1.ToString().Replace("/""-") 
      $time = Get-Date -Format t 
     
      $time = $time.ToString().Replace(":""-") 
      $time = $time.ToString().Replace(" """) 
     
      foreach ($n in $Name) 
      {$log += (Get-Location).Path + "\" + $folder + "\" + $n + "_" + $date1 + "_" + $time + "_.$Ext"} 
      return $log 
    } 
    "Message" 
    { 
      $date = Get-Date 
      $concatmessage = "|$date" + "|   |" + $Message +"|  |" + "$Severity|" 
      switch($Severity){ 
        "Information"{Write-Host -Object $concatmessage -ForegroundColor Green} 
        "Warning"{Write-Host -Object $concatmessage -ForegroundColor Yellow} 
        "Error"{Write-Host -Object $concatmessage -ForegroundColor Red} 
      } 
       
      Add-Content -Path $path -Value $concatmessage 
    } 
  } 
} #Function Write-Log 
 
function Start-ProgressBar 
{ 
  [CmdletBinding()] 
  param 
  ( 
    [Parameter(Mandatory = $true)] 
    $Title, 
    [Parameter(Mandatory = $true)] 
    [int]$Timer 
  ) 
     
  For ($i = 1; $i -le $Timer$i++) 
  { 
    Start-Sleep -Seconds 1; 
    Write-Progress -Activity $Title -Status "$i" -PercentComplete ($i /100 * 100) 
  } 
} #Function Start-ProgressBar 
 
function LaunchSOL 
{ 
  param 
  ( 
    $Domain, 
    $UserCredential 
  ) 
     
  Write-Host -Object "Enter Skype Online Credentials" -ForegroundColor Green 
  $CSSession = New-CsOnlineSession -Credential $UserCredential -OverrideAdminDomain $Domain -Verbose 
  Import-PSSession -Session $CSSession -Prefix "SOL" 
  return $UserCredential 
} 
Function RemoveSOL 
{ 
  $Session = Get-PSSession | Where-Object -FilterScript { $_.ComputerName -like "*.online.lync.com" } 
  Remove-PSSession $Session 
} 
 
#################Check if logs folder is created################## 
$logpath  = (Get-Location).path + "\logs"  
$testlogpath = Test-Path -Path $logpath 
if($testlogpath -eq $false) 
{ 
  Start-ProgressBar -Title "Creating logs folder" -Timer 10 
  New-Item -Path (Get-Location).path -Name Logs -Type directory 
} 
 
$Reportpath  = (Get-Location).path + "\Report"  
$testlogpath = Test-Path -Path $Reportpath  
if($testlogpath -eq $false) 
{ 
  Start-ProgressBar -Title "Creating Report folder" -Timer 10 
  New-Item -Path (Get-Location).path -Name Report -Type directory 
} 
####################Load variables and log####################### 
$log = Write-Log -Name "BulkADDRemoveTeamsonly-Log" -folder "logs" -Ext "log" 
$Report1 = Write-Log -Name "BulkADDRemoveTeamsonly-Report" -folder "Report" -Ext "csv" 
 
$users = Get-Content $Userlist 
$collection = @() 
Write-Log -Message "Start Script" -path $log 
 
######connect to Skob for checking user identity########## 
 try { 
    LaunchSOL -Domain $Domain -allowclobber 
    Write-Log -Message "Connected to SKOBOnline" -path $log } 
    catch  
    { 
      $exception = $($_.Exception.Message) 
      Write-Log -Message "$exception" -path $log -Severity Error 
      Write-Log -Message "Exception has occured in connecting to SOL" -path $log  -Severity Error 
      Exit; 
    } 
##################start processing users######################## 
 
if($Operation -eq "Enable"){ 
  Start-ProgressBar -Title "Enable operation selected" -Timer 10 
  Write-Log -Message "Enable operation selected" -path $log  
   
  if($users.count -gt "0"){ 
    $users | ForEach-Object{ 
      $error.clear() 
      $UPN = $_.trim() 
      $mcoll = "" | Select UPN, TeamModeStatus, ADGroupSTatus 
      $mcoll.UPN = $UPN 
      Write-Log -Message "Processing Enable operation on $UPN" -path $log 
      Grant-SOLCsTeamsUpgradePolicy -PolicyName UpgradeToTeams -Identity $UPN 
      if($error){ 
        $mcoll.TeamModeStatus = "Error" 
        Write-Log -Message "Error Processing Enable operation on $UPN" -path $log 
 
      } 
      else{ 
        $mcoll.TeamModeStatus= "Success" 
        Write-Log -Message "Successful Processing Enable operation on $UPN" -path $log 
        Write-Log -Message "ADD user $UPN to $group" -path $log 
        $getaduser = Get-ADUser -Filter {UserPrincipalName -eq $UPN} 
        Add-ADGroupMember -Identity $group -Members $getaduser.SamAccountName 
        if($error){ 
          $mcoll.ADGroupSTatus = "Error" 
          Write-Log -Message "Error Adding $upn operation on  $group" -path $log 
           
        } 
        else{ 
          $mcoll.ADGroupSTatus = "Added" 
          Write-Log -Message "Successfully added $upn to $group" -path $log 
        }   
      } 
       
      $collection+=$mcoll 
    } 
       
  } 
 
 
} 
$collection | export-csv $Report1 -NoTypeInformation 
##############Disable Operation########################## 
if($Operation -eq "Disable"){ 
  Start-ProgressBar -Title "Disable operation selected" -Timer 10 
  Write-Log -Message "Disable operation selected" -path $log  
   
  if($users.count -gt "0"){ 
    $users | ForEach-Object{ 
      $error.clear() 
      $UPN = $_.trim() 
      $mcoll = "" | Select UPN, TeamModeStatus, ADGroupSTatus 
      $mcoll.UPN = $UPN 
      Write-Log -Message "Processing Disable operation on $UPN" -path $log 
      Grant-SOLCsTeamsUpgradePolicy -PolicyName Islands -Identity $UPN 
      if($error){ 
        $mcoll.TeamModeStatus = "Error" 
        Write-Log -Message "Error Processing Disable operation on $UPN" -path $log 
 
      } 
      else{ 
        $mcoll.TeamModeStatus= "Success" 
        Write-Log -Message "Successful Procssing Disable operation on $UPN" -path $log 
        Write-Log -Message "Remove user $UPN to $group" -path $log 
        $getaduser = Get-ADUser -Filter {UserPrincipalName -eq $UPN} 
        Remove-ADGroupMember -Identity $group -Members $getaduser.SamAccountName -confirm:$false 
        if($error){ 
          $mcoll.ADGroupSTatus = "Error" 
          Write-Log -Message "Error Removing $upn operation on  $group" -path $log 
           
        } 
        else{ 
          $mcoll.ADGroupSTatus = "Removed" 
          Write-Log -Message "Successfully Removed $upn to $group" -path $log 
        }   
      } 
      $collection+=$mcoll 
    } 
  } 
} 
 
$collection | export-csv $Report1 -NoTypeInformation 
Write-log -Message "Script Finished" -path $log 
RemoveSOL 
#############################################################################################
 
Thanks for reading and downloading..

Tech Wizard

https://techwizard.cloud

https://www.syscloudpro.com/

PowerShell Cheat Book

Block PowerApps Onpremise Gateway installation


As Powerapps and Powerautomate (Flow) has grown rapidly so are the common issues that every organization faces.

One such issue is controlling PowerApps Onpremise Gateway which everyone who is interested in automation is installing it so that they can automate the process in the onpremise world but many organization's IT security department do not want that it should be open for everyone to use and these are spread all over the environment (laptop, desktop, test servers).

See below snapshot (many organization might have situation like below)



To avoid this in your organization, go to https://admin.powerplatform.microsoft.com/

Click on Data gateways --> Manage gateway installers




Turn On - Restrict users in your organization from installing gateways.



Add the users who you want are allowed to install the On-premise data gateways.

Now you have controlled the access to install gateways in your organization.



Thanks for reading..


Tech Wizard

https://techwizard.cloud

https://www.syscloudpro.com/

PowerShell Cheat Book

Friday, February 28, 2020

Parsing Emails thru flow (Reading Emails thru flow)

Ending February with Microsoft PowerAutomate(flow) Spell.

One of our team reached us as they have a legacy vbscript that runs on a server (from many years) but now giving them issues.

VB script is calling outlook and processing emails based on what it reads from message body.

I suggested them that if they can share the logic or script then same functionality we may be able to achieve with Microsoft PowerAutomate or thru Powershell script instead of using legacy methods.

Here is what needs to be done:
  • Email will be received in the mailbox with attachment
  • Message body will contain email addresses

  • Need to extract the email address and send email with attachment to them.
  • After that move the item to the processed folder.(optional)
Lets create PowerAutomate flow:

We need to create a trigger "When New email Arrives" and then initialize variables to read the email body.


First variable is to read the email body


Second variable to split the body by Customer Email ID: to get actual data.

split(variables('Emailbody'),'Customer Email ID:')



You can test flow by adding each step after creating so you know what you are getting in variables.




Third variable is to get the email addresses in an array so that these can be used by apply to each loop.

split(variables('ExtractEmail1'),'\r\n')


Now you can test flow again and see how the array looks like.

Finally add step Apply to each and a condition that if current items "@"



Condition will find email addresses and start sending email to each customer (you can drag and drop attachment name/attachment content from dynamic content)



Now when the flow will run it will send the emails to the customer with attachment as per the designed logic.

You can add extra step of "move email" to move the processed emails to processed folder.

This post is just an example on how you can use flow to parse thru email and automate the legacy processes in the environment without using single line of code.(some code of flow is definitely required, like split, variables etc)


Thanks for reading..

Tech Wizard

https://techwizard.cloud

https://www.syscloudpro.com/

PowerShell Cheat Book