Category Archives: Azure

Microsoft Azure – Leverage Manage Engine AD Manager and delegate MFA reset action to the Helpdesk Team

Currently there is no option as per this uservoice to delegate the MFA reset action to help desk team via an admin role. As of now only the global admin have the required privileges to perform this action from the azure portal. In this article we had a look into how to reset this option by creating an automation account and integrating with Microsoft Flow. Though this is a good option there is another way where this action can be delegated via ManageEngine AD manager plus. 

Most of the organizations have AD Manager plus and its features integrated on their on premise tenant. This can be used to execute office 365 and Azure AD operations in a hybrid environment. In this article we will have a look at the steps to integrate AD manager plus with Azure AD to  delegate this action to the help desk team.

Below are the prerequisites :

  1. AD manager plus server must be present in the hybrid domain. Not necessarily a hybrid domain it works well for cloud only accounts as well.
  2. The connectivity to the Azure IPs and URLs are required to connect azure module connect-msolservice
  3. Azure AD modules must be downloaded  on the AD manager plus server.
  4. AD delegation must be already assigned to the help desk team with AD management role.
  5. Global admin account is required to specify them as encrypted credentials with key on the AD manager plus server. This global admin account will only be used by the manage engine AD manager server in the backend and not exposed to the helpdesk team.

Implementation Steps:

First we need to create the encrypted credentials and key . Below command can be used.Kindly note that if we try to execute with plain text password it will not work, Since in our case we are doing an invoke session from AD manager plus and hence it works only with key file.

A very important note here is if there is a password policy for the global admin accounts, ensure to regenerate this key by re-running this script once after the new password is changed on the Global admin account.

$KeyFile = "Z:\ManageEngine\ADManager Plus\bin\AES256.key"
$Key = New-Object Byte[] 32
$Key | out-file $KeyFile
$credential = Get-Credential
$credential.Password | ConvertFrom-SecureString -Key $Key | Out-File "C:\ManageEngine\ADManager Plus\bin\credential.cred"

Later place this script on the AD manager plus bin folder as .ps1.

Connect-MsolService -Credential $cred
"`nConnected to MSOL" | Out-File $MFAlog -Append
Set-MsolUser -UserprincipalName $userPrincipalName -StrongAuthenticationMethod @()
"`nUpdated User $userprincipalname" | Out-File $MFAlog -Append

The above script will also  generate MFAActions.log file in the bin folder which will help us to track the MFA actions performed via AD manager by the help desk admins. Even this script must be placed in the bin folder in the AD manager plus server.

Now having done the Azure AD part we need to access Manage Engine AD Manager Plus admin portal and perform the below action:

  1. Go to AD Mgmt – User Modification Templates – Click Create New Template.
  2. Leave all the fields on all the tabs as default – Navigate to Custom Attributes – Select Run Custom Script on successful user modification script command:  add the below format to call our script via AD manager plus – PowerShell  -File mfa.ps1 %userprincipalname%
  3. Once done click on save template.
  4. Assign this template to the helpdesk team.

Once this above action is completed help desk can reset via below method – 

AD mgmt – Modify Single user – Search for affected user – Modify user – Change template – Choose MFA reset template – then click on update user.

Now the MFA value will be cleared for the requested user.

We can also check the status from Azure AD connected Powershell 

(Get-MSOlUser  -UserPrincipalName user@domain.com).strongauthenticationmethods

The value should return null for a user where the MFA reset is successful.

This action will help in achieving the delegation of MFA reset via manage engine. Helpdesk admins can for perform the MFA reset through the manage engine delegated help desk portal by selecting the assigned template and can perform this action.

Thanks & Regards
Sathish Veerapandian

Visualize Microsoft Teams Room Systems health components through Azure Monitor Workbooks

In the previous post we looked on how to configure Azure Monitor Alerts for Critical events that occurs on Microsoft Windows Devices which can be used for monitoring the Teams Room Systems. With Azure Log Analytics we could leverage few more components that will help us to visualize the status of the systems which are monitored through selected event logs and the performance counters.

Creating the Workbooks and making them visualize purely depends on the data that is been ingested on the corresponding log analytics workspace. So at the first stage its very important that we are sending all the required logs and counters which is mandatory for visualizing the metrics.

Firstly before creating the workbooks we need to devise a strategy on how to build a skeleton for the dashboard. This is very important since there are multiple options available and need to understand what important data that needs to be projected on the dashboard.

