Get Public Unified Groups

With the ramping up of Microsoft Teams and its intergration with SharePoint, you can understand that Administrators need a way to observe and ultimatley control the stream of creation of the Unified Groups that glue together the above technologies. A request came through recently to have a Scheduled Task running that sends an email to Administrators of all Public Unified Groups created within the last day, understanding the Manager, the Alias of the group and the SharePoint Site URL.

Note; you can find a little more on the first lines of this code here.

Code is below:

#Read-Host –AsSecureString | ConvertFrom-SecureString | Out-File C:\temp\EXOpassword.txt 

  

$password = Get-Content C:\temp\EXOpassword.txt | ConvertTo-SecureString

$userid =‘hpo@mysmartplace.net’
 

$cred = New-Object System.Management.Automation.PSCredential $userid,$password 

$session = New-PSSession ConfigurationName Microsoft.Exchange ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $cred -Authentication basic AllowRedirection

Import-PSSession $session AllowClobber

#Connect to O365 Tenant 

Connect-MsolService -Credential $cred 

  

$Groups = Get-UnifiedGroup | Where-Object {$_.WhenCreated ge ((Get-Date).AddDays(-1)) -and ($_.AccessType eq “Public”)} 

if ($Groups eq $null){

“”

} else {

$Body = $Groups | select Alias, AccessType, ManagedBy, SharePointSiteURL | fl 

$Body = $Body | Out-String 

$body = “The following PUBLIC groups were created in the last 24 hours. Please check with group owner that this is necessary.`n + $Body

Send-MailMessage -Body $Body -From Office365Reports@yourdom.ain -Subject “Office 365 Teams and Groups created in the last day” -To Administrator@yourdom.ain  

 SmtpServer SMTP.your.domain

} 

Scheduled Tasks in Office 365

It will become increasingly prominent that as customers delve into Office 365 that you will need to get Scheduled Tasks into production for your Office 365 tenancy. The main blocker of this will be that when you connect to either Exchange Online, Office 365 etc PowerShell modules you are prompted for your admin credentials. There is a method to secure your credentials in a hash file locally to bind into a credential variable.

Below is the PowerShell that you can append to your scripts in order to complete that:

Read-Host –AsSecureString | ConvertFrom-SecureString | Out-File C:\temp\EXOpassword.txt 

Initially you will need to create the hashed text file which the Read-Host will complete.

$Password = Get-Content C:\temp\EXOpassword.txt | ConvertTo-SecureString

 

$UserID =‘Enter.Username@yourdom.ain’

 

$Cred = New-Object System.Management.Automation.PSCredential $userid,$password 

 

$Session = New-PSSession ConfigurationName Microsoft.Exchange ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Cred -Authentication basic AllowRedirection
 

Import-PSSession $Session AllowClobber
 

#Connect to O365 Tenant

Connect-MsolService -Credential $Cred

This example will connect you to 0365 PowerShell.

You can place this at the start of your scripts in order to authenticate you to your relevant cloud service before then appending your scripts below. An example of this code in a working script is the below, which gets any Unified Groups that are created as Public and emailing an Administrator.

$Password = Get-Content C:\temp\EXOpassword.txt | ConvertTo-SecureString

 

$UserID =‘hpo@mysmartplace.net’

 

$Cred = New-Object System.Management.Automation.PSCredential $UserID,$Password 

 

$Session = New-PSSession ConfigurationName Microsoft.Exchange ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Cred -Authentication basic AllowRedirection

 

Import-PSSession $Session AllowClobber

 

#Connect to O365 Tenant 

Connect-MsolService -Credential $Cred 

  

$Groups = Get-UnifiedGroup | Where-Object {$_.WhenCreated ge ((Get-Date).AddDays(-1)) -and ($_.AccessType eq “Public”)}
 

if ($Groups eq $null){

 

“”

 

} else {

$Body = $Groups | select Alias, AccessType, ManagedBy, SharePointSiteURL | fl 

$Body = $Body | Out-String 

$Body = “The following PUBLIC groups were created in the last 24 hours. Please check with group owner that this is necessary.`n + $Body

 

Send-MailMessage -Body $Body -From Office365Reports@yourdom.ain -Subject “Office 365 Teams and Groups created in the last day” -To admin@yourdom.ain  

 SmtpServer SMTP.your.domain

 

} 

