During Workplace Ninja US, I did an in-person session on this topic, and now I am releasing for all. I’ve built Azure Virtual Desktop environments in a few different ways over the years — quick POCs, “just one host pool” builds, and full-blown enterprise deployments. The problem is the same every time: it starts simple and then you end up stitching together monitoring, scaling plans, RBAC, dashboards, and cost alerts… usually across multiple Terraform folders.
So I pulled everything into one modular Terraform repo that can deploy four AVD patterns (pooled/personal + desktop/RemoteApp), with optional enterprise-grade monitoring, dashboards, cost management, and scaling.
It also follows Microsoft Cloud Adoption Framework (CAF) naming patterns for the main AVD + network resources (host pool, app group, workspace, vnet/subnet/nsg, etc.).
Why this repo is “enterprise ready”
A few highlights that make this more than a basic host pool deployment:
Scaling plans for pooled deployments (desktop + RemoteApp) and environment-specific schedules
Monitoring & observability using Log Analytics + diagnostics
Custom dashboards for operational visibility
Cost management with budgets + alerts
CAF-friendly naming so your portal stays clean and consistent
Supported deployment types (quick view)
The configuration automatically adjusts host pool/app group settings depending on deployment_type (pooled vs personal, desktop vs RemoteApp).
The deployment guide uses a Service Principal stored in a local .env file (ignored by git), and a set-auth.ps1 script that loads the values into ARM_* environment variables for Terraform.
High level flow: .env → set-auth.ps1 → ARM_* env vars → Terraform
Create your .env from .env.example, then run:
.\set-auth.ps1
Scaling plans note: your Service Principal needs the Desktop Virtualization Power On Off Contributor role at subscription scope for scaling to work properly.
Terraform init / plan / apply
terraform init terraform plan -var-file=dev-pooled-desktop.tfvars terraform apply -var-file=dev-pooled-desktop.tfvars
Monitoring, dashboards, cost alerts (optional but worth it)
If you use one of the monitoring/scaling-enabled tfvars options, the repo can deploy:
Log Analytics + diagnostics
Dashboards for ops visibility
Budgets/alerts for cost tracking
A quick note on dependency ordering (why it matters)
The repo is intentional about resource ordering — especially for scaling plans — to avoid portal oddities and ensure the host pool association is reliable. The dependency flow is documented and includes a separate scaling plan host pool association resource.
Resoure Group (RG)
Application Groups (AG)
Wrap up
If you want a repeatable way to deploy AVD that supports pooled + personal and desktop + RemoteApp, while also giving you the option to turn on monitoring, dashboards, budgets/alerts, and scaling, this repo is designed for exactly that.
This is part one of a two-part series on Windows 365 Cloud Apps. In this post, we’ll walk through what Cloud Apps are and how to create the provisioning policy with PowerShell. In part two, we’ll publish the apps themselves. I’ll also include the PowerShell script that uses Azure/Graph REST APIs.
What is Windows 365 Cloud Apps?
Windows 365 Cloud Apps let you give users access to specific apps streamed from a Cloud PC—without handing out a full desktop to everyone. Under the hood, Cloud Apps run on Windows 365 Frontline Cloud PCs in Shared mode. That licensing model is designed for shift or part-time staff: many users can be assigned, but only one active session per license at a time.
Think of it as “just-the-apps” VDI: Outlook, Word, your line-of-business app—delivered from the cloud—with the management simplicity of Windows 365 and Intune.
Why customers care: You streamline app delivery, lower overhead, and modernize VDI without building and babysitting a big remote desktop estate.
Cloud Apps vs AVD Published Apps vs “Traditional” VDI Published Apps
Topic
Windows 365 Cloud Apps
Azure Virtual Desktop Published Apps
Traditional VDI Published Apps
What users see
Individual apps streamed from a Cloud PC; no full desktop
Individual apps from session hosts in Azure Virtual Desktop
Individual apps from on-prem or hosted RDS/Horizon/Citrix farms
Infra you manage
Cloud PC lifecycle via Intune; Microsoft operates the fabric
You design & operate host pools, scaling, FSLogix, images
You run the farm: brokers, gateways, hypervisors, storage
Licensing / sessions
Frontline: many users per license, 1 active session per license
Per-user/per-device or CALs + Azure consumption; multiple sessions per host
Per-user/device + on-prem infra costs
Admin plane
Intune + Windows 365
Azure Portal + ARM + Host pool automation
Vendor consoles + on-prem change management
App packaging
Start-menu discovered apps from the image (MSIX/Appx discovery expanding)
Image: Set $ImageType (e.g., "gallery") and $ImageId for your chosen image.
Region: $RegionName (e.g., australiaeast or "automatic").
Assignment:
$GroupId: Entra group whose members should see the Cloud Apps.
$ServicePlanId: the Frontline size (e.g., FL 2vCPU/8GB/128GB in the example).
$AllotmentCount: how many concurrent sessions you want available for this policy.
$AllotmentDisplayName: a friendly label that shows up with the assignment.
Verification/Polling: The script dumps the policy with assignments and can optionally poll for provisioned Cloud PCs tied to the policy.
Get-or-Create a Cloud Apps provisioning policy (userExperienceType = cloudApp, provisioningType = sharedByEntraGroup, Azure AD Join in a specified region).
Assigns the policy to an Entra group with service plan, capacity (allotment), and a friendly label
App discovery: Ensure the app has a Start menu shortcut on the image. That’s how Cloud Apps gets its list.
Security baselines: If your tenant enforces restrictions on PowerShell in the image at discovery time, discovery can fail.
MSIX/Appx: Discovery is expanding—classic installers show up first; some Appx/MSIX apps (e.g., newer Teams) may not appear yet.
Concurrency math: Active sessions for the policy are capped by assigned Frontline license count on that policy.
Schema drift: These are beta endpoints. If you hit a property/enum change, the script’s warnings will surface the response body—update the field names accordingly.
What’s next (Part 2)
We’ll move to All Cloud Apps to publish the discovered apps, tweak display name/description/command line/icon index, confirm they appear in Windows App, and cover unpublish/reset workflows—with your screenshots.
I hope you find this helpful information for creating a Cloud App using PowerShell. If I have missed any steps or details, I will be happy to update the post.
In this blog post, we’ll embark on an exciting journey of building an Image Captioning API using FastAPI and Hugging Face Transformers. Image captioning is a fascinating task that involves generating textual descriptions for given images. By leveraging the power of deep learning and natural language processing, we can create a system that automatically understands the content of an image and generates human-like captions. The example below, I input a image with a rider on a bike in a garage and the caption provides the exact details of the image.
The goal of this project is to develop a RESTful API that accepts an image as input and returns a generated caption describing the image. We’ll be using FastAPI, a modern and fast web framework for building APIs, along with Hugging Face Transformers, a popular library for natural language processing tasks.
The key components of our project include:
FastAPI: A web framework for building efficient and scalable APIs in Python.
Hugging Face Transformers: A library that provides state-of-the-art pre-trained models for various NLP tasks, including image captioning.
Docker: A containerization platform that allows us to package our application and its dependencies into a portable and reproducible environment.
Implementation Details
To build our Image Captioning API, we started by setting up a FastAPI project and defining the necessary endpoints. The main endpoint accepts an image file and an optional text input for conditional image captioning.
We utilized the pre-trained BLIP (Bootstrapping Language-Image Pre-training) model from Hugging Face Transformers for image captioning. BLIP is a powerful model that has been trained on a large dataset of image-caption pairs and achieves impressive results in generating accurate and coherent captions.
To ensure a smooth development experience, and ability for it to run on AnyCloud I containerized our application using Docker. This allowed us to encapsulate all the dependencies, including Python libraries and the pre-trained model, into a portable and reproducible environment.
This file contains the configuration settings for the application.
It defines a Settings class using the pydantic_settings library to store and manage application-specific settings.
The blip_model_name setting specifies the name of the BLIP model to be used for image captioning.
app/main.py:
This is the main entry point of the FastAPI application.
It sets up the FastAPI app, loads the BLIP model, and configures logging.
It defines the API endpoints, including the root path (“/”) and the image captioning endpoint (“/caption”).
The “/caption” endpoint accepts an image file and an optional text input, processes the image, generates a caption using the BLIP model, and returns the generated caption.
app/model.py:
This file contains the functions related to loading and using the BLIP model for image captioning.
The load_model function loads the pre-trained BLIP model and processor based on the specified model name.
The generate_caption function takes an image and optional text input, preprocesses the inputs, and generates a caption using the loaded BLIP model.
app/utils.py:
This file contains utility functions used in the project.
The load_image_from_file function reads an image file and converts it to the appropriate format (RGB) using the PIL library.
.dockerignore:
This file specifies the files and directories that should be excluded when building the Docker image.
It helps to reduce the size of the Docker image by excluding unnecessary files and directories.
.gitignore:
This file specifies the files and directories that should be ignored by Git version control.
It helps to keep the repository clean by excluding files that are not necessary to track, such as generated files, cache files, and environment-specific files.
compose.yaml:
This file contains the configuration for Docker Compose, which is used to define and run multi-container Docker applications.
It defines the services, including the FastAPI server, and specifies the build context, ports, and any necessary dependencies.
Dockerfile:
This file contains the instructions for building the Docker image for the FastAPI application.
It specifies the base image, sets up the working directory, installs dependencies, copies the application code, and defines the entry point for running the application.
logging.conf:
This file contains the configuration for the Python logging system.
It defines the loggers, handlers, formatters, and their respective settings.
It specifies the log levels, log file paths, and log message formats.
README.Docker.md:
This file provides documentation and instructions specific to running the application using Docker.
It may include information on how to build the Docker image, run the container, and any other Docker-related details.
requirements.txt:
This file lists the Python dependencies required by the application.
It includes the necessary libraries and their versions, such as FastAPI, Hugging Face Transformers, PIL, and others.
It is used by pip to install the required packages when building the Docker image or setting up the development environment.
Lessons Learned and Debugging
Throughout the development process, I encountered several challenges and learned valuable lessons:
Dependency Management: Managing dependencies can be tricky, especially when working with large pre-trained models. We learned the importance of properly specifying dependencies in our requirements file and using Docker to ensure consistent environments across different systems.
Debugging Permission Issues: We encountered permission-related issues when running our application inside a Docker container. Through debugging, we learned the significance of properly setting file and directory permissions and running the container as a non-root user to enhance security.
Logging Configuration: Proper logging is crucial for understanding the behavior of our application and troubleshooting issues. I learned how to configure logging using a configuration file and ensure that log files are written to directories with appropriate permissions.
Testing and Error Handling: Comprehensive testing and error handling are essential for building a robust API. We implemented thorough error handling to provide meaningful error messages to API users and conducted extensive testing to ensure the reliability of our image captioning functionality.
Validation of the API
After the container is up and running go to http://localhost:8004/docs and select Post method and pick try out. Upload any image of your choice and enter the text (optional) and further click Execute. You will have the caption below as the output.
Conclusion
Building an Image Captioning API with FastAPI and Hugging Face Transformers has been an incredible learning experience. By leveraging the power of pre-trained models and containerization, I created a scalable and efficient solution for generating image captions automatically.
Through this project, I gained valuable insights into dependency management, debugging permission issues, logging configuration, and the importance of testing and error handling. These lessons will undoubtedly be applicable to future projects and contribute to our growth as developers.
I hope that this blog post has provided you with a comprehensive overview of our Image Captioning API project and inspired you to explore the fascinating world of image captioning and natural language processing. Feel free to reach out with any questions or suggestions, and happy captioning!
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.
Select Devices > Scripts > Add > Windows 10 and later.
In Basics, enter the following properties, and select Next:
Name: AddDNSClientServers
Description: Additional DNS Server 3 & 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.
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.
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:
Windows PowerShell version 5.0 and above
Active Directory Module for Windows PowerShell
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.
Execute the script from a member server that is part of the domain and has the necessary permissions.
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)
#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.
In this blog post, we will explore how to extract highlighted data from a PDF using Python. Before we go ahead lets understand what is the usecase, you have the (CIS_Microsoft_Windows_Server_2022_Benchmark_v2.0.0.pdf) which is 1065 pages and you are reviewing the the policy against your enivornment and highlighting the pdf with specific color codes. For example, I use four colors for the following purposes:
Red Color – Missing Policies
Yellow Color – All existing policies
Pink – Policies not applicable
Green – Upgraded policies
Example of the highlighted text:
You dont have to use the same color codes like I have done but you get the idea. Once you have done the heavy lifting of reviewing the document and happy with the analysis. The next steps is you want to extract the highlighted data into a csv format so that the teams can review and action them.
Pre-requsites
We will use the PyMuPDF & Pandas library to parse the PDF file and extract the highlighted text. Additionally, we will apply this technique to the CIS Windows Server 2022 Benchmark PDF as an example.
Before we begin, make sure you have installed the necessary dependencies. You can install PyMuPDF and Pandas using pip:
pip install fitz
pip install pandas
First, I created a small script to go within the document pdf and detect the colors. I had to do this although, to my eyes, the colors are RED, Yellow, etc., the RGD color codes seem slightly different.
import fitz # PyMuPDF
# Open the PDF
doc = fitz.open('CIS_Microsoft_Windows_Server_2022_Benchmark_v2.0.0.pdf')
# Set to store unique colors
unique_colors = set()
# Loop through every page
for i in range(len(doc)):
page = doc[i]
# Get the annotations (highlights are a type of annotation)
annotations = page.annots()
for annotation in annotations:
if annotation.type[1] == 'Highlight':
# Get the color of the highlight
color = annotation.colors['stroke'] # Returns a RGB tuple
unique_colors.add(color)
# Print all unique colors
for color in unique_colors:
print(color)
You will get the following output post executing the script make sure you put the exact name of the PDF file and within the IDE of your choice cd to the directory where the above (CheckColor.py) resides.
Now we have the color codes it’s time to go ahead and extract the highlighted text. We iterate through each page of the PDF and check for any highlighted annotations. If an annotation is found, we extract the content and accumulate it in the extracted_text variable, followed by export to the csv.
Main Code
Replace "CIS_Microsoft_Windows_Server_2022_Benchmark_v2.0.0.pdf" with the actual path to your PDF file.
import fitz # PyMuPDF
import pandas as pd
# Open the PDF
doc = fitz.open('CIS_Microsoft_Windows_Server_2022_Benchmark_v2.0.0.pdf')
# Define the RGB values for your colors
PINK = (0.9686269760131836, 0.6000000238418579, 0.8196079730987549)
YELLOW = (1.0, 0.9411770105361938, 0.4000000059604645)
GREEN = (0.49019598960876465, 0.9411770105361938, 0.4000000059604645)
RED = (0.9215689897537231, 0.2862749993801117, 0.2862749993801117)
color_definitions = {"Pink": PINK, "Yellow": YELLOW, "Green": GREEN, "Red": RED}
# Create separate lists for each color
data_by_color = {"Pink": [], "Yellow": [], "Green": [], "Red": []}
# Loop through every page
for i in range(len(doc)):
page = doc[i]
annotations = page.annots()
for annotation in annotations:
if annotation.type[1] == 'Highlight':
color = annotation.colors['stroke'] # Returns a RGB tuple
if color in color_definitions.values():
# Get the detailed structure of the page
structure = page.get_text("dict")
# Extract highlighted text line by line
content = []
for block in structure["blocks"]:
for line in block["lines"]:
for span in line["spans"]:
r = fitz.Rect(span["bbox"])
if r.intersects(annotation.rect):
content.append(span["text"])
content = " ".join(content)
# Append the content to the appropriate color list
for color_name, color_rgb in color_definitions.items():
if color == color_rgb:
data_by_color[color_name].append(content)
# Convert each list to a DataFrame and write to a separate .csv file
for color_name, data in data_by_color.items():
if data:
df = pd.DataFrame(data, columns=["Text"])
df.to_csv(f'highlighted_text_{color_name.lower()}.csv', index=False)
After running the script, the extracted highlighted text will be saved under multiple csv files like the below screenshot:
You can now extract the highlighted text from the PDF using the above technique. Feel free to modify and adapt this code to suit your specific requirements. Extracting highlighted data from PDFs can be a powerful data analysis and research technique.
I hope you will find this helpful information for extracting data out from any PDF files. Please let me know if I have missed any steps or details, and I will be happy to update the post.
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.
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.
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.
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.
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.
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.
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
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.
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:
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.
GitHub Link
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.
Do you want to deploy an Azure Virtual Desktop – Host pools quickly and want a starting point for a golden image? Look no further in this blog post. I will show you how to create a golden image using PowerShell in no more than 10 min.
I will break down the code block into smaller chunks first to explain the critical bits, and in the end, I will post the entire code block that can be run all at once. In this way, explaining block by block becomes easier than pasting one single block.
Pre-requisites
Following are the pre-requisites before you begin
PowerShell 5.1 and above
Azure Subscription
Permissions within the Auzre Subscription for Azure Compute
Assumption
You have an existing Resource Group (RG)
You have an existing Azure Virtual Network (VNET)
You have an existing workload subnet within the VNET
Identify the VM Size you will be using for the golden image
We are going to use the Windows 11 22H2 Mutli-session – win11-22h2-avd within this script
Variable Region
Delcare all the variable within this section. Lets take a look at what we are declaring within the script:
Existing Resource Group within the Azure Subscription (AZ104-RG)
A location where you are deploying this virtual machine (Australia East)
Name of the golden image virtual machine (VM03)
NIC Interface name for the virtual machine (VM03-nic)
RG of the VNET (In my case they are same AZ104-RG, they can be seperate too and hence a independent variable)
Name of the existing subnet within the vNET (AZ104-VDI-Workload-L1)
Name of the existing VNET (AZ104-RG-vnet)
Mapping of the exisitng VNET
Mapping of the existing subnet
T-shirt size of the golden image we are deploying (Standard_D2s_v3)
Gallery details of the image
Published – MicrosoftWindowsDesktop
Offer – windows-11
SKU – win11-22h2-avd
version – Offcourse latest
Get credentials – A local admin account is created on the golden image (A input box to capture the uisername and password)
# Existing Resource Group to deploy the VM
$rgName = "AZ104-RG"
# Geo Location to deploy the VM
$location = "Australia East"
# Image template name
$vmName = "VM03"
# Networking Interfance Name for the VM
$nicName = "$vmName-nic"
# Resource Group for VNET
$vnetrgName = "AZ104-RG"
# Existing Subnet Name
$Existsubnetname = "AZ104-VDI-Workload-L1"
# Existing VNET Name
$Existvnetname = "AZ104-RG-vnet"
# Existing VNET where we are deploying this Virtual Machine
$vnet = Get-AzVirtualNetwork -Name $Existvnetname -ResourceGroupName $vnetrgName
# Existing Subnet within the VNET for the this virtual machine
$subnet = Get-AzVirtualNetworkSubnetConfig -Name $Existsubnetname -VirtualNetwork $vnet
# T-shirt size of the VM
$vmSize = "Standard_D2s_v3"
# Gallery Publisher of the Image - Microsoft
$publisher = "MicrosoftWindowsDesktop"
# Version of Windows 10/11
$offer = "windows-11"
# The SKY ending with avd are the multi-session
$sku = "win11-22h2-avd"
# Choosing the latest version
$version = "latest"
# Setting up the Local Admin on the VM
$cred = Get-Credential `
-Message "Enter a username and password for the virtual machine."
Execution block
Execution code block within this section. Lets take a look at what we are we executing within the script:
First its creating the network interface for the virtual machine (VM03)
Next, under the variable $VM all virtual machine configurations
Tshirt size of the virtual machine
Credentials for the local admin (username/password)
The network interface assignment along with the delete option (Note delete option is essential or/else during deletion of VM it will not delete the network interface)
The gallery image, sku, offer from the Microsoft Market Place gallery
The os disk assignment along with the delete option (Note delete option is essential or/else during deletion of VM it will not delete the disk)
The configuration around “Trusted Platform” and enabling of TPM and Secure Boot
The final command to create the virtual machine with all the above configurations
# Create New network interface for the virtual machine
$NIC = New-AzNetworkInterface -Name $nicName -ResourceGroupName $vnetrgName -Location $location -Subnet $subnet
# Creation of the new virtual machine with delete option for Disk/NIC together
$vm = New-AzVMConfig -VMName $vmName -VMSize $vmSize
$vm = Set-AzVMOperatingSystem `
-VM $vm -Windows `
-ComputerName $vmName `
-Credential $cred `
-ProvisionVMAgent `
-EnableAutoUpdate
# Delete option for NIC
$vm = Add-AzVMNetworkInterface -VM $vm `
-Id $NIC.Id `
-DeleteOption "Delete"
$vm = Set-AzVMSourceImage -VM $vm `
-PublisherName $publisher `
-Offer $offer `
-Skus $sku `
-Version $version
# Delete option for Disk
$vm = Set-AzVMOSDisk -VM $vm `
-StorageAccountType "StandardSSD_LRS" `
-CreateOption "FromImage" `
-DeleteOption "Delete"
# The sauce around enabling the Trusted Platform
$vm = Set-AzVmSecurityProfile -VM $vm `
-SecurityType "TrustedLaunch"
# The sauce around enabling TPM and Secure Boot
$vm = Set-AzVmUefi -VM $vm `
-EnableVtpm $true `
-EnableSecureBoot $true
New-AzVM -ResourceGroupName $rgName -Location $location -VM $vm
# Step 1: Import module
#Import-Module Az.Accounts
# Connect to the Azure Subcription
#Connect-AzAccount
# Get existing context
$currentAzContext = Get-AzContext
# Your subscription. This command gets your current subscription
$subscriptionID=$currentAzContext.Subscription.Id
# Command to get the Multi-session Image in Gallery
# Details from this command will help in filling out variables below on Gallery Image
# Get-AzVMImageSku -Location australiaeast -PublisherName MicrosoftWindowsDesktop -Offer windows-11
# Existing Resource Group to deploy the VM
$rgName = "AZ104-RG"
# Geo Location to deploy the VM
$location = "Australia East"
# Image template name
$vmName = "VM03"
# Networking Interfance Name for the VM
$nicName = "$vmName-nic"
# Resource Group for VNET
$vnetrgName = "AZ104-RG"
# Existing Subnet Name
$Existsubnetname = "AZ104-VDI-Workload-L1"
# Existing VNET Name
$Existvnetname = "AZ104-RG-vnet"
# Existing VNET where we are deploying this Virtual Machine
$vnet = Get-AzVirtualNetwork -Name $Existvnetname -ResourceGroupName $vnetrgName
# Existing Subnet within the VNET for the this virtual machine
$subnet = Get-AzVirtualNetworkSubnetConfig -Name $Existsubnetname -VirtualNetwork $vnet
# T-shirt size of the VM
$vmSize = "Standard_D2s_v3"
# Gallery Publisher of the Image - Microsoft
$publisher = "MicrosoftWindowsDesktop"
# Version of Windows 10/11
$offer = "windows-11"
# The SKY ending with avd are the multi-session
$sku = "win11-22h2-avd"
# Choosing the latest version
$version = "latest"
# Setting up the Local Admin on the VM
$cred = Get-Credential `
-Message "Enter a username and password for the virtual machine."
# Create New network interface for the virtual machine
$NIC = New-AzNetworkInterface -Name $nicName -ResourceGroupName $vnetrgName -Location $location -Subnet $subnet
# Creation of the new virtual machine with delete option for Disk/NIC together
$vm = New-AzVMConfig -VMName $vmName -VMSize $vmSize
$vm = Set-AzVMOperatingSystem `
-VM $vm -Windows `
-ComputerName $vmName `
-Credential $cred `
-ProvisionVMAgent `
-EnableAutoUpdate
# Delete option for NIC
$vm = Add-AzVMNetworkInterface -VM $vm `
-Id $NIC.Id `
-DeleteOption "Delete"
$vm = Set-AzVMSourceImage -VM $vm `
-PublisherName $publisher `
-Offer $offer `
-Skus $sku `
-Version $version
# Delete option for Disk
$vm = Set-AzVMOSDisk -VM $vm `
-StorageAccountType "StandardSSD_LRS" `
-CreateOption "FromImage" `
-DeleteOption "Delete"
# The sauce around enabling the Trusted Platform
$vm = Set-AzVmSecurityProfile -VM $vm `
-SecurityType "TrustedLaunch"
# The sauce around enabling TPM and Secure Boot
$vm = Set-AzVmUefi -VM $vm `
-EnableVtpm $true `
-EnableSecureBoot $true
New-AzVM -ResourceGroupName $rgName -Location $location -VM $vm
Note – It will give you a pop-up box for entering the username and password for the local account, and in under 10 mins you will see your virtual machine within the Azure portal
Next Steps on Golden Image
Now that the virtual machine is ready following are the next steps involved:
Using Azure Bastion console and installing all the required applications
Generalize and sysprep and shutdown the image
Capture the image to the Azure Compute Galleries
Deploy within the Azure Virtual Desktop
I hope you will find this helpful information for deploying a golden image within Azure – Virtual Machine to deploy the Azure Virtual Desktop – Host Pools. If you want to see a Powershell version of the host pool activities, leave me a comment below or on my socials. Please let me know if I have missed any steps or details, and I will be happy to update the post.
Recent Comments