We will go through few examples of how to get started with creating the workbooks and visualizing the data.

We need to prepare the required Kusto Query Language which is required for visualizing the data. Below is a small example of one which will visualize the count of the perf counters by object name

Perf
| where TimeGenerated > ago(1h)
| summarize count() by ObjectName

To Render them as a pie chart we can use the below information

Perf
| where TimeGenerated > ago(1h)
| summarize count() by ObjectName
| render piechart 

Example below will project only the affected systems which has failed windows updates, driver updates or any devices connected with room systems which are in a failed state.

search *
| where Type == "Event" 
| where EventLog == "System"
| where EventLevelName == "Error"
| extend Status = parse_json(RenderedDescription).Description
| where RenderedDescription has "failed"
| project TimeGenerated, Computer , RenderedDescription 

If we need to visualize them on a graphical pie chart we could do that as well by summarizing them to a string value which is available from the  parsed json file. Example it can be computer, Ip address , Device name or any data which is present on the raw event data.

search *
| where Type == "Event"
| where EventLevelName == "Error"
| extend Status = parse_json(RenderedDescription).Description
| project TimeGenerated, Computer,RenderedDescription 
| where RenderedDescription has "failed"
| summarize Count=count() by tostring(Computer) 
| render piechart

Above are just very few examples of rendering the data and making them visualize through kusto query language. There is a lot to explore and can project more data based on the logs that we are adding on the azure log analytics.

Now we have got some idea of how to create the visualization through the kusto query language there is an option to combine multiple queries and display them as a dashboard through Azure Workbooks. Earlier this option was enabled by view designer which is now replaced by enhanced version called Azure Workbooks.

There are multiple options which can be utilized and created dashboards with Azure Workbooks and below we will go through few of the options which will help us in creating our customized workbooks.

In order to get started with Workbook – Navigate to the log analytics workspace – Choose Workbooks

Click on New

We get the default summary of our query from our workspace with the below piechart view.

If we want to go with our own query we can remove the default query and select Add. Here in Add we have multiple options like below out of which Add Group seems to be very much interesting. With Add group we have the ability to add multiple queries and group them in a single workbook.

At the top of this group we have an option to add text which visualizes the workbook name and the details.

After selecting the group , now we have option to add query into the group.

When going into the advanced settings we have these options now to display the chart titles specific for this query.

In the style tab we do have some options to modify the HTML settings. By default this will fit in to one query per row and if we need to add three queries we need to adjust the width settings.
In below case I have added the width to 50 since trying to add 2 queries in a row. But its very important to note here that adding 3 columns and making them visible as a dashboard is fine only in Azure Dashboards. If we try to view them from Azure Workbooks 3 queries in a row is not sufficient to accommodate and we do not have option to modify the HTML editor at this moment.

Have added another query which will let us know the status of the systems which have reported the heartbeat in last 30 minutes through the perfom counters. In below case since I have only one system for demo it shows only 1 system.

The moment when we group them and display it shows the  view as below. By adding multiple queries based on our requirement it makes us easier to create the dashboards.

Further to this we have a lot of options in the visualization of the display based on the metric units. We can go through few of them.
For instance there are below options available to set visualization.

We can reduce the size of the visualization and we have 5 options.

Further in the chart settings we have option to define the column and the units.

In the series we have option to change the colour and add a custom display label.

To interpret further have chosen Graph which is very interesting.When entering into the graph settings we have the below options in the node format settings. This helps us to choose what fields that we can display on the view of these images in the dashboard.

We have furthermore tweaking information on the layout settings. The hive clusters are looking really nice like honeycomb in the visualization. And there is a category to group by field to select based on the available fields.

Now we have the category to choose based on the coloring type. Ideally this is very good to categorize based on healthy and unhealthy systems. This will group the healthy and unhealthy systems separately and finally display them as dashboards.

This blog gives an overview of how to visualize , group and create Azure Workbooks from Log Analytics WorkSpace. With Azure log analytics and Azure Workbooks it makes very much easier to monitor the modern Windows 10 & Linux devices. This facility can be very much leveraged easily in a direct cloud deployment model without the need of installing, configuring and maintaining a local monitoring solution.

Thanks & Regards

Sathish Veerapandian

Use Azure Log Analytics to notify critical events occurring on Microsoft Teams Room Systems

In the previous post we had an overview of how to create Azure Log Analytics and configure them to collect data from windows systems. Once the information is ingested in the workspace we currently have a choice to make alarms and notify the responsible team dependent on various signal logics which will be useful on monitoring these devices.