Move an Azure IaaS VM between vNets

Recently i had a requirement to move a number of VM’s from one Azure vNet to another. This isnt possible in the current Azure Portal (although hopefully is coming based on the comments on the Azure Advisory forums – https://feedback.azure.com/forums/34192–general-feedback), therefore you will need to use PowerShell to do this.

Warning: This action does incur downtime, the method will remove the VM, keeping the disk and create a new VM attaching the kept disk. The disk should keep any installed applications, features or roles.

<# 

Author: HP, July 2017.

 
 

Move a VM that has un-managed disks between vNets: 

 
 

1. Delete VM from the portal. 

2. Create a NIC in the new vNet. 

3. Get the NIC name and add it to variable: $NIC1. 

4. Ensure all other variables are filled out 

5. Ensure that the correct subscription is your default with (Get-AzureRmContext).Subscription.  

   If wrong set with Set-AzureRmContextSubscriptionName “SUBID” –TenantId “TENANTID” 

6. Run below script. 

 
 

#> 

 
 

# To login to Azure Resource Manager 

Login-AzureRmAccount 

          

# To view all subscriptions for your account 

#Get-AzureRmSubscription 

          

# To select a default subscription for your current session 

#Get-AzureRmSubscriptionSubscriptionID “SUBID” | Select-AzureRmSubscription 

          

$RGName = “Resource_Group_Name 

$VMLocation = “VM_Location 

$VMSize = “Enter_VM_Size 

$VMName = “VM_Name 

$VM = New-AzureRmVMConfigVMName $VMNameVMSize $VMSize; 

           

$NIC1 = Get-AzureRmNetworkInterface -Name (“VM_Name“) –ResourceGroupName $RGName; 

$NIC1Id = $NIC1.Id; 

#Uncomment if deploying with Multiple NICs 

#$NIC2 = Get-AzureRmNetworkInterface -Name (“NIC2Name”) –ResourceGroupName $RGName; 

#$NIC2Id = $NIC2.Id; 

           

$VM = Add-AzureRmVMNetworkInterface -VM $VM -Id $NIC1Id; 

#Uncomment if deploying with Multiple NICs 

#$VM = Add-AzureRmVMNetworkInterface -VM $VM -Id $NIC2Id;              

           

$osDiskName = “Disk_Name 

$osDiskVhdUri = “Enter_VHD_URL.vhd 

           

$VM = Set-AzureRmVMOSDisk -VM $VM –VhdUri $osDiskVhdUri -name $osDiskNameCreateOption attach -Windows 

           

New-AzureRmVMResourceGroupName $RGName -Location $VMLocation -VM $VM -Verbose 

In total this will take around 20 minutes a VM. There are ofcourse some things to be mindful of, and i will list them below:

  • You will need to reconfigure your VM Extensions to any VM’s you move.
  • NIC’s in the new vNet will need to be re-created.
  • You will need to have necessary permissions to the relevant subscriptions to move resources.
  • Always test a move pre doing this in your live environment.

Output your ForEach into a file

Something that i always forget after spending a little while perfecting the contents of your ForEach loop is that eventually it’ll be necessary to output the content as Objects or into a file of some sort, whether thats before or after some manipulation. The answer to this is a very simple one, you need to store your ForEach in a variable and then reference that Output at the end of the ForEach scriptblock, like below:

$process = Get-Process

$output = foreach($line in $process){

Write-Output $line | select Handles, Id, ProcessName

}

$output | Sort-Object -Property ProcessName | ft

The $output variable will now contain the objects in your ForEach and you can do whatever you want with them.

Get Exchange 2013 Database and Whitespace values.

In organisations that are still using Exchange 2013, you may want to be able to differentiate between the actual size of your databases and the whitespace provisioned for your databases to use.

The below PowerShell script can be added as a Scheduled Task in order to notify your Infrastructure teams.

# This script will take the database sizes from exchange and email them to a mail address.
# First we import the exchange module.

$ExchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://<SMTPServer>/PowerShell
Import-PSSession $ExchangeSession

# Creating our array to allow string and output of command into subject.
$string = “<Org> Database Sizes – ”
$Date = (Get-Date)
$SMTPSubject =  $string + $date

# Factor in the variables for the Send-MailMessage command.

$SMTPTo = “emailrecipient@domain”
$SMTPFrom = “emailsender@domain”
$SMTPServer = “<SMTPServer>”
$SmtpBody = Get-MailboxDatabase -Status | select name, databasesize, AvailableNewMailboxSpace | Sort-Object Name | Out-String

# Then output that into a mail message.

Send-MailMessage -SmtpServer $SMTPServer -From $SMTPFrom -To $SMTPTo -Body $SmtpBody -subject $SMTPSubject

Azure IaaS Patching

When on a customer site recently, one requirement the customer was looking to achieve was to incorporate their IaaS virtual machines into their monthly patching policy. Their Iaas VM’s were shutdown nightly and all day on a weekend by a runbook.

This can be done with a relatively simple PowerShell script split into two functions; Start-AzurePatching and Stop-AzurePatching. The logic of the Start-AzurePatching function is as follows:

  • Connect into Azure PowerShell and choose the subscription you want to work with.
  • First the script will aggregate the VM properties inside each resource group.
  • The runbook being used to shut down your VM’s is looking to interact with a Tag named “AutoShutdownSchedule”
  • If it finds any VM with the tag “AutoShutdownSchedule”  it will remove it, replacing it with one that will allow it to start on a Saturday.
  • The new tags will be set against the virtual machine
  • The VM’s will be started.

The logic of the Stop-AzurePatching is similar:

  • The script will again aggregate all the VM’s settings, specifically looking for VM’s with the “AutoShutdownSchedule” tag.
  • The tag set by Start-AzurePatching will be replaced with a tag that includes the original shutdown settings, meaning the VM’s will be shutdown on a saturday and sunday.
  • The new tags will then be applied to the VM’s.

There isn’t a need to then shut the machines down via this script, as the runbook upon its next cycle will identify these machines as being VM’s that should be offline, and shut them down for you.

<#
Azure Patching PowerShell script.
#>

Function Start-AzurePatching {

Login-AzureRmAccount
$subId = ( Get-AzureRmSubscription |
Out-GridView `
-Title “Select an Azure Subscription” -OutputMode Single
).SubscriptionId
Select-AzureRmSubscription -SubscriptionId $subId

foreach($AzureRmVm in (Get-AzureRmResourceGroup | Get-AzureRmVm))
{
if($AzureRmVm.Tags.Keys -like “*AutoShutdownSchedule*”)
{
$AzureRmVm.Tags.Remove(‘AutoShutdownSchedule’) | Out-Null
$AzureRmVm.Tags.Add(‘AutoShutdownSchedule’,’8PM -> 5AM, Sunday, December 25′) | Out-Null

Set-AzureRmResource -ResourceGroupName $AzureRmVm.ResourceGroupName -Name $AzureRMVm.Name -Tag $AzureRmVm.Tags -ResourceType ‘Microsoft.Compute/VirtualMachines’
}

}

Start-AzureRmVM -Name $AzureRmVm.Name -ResourceGroupName $AzureRmVm.ResourceGroupName
}

#Run this post patching, when you are ready for the servers to be turned off again.

function Stop-AzurePatching {

foreach($AzureRmVm in (Get-AzureRmResourceGroup | Get-AzureRmVm))
{
if($AzureRmVm.Tags.Keys -like “*AutoShutdownSchedule*”)
{
$AzureRmVm.Tags.Remove(‘AutoShutdownSchedule’) | Out-Null
$AzureRmVm.Tags.Add(‘AutoShutdownSchedule’,’8PM -> 5AM, Saturday, Sunday, December 25′) | Out-Null

Set-AzureRmResource -Confirm:$FALSE -ResourceGroupName $AzureRmVm.ResourceGroupName -Name $AzureRMVm.Name -Tag $AzureRmVm.Tags -ResourceType ‘Microsoft.Compute/VirtualMachines’
}
}

}

There is more on Azure Fundamentals here.