Azure Arc KQL Query Reference

Essential Log Analytics & Resource Graph queries for monitoring, troubleshooting, and agent status tracking

📖 15 min read
🎯 Intermediate
🔧 Technical Reference
💡 Real-World Queries

Introduction

KQL query reference for Azure Arc-enabled servers. These queries help you monitor agent status, track deployments, troubleshoot issues, and maintain your Arc infrastructure.

Failed Extension Installations

Track Azure Arc extension installation failures across your environment.

Detailed Failed Extension Report

This query identifies all servers with failed Azure Arc extension installations, showing server name, user, resource group, extension name, and IP address.

KQL - Failed Extension Details
AzureActivity
| where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE" and ActivityStatusValue == "Failure"
| extend Properties = (parse_json(Properties))
| extend Server = toupper(split(Properties.resource,"/")[0])
| extend ["Extension Name"] = split(Properties.resource,"/")[1]
| extend User = Properties.caller
| extend ["Resource Group"] = Properties.resourceGroup
| extend ["Susbcription ID"] = Properties.SubscriptionId
| extend ["IP Address"] = CallerIpAddress
| extend ["Activity Status"] = Properties.activityStatusValue
| project TimeGenerated, Server, User, ['Resource Group'], ["Extension Name"], ['Susbcription ID'], ['IP Address'], ["Activity Status"]
| sort by TimeGenerated

Failed Extensions Summary by Server

This query summarizes failed extension installations by extension name and server name, showing the count and list of failed extensions per server.

KQL - Failed Extensions Summary
AzureActivity
| where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE" and ActivityStatusValue == "Failure"
| extend Properties = parse_json(Properties)
| extend Server = toupper(split(Properties.resource,"/")[0])
| extend ["Extension Name"] = tostring(split(Properties.resource,"/")[1])
| summarize
    ['Extensions Count'] = dcount(["Extension Name"]),
    ['List of Extensions'] = make_set(["Extension Name"])
    by Server

Extension Activity Monitoring

Monitor all Azure Arc extension installations and modifications, including user activity, IP addresses, and status.

Critical: Extension write operations (EXTENSIONS/WRITE) include automated Azure operations that create significant noise:
  • AZURE UPDATE CENTER S2S SERVICE ROLE PROD - Daily update assessment scans (~90% of all operations)
  • AZURE GUEST PATCHING SERVICE ROLE - Automated patching operations (~1%)
Filter by Authorization.evidence.role to see only real deployments (human, Azure Policy, or MDE auto-deployment).

Extension Provisioning State Verification

List all Azure Arc extensions to verify they appear in inventory. Note: Just because an extension appears here doesn't mean it's functioning correctly.

Resource Graph - List All Extensions
resources
| where type == "microsoft.hybridcompute/machines/extensions"

Failed Extension Provisioning States

Identify extensions assigned to servers but not working properly. This query shows all extensions where ProvisioningState is not "Succeeded", helping you find extensions that require attention.

Resource Graph - Non-Succeeded Extensions
resources | where type == "microsoft.hybridcompute/machines"
| project ServerName = tostring(name)
| join kind = inner ( resources
    | where type == "microsoft.hybridcompute/machines/extensions"
    | extend ServerName = tostring(split(tostring(id),"/",8)[0])
    | extend ["Provisioning State"] = properties.provisioningState
    | where  ["Provisioning State"] != "Succeeded"
    | extend Extension = name
    )
    on ServerName
| project ServerName, Extension,["Provisioning State"]
PowerShell Alternative: Use the Get-AzConnectedMachineExtension cmdlet to list machine extensions, then filter for non-acceptable states. This approach works well when you need to verify extension status during troubleshooting or automation workflows.

Real Extension Deployments (Excluding Noise)

Track real extension deployments by filtering out automated Azure Update Manager and Guest Patching operations. Shows who deployed extensions (human users, Azure Policy, or MDE auto-deployment).