These alerts are scoped to each log analytics workspace. It will be a smart thought to isolate the services ,group them on singular workspace and create separate alerts for critical events happening on these monitored devices.

In order to create the alerts Navigate to alerts on the same workspace  – Click on New Alert Rule

Navigate to signal logic and choose the signal logic. There are multiple we need to see if any more interesting which suits our requirement can be added over here.

Now we have the required critical signals based on which the alert needs to be triggered. Usually the signal type will be from the collected events and the performance counters. In our scenario we could go with some default events from the list and also custom log search.

Device Restart Alert:

In our example for default one did choose the Choose the signal logic of heartbeat from the existing one – (Useful when the device turns off)

Select the required devices  – make operator threshold value 0 – aggregation 5 minutes & frequency of evaluation 1 minute (The frequency of aggregation and evaluation can be chosen based on the interval of how many times we want to check the heartbeat). In normal cases it is best recommended not to choose a smaller frequency time range for large volume of devices and probably for critical devices alone it can be selected on a smaller frequency time period.

Disk Threshold Alert:

Similarly like device restart we are having disk threshold alert by default which can be configured.

It notifies when it exceeds the configured space. Select the resource configured for Teams – Select the Condition – Select the computers – the object name whenever the % free space is greater than and choose the value 60 percent. The percentage can be altered based on our requirement.

Then we need to select the required object, instance , counter path and source system. In our case we have selected one performance counter % free space. This will alert us when the disk space crosses 60 percent of overall capacity.

Chosen aggregate period is 5 minutes and the frequency time is 1 minute for every evaluation. Again we can change the frequency of evaluation for this probably on two times in a day one on the earlier time and other one  on the evening.

Custom Alerts:

Custom Alerts are more intriguing. With custom alerts we must be able to avail most of our alerting mechanisms. We have to select the signal custom log search for the custom alerts.

Event  | where EventLog == "System" | where EventLevelName == "Error"
|where RenderedDescription != "*updatefailed*" 
| where EventData != "DCOM"
| project TimeGenerated, Computer, RenderedDescription

Example used the above query to report only the events which has error messages apart from windows update and DCOM alerts . We can further filter on not contains operator and create custom query based on  our requirement.

When any error messages apart from the excluded events comes up in the targeted devices we will be alerted for the same.

Note there are multiple action types – Email/SMS/Push/Voice, ITSM and Webhook will be more convenient for us in this case on Skype room systems monitoring.

Email – We can send email Email/SMS/Push/Voice when the alert is triggered. This will be the most convenient and easiest part to start with. This will help us to collect all the used cases initially and see which ones are really helpful and the ones which is not helping us. Once we devise a strategy from the email alerts then probably we can go with the other alerting mechanisms.

ITSM – We can integrate with IT service desk management tool to create incidents when these alerts are triggered. Most of the IT service desk management tools are capable of API integration especially with Azure AD and must be easier to suffice this requirement.

Webhook- We can configure to send push notification to teams channels when these alerts are triggered. Probably a dedicated teams channel can be created for the first level of NOC monitoring team. Post that the webhook can be configured to trigger the critical events alert to the teams channel.

Now with the email alert – Created action group – Chosen action type email/SMS/Push/Voice

By default there are no action group created. So an action group must be created and targeted to NOC team email group.

Added the email address for notification. Well there are other options as well like sending SMS and Voice which could also be leveraged.

We do have an option to modify the email subject based on the alert details.

Finally we name the alert details , mark the severity , enable and create them.

We have the option to see all the  configured rules.

Once after configuration, we can see the statistical dashboards which provides us the summary of total alerts that have been triggered and their status.

We are receiving the email alerts when the disk space exceeds the configured level of 60 percentage.

Similarly when the device was turned off, the configured heartbeat alert triggered an email to the recipient.

Similar like this we can create multiple required alerts for critical events.

At this moment we have option to create alerts for every action type which can be targeted for all computers and they are charged individually on a very nominal price. So for multiple alerting types we need to create multiple action types. These alerts are purely based only on the collected logs which are present on the azure log analytics workspace. Just in case if we are trying to collect more details which are not present on the collected logs then we wouldn’t be able to create the alerts. The Azure logs Alerting mechanisms provide a great way to alert the critical events happening across the monitoring systems.

Thanks in Advance

Sathish Veerapandian

