Tag Archives: PowerShell

Microsoft Intune – Add additional DNS Client Servers across the managed devices

24 Aug

I recently wrote a blog post about adding DNS Client via GPO, highlighting which methods work and which don’t. If you’re interested, you can read more about it on – GPO – PowerShell – Intune – Add additional DNS Client Servers across the enterprise | AskAresh. As promised, here are the steps for performing the same task in Microsoft Intune for all of your managed devices.

Note – The best method of assigning the DNS Servers is through the DHCP server. If you are setting the IP using DHCP, always make sure you add/remove additional DNS Client Servers from there. In my situation, there was no DHCP server, hence the detailed blog post.

Prerequsites

We are going to implement this configuration via Microsoft Intune using the Scripts:

  • The necessary Microsoft Intune permissions to create, the PowerShell Scripts.
  • A device group available within Microsoft Entra with all the devices you want to target this change.

    PowerShell Script for DNSClient (Additional DNS Servers)

    Save the below script and place on the desktop and we shall be uploading it to Microsft Intune portal – “AddDNSClient.ps1″

    • Please enter the proper DNS Server Address within the script based on your environment and requirement. In the example below the existing two DNS servers are 8.8.8.8 and 8.8.8.4. We are adding additional two DNS Servers 9.9.9.9 and 9.9.9.4.
    $dnsclient=Get-DnsClient  | Get-DnsClientServerAddress | where{$_.ServerAddresses -contains "8.8.8.8" -or $_.ServerAddresses -contains "8.8.8.4"}
    foreach($nic in $dnsclient){
    Set-DnsClientServerAddress -InterfaceIndex $nic.InterfaceIndex -ServerAddresses ("8.8.8.8","8.8.8.4","9.9.9.9","9.9.9.4")
    }

    Create a script policy and assign it – Intune

    1. Sign in to the Microsoft Intune admin center.
    2. Select Devices > Scripts > Add > Windows 10 and later.Screenshot that shows creating a new script for a Windows 10 device.
    3. In Basics, enter the following properties, and select Next:
      • Name: AddDNSClientServers
      • Description: Additional DNS Server 3 & 4
    4. In Script settings, enter the following properties, and select Next:
      • Script location: Browse to the PowerShell script. saved previously and upload it (AddDNSClient.ps1)
      • Run this script using the logged on credentials: Select No.
      • Enforce script signature check: Select No 
      • Run script in 64-bit PowerShell host: Select Yes to run the script in a 64-bit PowerShell host on a 64-bit client architecture.
    5. Select Assignments > Select groups to include. Add the AAD group “Win11-P-DG”

    Wait for approx. 15-20 minutes and the policy will apply to the managed devices. (Machine Win11-Intune-15)

    Managed Device

    You can validate that the settings have been applied to the client by going to the path – C:\ProgramData\Microsoft\IntuneManagementExtension\Logs and opening the file IntuneManagementExtension.txt. I copied the policy ID – cf09649b-78b7-4d98-8bcc-b122c29e5527 from the Intune portal hyperlink and searched within the log file. We can see the policy has been applied successfully.

    I hope you will find this helpful information for applying additional DNS servers via Intune – Scripts and PowerShell. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    GPO – PowerShell – Intune – Add additional DNS Client Servers across the enterprise

    16 Aug

    Let’s say you have the entire Windows member server fleet of Windows Server 2016/2019/2022, Windows 11 Pro/Enterprise etc., using DNS Server 1 and Server 2 within their TCP-IP properties and now you decide to add DNS Server address 3 and Server 4 to the member servers to increase resiliency.

    In the blog post, I will demonstrate how you can add the additional DNS Server using Group Policy Object and PowerShell with your enterprise.

    What doesn’t work?

    It would be best if you didn’t waste time – The GPO Computer Configuration –> Administrative Templates –> Network –> DNS Client –> DNS Servers doesn’t work. The “Supported On” version doesn’t include Windows Server 2016\Windows 10 in the compatibility. Even if you apply this GPO, it will apply to the server within the registry, but there will be no visible change under the TCP-IP properties.

    Prerequsites

    We are going to implement this configuration via group policy object within the enterprise:

    • The necessary active directory permissions to create, apply and link the GPOs
    • Access to the Sysvol folder to store the script
    • WMI Filters to target the script\GPO to specific subnets (More details below)

    PowerShell Script for DNSClient (Additional DNS Servers)

    Save the below script and place it within the location – \\DOMAINNAME\SYSVOL\DOMAINNAME\scripts\SetDNSAddress.ps1″

    • Please enter the proper DNS Server Address within the script based on your environment and requirements.
    $dnsclient=Get-DnsClient  | Get-DnsClientServerAddress | where{$_.ServerAddresses -contains "192.168.0.3" -or $_.ServerAddresses -contains "192.168.0.4"}
    foreach($nic in $dnsclient){
    Set-DnsClientServerAddress -InterfaceIndex $nic.InterfaceIndex -ServerAddresses ("192.168.0.3","192.168.0.4","192.168.0.5","192.168.0.6")
    }

    Create the GPO (Additional DNS Servers)

    On a member server with administrative privileges, press Win + R to open the Run box. Type gpmc.msc and press Enter to open the Group Policy Management Console.

    • In the GPMC, expand the forest and domain trees on the left pane to locate the domain you want to create the GPO in.
    • Right-click on “Group Policy Objects” under the domain and select “New” to create a new GPO.
    • In the “New GPO” dialog box, provide a name for the GPO (e.g., “Additional DNS Servers”) and click “OK”.
    • Right-click on the newly created GPO and select “Edit” to open the Group Policy Management Editor.
    • Navigate to Computer Configuration > Preferences > Control Panel Settings > Scheduled Tasks
    • Right Click on Scheduled Tasks > Configure the task as Immediate Task.
    • Give it a name – SetDNSClient
    • Set the user account as SYSTEM. It will automatically convert into NT Authority\system.
    • Set the check “run with highest privileges”
    • In the Actions tab, create a new “Start a program” action.
    • Set the Program as: PowerShell.exe
    • Set the Add Arguments point to this line, and modify including your network share and file: ExecutionPolicy Bypass -command “& \\DOMAINNAME\SYSVOL\DOMAINNAME\scripts\SetDNSAddress.ps1”
    • Set the following in common Tab. – “Apply once and do not reapply”

    Bonus Tip – WMI Filters

    You want to target the GPO to a specific set of member servers who’s IP range starts with a particular IP address. Then you can create a WMI filter such as the below to target particular computers that meet the below range. In the below example, the GPO will apply to the machine starting with IP Address 10.XX OR 10.XX.

    Select * FROM Win32_IP4RouteTable
    WHERE (Mask='255.255.255.255'
    AND (Destination Like '192.168.%' OR Destination Like '192.169.%'))

    Intune (Configuration Profiles – Doesn’t Work)

    As of writing the blog post the Intune built-in setting\CSP is showing similar behaviour like the DNS Server GPO it doesn’t work.

    CSP

    Under both situations (CSP & ADMX templates), the report says the policy is applied successfully. However, there is no visible impact on the operating system’s TCP-IP properties. I am optimistic that using the Scripts method and PowerShell can achieve the same results in Intune. Please let me know in the comments sections if you got it working or/else if you would like to see a blog post on using Intune Scripts to set the DNS Client on member servers.

    Following are the references and important links worth going through for more details:

    DescriptionLinks
    Static DNS Servers via GPOUpdate DNS static servers in your local Network (itdungeon.blogspot.com)
    DNS Server GPO doesn’t workDNS Server GPO Settings Invisible in IPConfig – CB5 Solutions LLC (cbfive.com)

    I hope you will find this helpful information for applying additional DNS servers via the GPO and PoweShell. I want to thank my friend Eqbal Hussian for his assistance and additional rounds of testing\validations. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    PowerShell – GPO Analysis – Search for a specific or list of GPO Setting across multiple GPOs within a domain

    20 Jul

    Suppose you’ve ever had to search for a particular or a list of GPO settings across a large number of Group Policy Objects (GPOs) within your domain. In that case, you know how tedious it can be to find specific settings across hundreds or thousands of GPOs. PowerShell comes to the rescue with a powerful script that can search for GPO settings across all your existing GPOs and generate an organized CSV output. In this blog post, we’ll walk you through the process and ensure you have all the prerequisites to get started.

    Usecase

    You have approx. 50 to 60 GPO settings from the Center of Internet Security (CIS) benchmark policies document (CIS Microsoft Windows Desktop Benchmarks/CIS Microsoft Windows Server Benchmarks), which you may want to search against your domain, whether they are already preconfigured\existing available within a GPO or not present in the environment. Instead of searching manually one by one, you may want to use the below PowerShell to get results like a champion.

    Prerequisites

    Before using the PowerShell script, ensure you have the following prerequisites in place:

    1. Windows PowerShell version 5.0 and above
    2. Active Directory Module for Windows PowerShell
    3. Permissions: Ensure you have sufficient permissions to access and analyze GPO settings. Typically, you need to be a member of the Domain Administrators group or have equivalent privileges.
    4. Execute the script from a member server that is part of the domain and has the necessary permissions.
    5. Prepare the input file (inputgpo.txt) and enter the GPO setting one per line and save the file. In my situation, it’s present in C:\Temp
    Relax minimum password length limits
    Allow Administrator account lockout
    Generate security audits
    Impersonate a client after authentication
    Lock pages in memory
    Replace a process level token
    Accounts: Block Microsoft accounts
    Interactive logon: Machine inactivity limit
    Microsoft network server: Server SPN target name validation level
    Network access: Remotely accessible  registry paths
    Network security: Configure encryption types allowed for Kerberos
    Audit Security State Change
    Do not allow password expiration time longer than required by policy
    Password Settings: Password Complexity
    Password Settings: Password Length
    Password Settings: Password Age (Days)

    PowerShell Script

    Now that you have the prerequisites in place, let’s dive into the PowerShell script. GitHub – avdwin365mem/GPOSettingsSearch at main · askaresh/avdwin365mem (github.com)

    • Enter the name of your domain (E.g askaresh.com)
    • Make sure the Input file is present in C:\Temp
    #Domain
    $DomainName = "askaresh.com"
    
    # Initialize matchlist
    $matchlist = @()
    
    # Collect all GPOs
    $GPOs = Get-GPO -All -Domain $DomainName
    
    # Read search strings from text file
    # A list of GPOs settings you want to search
    $SearchStrings = Get-Content -Path "C:\Temp\inputgpo.txt"
    
    # Hunt through each GPO XML for each search string
    foreach ($searchString in $SearchStrings) {
        $found = $false
        foreach ($gpo in $GPOs) {
            $GPOReport = Get-GPOReport -Guid $gpo.Id -ReportType Xml
            if ($GPOReport -match $searchString) {
                $match = New-Object PSObject -Property @{
                    "SearchString" = $searchString
                    "GPOName" = $gpo.DisplayName
                }
                $matchlist += $match
                $found = $true
            }
        }
        if (-not $found) {
            $match = New-Object PSObject -Property @{
                "SearchString" = $searchString
                "GPOName" = "No results found"
            }
            $matchlist += $match
        }
    }
    
    # Output results to CSV, Search results
    
    # This step will take time depending how many 100's or 1000's policies present in the enviornment
    $matchlist | Export-Csv -Path "C:\Temp\gposearch.csv" -NoTypeInformation
    

    Output (Results)

    The ouput will look like the following within CSV:

    I hope you will find this helpful information for searching GPO settings across 100’s and 1000’s of GPOs within your domain. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    PowerShell – Frontline Workers – Create Windows 365 Cloud PC Provisioning Policy

    23 May

    I have a blog post about creating a Windows 365 Cloud PC Provisioning Policy using PowerShell. In this post blog, I will demonstrate how to create the provisioning policy using PowerShell and MS Graph API with beta modules for Windows 365 Cloud PC – Frontline Workers.

    Windows 365 Frontline Worker

    Introduction

    I will not attempt to explain Frontline, but the best explanation is here: What is Windows 365 Frontline? | Microsoft Learn.

    Example – Each Windows 365 Frontline license can be shared with up to three employees. This means that if you have 30 employees, you only need to purchase 10 licenses to provision the CloudPC for all 30 employees with access over the day. However, note you are buying the frontline license based on the active sessions. You must purchase the license accordingly if you have more than 10 active workers in a shift.

    What happens when license are exhausted?

    In my demo tenant, I have two licenses for Frontline workers. When I try to log in to the third one (Note I have already logged into 2 active sessions and running them.) Get the following message.

    Connect to MS Graph API

    Step 1 – Install the MS Graph Powershell Module

    #Install Microsoft Graph Beta Module
    PS C:WINDOWSsystem32> Install-Module Microsoft.Graph.Beta

    Step 2 – Connect to scopes and specify which API you wish to authenticate to. If you are only doing read-only operations, I suggest you connect to “CloudPC.Read.All” in our case, we are creating the policy, so we need to change the scope to “CloudPC.ReadWrite.All”

    #Read-only
    PS C:WINDOWSsystem32> Connect-MgGraph -Scopes "CloudPC.Read.All" -NoWelcome
    Welcome To Microsoft Graph!
    
    OR
    
    #Read-Write
    PS C:WINDOWSsystem32> Connect-MgGraph -Scopes "CloudPC.ReadWrite.All" -NoWelcome
    Welcome To Microsoft Graph!
    Permissions for MS Graph API

    Step 3 –  Check the User account by running the following beta command.

    #Beta APIs
    PS C:WINDOWSsystem32> Get-MgBetaUser -UserId admin@wdomain.com

    Create Provisioning Policy (Frontline Worker)

    We are creating a provisioning policy that involves the following: avdwin365mem/win365frontlineCreateProvPolicy at main · askaresh/avdwin365mem · GitHub

    • Azure AD Joined Cloud PC desktops
    • The region for deployment – Australia East
    • Image Name – Windows 11 Enterprise + Microsoft 365 Apps 22H2 (from the Gallery)
    • Language & Region – English (United States)
    • Network – Microsoft Managed
    • Cloud PC Naming format – FLW-%USERNAME:5%-%RAND:5% (FLW – Frontline Worker)
    $params = @{
    	displayName = "Demo-FrontLine"
    	description = "Front Line Workers Prov Policy"
    	provisioningType = "shared"
    	managedBy = "windows365"
    	imageId = "MicrosoftWindowsDesktop_windows-ent-cpc_win11-22h2-ent-cpc-m365"
    	imageDisplayName = "Windows 11 Enterprise + Microsoft 365 Apps 22H2"
    	imageType = "gallery"
    	microsoftManagedDesktop = @{
    		type = "starterManaged"
    		profile = $null
    	}
    	enableSingleSignOn = $true
    	domainJoinConfigurations = @(
    		@{
    			type = "azureADJoin"
    			regionGroup = "australia"
    			regionName = "automatic"
    		}
    	)
    	windowsSettings = @{
    		language = "en-US"
    	}
    	cloudPcNamingTemplate = "FLW-%USERNAME:5%-%RAND:5%"
    }
    
    New-MgBetaDeviceManagementVirtualEndpointProvisioningPolicy -BodyParameter $params

    Note – Post provisioning, you need to add the assignment of a AAD group consisting of all the frontline users. In the future I can demonstrate the API call for assignments. You can also use Andrew Taylors post around using Graph to create the Windows 365 Group – Creating Windows 365 Groups and assigning licenses using Graph and PowerShell

    Powershell Output

    Policy will show up in the MEM Portal

    Optional Properties

    If you are doing on-premise network integration (Azure Network Connection) , then the following additional property and value is required. In my lab, I am leveraging the Microsoft Managed Network, so this is not required.

    OnPremisesConnectionId = "4e47d0f6-6f77-44f0-8893-c0fe1701ffff"

    I hope you will find this helpful information for creating a frontline worker provisioning policy using PowerShell. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Pooled Remote App aka Published Applications (Part 3)

    15 May

    In the previous blog post we look at creating the Personal Desktop (1×1 mapping) and Pooled Desktop (1 x Many) using Terraform Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Personal Desktop (Part 1) | AskAresh and Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Pooled Desktop (Part 2). In this blog post series I am going to demonstrate how to create the AVD Host Pool, Application Group and Workspace using Terraform for Pooled Remote App aka Published Applications (1xMany)

    We are going to create the following three types of configurations using Terraform:

    • Azure Virtual Desktop – Personal Desktop (1×1) – Part 1
    • Azure Virtual Desktop – Pooled Desktop (Multi-Session Full Desktop Experience) – Part 2
    • Azure Virtual Desktop – Remote App (Multi-Session Application aka Published Apps) – Part 3

    Note – We are creating the Pooled RemoteApp in this post and in the subsequent post the other types were. In this post In this post I will not show case the creation of service principal and secret please refer for the Part 1 for that activity.

    Pre-requisites

    Following are the pre-requisites before you begin

    • An Azure subscription
    • The Terraform CLI
    • The Azure CLI
    • Permissions within the Azure Subscription for using Terraform

    Terraform – Authenticating via Service Principal & Client Secret

    Before running any Terraform code the following powershell (Make sure run as administrator) we will execute and store the credentials as enviornment variables. If we do this via the environment variable we dont have to store the below information within the providers.tf file. In the future blog post there are better way to store the below details and I hope to showcase them:

    # PowerShell
    $env:ARM_CLIENT_ID = "9e453b62-0000-0000-0000-00000006e1ac"
    $env:ARM_CLIENT_SECRET = "Z318Q~00000000000000000000000000000000_"
    $env:ARM_TENANT_ID = "a02e602c-0000-000-0000-0e0000008bba61"
    $env:ARM_SUBSCRIPTION_ID = "7b051460-00000-00000-00000-000000ecb1"
    • Azure Subcription ID – Azure Portal Subcription copy the ID
    • Client ID – From the above step you will have the details
    • Client Secret – From the above step you will have the details
    • Tenant ID – While creating the Enterprise Apps in ADD you will have the details

    Terraform Folder Structure

    The following is the folder structure for the terrraform code:

    Azure Virtual Desktop Pooled RemoteApp – Create a directory in which the below Terraform code will be published (providers.tf, main.tf, variables.tf and output.tf)

    +---Config-AVD-Pooled-RemoteApp
    |   |   main.tf
    |   |   output.tf
    |   |   providers.tf
    |   |   variables.tf

    Configure AVD – Pooled RemoteApp – Providers.tf

    Create a file named providers.tf and insert the following code:

    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "3.49.0"
        }
        azuread = {
          source = "hashicorp/azuread"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }

    Configure AVD – Pooled RemoteApp – main.tf

    Create a file named main.tf and insert the following code. Let me explain what all we are attempting to accomplish here:

    • Create a Resource Group
    • Create a Workspace
    • Create a Host Pool
    • Create a Remote Application Group (RAG)
    • Associate Workspace and RAG
    • Assign Azure AD Group to the Desktop Application Group (RAG)
    • Assign Azure AD Group to the Resource Group for RBAC for the Session Host (Virtual Machine User Login)
    # Resource group name is output when execution plan is applied.
    resource "azurerm_resource_group" "rg" {
      name     = var.rg_name
      location = var.resource_group_location
      tags = var.tags
    }
    
    # Create AVD workspace
    resource "azurerm_virtual_desktop_workspace" "workspace" {
      name                = var.workspace
      resource_group_name = azurerm_resource_group.rg.name
      location            = azurerm_resource_group.rg.location
      friendly_name       = "${var.prefix} Workspace"
      description         = "${var.prefix} Workspace"
      tags = var.tags
    }
    
    # Create AVD host pool
    resource "azurerm_virtual_desktop_host_pool" "hostpool" {
      resource_group_name      = azurerm_resource_group.rg.name
      location                 = azurerm_resource_group.rg.location
      name                     = var.hostpool
      friendly_name            = var.hostpool
      validate_environment     = true #[true false]
      start_vm_on_connect      = true
      custom_rdp_properties    = "targetisaadjoined:i:1;drivestoredirect:s:*;audiomode:i:0;videoplaybackmode:i:1;redirectclipboard:i:1;redirectprinters:i:1;devicestoredirect:s:*;redirectcomports:i:1;redirectsmartcards:i:1;usbdevicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;enablerdsaadauth:i:1;"
      description              = "${var.prefix} HostPool"
      type                     = "Pooled" #[Pooled or Personal]
      preferred_app_group_type = "RailApplications" #[Desktop or RailApplications]
      maximum_sessions_allowed = 5  #[Tweak based on your vm tshirt size]
      load_balancer_type       = "DepthFirst" #[BreadthFirst or DepthFirst]
      tags = var.tags
    scheduled_agent_updates {
      enabled = true
      timezone = "AUS Eastern Standard Time"  # Update this value with your desired timezone
      schedule {
        day_of_week = "Saturday"
        hour_of_day = 1   #[1 here means 1:00 am]
      }
    }
    }
    
    resource "azurerm_virtual_desktop_host_pool_registration_info" "registrationinfo" {
      hostpool_id     = azurerm_virtual_desktop_host_pool.hostpool.id
      expiration_date = var.rfc3339
    }
    
    # Create AVD RAG
    resource "azurerm_virtual_desktop_application_group" "rag" {
      resource_group_name = azurerm_resource_group.rg.name
      host_pool_id        = azurerm_virtual_desktop_host_pool.hostpool.id
      location            = azurerm_resource_group.rg.location
      type                = "RemoteApp"
      name                = var.app_group_name
      friendly_name       = "RemoteApp AppGroup"
      description         = "${var.prefix} AVD RemoteApp application group"
      depends_on          = [azurerm_virtual_desktop_host_pool.hostpool, azurerm_virtual_desktop_workspace.workspace]
      tags = var.tags
    }
    
    # Associate Workspace and DAG
    resource "azurerm_virtual_desktop_workspace_application_group_association" "ws-dag" {
      application_group_id = azurerm_virtual_desktop_application_group.rag.id
      workspace_id         = azurerm_virtual_desktop_workspace.workspace.id
    }
    
    # Assign AAD Group to the Remote Application Group (RAG)
    resource "azurerm_role_assignment" "AVDGroupRemoteAppAssignment" {
      scope                = azurerm_virtual_desktop_application_group.rag.id
      role_definition_name = "Desktop Virtualization User"
      principal_id         = data.azuread_group.AVDGroup.object_id
    }
    
    # Assign AAD Group to the Resource Group for RBAC for the Session Host
    resource "azurerm_role_assignment" "RBACAssignment" {
      scope                = azurerm_resource_group.rg.id
      role_definition_name = "Virtual Machine User Login"
      principal_id         = data.azuread_group.AVDGroup.object_id
    }

    Note – The individual applications are not published yet. They can be published once you have the session host created. After which, using Terraform, the individual applications can be published too. The exe path of apps needs to be mapped within the operating system. I plan to create a separate blog post on session host creation via Terraform.

    Configure AVD – Pooled RemoteApp – variables.tf

    Create a file named variables.tf and insert the following code:

    variable "resource_group_location" {
      default     = "australiaeast"
      description = "Location of the resource group - Australia East"
    }
    
    variable "rg_name" {
      type        = string
      default     = "AE-DEV-AVD-01-PO-A-RG"
      description = "Name of the Resource group in which to deploy service objects"
    }
    
    variable "workspace" {
      type        = string
      description = "Name of the Azure Virtual Desktop workspace"
      default     = "AE-DEV-AVD-01-WS"
    }
    
    variable "hostpool" {
      type        = string
      description = "Name of the Azure Virtual Desktop host pool"
      default     = "AE-DEV-AVD-01-PO-A-HP"
    }
    
    variable "app_group_name" {
      description = "Name of the Azure Virtual Desktop application group"
      type        = string
      default     = "AE-DEV-AVD-01-RAG"
    }
    
    variable "rfc3339" {
      type        = string
      default     = "2023-05-20T12:43:13Z"  #Update this value with a future date
      description = "Registration token expiration"
    }
    
    variable "prefix" {
      type        = string
      default     = "AE-DEV-AVD-01-HP-"
      description = "Prefix of the name of the AVD HostPools"
    }
    
    variable "tags" {
      type    = map(string)
      default = {
        Environment = "Dev"
        Department  = "IT"
        Location = "AustraliaEast"
        ServiceClass = "DEV"
        Workload = "Host Pool 01"
      }
    }
    
    data "azuread_client_config" "AzureAD" {}
    
    data "azuread_group" "AVDGroup" {
      display_name     = "Win365-Users"  
    }

    Configure AVD – Pooled RemoteApp – output.tf

    Create a file named output.tf and insert the following code. This will showcase in the console what is getting deployed in form of a output.

    output "azure_virtual_desktop_compute_resource_group" {
      description = "Name of the Resource group in which to deploy session host"
      value       = azurerm_resource_group.rg.name
    }
    
    output "azure_virtual_desktop_host_pool" {
      description = "Name of the Azure Virtual Desktop host pool"
      value       = azurerm_virtual_desktop_host_pool.hostpool.name
    }
    
    output "azurerm_virtual_desktop_application_group" {
      description = "Name of the Azure Virtual Desktop DAG"
      value       = azurerm_virtual_desktop_application_group.rag.name
    }
    
    output "azurerm_virtual_desktop_workspace" {
      description = "Name of the Azure Virtual Desktop workspace"
      value       = azurerm_virtual_desktop_workspace.workspace.name
    }
    
    output "location" {
      description = "The Azure region"
      value       = azurerm_resource_group.rg.location
    }
    
    data "azuread_group" "aad_group" {
      display_name = "Win365-Users"
    }
    
    output "AVD_user_groupname" {
      description = "Azure Active Directory Group for AVD users"
      value       = data.azuread_group.aad_group.display_name
    }

    Intialize Terraform – AVD – Pooled RemoteApp

    Run terraform init to initialize the Terraform deployment. This command downloads the Azure provider required to manage your Azure resources. (Its pulling the AzureRM and AzureAD)

    terraform init -upgrade

    Create Terraform Execution Plan – AVD – Pooled RemoteApp

    Run terraform plan to create an execution plan.

    terraform plan -out mainavdremoteapp.tfplan

    Apply Terraform Execution Plan – AVD – Pooled RemoteApp

    Run terraform apply to apply the execution plan to your cloud infrastructure.

    terraform apply mainavdremoteapp.tfplan

    Validate the Output in Azure Portal

    Go to the Azure portal, Select Azure Virtual Desktop and Select Host pools, Application Group and Workspace created using Terraform.

    Clean-up the above resources (Optional)

    If you want to delete all the above resources then you can use the following commands to destroy. Run terraform plan and specify the destroy flag.

    terraform plan -destroy -out mainavdremoteapp.destroy.tfplan

    Run terraform apply to apply the execution plan.

    terraform apply mainavdremoteapp.destroy.tfplan

    The intention here is to get you quickly started with Terraform on Azure Virtual Desktop Solution:

    DescriptionLinks
    Setting up your computer to get started with Terrafor using PowershellInstall Terraform on Windows with Azure PowerShell
    AVD Configure Azure Virtual Desktophttps://learn.microsoft.com/en-us/azure/developer/terraform/configure-azure-virtual-desktop
    Terraform Learninghttps://youtube.com/playlist?list=PLLc2nQDXYMHowSZ4Lkq2jnZ0gsJL3ArAw

    I hope you will find this helpful information for getting started with Terraform to deploy the Azure Virtual Desktop – Pooled Remote App. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Pooled Desktop (Part 2)

    15 May

    In the previous blog post we look at creating the Personal Desktop (1×1 mapping) using Terraform. Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Personal Desktop (Part 1) | AskAresh. In this blog post series I am going to demonstrate how to create the AVD Host Pool, Application Group and Workspace using Terraform for Pooled Desktop (1xMany)

    We are going to create the following three types of configurations using Terraform:

    • Azure Virtual Desktop – Personal Desktop (1×1) – Part 1
    • Azure Virtual Desktop – Pooled Desktop (Multi-Session Full Desktop Experience) – Part 2
    • Azure Virtual Desktop – Remote App (Multi-Session Application aka Published Apps) – Part 3

    Note – We are creating the Pooled Desktop in this post and in the subsequent post the other types will be created. In this post In this post I will not show case the creation of service principal and secret please refer for the Part 1 for that activity.

    Pre-requisites

    Following are the pre-requisites before you begin

    • An Azure subscription
    • The Terraform CLI
    • The Azure CLI
    • Permissions within the Azure Subscription for using Terraform

    Terraform – Authenticating via Service Principal & Client Secret

    Before running any Terraform code the following powershell (Make sure run as administrator) we will execute and store the credentials as enviornment variables. If we do this via the environment variable we dont have to store the below information within the providers.tf file. In the future blog post there are better way to store the below details and I hope to showcase them:

    # PowerShell
    $env:ARM_CLIENT_ID = "9e453b62-0000-0000-0000-00000006e1ac"
    $env:ARM_CLIENT_SECRET = "Z318Q~00000000000000000000000000000000_"
    $env:ARM_TENANT_ID = "a02e602c-0000-000-0000-0e0000008bba61"
    $env:ARM_SUBSCRIPTION_ID = "7b051460-00000-00000-00000-000000ecb1"
    • Azure Subcription ID – Azure Portal Subcription copy the ID
    • Client ID – From the above step you will have the details
    • Client Secret – From the above step you will have the details
    • Tenant ID – While creating the Enterprise Apps in ADD you will have the details

    Terraform Folder Structure

    The following is the folder structure for the terrraform code:

    Azure Virtual Desktop Pooled Desktop – Create a directory in which the below Terraform code will be published (providers.tf, main.tf, variables.tf and output.tf)

    +---Config-AVD-Pooled-Desktop
    |   |   main.tf
    |   |   output.tf
    |   |   providers.tf
    |   |   variables.tf

    Configure AVD – Pooled Desktop Pool – Providers.tf

    Create a file named providers.tf and insert the following code:

    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "3.49.0"
        }
        azuread = {
          source = "hashicorp/azuread"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }

    Configure AVD – Pooled Desktop Pool – main.tf

    Create a file named main.tf and insert the following code. Let me explain what all we are attempting to accomplish here:

    • Create a Resource Group
    • Create a Workspace
    • Create a Host Pool (Pooled Desktops and Depth first load balancing)
    • Create a Desktop Application Group (DAG)
    • Associate Workspace and DAG
    • Assign Azure AD Group to the Desktop Application Group (DAG)
    • Assign Azure AD Group to the Resource Group for RBAC for the Session Host (Virtual Machine User Login)
    # Resource group name is output when execution plan is applied.
    resource "azurerm_resource_group" "rg" {
      name     = var.rg_name
      location = var.resource_group_location
      tags = var.tags
    }
    
    # Create AVD workspace
    resource "azurerm_virtual_desktop_workspace" "workspace" {
      name                = var.workspace
      resource_group_name = azurerm_resource_group.rg.name
      location            = azurerm_resource_group.rg.location
      friendly_name       = "${var.prefix} Workspace"
      description         = "${var.prefix} Workspace"
      tags = var.tags
    }
    
    # Create AVD host pool
    resource "azurerm_virtual_desktop_host_pool" "hostpool" {
      resource_group_name      = azurerm_resource_group.rg.name
      location                 = azurerm_resource_group.rg.location
      name                     = var.hostpool
      friendly_name            = var.hostpool
      validate_environment     = true #[true false]
      start_vm_on_connect      = true
      custom_rdp_properties    = "targetisaadjoined:i:1;drivestoredirect:s:*;audiomode:i:0;videoplaybackmode:i:1;redirectclipboard:i:1;redirectprinters:i:1;devicestoredirect:s:*;redirectcomports:i:1;redirectsmartcards:i:1;usbdevicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;enablerdsaadauth:i:1;"
      description              = "${var.prefix} HostPool"
      type                     = "Pooled" #[Pooled or Personal]
      maximum_sessions_allowed = 5
      load_balancer_type       = "DepthFirst" #[BreadthFirst DepthFirst]
      tags = var.tags
    scheduled_agent_updates {
      enabled = true
      timezone = "AUS Eastern Standard Time"  # Update this value with your desired timezone
      schedule {
        day_of_week = "Saturday"
        hour_of_day = 1   #[1 here means 1:00 am]
      }
    }
    }
    
    resource "azurerm_virtual_desktop_host_pool_registration_info" "registrationinfo" {
      hostpool_id     = azurerm_virtual_desktop_host_pool.hostpool.id
      expiration_date = var.rfc3339
    }
    
    # Create AVD DAG
    resource "azurerm_virtual_desktop_application_group" "dag" {
      resource_group_name = azurerm_resource_group.rg.name
      host_pool_id        = azurerm_virtual_desktop_host_pool.hostpool.id
      location            = azurerm_resource_group.rg.location
      type                = "Desktop"
      name                = var.app_group_name
      friendly_name       = "Desktop AppGroup"
      description         = "${var.prefix} AVD application group"
      depends_on          = [azurerm_virtual_desktop_host_pool.hostpool, azurerm_virtual_desktop_workspace.workspace]
      tags = var.tags
    }
    
    # Associate Workspace and DAG
    resource "azurerm_virtual_desktop_workspace_application_group_association" "ws-dag" {
      application_group_id = azurerm_virtual_desktop_application_group.dag.id
      workspace_id         = azurerm_virtual_desktop_workspace.workspace.id
    }
    
    # Assign AAD Group to the Desktop Application Group (DAG)
    resource "azurerm_role_assignment" "AVDGroupDesktopAssignment" {
      scope                = azurerm_virtual_desktop_application_group.dag.id
      role_definition_name = "Desktop Virtualization User"
      principal_id         = data.azuread_group.AVDGroup.object_id
    }
    
    # Assign AAD Group to the Resource Group for RBAC for the Session Host
    resource "azurerm_role_assignment" "RBACAssignment" {
      scope                = azurerm_resource_group.rg.id
      role_definition_name = "Virtual Machine User Login"
      principal_id         = data.azuread_group.AVDGroup.object_id
    }

    Configure AVD – Pooled Desktop Pool – variables.tf

    Create a file named variables.tf and insert the following code:

    variable "resource_group_location" {
      default     = "australiaeast"
      description = "Location of the resource group - Australia East"
    }
    
    variable "rg_name" {
      type        = string
      default     = "AE-DEV-AVD-01-PO-D-RG"
      description = "Name of the Resource group in which to deploy service objects"
    }
    
    variable "workspace" {
      type        = string
      description = "Name of the Azure Virtual Desktop workspace"
      default     = "AE-DEV-AVD-01-WS"
    }
    
    variable "hostpool" {
      type        = string
      description = "Name of the Azure Virtual Desktop host pool"
      default     = "AE-DEV-AVD-01-PO-D-HP"
    }
    
    variable "app_group_name" {
      description = "Name of the Azure Virtual Desktop application group"
      type        = string
      default     = "AE-DEV-AVD-01-DAG"
    }
    
    variable "rfc3339" {
      type        = string
      default     = "2023-05-20T12:43:13Z"  #Update this value with a future date
      description = "Registration token expiration"
    }
    
    variable "prefix" {
      type        = string
      default     = "AE-DEV-AVD-01-HP-"
      description = "Prefix of the name of the AVD machine(s)"
    }
    
    variable "tags" {
      type    = map(string)
      default = {
        Environment = "Dev"
        Department  = "IT"
        Location = "AustraliaEast"
        ServiceClass = "DEV"
        Workload = "Host Pool 01"
      }
    }
    
    data "azuread_client_config" "AzureAD" {}
    
    data "azuread_group" "AVDGroup" {
      display_name     = "Win365-Users"  
    }

    Configure AVD – Pooled Desktop Pool – output.tf

    Create a file named output.tf and insert the following code. This will showcase in the console what is getting deployed in form of a output.

    output "azure_virtual_desktop_compute_resource_group" {
      description = "Name of the Resource group in which to deploy session host"
      value       = azurerm_resource_group.rg.name
    }
    
    output "azure_virtual_desktop_host_pool" {
      description = "Name of the Azure Virtual Desktop host pool"
      value       = azurerm_virtual_desktop_host_pool.hostpool.name
    }
    
    output "azurerm_virtual_desktop_application_group" {
      description = "Name of the Azure Virtual Desktop DAG"
      value       = azurerm_virtual_desktop_application_group.dag.name
    }
    
    output "azurerm_virtual_desktop_workspace" {
      description = "Name of the Azure Virtual Desktop workspace"
      value       = azurerm_virtual_desktop_workspace.workspace.name
    }
    
    output "location" {
      description = "The Azure region"
      value       = azurerm_resource_group.rg.location
    }
    
    data "azuread_group" "aad_group" {
      display_name = "Win365-Users"
    }
    
    output "AVD_user_groupname" {
      description = "Azure Active Directory Group for AVD users"
      value       = data.azuread_group.aad_group.display_name
    }
    

    Intialize Terraform – AVD – Pooled Desktop Pool

    Run terraform init to initialize the Terraform deployment. This command downloads the Azure provider required to manage your Azure resources. (Its pulling the AzureRM and AzureAD)

    terraform init -upgrade

    Create Terraform Execution Plan – AVD – Pooled Desktop Pool

    Run terraform plan to create an execution plan.

    terraform plan -out mainavdpooled.tfplan

    Apply Terraform Execution Plan – AVD – Pooled Desktop Pool

    Run terraform apply to apply the execution plan to your cloud infrastructure.

    terraform apply mainavdpooled.tfplan

    Validate the Output in Azure Portal

    Go to the Azure portal, Select Azure Virtual Desktop and Select Host pools, Application Group and Workspace created using Terraform.

    Clean-up the above resources (Optional)

    If you want to delete all the above resources then you can use the following commands to destroy. Run terraform plan and specify the destroy flag.

    terraform plan -destroy -out mainavdpooled.destroy.tfplan

    Run terraform apply to apply the execution plan.

    terraform apply mainavdpooled.destroy.tfplan

    The intention here is to get you quickly started with Terraform on Azure Virtual Desktop Solution:

    DescriptionLinks
    Setting up your computer to get started with Terrafor using PowershellInstall Terraform on Windows with Azure PowerShell
    AVD Configure Azure Virtual Desktophttps://learn.microsoft.com/en-us/azure/developer/terraform/configure-azure-virtual-desktop
    Terraform Learninghttps://youtube.com/playlist?list=PLLc2nQDXYMHowSZ4Lkq2jnZ0gsJL3ArAw

    I hope you will find this helpful information for getting started with Terraform to deploy the Azure Virtual Desktop – Pooled Desktop. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Personal Desktop (Part 1)

    8 May

    In the past, I have written blog posts on creating the Azure Virtual Desktop (AVD) solution using PowerShell. In this blog post series, I will demonstrate how to create the AVD Host Pool, Application Group and Workspace using Terraform. Terraform is an open-source infrastructure as code (IaC) software tool that enables you to safely and predictably create, change, and improve infrastructure. Terraform can be used to manage infrastructure on various cloud providers, including Azure.

    We are going to create the following three types of configurations using Terraform:

    • Azure Virtual Desktop – Personal Desktop (1×1)
    • Azure Virtual Desktop – Pooled Desktop (Multi-Session Full Desktop Experience)
    • Azure Virtual Desktop – Remote App (Multi-Session Application aka Published Apps)

    Note – We are creating the Personal Desktop in this post, and the other desktop/app types will be created in the subsequent post. In this post, I will showcase the creation of service principal and secret. In the next part, we shall move straight onto the Terraform code. Referring to part 1 in the series will be essential if you are doing the basics.

    Pre-requisites

    Following are the pre-requisites before you begin

    • An Azure subscription
    • The Terraform CLI
    • The Azure CLI
    • Permissions within the Azure Subscription for using Terraform

    Terraform Service Principal and Secret (Azure AD – App Registrations)

    Let’s pre-create the application ID and client secret we will use to connect and leverage the Terraform code in VScode.

    • Connect to Azure Portal and go to Azure Active Directory
    • Click on App Registrations and select – New Registration
    • Give the App a Name – Terraform
    • You will get two important information created for later use within Terraform
      • Application ID
      • Tenant ID
    • Now let’s grant this App Terraform Permission. Click on Add a permission and select MS Graph and search for AppRoleAssignment.ReadWrite.All and select read/write permissions and Add Permissions
    • Select Grant admin consent for domain
    • We are using client secret so now lets enable that. Click on Certificates & Secrets – Client Secrets and select New client secret\
    • Give it a name (Terra-secret) and expiry date (12 months)
    • Copy the Secret Value

    Terraform – Authenticating via Service Principal & Client Secret

    In the above step, we created the Service Principal and Client secret. We will use it before running any Terraform code in PowerShell (Ensure to run as administrator). We will execute and store the credentials as environment variables. If we do this via the environment variable, we don’t have to store the below information within the providers.tf file. In a future blog post, there are better ways to keep the below details, and I hope to showcase them:

    # PowerShell
    $env:ARM_CLIENT_ID = "9e453b62-0000-0000-0000-00000006e1ac"
    $env:ARM_CLIENT_SECRET = "Z318Q~00000000000000000000000000000000_"
    $env:ARM_TENANT_ID = "a02e602c-0000-000-0000-0e0000008bba61"
    $env:ARM_SUBSCRIPTION_ID = "7b051460-00000-00000-00000-000000ecb1"
    • Azure Subscription ID – Azure Portal Subscription copy the ID.
    • Client ID – From the above step, you will have the details
    • Client Secret – From the above step, you will have the details
    • Tenant ID – While creating the Enterprise Apps in Azure AD, you will have the details

    Terraform Folder Structure

    The following is the folder structure for the Terraform code:

    Azure Virtual Desktop Personal Pool – Create a directory in which the below Terraform code will be published (providers.tf, main.tf, variables.tf and output.tf)

    +---Config-AVD-Personal-Desktop
    |   |   main.tf
    |   |   output.tf
    |   |   providers.tf
    |   |   variables.tf

    Note – I am not demonstrating how to install Terraform as it’s dead simple, and the information is available everywhere.

    Configure AVD – Personal Desktop Pool – Providers.tf

    Create a file named providers.tf and insert the following code. (We are using the AzureRM and AzureAD providers)

    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "3.49.0"
        }
        azuread = {
          source = "hashicorp/azuread"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }

    Configure AVD – Personal Desktop Pool – main.tf

    Create a file named main.tf and insert the following code. Let me explain what we are attempting to accomplish here: (Note I have # commented the lines with additional info)

    • Create a Resource Group
    • Create a Workspace
    • Create a Host Pool
    • Create a Desktop Application Group (DAG)
    • Associate Workspace and DAG
    • Assign Azure AD Group to the Desktop Application Group (DAG)
    • Assign Azure AD Group to the Resource Group for RBAC for the Session Host (Virtual Machine User Login)
    # Resource group name is output when execution plan is applied.
    resource "azurerm_resource_group" "rg" {
      name     = var.rg_name
      location = var.resource_group_location
      tags = var.tags
    }
    
    # Create AVD workspace
    resource "azurerm_virtual_desktop_workspace" "workspace" {
      name                = var.workspace
      resource_group_name = azurerm_resource_group.rg.name
      location            = azurerm_resource_group.rg.location
      friendly_name       = "${var.prefix} Workspace"
      description         = "${var.prefix} Workspace"
      tags = var.tags
    }
    
    # Create AVD host pool
    resource "azurerm_virtual_desktop_host_pool" "hostpool" {
      resource_group_name      = azurerm_resource_group.rg.name
      location                 = azurerm_resource_group.rg.location
      name                     = var.hostpool
      friendly_name            = var.hostpool
      validate_environment     = true #[true false]
      start_vm_on_connect      = true
      custom_rdp_properties    = "targetisaadjoined:i:1;drivestoredirect:s:*;audiomode:i:0;videoplaybackmode:i:1;redirectclipboard:i:1;redirectprinters:i:1;devicestoredirect:s:*;redirectcomports:i:1;redirectsmartcards:i:1;usbdevicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;enablerdsaadauth:i:1;"
      description              = "${var.prefix} HostPool"
      type                     = "Personal" #[Pooled or Personal]
      personal_desktop_assignment_type = "Automatic"
      load_balancer_type       =  "Persistent"
      tags = var.tags
    scheduled_agent_updates {
      enabled = true
      timezone = "AUS Eastern Standard Time"  # Update this value with your desired timezone
      schedule {
        day_of_week = "Saturday"
        hour_of_day = 1   #[1 here means 1:00 am]
      }
    }
    }
    
    resource "azurerm_virtual_desktop_host_pool_registration_info" "registrationinfo" {
      hostpool_id     = azurerm_virtual_desktop_host_pool.hostpool.id
      expiration_date = var.rfc3339
    }
    
    # Create AVD DAG
    resource "azurerm_virtual_desktop_application_group" "dag" {
      resource_group_name = azurerm_resource_group.rg.name
      host_pool_id        = azurerm_virtual_desktop_host_pool.hostpool.id
      location            = azurerm_resource_group.rg.location
      type                = "Desktop"
      name                = var.app_group_name
      friendly_name       = "Desktop AppGroup"
      description         = "${var.prefix} AVD application group"
      depends_on          = [azurerm_virtual_desktop_host_pool.hostpool, azurerm_virtual_desktop_workspace.workspace]
      tags = var.tags
    }
    
    # Associate Workspace and DAG
    resource "azurerm_virtual_desktop_workspace_application_group_association" "ws-dag" {
      application_group_id = azurerm_virtual_desktop_application_group.dag.id
      workspace_id         = azurerm_virtual_desktop_workspace.workspace.id
    }
    
    # Assign AAD Group to the Desktop Application Group (DAG)
    resource "azurerm_role_assignment" "AVDGroupDesktopAssignment" {
      scope                = azurerm_virtual_desktop_application_group.dag.id
      role_definition_name = "Desktop Virtualization User"
      principal_id         = data.azuread_group.AVDGroup.object_id
    }
    
    # Assign AAD Group to the Resource Group for RBAC for the Session Host
    resource "azurerm_role_assignment" "RBACAssignment" {
      scope                = azurerm_resource_group.rg.id
      role_definition_name = "Virtual Machine User Login"
      principal_id         = data.azuread_group.AVDGroup.object_id
    }

    Configure AVD – Personal Desktop Pool – variables.tf

    Create a file named variables.tf and insert the following code. I have followed a naming convention that includes the following:

    • AE – Australia East
    • Environment – PROD or DEV
    • Instance – 01
    • RG – Resource Group
    • WS – Workspace
    • DAG – Desktop Application Group
    variable "resource_group_location" {
      default     = "australiaeast"
      description = "Location of the resource group - Australia East"
    }
    
    variable "rg_name" {
      type        = string
      default     = "AE-DEV-AVD-01-RG"
      description = "Name of the Resource group in which to deploy service objects"
    }
    
    variable "workspace" {
      type        = string
      description = "Name of the Azure Virtual Desktop workspace"
      default     = "AE-DEV-AVD-01-WS"
    }
    
    variable "hostpool" {
      type        = string
      description = "Name of the Azure Virtual Desktop host pool"
      default     = "AE-DEV-AVD-01-PE-D-HP"
    }
    
    variable "app_group_name" {
      description = "Name of the Azure Virtual Desktop application group"
      type        = string
      default     = "AE-DEV-AVD-01-DAG"
    }
    
    variable "rfc3339" {
      type        = string
      default     = "2023-05-20T12:43:13Z" #Update this value with a future date
      description = "Registration token expiration"
    }
    
    variable "prefix" {
      type        = string
      default     = "AE-DEV-AVD-01-HP-"
      description = "Prefix of the name of the AVD machine(s)"
    }
    
    variable "tags" {
      type    = map(string)
      default = {
        Environment = "Dev"
        Department  = "IT"
        Location = "AustraliaEast"
        ServiceClass = "DEV"
        Workload = "Host Pool 01"
      }
    }
    
    data "azuread_client_config" "AzureAD" {}
    
    data "azuread_group" "AVDGroup" {
      display_name     = "Win365-Users"  
    }

    Configure AVD – Personal Desktop Pool – output.tf

    Create a file named output.tf and insert the following code. This will showcase in the console what is getting deployed as output.

    output "azure_virtual_desktop_compute_resource_group" {
      description = "Name of the Resource group in which to deploy session host"
      value       = azurerm_resource_group.rg.name
    }
    
    output "azure_virtual_desktop_host_pool" {
      description = "Name of the Azure Virtual Desktop host pool"
      value       = azurerm_virtual_desktop_host_pool.hostpool.name
    }
    
    output "azurerm_virtual_desktop_application_group" {
      description = "Name of the Azure Virtual Desktop DAG"
      value       = azurerm_virtual_desktop_application_group.dag.name
    }
    
    output "azurerm_virtual_desktop_workspace" {
      description = "Name of the Azure Virtual Desktop workspace"
      value       = azurerm_virtual_desktop_workspace.workspace.name
    }
    
    output "location" {
      description = "The Azure region"
      value       = azurerm_resource_group.rg.location
    }
    
    data "azuread_group" "aad_group" {
      display_name = "Win365-Users"
    }
    
    output "AVD_user_groupname" {
      description = "Azure Active Directory Group for AVD users"
      value       = data.azuread_group.aad_group.display_name
    }
    

    Intialize Terraform – AVD – Personal Desktop Pool

    Run the following command to initialize the Terraform deployment. This command downloads the Azure provider required to manage your Azure resources.

    terraform init -upgrade

    Create Terraform Execution Plan – AVD – Personal Desktop Pool

    Run the following command to create an execution plan.

    terraform plan -out mainavdpersonal.tfplan

    Apply Terraform Execution Plan – AVD – Personal Desktop Pool

    Run the following command to apply the execution plan to your cloud infrastructure.

    terraform apply mainavdpersonal.tfplan

    Validate the Output in Azure Portal

    Go to the Azure portal, Select Azure Virtual Desktop and Select Host pools, Application Group and Workspace created using Terraform.

    Clean-up the above resources (Optional)

    If you want to delete all the above resources then you can use the following commands to destroy. Run terraform plan and specify the destroy flag.

    terraform plan -destroy -out mainavdpersonal.destroy.tfplan

    Run terraform apply to apply the execution plan.(Destroy)

    terraform apply mainavdpersonal.destroy.tfplan

    The intention here is to get you quickly started with Terraform on Azure Virtual Desktop Solution:

    DescriptionLinks
    Setting up your computer to get started with Terrafor using PowershellInstall Terraform on Windows with Azure PowerShell
    AVD Configure Azure Virtual Desktophttps://learn.microsoft.com/en-us/azure/developer/terraform/configure-azure-virtual-desktop
    Terraform Learninghttps://youtube.com/playlist?list=PLLc2nQDXYMHowSZ4Lkq2jnZ0gsJL3ArAw

    I hope you will find this helpful information for getting started with Terraform to deploy the Azure Virtual Desktop – Personal Desktop Pool. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    PowerShell – Microsoft Security Vulnerabilities with CVE ID and details as a monthly report for Windows 10\11 or Windows Server OS

    27 Mar

    Microsoft Security Response Center (MSRC) publishes a monthly consolidated report for all the Critical, Important, Moderate and Low security vulnerabilities affecting Microsoft products. The information posted there helps organizations manage security risks and keep their systems protected.

    https://msrc.microsoft.com/update-guide

    The monthly release notes provide https://msrc.microsoft.com/update-guide/releaseNote/2023-Mar lot of additional information for all affected products.

    Requirements (What are we trying to solve?)

    Looking at the overall release notes for all the affected products (30+ products) and filtering the OS you are interested in can become overwhelming. E.g. You are only interested in products Operating Systems – Windows 11 22h2 or Windows Server 2016/2019/2022. Not saying other information is not essential, but imagine you are only responsible for the Operating Sytems. In such situations, you can use the below script to get a monthly report of CVE (Critical & Important) for a particular OS over to you in an email.

    Prerequsites

    You will need the MSRCSecurity PowerShell module. Run the command to install the module; further, you can import the module within the script.

    #Install Module
    Install-Module MSRCSecurityUpdates -Force
    
    #Import Module
    Import-Module MSRCSecurityUpdates

    Following are the Operating System (OS) products you can fetch the information against. If you want details for any other operating systems, copy that value and, in my script, paste it under the variable $ClientOS_Type. In my demonstration, we used “Windows 11 Version 22H2 for x64-based Systems”

    $ID = Get-MsrcCvrfDocument -ID $Month
    
    $ID.ProductTree.FullProductName
    
    ProductID Value                                                                                 
    --------- -----                                                                                 
    10049     Windows Server 2008 R2 for x64-based Systems Service Pack 1 (Server Core installation)
    10051     Windows Server 2008 R2 for x64-based Systems Service Pack 1                           
    10287     Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation)      
    10378     Windows Server 2012                                                                   
    10379     Windows Server 2012 (Server Core installation)                                        
    10407     Microsoft Outlook 2013 RT Service Pack 1                                              
    10483     Windows Server 2012 R2                                                                
    10543     Windows Server 2012 R2 (Server Core installation)                                     
    10601     Microsoft Office 2013 Service Pack 1 (32-bit editions)                                
    10602     Microsoft Office 2013 Service Pack 1 (64-bit editions)                                
    10603     Microsoft Office 2013 RT Service Pack 1                                               
    10611     Microsoft Office Web Apps Server 2013 Service Pack 1                                  
    10612     Microsoft SharePoint Foundation 2013 Service Pack 1                                   
    10654     Microsoft Excel 2013 Service Pack 1 (32-bit editions)                                 
    10655     Microsoft Excel 2013 Service Pack 1 (64-bit editions)                                 
    10656     Microsoft Excel 2013 RT Service Pack 1                                                
    10729     Windows 10 for 32-bit Systems                                                         
    10735     Windows 10 for x64-based Systems                                                      
    10739     Microsoft Excel 2016 (32-bit edition)                                                 
    10740     Microsoft Excel 2016 (64-bit edition)                                                 
    10753     Microsoft Office 2016 (32-bit edition)                                                
    10754     Microsoft Office 2016 (64-bit edition)                                                
    10765     Microsoft Outlook 2016 (32-bit edition)                                               
    10766     Microsoft Outlook 2016 (64-bit edition)                                               
    10810     Microsoft Outlook 2013 Service Pack 1 (32-bit editions)                               
    10811     Microsoft Outlook 2013 Service Pack 1 (64-bit editions)                               
    10816     Windows Server 2016                                                                   
    10852     Windows 10 Version 1607 for 32-bit Systems                                            
    10853     Windows 10 Version 1607 for x64-based Systems                                         
    10855     Windows Server 2016 (Server Core installation)                                        
    10950     Microsoft SharePoint Enterprise Server 2016                                           
    11099     Microsoft SharePoint Enterprise Server 2013 Service Pack 1                            
    11568     Windows 10 Version 1809 for 32-bit Systems                                            
    11569     Windows 10 Version 1809 for x64-based Systems                                         
    11570     Windows 10 Version 1809 for ARM64-based Systems                                       
    11571     Windows Server 2019                                                                   
    11572     Windows Server 2019 (Server Core installation)                                        
    11573     Microsoft Office 2019 for 32-bit editions                                             
    11574     Microsoft Office 2019 for 64-bit editions                                             
    11575     Microsoft Office 2019 for Mac                                                         
    11585     Microsoft SharePoint Server 2019                                                      
    11600     Microsoft Visual Studio 2017 version 15.9 (includes 15.0 - 15.8)                      
    11605     Microsoft Office Online Server                                                        
    11655     Microsoft Edge (Chromium-based)                                                       
    11664     Microsoft Dynamics 365 (on-premises) version 9.0                                      
    11726     OneDrive for Android                                                                  
    11762     Microsoft 365 Apps for Enterprise for 32-bit Systems                                  
    11763     Microsoft 365 Apps for Enterprise for 64-bit Systems                                  
    11800     Windows 10 Version 20H2 for x64-based Systems                                         
    11801     Windows 10 Version 20H2 for 32-bit Systems                                            
    11802     Windows 10 Version 20H2 for ARM64-based Systems                                       
    11902     Microsoft Malware Protection Engine                                                   
    11921     Microsoft Dynamics 365 (on-premises) version 9.1                                      
    11923     Windows Server 2022                                                                   
    11924     Windows Server 2022 (Server Core installation)                                        
    11926     Windows 11 version 21H2 for x64-based Systems                                         
    11927     Windows 11 version 21H2 for ARM64-based Systems                                       
    11929     Windows 10 Version 21H2 for 32-bit Systems                                            
    11930     Windows 10 Version 21H2 for ARM64-based Systems                                       
    11931     Windows 10 Version 21H2 for x64-based Systems                                         
    11935     Microsoft Visual Studio 2019 version 16.11 (includes 16.0 - 16.10)                    
    11951     Microsoft Office LTSC for Mac 2021                                                    
    11952     Microsoft Office LTSC 2021 for 64-bit editions                                        
    11953     Microsoft Office LTSC 2021 for 32-bit editions                                        
    11961     Microsoft SharePoint Server Subscription Edition                                      
    11969     Microsoft Visual Studio 2022 version 17.0                                             
    11987     Azure HDInsights                                                                      
    12051     Microsoft Visual Studio 2022 version 17.2                                             
    12085     Windows 11 Version 22H2 for ARM64-based Systems                                       
    12086     Windows 11 Version 22H2 for x64-based Systems                                         
    12097     Windows 10 Version 22H2 for x64-based Systems                                         
    12098     Windows 10 Version 22H2 for ARM64-based Systems                                       
    12099     Windows 10 Version 22H2 for 32-bit Systems                                            
    12129     Microsoft Visual Studio 2022 version 17.4                                             
    12137     CBL Mariner 1.0 x64                                                                   
    12138     CBL Mariner 1.0 ARM                                                                   
    12139     CBL Mariner 2.0 x64                                                                   
    12140     CBL Mariner 2.0 ARM                                                                   
    12142     Microsoft Edge (Chromium-based) Extended Stable                                       
    12155     Microsoft Office for Android                                                          
    12156     Microsoft Office for Universal                                                        
    12167     Microsoft Visual Studio 2022 version 17.5                                             
    12169     OneDrive for MacOS Installer                                                          
    12170     OneDrive for iOS                                                                      
    12171     Azure Service Fabric 9.1 for Windows                                                  
    12172     Azure Service Fabric 9.1 for Ubuntu                                                   
    12173     Snipping Tool                                                                         
    12174     Snip & Sketch for Windows 10                                                          
    9312      Windows Server 2008 for 32-bit Systems Service Pack 2                                 
    9318      Windows Server 2008 for x64-based Systems Service Pack 2                              
    9344      Windows Server 2008 for x64-based Systems Service Pack 2 (Server Core installation)  

    Variable Region

    Delcare all the variable within this section. Lets take a look at what we are declaring within the script:

    • The MSRC website releases the montly report in the following yyyy-MM format
    #Month Format for MSRC
    $Month = Get-Date -Format 'yyyy-MMM'
    • The operating system we want to focus on and leave the rest. If you are interested in any other OS, change the value from the above prerequisites, and it will give you Critical/Import vulnerabilities for that OS or product.
    # Enter the Operating System you specifically want to focus on
    $ClientOS_Type = "Windows 11 Version 22H2 for x64-based Systems"
    • Enter the details for sending the email (subject line, to and from etc.) for the report
    #Email Details
    $Recipients = "askaresh@askaresh.com", "someone@askaresh.com"
    $Sender = "cve-report@askaresh.com"
    $SMTP_Server = "smtp.askaresh.com"
    $Subject = 'CVE List for Windows 11 22H2 on '+$Month
    • HTML report formatting (CSS, Title of the report, Logo and Header) information
    $Css="<style>
    body {
        font-family: cursive;
        font-size: 14px;
        color: #000000;
        background: #FEFEFE;
    }
    #title{
        color:#000000;
        font-size: 30px;
        font-weight: bold;
        height: 50px;
        margin-left: 0px;
        padding-top: 10px;
    }
    
    #subtitle{
        font-size: 16px;
        margin-left:0px;
        padding-bottom: 10px;
    }
    
    table{
        width:100%;
        border-collapse:collapse;
    }
    table td, table th {
        border:1px solid #000000;
        padding:3px 7px 2px 7px;
    }
    table th {
        text-align:center;
        padding-top:5px;
        padding-bottom:4px;
        background-color:#000000;
        color:#fff;
    }
    table tr.alt td {
        color:#000;
        background-color:#EAF2D3;
    }
    tr.critical {
        color: white;
        background-color: red;
    }
    </style>"
    $Title = "<span style='font-weight:bold;font-size:24pt'>CVE List for Windows 11 22H2 on " + $Month + "</span>"
    $Logo = "<img src='C:\Scripts\WinSvr\askareshlogo.png' alt='Logo' height='100' width='100'>"
    $Header = "<div id='banner'>$Logo</div>`n" +
              "<div id='title'>$Title</div>`n" +
              "<div id='subtitle'>Report generated: $(Get-Date)</div>"

    Execution block

    Execution code block within this section. Lets take a look at what we are we executing within the script:

    • We are quering the MSRC using the powershell module and getting all the vulnerablity only for my OS – Windows 11 22H2
    • I am filtering only Critical/Important as I am not interested in Moderate and Low
    • Add additional tables for Base and Temporal scores
    • Adding the HTML formatting to highlight the Critical vulnerabilities in RED
    #Main Script Logic
    $ID = Get-MsrcCvrfDocument -ID $Month
    $ProductName = Get-MsrcCvrfAffectedSoftware -Vulnerability $id.Vulnerability -ProductTree $id.ProductTree | Where-Object { $_.Severity -in 'Critical', 'Important' -and $_.FullProductName -like $Server_Type }
    
    $Report = $ProductName | Select CVE, FullProductName, Severity, Impact, @{Name='KBArticle'; Expression={($_.KBArticle.ID | Select-Object -Unique) -join ', '}}, @{Name='BaseScore'; Expression={$_.CvssScoreSet.Base}}, @{Name='TemporalScore'; Expression={$_.CvssScoreSet.Temporal}}, @{Name='Vector'; Expression={$_.CvssScoreSet.Vector}} | ConvertTo-Html -PreContent $Css -PostContent "</table><br>" -As Table -Fragment | ForEach-Object {
        if($_ -match "<td.*?Critical.*?>") {
            $_ -replace "<tr>", "<tr class='critical'>"
        }
        else {
            $_
        }
    }

    Final Script

    Here I will paste the entire script block for seamless execution in a single run. Following is the link to my GitHub for this script – https://github.com/askaresh/avdwin365mem/blob/main/Win11VulnMSRCReport

    ### Install the module
    #Install-Module MSRCSecurityUpdates -Force
    
    ### Load the module
    Import-Module -Name MsrcSecurityUpdates
    
    #Email Details
    $Recipients = "askaresh@askaresh.com", "someone@askaresh.com"
    $Sender = "cve-report@askaresh.com"
    $SMTP_Server = "smtp.askaresh.com"
    $Subject = 'CVE List for Windows 11 22H2 on '+$Month
    
    #Month Format for MSRC
    $Month = Get-Date -Format 'yyyy-MMM'
    
    # Enter the Operating System you specifically want to focus on
    $ClientOS_Type = "Windows 11 Version 22H2 for x64-based Systems"
    
    # Environment Variables
    $Css="<style>
    body {
        font-family: cursive;
        font-size: 14px;
        color: #000000;
        background: #FEFEFE;
    }
    #title{
        color:#000000;
        font-size: 30px;
        font-weight: bold;
        height: 50px;
        margin-left: 0px;
        padding-top: 10px;
    }
    
    #subtitle{
        font-size: 16px;
        margin-left:0px;
        padding-bottom: 10px;
    }
    
    table{
        width:100%;
        border-collapse:collapse;
    }
    table td, table th {
        border:1px solid #000000;
        padding:3px 7px 2px 7px;
    }
    table th {
        text-align:center;
        padding-top:5px;
        padding-bottom:4px;
        background-color:#000000;
        color:#fff;
    }
    table tr.alt td {
        color:#000;
        background-color:#EAF2D3;
    }
    tr.critical {
        color: white;
        background-color: red;
    }
    </style>"
    $Title = "<span style='font-weight:bold;font-size:24pt'>CVE List for Windows 11 22H2 on " + $Month + "</span>"
    $Logo = "<img src='C:\Scripts\WinSvr\askareshlogo.png' alt='Logo' height='100' width='100'>"
    $Header = "<div id='banner'>$Logo</div>`n" +
              "<div id='title'>$Title</div>`n" +
              "<div id='subtitle'>Report generated: $(Get-Date)</div>"
    
    
    #Main Script Logic
    $ID = Get-MsrcCvrfDocument -ID $Month
    $ProductName = Get-MsrcCvrfAffectedSoftware -Vulnerability $id.Vulnerability -ProductTree $id.ProductTree | Where-Object { $_.Severity -in 'Critical', 'Important' -and ($_.FullProductName -match $ClientOS_Type) }
    
    
    $Report = $ProductName | Select CVE, FullProductName, Severity, Impact, @{Name='KBArticle'; Expression={($_.KBArticle.ID | Select-Object -Unique) -join ', '}}, @{Name='BaseScore'; Expression={$_.CvssScoreSet.Base}}, @{Name='TemporalScore'; Expression={$_.CvssScoreSet.Temporal}}, @{Name='Vector'; Expression={$_.CvssScoreSet.Vector}} | ConvertTo-Html -PreContent $Css -PostContent "</table><br>" -As Table -Fragment | ForEach-Object {
        if($_ -match "<td.*?Critical.*?>") {
            $_ -replace "<tr>", "<tr class='critical'>"
        }
        else {
            $_
        }
    }
    
    #Send Email
    Send-MailMessage -To $recipients -From $Sender -Subject $Subject -Body "$Header $Report" -SmtpServer $SMTP_Server -BodyAsHtml

    I recommend you create a schedule task for running this report on every 2nd Tuesday of the month.

    Report

    After you finish running the script, you will receive an email which should be like the following:

    Useful LinksCredits
    Security Update Guide – https://msrc.microsoft.com/update-guideMicrosoft
    Release Notes for Security Updates – https://msrc.microsoft.com/update-guide/releaseNote/2023-Mar (Simply replace the last three letter of the Month for previous reports)Microsoft
    Original Script and Credits of this work – How to Get Latest CVE from MSRC with PowerShell – AventisTechAventis Technologies

    I hope you will find this helpful information to gather Microsoft Security vulnerability reports for a specific operating system using PowerShell. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    PowerShell Enable Remote Help in Microsoft Intune

    7 Mar

    Remote Help in Microsoft Intune works by enabling IT administrators to remotely control a user’s mobile device, allowing them to view the device’s screen and interact with it in real-time. This enables administrators to quickly diagnose and fix issues on the device, without needing to be physically present with the user.

    To use Remote Help in Microsoft Intune, IT administrators first need to enable the feature in the Intune console. Once enabled, administrators can initiate a remote session with a user’s device by sending an invitation link to the user via email or text message. The user then clicks on the link to join the remote session, allowing the administrator to remotely control the device.

    In the blog post I will showcase how to enable this feature via PowerShell instead of the Microsoft Intune admin center portal.

    Pre-requsites

    • An active Microsoft Intune subscription.
    • An Azure AD (Active Directory) subscription with administrative access.
    • The Azure AD application registration credentials, including client ID and secret.
    • Permissions to access and manage Microsoft Intune and Microsoft Graph API resources.
    • PowerShell and AzureAD PowerShell module installed on the local machine to run PowerShell scripts.
    • A valid Azure AD authentication token to authenticate and authorize Microsoft Graph API requests.

    Create the Client Secret for MS Graph

    Let’s pre-create the application ID and client secret we will use to connect and leverage the Microsoft Graph APIs via Powershell

    • Connect to Azure Portal and go to Azure Active Directory
    • Click on App Registrations and select – New Registration
    • Give the App a Name – MSGraph-DeviceMgmt-Secret
    • You will get two important information created for later use within Powershell
      • Application ID
      • Tenant ID
    • Now let’s grant this App MSGraph Permission. Click on Add a permission and select MS Graph and search for Device – DeviceManagementConfiguration and select read-write permissions and Add Permissions
    • Select Grant admin consent for domain

    Note that RemoteSettings, aka Remote Help, falls under Device Management Configurations. We will use that for the permissions (read-write)

    • We are using client secret so now lets enable that. Click on Certificates & Secrets – Client Secrets and select New client secret\
    • Give it a name (Deviceconfig_secret) and expiry date (12 months)
    • Copy the Secret Value

    Variable Region

    Delcare all the variable within this section. Lets take a look at what we are declaring within the script:

    • GraphEndpoint and resource URL if you notice we are using the remoteAssistanceSettings
    $graphEndpoint = "https://graph.microsoft.com"
    $resourceUrl = "$graphEndpoint/beta/deviceManagement/remoteAssistanceSettings"
    • From the above section we have the values for Client ID, Secret and tenant id which we will paste in here.
    $clientId = "XXXXXXXX-6f08-XXXXX-a6ff-XXXXXXXXXXXXX"
    $clientSecret = "Q-D8Q~XXXXXXXXXXXXXXXXXXXXXXXXXXX"
    $tenantId = "XXXXXXXXXX-d8f4-4c55-XXXXX-XXXXXXXXXXX"
    $authority = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
    $scope = "https://graph.microsoft.com/.default"

    Execution block

    Execution code block within this section. Lets take a look at what we are we executing within the script:

    • The body payload to enable disable the Remote Help Assistance settings
      • RemoteAssistanceState – Enabled/Disabled
      • AllowSession to Unenrolled Devices – $true or $false
      • Block chat – $true or $false
    $payload = @{
        "@odata.type" = "#microsoft.graph.remoteAssistanceSettings"
        "remoteAssistanceState" = "disabled"
        "allowSessionsToUnenrolledDevices" = $false
        "blockChat" = $false
    } | ConvertTo-Json

    Final Script

    Here I will paste the entire script block for seamless execution in a single run. Following is the link to my GitHub for this script – https://github.com/askaresh/avdwin365mem/blob/main/enableremotehelpmem

    # Define the Graph API endpoint and resource URL
    $graphEndpoint = "https://graph.microsoft.com"
    $resourceUrl = "$graphEndpoint/beta/deviceManagement/remoteAssistanceSettings"
    
    # Define the authentication parameters
    $clientId = "XXXXXXXX-6f08-XXXXX-a6ff-XXXXXXXXXXXXX"
    $clientSecret = "Q-D8Q~XXXXXXXXXXXXXXXXXXXXXXXXXXX"
    $tenantId = "XXXXXXXXXX-d8f4-4c55-XXXXX-XXXXXXXXXXX"
    $authority = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
    $scope = "https://graph.microsoft.com/.default"
    
    # Authenticate to the Graph API and obtain an access token
    $tokenResponse = Invoke-RestMethod -Method Post -Uri $authority `
        -Body @{
            client_id = $clientId
            client_secret = $clientSecret
            scope = $scope
            grant_type = "client_credentials"
        } `
        -Headers @{
            "Content-Type" = "application/x-www-form-urlencoded"
        }
    
    $accessToken = $tokenResponse.access_token
    
    
    # Define the payload for the PATCH request
    $payload = @{
        "@odata.type" = "#microsoft.graph.remoteAssistanceSettings"
        "remoteAssistanceState" = "enabled"
        "allowSessionsToUnenrolledDevices" = $false
        "blockChat" = $false
    } | ConvertTo-Json
    
    
    # Send a PATCH request to the remoteAssistanceSettings resource with the updated payload
    $headers = @{
        "Authorization" = "Bearer $accessToken"
        "Content-Type" = "application/json"
        "Content-length" = $payload.Length
    }
    
    Invoke-RestMethod -Method Patch -Uri $resourceUrl -Headers $headers -Body $payload

    Validations

    After running the powershell script now check the portat it will be enabled

    Overall, Remote Help in Microsoft Intune is a powerful tool for IT administrators, enabling them to quickly diagnose and fix issues on mobile devices, improving productivity and reducing downtime. If you’re using Microsoft Intune, be sure to take advantage of this powerful feature to improve your device management capabilities.

    Useful LinksCredits
    Update remoteAssistanceSettings – https://learn.microsoft.com/en-us/graph/api/intune-remoteassistance-remoteassistancesettings-update?view=graph-rest-betaMicrosof
    Enabling Remote Help and Supporting Users with Intune – Microsoft Community HubMicrosoft

    I hope you will find this helpful information for enabling Remote Help using PowerShell. Please let me know if I have missed any steps or details, and I will be happy to update the post.

    Thanks,
    Aresh Sarkari

    Consolidated Scripts – All configurational task via PowerShell for Windows 365 Cloud PC under Microsoft Intune Portal (MEM)

    18 Jan

    I have written various individual blog posts on PowerShell creation of all configurational task for Windows 365 Cloud PC under Microsoft Endpoint Portal (MEM).

    Based on public demand, I want to create a consolidated post for all the scripts and configuration items that can get you started with Windows 365 Cloud PC using PowerShell: (Of course all the below features can also be configured using the UI, however below is the guidance strictly using PowerShell)

    PowerShell links to my blog post

    Following are the links to my blog post for each and individual task:

    PowerShell – Create Windows 365 Cloud PC Provisioning Policy https://askaresh.com/2022/10/11/powershell-create-windows-365-cloud-pc-provisioning-policy/

    PowerShell – Assign a AAD group to the Windows 365 Cloud PC Provisioning Policy
    https://askaresh.com/2022/10/12/powershell-assign-a-aad-group-to-the-windows-365-cloud-pc-provisioning-policy/

    PowerShell – Unassign/Delete the Windows 365 Cloud PC Provisioning Policy
    https://askaresh.com/2022/10/14/powershell-unassign-delete-the-windows-365-cloud-pc-provisioning-policy/

    PowerShell – Create a custom Windows 11 Enterprise (22H2) + Microsoft 365 Apps golden image for Windows 365 Cloud PC using Marketplace Image
    https://askaresh.com/2022/12/01/powershell-create-a-custom-windows-11-enterprise-22h2-microsoft-365-apps-golden-image-for-windows-365-cloud-pc-using-marketplace-image/

    PowerShell – Create Azure Network Connection (ANC) for Windows 365 Cloud PC
    https://askaresh.com/2023/01/16/powershell-create-azure-network-connection-anc-for-windows-365-cloud-pc/

    PowerShell – Create and Assign Windows 365 Cloud PC – User Settings
    https://askaresh.com/2022/11/08/powershell-create-and-assign-windows-365-cloud-pc-user-settings/

    PowerShell – Report – Get Cloud PC Windows 365 with low utilization
    https://askaresh.com/2022/11/24/powershell-report-get-cloud-pc-windows-365-with-low-utilization/

    I promise you once you have done the hard work, you can get up and running in a few hours using all the above PowerShell scripts with Windows 365 Cloud PC.

    Here is the repo with all the scripts and more – askaresh/avdwin365mem (github.com). A big thanks to Andrew Taylor for collabrating and updating the Provisioning policy script with the SSO details that was release in late Nov 2022.

    I hope you will find this helpful information for all things PowerShell w.r.t Windows 365 Cloud PC. I will update the post if I publish or update more information.

    Thanks,
    Aresh Sarkari