Azure Activity - Real Extension Deployments
AzureActivity
| where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE"
| where ActivityStatusValue == "Success"
| extend Auth = parse_json(Authorization)
| extend AuthEvidence = parse_json(tostring(Auth.evidence))
| extend PrincipalType = tostring(AuthEvidence.principalType)
| extend Role = tostring(AuthEvidence.role)
| where Role !in ("AZURE UPDATE CENTER S2S SERVICE ROLE PROD", "AZURE GUEST PATCHING SERVICE ROLE")
| extend Properties = parse_json(Properties)
| extend Server = toupper(tostring(split(Properties.resource,"/")[0]))
| extend ["Extension Name"] = tostring(split(Properties.resource,"/")[1])
| extend ["Resource Group"] = tostring(Properties.resourceGroup)
| extend Classification = case(
    PrincipalType == "User", "Human",
    Role == "Security RP Service Role", "Auto MDE",
    Role in ("Contributor", "Owner"), "Azure Policy",
    "Other")
| project TimeGenerated, Server, ['Extension Name'], Caller, PrincipalType, Role, Classification, ['Resource Group']
| sort by TimeGenerated desc
Classification Reference:
  • Human - User manually deployed extension (PrincipalType = "User")
  • Azure Policy - Deployed via Azure Policy (ServicePrincipal + Contributor/Owner role)
  • Auto MDE - Microsoft Defender for Endpoint auto-deployment (Security RP Service Role)

All Extension Write Operations (Including Noise)

Track all extension installation and modification activities across Arc-enabled servers, including automated operations. Use this for complete audit trails.

Azure Activity - All Extension Operations (Unfiltered)
AzureActivity
| where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE"
| extend Auth = parse_json(Authorization)
| extend AuthEvidence = parse_json(tostring(Auth.evidence))
| extend PrincipalType = tostring(AuthEvidence.principalType)
| extend Role = tostring(AuthEvidence.role)
| extend Properties = parse_json(Properties)
| extend Server = toupper(tostring(split(Properties.resource,"/")[0]))
| extend ["Extension Name"] = tostring(split(Properties.resource,"/")[1])
| extend ["Resource Group"] = tostring(Properties.resourceGroup)
| extend ["IP Address"] = CallerIpAddress
| extend ["Activity Status"] = ActivityStatusValue
| project TimeGenerated, Server, ['Extension Name'], Caller, PrincipalType, Role, ['Resource Group'], ['IP Address'], ["Activity Status"]
| sort by TimeGenerated desc
Security Note: Monitor extension installations carefully. Malicious actors can exploit Custom Script Extensions to execute unauthorized PowerShell or Bash scripts on your servers. Use this query in Microsoft Sentinel for security detection and alerting. Focus on "Human" and "Other" classifications for security review.

Extension Operations Classification Breakdown

Get a statistical breakdown of extension operations by classification. This query shows what percentage of operations are real deployments vs automated noise, helping you understand your environment's activity patterns.

Azure Activity - Extension Classification Stats
AzureActivity
| where TimeGenerated >= ago(30d)
| where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE"
| where ActivityStatusValue == "Success"
| extend Auth = parse_json(Authorization)
| extend AuthEvidence = parse_json(tostring(Auth.evidence))
| extend PrincipalType = tostring(AuthEvidence.principalType)
| extend Role = tostring(AuthEvidence.role)
| extend Classification = case(
    PrincipalType == "User", "Human Deployment",
    Role == "AZURE UPDATE CENTER S2S SERVICE ROLE PROD", "Update Scanning (NOISE)",
    Role == "AZURE GUEST PATCHING SERVICE ROLE", "Patching (NOISE)",
    Role == "Security RP Service Role", "Auto MDE Deployment",
    Role in ("Contributor", "Owner"), "Azure Policy Deployment",
    "Other")
| summarize Count = dcount(CorrelationId) by Classification
| extend Total = toscalar(
    AzureActivity
    | where TimeGenerated >= ago(30d)
    | where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE"
    | where ActivityStatusValue == "Success"
    | summarize dcount(CorrelationId))