Microsoft Intune – Configure customized role based access control in a redistributed IT environment.

In a huge enterprise scale deployments there will be various teams who handles the services with multiple administrator accounts.These executives must be furnished with administrator accounts which are appropriate to their boundaries.Microsoft intune being a device,apps and office 365 administration management there are high prospects that this element may be used over various departments,applications,devices and from various areas. Microsoft Intune having lots of features and capabilities now most of the organizations are moving as managed tenant with Microsoft intune.

For instance there can be multiple app protection policies, device compliance policies, app configuration policies ,etc., are created for multiple services one for meeting room management, another for BYOD devices and for corporate windows devices. In these situations we need to create customized role based access control for each users.

With the default intune admin role assignments, we cannot manage to provide custom permissions and hence need to take little bit different approach in order to deploy in a decentralized environment.

We shall consider a scenario where there are 2 different cases of leveraging Microsoft Intune as a managment authority one for Meeting rooms and another one for managing office 365 and Line of business apps in BYOD devices.

Ideally in this scenario we must be having two sets of policies ,intune services with different role sets and visibility of policies to the administrators.

Below policies for BYOD devices were created –

App Protection Policies

App Configuration Policies

Compliance Policies

Below Policies for Meeting rooms were created –

App Protection Policies

App Configuration Policies

Compliance Policies

Having the policies created now we need to segregate them by tagging to associated admin groups, device groups and scope tags.

Created Admin Groups –

Group 1: MRM Admins – To manage only the Meeting room  intune policies.

Group 2: Pilot Mobile Admins – To manage only the Andriod/IOS Intune  device policies.

Created Device Groups –

Group 1: Meeting Rooms – Created to add the meeting room devices and service accounts. This is required to scope this group in the custom RBAC role that we are creating and targeting for meeting room systems and their service accounts.

Group 2: IntuneMobileDevices – Created to add the BYOD users accounts . This is required to scope this group in the custom RBAC role that we are creating and targeting for byod users.

Created Scope Tags –

Scope Tag 1: Mobile-Admin – To tag all the BYOD mobile IOS/Andriod policies, users and devices. We have added the created group for intune users. One important point to note here is that all new users who needs to be part of intune policies needs to be added to this group.

The policies can be tagged to their related scope tags from the properties page.

Scope Tag 2: SRS-Admin – To tag all the meeting room devices and the service accounts.

In the same way we did for BYOD devices meeting room policies were tagged to this scope tag.

Scope tags are very much required and they are the basic benchmarks which are used to segregate the roles, permissions, devices and users. In this case we have created two scope tags and associated them to their corresponding policies,users,devices and admins.

Created 2 Custom RBAC roles –

Role 1: Meeting Room Admin – Clone copy of policy and profile manager role scoped only to MRM admins group. Tagged this role to SRS-Admin scope tag.

Role 2: Mobile Administrators – Clone copy of policy and profile manager role scoped only to Pilot Mobile Admins  admins group. Tagged this role to Mobile-Admin Scope tag.

The default RBAC roles will provide visibility to all the policies and hence we need to create new roles.Here we have created two clones of the default policy (policy and profile manager). Tagging these two roles to the appropriate scope tags is very important. Ideally scope tags are the components which seperates the role segregation based on policies and users defined on them.

Finally created few policies and tagged them separately for Mobile devices and meeting rooms.

Admin log in experience:

Policies  visibility from Global Admin account where we could see all the policies in the intune portal.

When logging in from mobile admin we see only mobile device policies for byod associated with him.

Only BYOD device compliance policies are present.

In the same way when logging from SRS admin we see only the meeting room policies associated with him.

Only meeting room app protection policies are found.

Caveats :

  1. For custom RBAC role it is requesting an EMS license to be assigned mandatorily for the admin accounts. I attempted the admin accounts without the licenses and it is not working.
  2. Once the policy is applied to admin accounts it is taking almost 24 hours’ time to be in effect.

We can utilize role based access control in combination with scope tags to ensure that the privilege administrator accounts have the correct access and perceivability to the right Intune objects. Scope tags figure out which objects administrators can see from their admin portal.

Thanks & Regards

Sathish Veerapandian

Microsoft Teams – Enforce Multifactor Authentication on guest accounts

Post the ignite sessions last month on Microsoft Teams, we have enhancements on security perspective that can be enabled which adds extra protection in any organization.

