Saturday, May 30, 2020

Set Teams Only Mode Based AD Group

Today, I am sharing another Magical PowerShell Spell related to Microsoft Teams.

This solution will assist the organizations that want to slowly migrate to Teams Only mode before updating the the settings at the organizational level.

Download it from below GitHub Link:
Teams Only Mode Based AD Group

Prerequisites for this Solution:
  • Active directory Module (https://docs.microsoft.com/en-us/powershell/module/addsadministration/?view=win10-ps)
  • Skype for Business Online PowerShell Module (https://www.microsoft.com/en-us/download/details.aspx?id=39366)
You can run this script by adding below paramters.

Below parameters are required for script to function:
[string]$Adgroup = $(Read-Host "Enter AD Group as Source"),
[string]$Domain = $(Read-Host "Enter onmicrosoft domain"),
[string]$user1 = $(Read-Host "Enter the Admin User id to conenct to SKOBOnline"),
$password1 = $(Read-Host "Enter the passwrod" -AsSecureString),
[string]$smtpserver = $(Read-Host "Enter SMTP Server"),
[string]$from = $(Read-Host "Enter From Address"),
[string]$erroremail = $(Read-Host "Enter Address for Report and Errors"),
$countofchanges = $(Read-Host "Enter Count of changes")



Count of changes is the threshold and depends on how much you expect daily migrations, enter the value based on that.

This will prevent any malicious actor coming into play.

Script will extract the members of the AD group, compare it with Skype online to check who is not enabled for teams only mode and if number is less than the set threshold, it will update the teams upgrade policy to UpgradeToTeams using the below command.

Grant-SOLCsTeamsUpgradePolicy -PolicyName UpgradeToTeams -Identity $upn

Here is the source code if you are not able to get it from Github link (Teams Only Mode Based AD Group)




<#
.NOTES
===========================================================================
Created with: ISE
Created on: 5/18/2020 1:46 PM
Created by: Vikas Sukhija
Organization: https://techwizard.cloud/ https://syscloudpro.com/
Filename: TeamOnlyBasedonADGroup.ps1
===========================================================================
.DESCRIPTION
This will run daily and if any user found without Teamsonly mode, it will upgrade the policy.
#>
param (
[string]$Adgroup = $(Read-Host "Enter AD Group as Source"),
[string]$Domain = $(Read-Host "Enter onmicrosoft domain"),
[string]$user1 = $(Read-Host "Enter the Admin User id to conenct to SKOBOnline"),
$password1 = $(Read-Host "Enter the passwrod" -AsSecureString),
[string]$smtpserver = $(Read-Host "Enter SMTP Server"),
[string]$from = $(Read-Host "Enter From Address"),
[string]$erroremail = $(Read-Host "Enter Address for Report and Errors"),
$countofchanges = $(Read-Host "Enter Count of changes")
)
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 /10 * 100)
}
}
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
}
####################Load variables and log##########
$log = Write-Log -Name "Teamsonlymode-Log" -folder "logs" -Ext "log"
########################Start Script###################
Write-Log -Message "Start script" -path $log
###########userid & password#############
$Credential1 = New-Object System.Management.Automation.PSCredential -ArgumentList $User1, $password1
##################Loading modules############################
try{
Import-module Activedirectory
LaunchSOL -Domain $Domain -allowclobber -UserCredential $Credential1
Write-Log -Message "Loaded all modules" -path $log
}
catch{
$exception = $($_.Exception.Message)
Start-ProgressBar -Title "Error loading Modules and functions" -timer 10
Write-Log -Message "Loaded all modules" -path $log -Severity Error
Write-Log -Message "$exception" -path $log -Severity Error
Send-MailMessage -SmtpServer $smtpserver -From $from -To $erroremail -Subject "Error has occured loading Modules - TeamsOnlyBasedonADGroup" -Body $($_.Exception.Message)
exit
}
#########Fetch Ad group members that are not teamsonly###########
try{
Write-Log -Message "Start fetching group membership information $ADgroup" -path $log
$collADgroup = Get-ADGroup $Adgroup -Properties members | select -ExpandProperty members | Get-ADUser | select -ExpandProperty userprincipalname | Get-SOLCsOnlineUser | Select userprincipalname,TeamsUpgradeEffectiveMode,TeamsUpgradePolicy
$collnotteamonlymode = $collADgroup | where{$_.TeamsUpgradeEffectiveMode -ne "TeamsOnly"} | select -ExpandProperty userprincipalname
$countmem = $collnotteamonlymode.count
Write-Log -Message "Fetched Groupmembership that are not Teamsonly count = $countmem" -path $log
}
catch{
$exception = $_.Exception
Write-Log -Message "Error fetching group membership information $ADgroup" -path $log -Severity Error
Write-Log -Message $exception -path $log -Severity error
Send-MailMessage -SmtpServer $smtpserver -From $from -To $erroremail -Subject "Error has occured fetching group membership information - TeamsOnlyBasedonADGroup" -Body $($_.Exception.Message)
exit;
}
if(($countmem -lt $countofchanges) -and ($countmem -gt "0")) {
$collnotteamonlymode | ForEach-Object{
$upn = $_
try{
Write-Log -Message "Turning Teams Only Mode ON for $upn" -path $log
Grant-SOLCsTeamsUpgradePolicy -PolicyName UpgradeToTeams -Identity $upn
}
catch{
$exception = $_.Exception
Write-Log -Message "Error converting $UPN to TeamsOnly" -path $log -Severity Error
Write-Log -Message $exception -path $log -Severity error
Send-MailMessage -SmtpServer $smtpserver -From $from -To $erroremail -Subject "Error converting $UPN to TeamsOnly - TeamsOnlyBasedonADGroup" -Body $($_.Exception.Message)
}
}
}
elseif ($countmem -ge $countofchanges)
{
Write-Host "Number of Teams Only Mode request are more than $countofchanges - TeamsOnlyBasedonADGroup" -ForegroundColor Yellow
Send-MailMessage -SmtpServer $smtpserver -From $from -To $erroremail -Subject "Number of Teams Only Mode request are more than $countofchanges - TeamsOnlyBasedonADGroup"
}
RemoveSOL
########################Recycle reports & logs###############################
$path1 = $logpath
$limit = (Get-Date).AddDays(-60) #for report recycling
Get-ChildItem -Path $path1 |
Where-Object -FilterScript {$_.CreationTime -lt $limit} |
Remove-Item -Recurse -Force
Write-Log -Message "Script Finished" -path $log
Send-MailMessage -SmtpServer $smtpserver -From $from -To $erroremail -Subject "TeamsOnlyBasedonADGroup - log" -Body "TeamsOnlyBasedonADGroup -log" -Attachments $log
###############################################################################