| extend Percentage = round((Count * 100.0) / Total, 1)
| project Classification, Count, Percentage
| order by Count desc
Typical Results: In most environments, you'll see ~90% of operations are "Update Scanning (NOISE)" from Azure Update Manager. Real deployments (Human + Azure Policy + Auto MDE) typically account for less than 10% of total operations.

Activity Summary by User/Principal

Identify WHO is performing operations across your Arc environment. This query shows all callers (users and service principals), their roles, and operation counts - essential for security auditing and understanding who has access to your Arc infrastructure.

Azure Activity - Activity by User/Principal
AzureActivity
| where TimeGenerated >= ago(30d)
| where OperationNameValue in ("MICROSOFT.HYBRIDCOMPUTE/MACHINES/WRITE", "MICROSOFT.HYBRIDCOMPUTE/MACHINES/DELETE", "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE")
| where ActivityStatusValue == "Success"
| extend Auth = parse_json(Authorization)
| extend AuthAction = tostring(Auth.action)
| extend AuthEvidence = parse_json(tostring(Auth.evidence))
| extend PrincipalType = tostring(AuthEvidence.principalType)
| extend Role = tostring(AuthEvidence.role)
// Exclude noise from Update Center and Guest Patching
| where Role !in ("AZURE UPDATE CENTER S2S SERVICE ROLE PROD", "AZURE GUEST PATCHING SERVICE ROLE")
// Exclude tag operations for machine writes
| where not(OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/WRITE" and AuthAction != "Microsoft.HybridCompute/machines/write")
| extend OperationType = case(
    OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/WRITE", "MachineWrite",
    OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/DELETE", "MachineDelete",
    OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE", "ExtensionDeploy",
    "Other")
| summarize
    MachineWrites = dcountif(CorrelationId, OperationType == "MachineWrite"),
    ExtensionDeployments = dcountif(CorrelationId, OperationType == "ExtensionDeploy"),
    MachineDeletes = dcountif(CorrelationId, OperationType == "MachineDelete")
    by Caller, PrincipalType, Role
| extend TotalOps = MachineWrites + ExtensionDeployments + MachineDeletes
| project Caller, PrincipalType, Role, MachineWrites, ExtensionDeployments, MachineDeletes, TotalOps
| order by TotalOps desc
Security Review: Pay attention to:
  • Unknown callers with high operation counts
  • User principals performing bulk operations (could indicate compromised account)
  • Service principals with unexpected roles or permissions

Deleted Server Tracking

Track who deleted Azure Arc-enabled servers from your environment.

Arc Server Deletion Audit

Identify deleted Azure Arc servers, including who deleted them, when, and from which resource group. Critical for security auditing and troubleshooting missing servers.

Azure Activity - Deleted Arc Servers
AzureActivity
| where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/DELETE" and ActivityStatusValue == "Success"
| extend Properties = (parse_json(Properties))
| extend Server = toupper(split(Properties.resource,"/")[0])
| extend User = Properties.caller
| extend ["Resource Group"] = Properties.resourceGroup
| project TimeGenerated, Server, User, ['Resource Group']
| sort by TimeGenerated desc

Azure Monitoring Agent (AMA) Removal Detection

Detect when Azure Monitoring Agent extensions are removed from Arc-enabled servers. Critical for maintaining security monitoring coverage.

AMA Extension Removal Audit

Track AMA extension deletions across your Arc infrastructure. Shows who removed the extension, when, and from which server. Essential for Microsoft Sentinel monitoring and compliance.

Azure Activity - AMA Extension Removal
AzureActivity
| where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/DELETE" and ActivityStatusValue == "Success"
| extend Properties = (parse_json(Properties))
| extend Server = toupper(split(Properties.resource,"/")[0])
| extend ["Extension Name"] = split(Properties.resource,"/")[1]
| extend User = Properties.caller
| extend ["Resource Group"] = Properties.resourceGroup
| extend ["Susbcription ID"] = Properties.SubscriptionId
| extend ["IP Address"] = CallerIpAddress
| extend ["Activity Status"] = Properties.activityStatusValue
| where ['Extension Name'] == "amawindows" or ['Extension Name'] == "azuremonitorwindowsagent"
| project TimeGenerated, Server, User, ['Resource Group'], ["Extension Name"], ['Susbcription ID'], ['IP Address'], ["Activity Status"]
| sort by TimeGenerated
Note: This query checks for two AMA extension names: amawindows and azuremonitorwindowsagent. Extension naming varies based on your Azure Arc implementation date.

New Server Onboarding Tracking

Identify new Azure Arc-enabled server onboardings to track environment expansion and detect unauthorized server registrations.

Important: The MACHINES/WRITE operation includes multiple action types: actual onboardings, tag operations, resource moves, and agent reconnections. You must filter by Authorization.action and Authorization.evidence.role to get TRUE new onboardings only.

New Arc Server Onboardings (TRUE Onboardings Only)

Track new Azure Arc server onboardings with server name, user, resource group, and subscription details. This query filters for the "Azure Connected Machine Onboarding" role which is used exclusively during azcmagent connect operations.

Azure Activity - New Arc Onboardings
AzureActivity
| where OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/WRITE"
| where ActivityStatusValue == "Success"
| extend AuthAction = tostring(parse_json(Authorization).action)
| where AuthAction == "Microsoft.HybridCompute/machines/write"
| extend Role = tostring(parse_json(tostring(parse_json(Authorization).evidence)).role)
| where Role == "Azure Connected Machine Onboarding"
| extend Properties = parse_json(Properties)
| extend Server = toupper(tostring(split(Properties.resource,"/")[0]))
| extend ["Resource Group"] = tostring(Properties.resourceGroup)
| extend ["Subscription ID"] = tostring(SubscriptionId)
| project TimeGenerated, Server, Caller, ['Resource Group'], ['Subscription ID']
| sort by TimeGenerated desc
Role Reference:
  • Azure Connected Machine Onboarding - TRUE new onboarding (azcmagent connect)
  • Access NRP Service Role and HCRP - Agent reconnection or property update (not a new machine)

Failed Update Deployments

Track failed Azure Update Manager deployments on Arc-enabled servers to maintain patching compliance and troubleshoot update issues.

Failed Patch Installation Tracking

Identify failed update deployments from Azure Update Manager. Shows which servers failed to install patches, when, and why.

Azure Activity - Failed Update Deployments
AzureActivity
| where OperationNameValue == "MICROSOFT.COMPUTE/VIRTUALMACHINES/INSTALLPATCHES/ACTION" and ActivityStatusValue == "Failed"
| extend Properties = (parse_json(Properties))
| extend Server = toupper(split(Properties.resource,"/")[0])
| extend User = Properties.caller
| extend ["Resource Group"] = Properties.resourceGroup
| extend ["Subscription ID"] = Properties.SubscriptionId
| extend ["Activity Status"] = Properties.activityStatusValue
| project TimeGenerated, Server, User, ['Resource Group'], ['Subscription ID'], ["Activity Status"]
| sort by TimeGenerated desc
Note: This query works with Azure Update Manager deployments on Arc-enabled servers. Failed deployments indicate patching issues that require troubleshooting.

Resource Health & Connectivity Tracking

Monitor Azure Arc agent connectivity and track disconnection events to identify connectivity issues and agent failures.

Arc Agent Disconnection Tracking

Track Arc agent disconnection and reconnection events. Shows when servers lost connectivity (ActivityStatusValue = "Active") and when they reconnected (ActivityStatusValue = "Resolved"). Use this to identify connectivity patterns and investigate prolonged disconnections.

Azure Activity - Resource Health Events
AzureActivity
| where CategoryValue == "ResourceHealth"
| where ResourceProviderValue == "MICROSOFT.HYBRIDCOMPUTE"
| extend Properties = (parse_json(Properties))
| extend Server = toupper(split(Properties.resource,"/")[0])
| extend ["Resource Group"] = Properties.resourceGroup
| extend ["Health Status"] = ActivityStatusValue
| project TimeGenerated, Server, ['Resource Group'], ["Health Status"]
| sort by TimeGenerated desc
Connectivity Analysis: "Active" status indicates agent disconnection. "Resolved" status indicates reconnection. Brief disconnections are normal, but prolonged disconnections require investigation.

Activity Timeline Dashboard

Get a daily breakdown of all Azure Arc operations across your environment. This query provides executive-level visibility into onboardings, removals, and extension deployments with proper noise filtering.

Daily Activity Summary

Track daily operational activity with proper classification. Shows new onboardings, machine removals, and real extension deployments (excluding Update Manager noise).

Azure Activity - Daily Activity Timeline
AzureActivity
| where TimeGenerated >= ago(30d)
| where OperationNameValue in ("MICROSOFT.HYBRIDCOMPUTE/MACHINES/WRITE", "MICROSOFT.HYBRIDCOMPUTE/MACHINES/DELETE", "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE")
| where ActivityStatusValue == "Success"
| extend Auth = parse_json(Authorization)
| extend AuthAction = tostring(Auth.action)
| extend AuthEvidence = parse_json(tostring(Auth.evidence))
| extend PrincipalType = tostring(AuthEvidence.principalType)
| extend Role = tostring(AuthEvidence.role)
// Classify operations
| extend IsNewOnboarding = OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/WRITE"
    and AuthAction == "Microsoft.HybridCompute/machines/write"
    and Role == "Azure Connected Machine Onboarding"
| extend IsRemoval = OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/DELETE"
| extend IsExtension = OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE"
| extend IsHumanDeploy = IsExtension and PrincipalType == "User"
| extend IsPolicyDeploy = IsExtension and Role in ("Contributor", "Owner") and PrincipalType == "ServicePrincipal"
| extend IsMDEDeploy = IsExtension and Role == "Security RP Service Role"
| extend IsUpdateScan = IsExtension and Role == "AZURE UPDATE CENTER S2S SERVICE ROLE PROD"
| extend IsPatching = IsExtension and Role == "AZURE GUEST PATCHING SERVICE ROLE"
// Summarize by day
| summarize
    NewOnboardings = dcountif(CorrelationId, IsNewOnboarding),
    Removals = dcountif(CorrelationId, IsRemoval),
    HumanDeploys = dcountif(CorrelationId, IsHumanDeploy),
    PolicyDeploys = dcountif(CorrelationId, IsPolicyDeploy),
    MDEDeploys = dcountif(CorrelationId, IsMDEDeploy),
    UpdateScans = dcountif(CorrelationId, IsUpdateScan),
    PatchingOps = dcountif(CorrelationId, IsPatching)
    by bin(TimeGenerated, 1d)
| extend RealExtDeploys = HumanDeploys + PolicyDeploys + MDEDeploys
| extend NoiseOps = UpdateScans + PatchingOps
| project
    Date = TimeGenerated,
    NewOnboardings,
    Removals,
    RealExtDeploys,
    HumanDeploys,
    PolicyDeploys,
    MDEDeploys,
    NoiseOps
| order by Date desc
Column Reference:
  • NewOnboardings - TRUE new machines (azcmagent connect)
  • Removals - Machines deleted from Arc
  • RealExtDeploys - Total real extension deployments
  • HumanDeploys - Manual user deployments
  • PolicyDeploys - Azure Policy deployments
  • MDEDeploys - Microsoft Defender auto-deployments
  • NoiseOps - Update scans + patching (informational)

Weekly Activity Summary

For longer-term trend analysis, aggregate by week instead of day.

Azure Activity - Weekly Activity Summary
AzureActivity
| where TimeGenerated >= ago(90d)
| where OperationNameValue in ("MICROSOFT.HYBRIDCOMPUTE/MACHINES/WRITE", "MICROSOFT.HYBRIDCOMPUTE/MACHINES/DELETE", "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE")
| where ActivityStatusValue == "Success"
| extend Auth = parse_json(Authorization)
| extend AuthAction = tostring(Auth.action)
| extend Role = tostring(parse_json(tostring(Auth.evidence)).role)
| extend PrincipalType = tostring(parse_json(tostring(Auth.evidence)).principalType)
| extend IsNewOnboarding = OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/WRITE"
    and AuthAction == "Microsoft.HybridCompute/machines/write"
    and Role == "Azure Connected Machine Onboarding"
| extend IsRemoval = OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/DELETE"
| extend IsRealExtension = OperationNameValue == "MICROSOFT.HYBRIDCOMPUTE/MACHINES/EXTENSIONS/WRITE"
    and Role !in ("AZURE UPDATE CENTER S2S SERVICE ROLE PROD", "AZURE GUEST PATCHING SERVICE ROLE")
| summarize
    NewOnboardings = dcountif(CorrelationId, IsNewOnboarding),
    Removals = dcountif(CorrelationId, IsRemoval),
    ExtensionDeploys = dcountif(CorrelationId, IsRealExtension)
    by Week = startofweek(TimeGenerated)
| project Week, NewOnboardings, Removals, ExtensionDeploys
| order by Week desc

Resource Graph Inventory Queries

Use these Resource Graph queries to inventory and track your Azure Arc-enabled servers across subscriptions.

List All Azure Arc Machines

Basic query to list all Azure Arc-enabled servers in your environment.

Resource Graph - List Arc Machines
resources
| where type == "microsoft.hybridcompute/machines"

Count Machines by Subscription and Resource Group

Aggregate Azure Arc machines by subscription and resource group to understand distribution across your environment.

Resource Graph - Count by Subscription/RG
resources
| where type == "microsoft.hybridcompute/machines"
| summarize machineCount = count() by subscriptionId, resourceGroup

Enrich with Subscription Names

Join Azure Arc machine data with subscription information to show subscription names alongside machine counts.

Resource Graph - Enrich with Subscription Names
resources
| where type == "microsoft.hybridcompute/machines"
| project serverName = name, subscriptionId, resourceGroup
| join kind=inner (
    resourcecontainers
    | where type == "microsoft.resources/subscriptions"
    | project subscriptionName = name, subscriptionId
) on subscriptionId
| summarize machineCount = count() by subscriptionId, subscriptionName, resourceGroup

Count Machines by Status

Track the operational status distribution of your Azure Arc machines (Connected, Disconnected, Error).

Resource Graph - Count by Status
resources
| where type == "microsoft.hybridcompute/machines"
| extend machineStatus = tostring(properties.status)
| summarize machineCount = count() by machineStatus

Agent Version Inventory

List all Arc-enabled servers with their agent versions and connection status. Use this to identify servers running outdated agents.

Resource Graph - Agent Versions
resources
| where type == "microsoft.hybridcompute/machines"
| extend ["Server Name"] = toupper(name)
| extend ["Agent Version"] = properties.agentVersion
| extend ["Connection Status"] = properties.status
| project ["Server Name"], ["Agent Version"], ["Connection Status"]

About the Author

Kaido Järvemets - Microsoft MVP

Kaido Järvemets

Microsoft MVP | Microsoft Hybrid-Cloud Security Expert

With over 15 years of experience in IT, cybersecurity, and Microsoft technologies, Kaido specializes in Microsoft Azure, Microsoft 365, and hybrid-cloud security solutions. As a Microsoft MVP since 2010, he has deep expertise in Configuration Manager, Enterprise Mobility, and Azure Hybrid & Security.

Kaido is a Microsoft Certified Trainer who has been traveling across Europe for the past 12 years, speaking at events including the Microsoft Management Summit and Midwest Management Summit. He founded User Group Estonia and System Center User Group Estonia, building strong communities of Microsoft technology professionals.

🎯 Specializations

Microsoft Security:
  • Microsoft Defender XDR
  • Microsoft Sentinel SIEM & SOAR
  • Microsoft Entra ID (Azure AD)
  • Microsoft Intune
Azure & Hybrid Cloud:
  • Azure Arc Services
  • Azure Log Analytics
  • Azure Automation
  • Hybrid Cloud Management

"I simplify the process and make each change meaningful. It's all about adopting modern solutions that replace archaic ones and make the workplace easier for everyone involved."