Inviting the external guest users to the teams channel have been a welcoming option for all of us which increases the communication between them and surges the productivity. However, there are few security guidelines that needs to be followed to ensure that our data is always secure even when they are shared outside the boundary. For instance, a guest account getting compromised where he is a member of a finance team will become a major security incident in any organization.

This article outlines the steps that can be carried over to enhance the security on Microsoft Teams guest accounts by enforcing the multi factor authentication.

Below are the steps to enforce the MFA on guest accounts:

First create a dynamic distribution group and target the guest account

Login to Azure AD Tenant with Admin privilege’s- Go to Groups – Create new group – make them security – membership type make them dynamic.

Now we need to add a dynamic query where the property is usertype  and the value is guest.

Once done populate the rule syntax and save them.

After some time now, we could see that the populated guest users in our Azure AD tenant will become the members of this group. Since it’s a dynamic query all the new upcoming accounts will be getting occupied automatically.

Create conditional access policy for guest accounts:

Now we need to create a conditional access policy for the Microsoft Teams guest accounts.

Navigate to enterprise applications – click on conditional access.

Now we need to target the dynamic group on this conditional access policy.

In cloud apps select Microsoft Teams , also better to select Sharepoint online which will enforce MFA for these Sharepoint guest users as well.

In conditions we are selecting only the locations. Further it can be manipulated based on the business prerequisite.

In the access control we are selecting only require MFA and the IT policy.

Now we have the MFA enforced on the guest accounts and we will see the action of this configuration from the invited user.

Experience of the guest users enforced with MFA:

In order to simulate this behavior , we are just adding one guest user a teams channel

Post after that the invited user receives  a welcome email and this is usual behavior for any invited Azure AD guest user accounts.

When clicking to login the user will be prompted to register and enroll in MFA.

User will be prompted to enter the mobile number in the invited tenant for MFA and needs to complete the initial authentication process.

If we have enabled the IT policy user will be prompted to read and accept the IT policy.

Finally the user is logged in with the guest account and able to participate on the invited team through a secured way of authentication.

With very nominal steps through the conditional access it creates a overall better security for Microsoft Teams.

Use Azure Automation accounts, Run Books and Schedules to start stop VMs automatically running in Azure

By using this article, we can start/stop VMs during off-business houses.This greatly benefits the customers especially in cost optimization and manual task overhead of performing this action manually. But we need to make sure that the VMs that we are selecting is present in the same subscription where the automation account and this schedule is created by selecting only the required VMs and excluding the other VMs.

Login to Azure portal

Go to ALL Services and Type Automation Account and Create Automation Account.

Under Process Automation, click Runbooks to open the list of runbooks.

Click on + Create a runbook button to create a new runbook

Provide and Name and Runbook Type as PowerShell for the new runbook and then click Create button.

The Run Book is Empty, must deploy the Code  then Save and Publish

Note: You can Find lot of powershell scripts for this task in the github and technet gallery. You can use the below one as well taken from github.

#PowerShell Script to Start and Stop VM's in Azure on Scheduled Intervals using Azure Automation Account#
Param(
[Parameter(Mandatory=$true,HelpMessage="Enter the value for Action. Values can be either stop or start")][String]$Action,
[Parameter(Mandatory=$false,HelpMessage="Enter the value for WhatIf. Values can be either true or false")][bool]$WhatIf = $false,
[Parameter(Mandatory=$false,HelpMessage="Enter the VMs separated by comma(,)")][string]$VMList
)

function ValidateVMList ($FilterVMList)
{
[boolean] $ISexists = $false
[string[]] $invalidvm=@()
$ExAzureVMList=@()

foreach($filtervm in $FilterVMList) 
{
    $currentVM = Get-AzureRmVM | where Name -Like $filtervm.Trim()  -ErrorAction SilentlyContinue

    if ($currentVM.Count -ge 1)
    {
        $ExAzureVMList+= @{Name = $currentVM.Name; Location = $currentVM.Location; ResourceGroupName = $currentVM.ResourceGroupName; Type = "ResourceManager"}
        $ISexists = $true
    }
    elseif($ISexists -eq $false)
    {
        $invalidvm = $invalidvm+$filtervm                
    }
}

if($invalidvm -ne $null)
{
    Write-Output "Runbook Execution Stopped! Invalid VM Name(s) in the VM list: $($invalidvm) "
    Write-Warning "Runbook Execution Stopped! Invalid VM Name(s) in the VM list: $($invalidvm) "
    exit
}
else
{
    return $ExAzureVMList
}
}