Thanks for reading and downloading..

Tech Wizard

https://techwizard.cloud

https://syscloudpro.com/

PowerShell Cheat Book

Sunday, May 17, 2020

Updated members of Office 365 Group based on AD Group or Distribution list

As the Collaboration world is moving at rapid pace towards Office 365 groups along with many features that are available only for these modern groups and are limited to Security groups or Distribution groups.
One such feature is Microsoft streams group channel, when you create it you can only select office 365 group you can not select security group or Distribution group.
Our organization Senior Staff publish the videos on regular basis and wants these videos to be available to whole employee group that is a mail security group which is already automated from HR feed. (They do not want to assign the permission each time on Videos).
After discussion, we came up with an idea of Powershell Spell which can accomplish this by populating the O365 group with the members of the  mail security group.
Here is the magical script that you can download from github
Prerequisites:
Now execute the script, you need to enter the following parameters:
[string]$Adgroup = $(Read-Host “Enter AD Group as Source”),
[string]$o365group = $(Read-Host “Enter the o365 group as Destination”),
[string]$Removeanswer = $(Read-Host “If removal of members is required ?, type Yes or No”),
[string]$user1 = $(Read-Host “Enter the Admin User id to conenct to Exchange Online”),
$password1 = $(Read-Host “Enter the passwrod” -AsSecureString),
[string]$smtpserver = $(Read-Host “Enter SMTP Server”),
[string]$from = $(Read-Host “Enter From Address”),
[string]$erroremail = $(Read-Host “Enter Address for Report and Errors”),
$countofchanges = $(Read-Host “Enter Count of changes”)
[string]$Removeanswer = $(Read-Host “If removal of members is required ?, type Yes or No”)
If you will answer Yes then sync will happen and O365 group will have exact members as Active Directory group but we do not wanted that in our situation, we wanted only addition so that if senior staff wants to add some one manually, it will not get removed.
On first run, logs folder will be created for logs to be saved for each run, script will also recycle the logs that are older then 60 days (code is at the end of the script if you want to modify the days for recycling)
$countofchanges = $(Read-Host “Enter Count of changes”)
Count of changes variable has been used for protection as we will be running it daily so if it goes beyond certain number it will not execute. (In our case it can never go beyond 100 with in a single day)
Script compares the existing members of O365 group with AD group to check how many additions or removal will happen. (so its quite fast as daily additions will be very few)
On first run you can add the count of changes variable number as more than actual number of members  in AD group, on subsequent run you can update it to the threshold as per your needs.
You need to modify the script if you want to schedule it via task scheduler, I am not explaining that part in this blog as I am assuming that you all are aware about that part or you can read my other blogs if that is the requirement.
Here is the snippet of the script execution:

Thanks for reading and downloading..
Tech Wizard

Sunday, May 10, 2020

Get Extension Attributes Using Microsoft Graph

There can be situations where you as a DevOps  engineer or infrastructure administrator want to access extension attributes or other onpremise attribute values from the cloud without accessing these thru on-premise infrastructure.

One such situation I have been encountered with Microsoft flow where I want to get back-end properties when user fill the powerapps form.

I can not get these properties using existing flow connectors like Office 365 users or Azure AD.

Looking at this problem what comes immediate in my mind is to utilize Microsoft Graph which can be used with flow, powerapps , powershell or any other methods, we just need to know the uri that needs to be used for fetching that information.

Launch Graph explorer:

https://developer.microsoft.com/en-us/graph/graph-explorer

Here is the uri to get the onpremise attributes information (note: onPremisesExtensionAttributes)

Update the ‘VikasSukhija@labtest.com’  –> with UserPrincipalName for which you want to extract these properties.

https://graph.microsoft.com/v1.0/users?$filter=startswith(userPrincipalName,'Vikas.Sukhija@labtest.com')&$select=id,displayname,mail,officeLocation,onPremisesExtensionAttributes

 

Now you know the graph uri for on-premise attributes and you have tested these with graph explorer.

You can now use these using powershell, flow, powerapps or any other method that you want.

 

 

Thanks for reading …..

Tech Wizard

https://techwizard.cloud

https://www.syscloudpro.com/

PowerShell Cheat Book

Sunday, May 3, 2020

Set Onedrive Quota from file or AD Group

Lets do a magic this time with Onedrive quota.
Requirement:
We have updated the default quota for all E3 Onedrive sites up to max limit that Microsoft allows that is 5 TB.
We thought that onedrive for all users will update with new quota automatically but it was not the case, on the contrary in our small tenant it happened automatically.
So here is the Powershell magic we have created for updating our 35000 users onedrive as 5TB quota.
All our E3 users are licensed based on one AD group so we created the script based on group but for broader use I have expanded it with option of text file as well.
Download the Script from below link:
Prerequisites:
When you will run this script it will ask you for below parameters:
If you will answer No for run from file option then you need to enter name of text file like onedrive.txt  which is inside the script folder and have one drive urls.
Example:
Just press enter and Script will start processing the Onedrive sites to set the appropriate Quotas.
Thanks for reading and downloading..
Tech Wizard

Saturday, April 25, 2020

Distribution group update based on AD attributes – PowerShell

On-premise dynamic distribution groups have limitations and you as a admin need to create contacts to make them work with hybrid environments as mentioned in the below article.
There are other issues as well like you can not use these for Sharepoint permissions or other things like inviting the members to Microsoft Teams.
We can create Azure AD dynamic groups but not all Active Directory attributes for an organization are synchronized to Azure AD.
Powershell is magical and  flexible enough to update group on any criteria and can fill all these gaps.
Distribution group will still be Static but can be updated daily on schedule with adds and remove of members based on the criteria that you will define inside the script.
I am sharing a sample script to achieve this, which you modify as per your requirements.
The method used in this script is super fast, I am running this same method with the org sizes of 100000 users and it takes 5-10 mins.
Here is the sample script that I have uploaded to GITHUB.


Download the script from above link:
Prerequisites: CSVDE and Active Directory Module
Go to variables and log section that starts at line number:102
See the $csvdefilter –> it is selecting all user mailboxes on-premise or online which is not hidden in GAL and account is not disabled.
define smtp server for sending error and logs
$count is the threshold to detect the number of updates (add or removes) – just to be on safe if it exceeds that number than script will stop and will send an alert.
For first time run, you need to make this number large and then you can decrease it to the threshold according to your environment. (500, 100, 1000 etc)
$dl1 is the Distribution group that you have created and want to update it daily with certain criteria. (add one user to it for first run only as I am using compare function)
$div for this sample script is the division which is in particular attribute of AD for this organization.
$loc  for this sample script is the location which is stored in City attribute in AD.
#############Variables/Logs####################################
$log = Write-Log -Name “DLautomationADattributes” -folder “logs” -Ext “log”
$Csvde = (Get-Location).path + “\temp\csvdeexport.csv”
$csvdefilter = “(&(objectClass=user)(objectCategory=person)(|(msExchHomeServerName=*)(msExchRecipientTypeDetails=2147483648))(!msExchHideFromAddressLists=TRUE)(!useraccountcontrol:1.2.840.113556.1.4.803:=2))”
$smtpserver = “smtpserver”
$erroremail = “Reports@labtest.com”
$from = “DoNotReply@labtest.com”
$count = “3000”
$dl1 = “DynamicStaticDL”
$div = “Tech”
$loc = “Galway”
########################Start main script##########################
Now go to line number 34, update the attributes from AD that you want to utilize for distribution group update criteria (samaccountname should always be there as that is used for adding and removing members)
try {CSVDE -f $Csvde -r $csvdefilter -l “mail,sAMAccountName,employeeType,extensionattribute3,l”}
Last line to update is Line number : 154 which is the criteria
if((($_.EmployeeType -eq “Employee”) -or ($_.EmployeeType -eq “Non-Employee”)) -and (($_.extensionattribute3.trim() -eq $div) -or ($_.l.trim() -eq $loc))) #condition for creating dymanic DL
Here it says that employeetype is employee or non-employee  and extenstionattribute3 equals division or location is galway then take add or remove action.
Now we are ready to execute the script, please update the group with one member just for first run , may be just yourself (do not  worry this member will be removed if it does not met the criteria)
Script uses two important methods to make it super sonic for large AD environments and even for large distribution groups.
  1. CSVDE which first exports the filtered ad attributes in CSV file, place it in temp location. – script imports this csv file and then process the updates.
  2. Use of compare method to just update the incremental changes to the distribution group.
Code of this script ends with deleting the csv file created by csvde, recycling of logs (created more than 60 days ago) and sending the execution log to the email address you have defined in the beginning.
#################################Completed Distribution group code###########
Remove-Item -Path $Csvde
########################Recycle reports & logs##############################
$path2 = (Get-Location).path + “\Logs\”
$limit = (Get-Date).AddDays(-60) #for report recycling
Get-ChildItem -Path $path2 |
Where-Object {$_.CreationTime -lt $limit} |
Remove-Item -recurse -Force
Get-Date
Write-Log -Message “Script — Finished” -path $log
Send-MailMessage -SmtpServer $smtpserver -From $from -To $erroremail -Subject “Transcript Log – DlautomationADattributes” -Body “Transcript Log – DlautomationADattributes” -Attachments $log
###########################################################################
This is end of this magical spell, hope you can modify it according to your needs.

Thanks for reading …
Tech Wizard