function CheckExcludeVM ($FilterVMList)
{
[boolean] $ISexists = $false
[string[]] $invalidvm=@()
$ExAzureVMList=@()
<pre><code>foreach($filtervm in $FilterVMList) 
{
    $currentVM = Get-AzureRmVM | where Name -Like $filtervm.Trim()  -ErrorAction SilentlyContinue
    if ($currentVM.Count -ge 1)
    {
        $ExAzureVMList+=$currentVM.Name
        $ISexists = $true
    }
    elseif($ISexists -eq $false)
    {
        $invalidvm = $invalidvm+$filtervm
    }

}
if($invalidvm -ne $null)
{
    Write-Output "Runbook Execution Stopped! Invalid VM Name(s) in the exclude list: $($invalidvm) "
    Write-Warning "Runbook Execution Stopped! Invalid VM Name(s) in the exclude list: $($invalidvm) "
    exit
}
else
{
    Write-Output "Exclude VM's validation completed..."
}    </code></pre>
}
<h1>-----L O G I N - A U T H E N T I C A T I O N-----</h1>
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
<pre><code>"Logging in to Azure..."
Add-AzureRmAccount `
    -ServicePrincipal `
    -TenantId $servicePrincipalConnection.TenantId `
    -ApplicationId $servicePrincipalConnection.ApplicationId `
    -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint </code></pre>
}
catch
{
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
<h1>---------Read all the input variables---------------</h1>
$StartResourceGroupNames = Get-AutomationVariable -Name 'RG-Of-VMs-To-Start'
$StopResourceGroupNames = Get-AutomationVariable -Name 'RG-Of-VMs-To-Stop'
$ExcludeVMNames = Get-AutomationVariable -Name 'Excluded-List-Of-VMs'

try
{
$Action = $Action.Trim().ToLower()
<pre><code>    if(!($Action -eq "start" -or $Action -eq "stop"))
    {
        Write-Output "`$Action parameter value is : $($Action). Value should be either start or stop."
        Write-Output "Completed the runbook execution..."
        exit
    }            
    Write-Output "Runbook Execution Started..."
    [string[]] $VMfilterList = $ExcludeVMNames -split ","
    #If user gives the VM list with comma seperated....
    $AzurVMlist = Get-AutomationVariable -Name $VMList
    if(($AzurVMlist))
    {
        Write-Output "list of  all VMs = $($AzurVMlist)"
        [string[]] $AzVMList = $AzurVMlist -split ","        
    }
    if($Action -eq "stop")
    {
        Write-Output "List of  all ResourceGroups = $($StopResourceGroupNames)"
        [string[]] $VMRGList = $StopResourceGroupNames -split ","
    }

    if($Action -eq "start")
    {
        Write-Output "List of  all ResourceGroups = $($StopResourceGroupNames)"
        [string[]] $VMRGList = $StartResourceGroupNames -split ","
    }

    #Validate the Exclude List VM's and stop the execution if the list contains any invalid VM
    if (([string]::IsNullOrEmpty($ExcludeVMNames) -ne $true) -and ($ExcludeVMNames -ne "none"))
    {
        Write-Output "Values exist on the VM's Exclude list. Checking resources against this list..."
        CheckExcludeVM -FilterVMList $VMfilterList 
    } 
    $AzureVMListTemp = $null
    $AzureVMList=@()

    if ($AzVMList -ne $null)
    {
        ##Action to be taken based on VM List and not on Resource group.
        ##Validating the VM List.
        Write-Output "VM List is given to take action (Exclude list will be ignored)..."
        $AzureVMList = ValidateVMList -FilterVMList $AzVMList 
    } 
    else
    {

        ##Getting VM Details based on RG List or Subscription
        if (($VMRGList -ne $null) -and ($VMRGList -ne "*"))
        {
            foreach($Resource in $VMRGList)
            {
                Write-Output "Validating the resource group name ($($Resource))"  
                $checkRGname = Get-AzureRmResourceGroup -Name $Resource.Trim() -ev notPresent -ea 0  

                if ($checkRGname -eq $null)
                {
                    Write-Warning "$($Resource) is not a valid Resource Group Name. Please verify your input"
                }
                else
                {    
                    # Get resource manager VM resources in group and record target state for each in table
                    $taggedRMVMs =  Get-AzureRmVM | ? { $_.ResourceGroupName -eq $Resource} 
                     foreach($vmResource in $taggedRMVMs)
                    {
                        if ($vmResource.ResourceGroupName -Like $Resource)
                        {
                            $AzureVMList += @{Name = $vmResource.Name; ResourceGroupName = $vmResource.ResourceGroupName; Type = "ResourceManager"}
                        }
                    }
                }
            }
        } 
        else
        {
            Write-Output "Getting all the VM's from the subscription..."  
            $ResourceGroups = Get-AzureRmResourceGroup 

            foreach ($ResourceGroup in $ResourceGroups)
            {    

                # Get resource manager VM resources in group and record target state for each in table
                $taggedRMVMs = Get-AzureRmVM | ? { $_.ResourceGroupName -eq $ResourceGroup.ResourceGroupName}

                foreach($vmResource in $taggedRMVMs)
                {
                    Write-Output "RG : $($vmResource.ResourceGroupName) , ARM VM $($vmResource.Name)"
                    $AzureVMList += @{Name = $vmResource.Name; ResourceGroupName = $vmResource.ResourceGroupName; Type = "ResourceManager"}
                }
            }

        }
    }

    $ActualAzureVMList=@()

    if($AzVMList -ne $null)
    {
        $ActualAzureVMList = $AzureVMList
    }
    #Check if exclude vm list has wildcard       
    elseif(($VMfilterList -ne $null) -and ($VMfilterList -ne "none"))
    {
        $ExAzureVMList = ValidateVMList -FilterVMList $VMfilterList 

        foreach($VM in $AzureVMList)
        {  
            ##Checking Vm in excluded list                         
            if($ExAzureVMList.Name -notcontains ($($VM.Name)))
            {
                $ActualAzureVMList+=$VM
            }
        }
    }
    else
    {
        $ActualAzureVMList = $AzureVMList
    }

    Write-Output "The current action is $($Action)"

    $ActualVMListOutput=@()

    if($WhatIf -eq $false)
    {   
        $AzureVMListARM=@()


        # Store the ARM VM's
        $AzureVMListARM = $ActualAzureVMList | Where-Object {$_.Type -eq "ResourceManager"}


        # process the ARM VM's
        if($AzureVMListARM -ne $null)
        {
            foreach($VM in $AzureVMListARM)
            {  
                $ActualVMListOutput = $ActualVMListOutput + $VM.Name + " "
                #ScheduleSnoozeAction -VMObject $VM -Action $Action

                #------------------------
                try
                {          
                    Write-Output "VM action is : $($Action)"
                    Write-OutPut $VM.ResourceGroupName

                    $VMState = Get-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -status | Where-Object { $_.Name -eq  $VM.Name }
                    if ($Action.Trim().ToLower() -eq "stop")
                    {
                        Write-Output "Stopping the VM : $($VM.Name)"
                        Write-Output "Resource Group is : $($VM.ResourceGroupName)"


                        if($VMState.Statuses[1].DisplayStatus -ne "VM running")
                        {
                            Write-Output "VM is not in running state, No actions performed"
                        }
                        else
                        {
                            $Status = Stop-AzureRmVM -Name $VM.Name -ResourceGroupName $VM.ResourceGroupName -Force

                            if($Status -eq $null)
                            {
                                Write-Output "Error occured while stopping the Virtual Machine."
                            }
                            else
                            {
                                Write-Output "Successfully stopped the VM $($VM.Name)"
                            }            
                        }

                    }
                    elseif($Action.Trim().ToLower() -eq "start")
                    {
                        Write-Output "Starting the VM : $($VM.Name)"
                        Write-Output "Resource Group is : $($VM.ResourceGroupName)"

                        if($VMState.Statuses[1].DisplayStatus -eq "VM running")
                        {
                            Write-Output "VM already Running, No actions performed"
                        }
                        else
                        {
                            $Status = Start-AzureRmVM -Name $VM.Name -ResourceGroupName $VM.ResourceGroupName

                            if($Status -eq $null)
                            {
                                Write-Output "Error occured while starting the Virtual Machine $($VM.Name)"
                            }
                            else
                            {
                                Write-Output "Successfully started the VM $($VM.Name)"
                            }
                        }
                    }      

                }
                catch
                {
                    Write-Output "Error Occurred..."
                    Write-Output $_.Exception
                }
                #--------------------------
            }
            Write-Output "Completed the $($Action) action on the following ARM VMs: $($ActualVMListOutput)"
        }


    }
    elseif($WhatIf -eq $true)
    {
        Write-Output "WhatIf parameter is set to True..."
        Write-Output "When 'WhatIf' is set to TRUE, runbook provides a list of Azure Resources (e.g. VMs), that will be impacted if you choose to deploy this runbook."
        Write-Output "No action will be taken at this time..."
        Write-Output $($ActualAzureVMList) 
    }
    Write-Output "Runbook Execution Completed..."
}
catch
{
    $ex = $_.Exception
    Write-Output $_.Exception
}

Now in Automation Account, under Shared Resources click Variables and add these variables [Note: while creating the variables you have to provide some Value, later you can delete the value if required]


Explanation of these variables-

RG-Of-VMs-To-Start: ResourceGroup that contains VMs to be started. Must be in the same subscription that the Azure Automation Run-As account has permission to manage.

RG-Of-VMs-To-Stop: ResourceGroup that contains VMs to be stopped. Must be in the same subscription that the Azure Automation Run-As account has permission to manage.

Excluded-List-Of-VMs: VM names to be excluded from being started/Stopped

Note: These Variables are defined in the PowerShell Code and should not be changed if used by default.

VMstoStartStop: Provide the list of the VMs to be started or stopped.

Now we will create schedule for the start & stop of VMs. Under Shared Resources, click on Schedules and then click + Add a schedule and provide a Name and time and recurrence frequency for the schedule and Click Create

Similarly create schedule for Stop_VM


Now we will attach these schedules with the runbook. Go to Runbook and then open the runbook, click schedules and then + Add a schedule

Now link Start_VM and then provide parameter values. ACTION can have values like start or stop. In VMLIST provide the variable name “VMstoStartStop” which contains the VM names. Click create

Similarly attach the Stop_VM and provide the Action value Stop and VMList value VMstoStartstop.

So now we have two schedules start-vm and stop-vm which would be running on the defined schedules.

Now your runbook will execute the start of VM and stop of VM as per the schedule attached. The results of runbook execution can be seen under Process Automation –> Jobs.

This task greatly benefits the hassle of maintaining and performing this task manually from the admin side.

Extend local AD extension attributes to Azure AD in a non-hybrid exchange online only environment

There might be a scenario where the environment has Azure AD synced users from local Active Directory. The mailboxes will be created directly in exchange online with no hybrid configured from the underlying time as a rule for new businesses.

Usually developers for customizing the login experience for different business units in their application consume the local extension AD attributes and its usually fine for fully on premise environments.

If we have exchange installed in the environment , the active directory schema will be extended to include user extensionattributes in the exchange mailbox properties.

There is another option of Using the Exchange Server install media, extend only the local Active Directory schema. Usually this option is not recommended. Doing this would add Exchange attributes to the local Active Directory. These attributes could then be set, and Azure AD Sync would then be configured to sync these attributes to Office 365.This option requires much testing, and there is always risk associated with AD schema changes.

Even in hybrid setup these values gets populated in Exchange online via exchange hybrid configuration for all users.

In the third scenario where we do not own a exchange hybrid and if the developer is using Azure AD via graph API and expecting these values on azure AD for the customization. In this case we have a better option of extending these values from the Azure AD connect by running them again and selecting only the required AD extension attributes.

Login to Azure AD with global admin credentials and select customize synchronization options

Select directory extension attribute sync.

Here we will have the option to choose the local active directory attributes. In our case we are selecting the two atttributes extensionattribute7 and extensionattribute8 .

Once done go ahead and click on configure.

It must be working usually in this steps but in this case we did a directory refresh schema.

Selected the directory for refresh.

Now went to the local Active Directory and populated the extensionattribute8 for one user.

Once after the sync is completed we can verify if the value is populated in the azure ad via graph explorer.

Login to the graph explorer from the below url.

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

We can login with any valid credentials from your tenant.

We will be asked for the admin consent and needs to be selected based on the requirement.

Run the below query.

https://graph.microsoft.com/v1.0/me?$select=mail,jobTitle,companyName,onPremisesExtensionAttributes

For Reading on premise attributes (mail, jobTitle, company Name and onPremisesExtensionAttributes) using Graph API. You should see the extensionAttribute8 under onPremisesExtensionAttributes which is being used currently.

In our case we can see the extension attribute8 value which has been synched and available in Azure AD.

Using the directory extension option in the azure ad connect achieves this task in a lot less simpler way.

Thanks & Regards

Sathish Veerapandian

%d bloggers like this: