How to customize the image with Log Analytics virtual machine extension using Azure Image Builder - azure

I have created a Windows VM with Azure Image Builder using PowerShell by following this documentation.
param (
[Parameter(Mandatory = $true)]
[string]
$imageResourceGroup,
[Parameter(Mandatory = $true)]
[string]
$location,
[Parameter(Mandatory = $true)]
[string]
$imageTemplateName,
[Parameter(Mandatory = $true)]
[string]
$runOutputName,
[Parameter(Mandatory = $true)]
[string]
$myGalleryName,
[Parameter(Mandatory = $true)]
[string]
$imageDefName
)
## Register features
Get-AzResourceProvider -ProviderNamespace Microsoft.Compute, Microsoft.KeyVault, Microsoft.Storage, Microsoft.VirtualMachineImages, Microsoft.Network |
Where-Object RegistrationState -ne Registered |
Register-AzResourceProvider
## Install modules
#Install-Module -Name Az.ManagedServiceIdentity -RequiredVersion 0.7.2 -Force
#Install-Module -Name Az.ImageBuilder -Force
## Your Azure Subscription ID
$subscriptionID = (Get-AzContext).Subscription.Id
Write-Output $subscriptionID
## Create a resource group
New-AzResourceGroup -Name $imageResourceGroup -Location $location
## Create user identity and set role permissions
[int]$timeInt = $(Get-Date -UFormat '%s')
$imageRoleDefName = "Azure Image Builder Image Def $timeInt"
$identityName = "myIdentity$timeInt"
## Create a user identity.
New-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $identityName
## Store the identity resource and principal IDs in variables.
$identityNameResourceId = (Get-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $identityName).Id
$identityNamePrincipalId = (Get-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $identityName).PrincipalId
## Assign permissions for identity to distribute images
$myRoleImageCreationUrl = 'https://raw.githubusercontent.com/azure/azvmimagebuilder/master/solutions/12_Creating_AIB_Security_Roles/aibRoleImageCreation.json'
$myRoleImageCreationPath = "$env:TEMP\myRoleImageCreation.json"
Invoke-WebRequest -Uri $myRoleImageCreationUrl -OutFile $myRoleImageCreationPath -UseBasicParsing
$Content = Get-Content -Path $myRoleImageCreationPath -Raw
$Content = $Content -replace '<subscriptionID>', $subscriptionID
$Content = $Content -replace '<rgName>', $imageResourceGroup
$Content = $Content -replace 'Azure Image Builder Service Image Creation Role', $imageRoleDefName
$Content | Out-File -FilePath $myRoleImageCreationPath -Force
## Create the role definition.
New-AzRoleDefinition -InputFile $myRoleImageCreationPath
## Grant the role definition to the image builder service principal.
$RoleAssignParams = #{
ObjectId = $identityNamePrincipalId
RoleDefinitionName = $imageRoleDefName
Scope = "/subscriptions/$subscriptionID/resourceGroups/$imageResourceGroup"
}
New-AzRoleAssignment #RoleAssignParams
## Create an Azure Compute Gallery
## Create the gallery.
#$myGalleryName = 'myImageGallery'
#$imageDefName = 'winSvrImages'
New-AzGallery -GalleryName $myGalleryName -ResourceGroupName $imageResourceGroup -Location $location
## Create a gallery definition.
$GalleryParams = #{
GalleryName = $myGalleryName
ResourceGroupName = $imageResourceGroup
Location = $location
Name = $imageDefName
OsState = 'generalized'
OsType = 'Windows'
Publisher = 'myCo'
Offer = 'Windows'
Sku = 'Win2019'
}
New-AzGalleryImageDefinition #GalleryParams
## Create an image
## Create an Azure image builder source object.
$SrcObjParams = #{
SourceTypePlatformImage = $true
Publisher = 'MicrosoftWindowsServer'
Offer = 'WindowsServer'
Sku = '2019-Datacenter'
Version = 'latest'
}
$srcPlatform = New-AzImageBuilderSourceObject #SrcObjParams
## Create an Azure image builder distributor object.
$disObjParams = #{
SharedImageDistributor = $true
ArtifactTag = #{tag = 'dis-share' }
GalleryImageId = "/subscriptions/$subscriptionID/resourceGroups/$imageResourceGroup/providers/Microsoft.Compute/galleries/$myGalleryName/images/$imageDefName"
ReplicationRegion = $location
RunOutputName = $runOutputName
ExcludeFromLatest = $false
}
$disSharedImg = New-AzImageBuilderDistributorObject #disObjParams
## Create an Azure image builder customization object.
$ImgCustomParams01 = #{
PowerShellCustomizer = $true
CustomizerName = 'settingUpMgmtAgtPath'
RunElevated = $false
Inline = #("mkdir c:\\buildActions", "mkdir c:\\buildArtifacts", "echo Azure-Image-Builder-Was-Here > c:\\buildActions\\buildActionsOutput.txt")
}
$Customizer01 = New-AzImageBuilderCustomizerObject #ImgCustomParams01
## Create a second Azure image builder customization object.
$ImgCustomParams02 = #{
FileCustomizer = $true
CustomizerName = 'downloadBuildArtifacts'
Destination = 'c:\\buildArtifacts\\index.html'
SourceUri = 'https://raw.githubusercontent.com/azure/azvmimagebuilder/master/quickquickstarts/exampleArtifacts/buildArtifacts/index.html'
}
$Customizer02 = New-AzImageBuilderCustomizerObject #ImgCustomParams02
## Create an Azure image builder template.
$ImgTemplateParams = #{
ImageTemplateName = $imageTemplateName
ResourceGroupName = $imageResourceGroup
Source = $srcPlatform
Distribute = $disSharedImg
Customize = $Customizer01, $Customizer02
Location = $location
UserAssignedIdentityId = $identityNameResourceId
}
New-AzImageBuilderTemplate #ImgTemplateParams
## To determine if the template creation process was successful, you can use the following example.
Get-AzImageBuilderTemplate -ImageTemplateName $imageTemplateName -ResourceGroupName $imageResourceGroup |
Select-Object -Property Name, LastRunStatusRunState, LastRunStatusMessage, ProvisioningState
## Start the image build
## Submit the image configuration to the VM image builder service.
Start-AzImageBuilderTemplate -ResourceGroupName $imageResourceGroup -Name $imageTemplateName
## Create a VM
## Store login credentials for the VM in a variable. The password must be complex.
$Cred = Get-Credential
## Create the VM using the image you created.
$ArtifactId = (Get-AzImageBuilderRunOutput -ImageTemplateName $imageTemplateName -ResourceGroupName $imageResourceGroup).ArtifactId
New-AzVM -ResourceGroupName $imageResourceGroup -Image $ArtifactId -Name myWinVM01 -Credential $Cred
## Verify the customizations
Get-Content -Path C:\buildActions\buildActionsOutput.txt
Get-ChildItem c:\buildArtifacts\
## Delete the image builder template
#Remove-AzImageBuilderTemplate -ResourceGroupName $imageResourceGroup -Name $imageTemplateName
## Delete the image resource group
#Remove-AzResourceGroup -Name $imageResourceGroup
I want to add the Log Analytics virtual machine extension for Windows to the custom image.

Did you tried the same custom params that I see in your script, something in inline (Silent installation commands) comments with workid or key?
however, the easiest way is to enabled log analytics auto provisioning in security center now it's called microsoft defender for cloud (I am using it)

Related

Storage Account vnet details

I am trying to create a report to find all the storage account and its associated vnet details.
& {
foreach ($storageAccount in Get-AzStorageAccount) {
$storageAccountName = $storageAccount.StorageAccountName
$resourceGroupName = $storageAccount.ResourceGroupName
$context = (Get-AzStorageAccount -StorageAccountName $storageAccountName -ResourceGroupName $resourceGroupName).NetworkRuleSet.VirtualNetworkRules.VirtualNetworkResourceId
$splitarray = $context.Split('/')
$vnetid = $splitarray[8]
$subscriptionid = $splitarray[2]
New-Object psobject -Property #{
Name = $storageAccountName;
Context = $vnetid;
ResourceGroupName = $resourceGroupName
Subscriptionid = $subscriptionid
}
}
} | Format-Table Name, Context, subscriptionid, ResourceGroupName
I am currently getting the below output:
storage account vnet report
As you can see from the output the vnet name is not properly fetched for the storage accounts.
Storage account testfnapp2oct16 has vnet testfnvnet attached, this is correct.
Storage accounts unz2versvaultea, cs1f7b27d61e31e, win10guestdiag954 doesn't have any vnet attached but 'testfnvnet' is repeated until the value changes for a different storage account.
Storage account testfnapp9eb7 has two vnets but only testvnet1 is shown and the value 'testvnet1' is repeated for next storage account.
Any help is much appreciated.
I tried to reproduce the same in my environment it's work me successfully.
I have created sample storage account fetched with vnet and without attached with vnet when I tried, your code I got the same error as below.
To resolve this issue Please utilise the condition I have changed in the code below to execute this issue's solution properly.
& {
foreach ($storageAccount in Get-AzStorageAccount) {
$storageAccountName = $storageAccount.StorageAccountName
$resourceGroupName = $storageAccount.ResourceGroupName
$context = (Get-AzStorageAccount -StorageAccountName $storageAccountName -ResourceGroupName $resourceGroupName).NetworkRuleSet.VirtualNetworkRules.VirtualNetworkResourceId
$ErrorActionPreference = ‘SilentlyContinue’
if ($context -eq $null){
New-Object psobject -Property #{
Name = $storageAccountName;
Context = "Empty" ;
ResourceGroupName = $resourceGroupName
Subscriptionid = $subscriptionid
}
}
else {
$splitarray = $context.Split('/')
$vnetid = $splitarray[8]
$subscriptionid = $splitarray[2]
New-Object psobject -Property #{
Name = $storageAccountName;
Context = $vnetid;
ResourceGroupName = $resourceGroupName
Subscriptionid = $subscriptionid
}
}
}
} | Format-Table Name, Context, subscriptionid, ResourceGroupName
Result:
Now, whichever vnet are not fetched in my storage account it's show Empty like below.

Assistance with looping through multiple subscriptions

I'm using the below script from http://vcloud-lab.com/entries/microsoft-azure/get-azure-virtual-machine-backup-reports-using-powershell to pull Azure VM backup details. Currently I have to run the script against each subscription, I would love to have it loop though all subscriptions.
I've been trying to get it working using this example https://www.jpaul.me/2019/05/azure-automation-how-to-quickly-work-with-many-subscriptions/ but I'm new to powershell and am struggling. Any suggestions would be really appreciated.
[CmdletBinding(SupportsShouldProcess=$True,
ConfirmImpact='Medium',
HelpURI='http://vcloud-lab.com',
DefaultParameterSetName = 'AllVirtualMachines'
)]
<#
.SYNOPSIS
Collect Azure VM Backup Information
.DESCRIPTION
This Script collects Azure Virtual Machine Backup Recovery service vault information, This report includes the complete backup status Information of VM.
.PARAMETER AllVirtualMachines
Collect Backup information of the all Azure Virtual Machines, This is default parameter.
.PARAMETER VirtualMachineList
You can specify for which virtual machine you want backup information.
.INPUTS
None. Provides virtual machine information.
.OUTPUTS
Generate Backup information. You can pipe information to Export-CSV.
.EXAMPLE
PS> .\Get-AzVMBackupInformation.ps1
VM_Name : vcloud-lab-vm01
VM_Location : uksouth
VM_ResourceGroupName : VCLOUD-LAB.COM
VM_BackedUp : True
VM_RecoveryVaultName : vault828
VM_RecoveryVaultPolicy : DailyPolicy-kosrnox0
VM_BackupHealthStatus : Passed
VM_BackupProtectionStatus : Healthy
VM_LastBackupStatus : Completed
VM_LastBackupTime : 27-05-2021 19:32:34
VM_BackupDeleteState : NotDeleted
VM_BackupLatestRecoveryPoint : 27-05-2021 19:32:37
VM_Id : /subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/VCLOUD-LAB.COM/providers/Microsoft.Compute/virtualMachines/vcloud-lab-vm01
RecoveryVault_ResourceGroupName : vCloud-lab.com
RecoveryVault_Location : uksouth
RecoveryVault_SubscriptionId : /subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vCloud-lab.com/providers/Microsoft.RecoveryServices/vaults/vault828
.EXAMPLE
PS> .\Get-AzVMBackupInformation.ps1 -AllVirtualMachines
This produces same result as .\Get-AzVMBackupInformation.ps1 from all VMs
.EXAMPLE
PS> .\Get-AzVMBackupInformation.ps1 -VirtualMachineList
Provide either single virtual machine name or in list
.LINK
Online version: http://vcloud-lab.com
.LINK
Get-AzVMBackupInformation.ps1
#>
Param
(
[parameter(Position=0, ParameterSetName = 'AllVMs' )]
[Switch]$AllVirtualMachines,
[parameter(Position=0, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True, ParameterSetName = 'VM' )]
[alias('Name')]
[String[]]$VirtualMachineList
) #Param
Begin
{
#Collecing Azure virtual machines Information
Write-Host "Collecing Azure virtual machine Information" -BackgroundColor DarkGreen
if (($PSBoundParameters.ContainsKey('AllVirtualMachines')) -or ($PSBoundParameters.Count -eq 0))
{
$vms = Get-AzVM
} #if ($PSBoundParameters.ContainsKey('AllVirtualMachines'))
elseif ($PSBoundParameters.ContainsKey('VirtualMachineList'))
{
$vms = #()
foreach ($vmname in $VirtualMachineList)
{
$vms += Get-AzVM -Name $vmname
} #foreach ($vmname in $VirtualMachineList)
} #elseif ($PSBoundParameters.ContainsKey('VirtualMachineList'))
#Collecing All Azure backup recovery vaults Information
Write-Host "Collecting all Backup Recovery Vault information" -BackgroundColor DarkGreen
$backupVaults = Get-AzRecoveryServicesVault
} #Begin
Process
{
$vmBackupReport = [System.Collections.ArrayList]::new()
foreach ($vm in $vms)
{
$recoveryVaultInfo = Get-AzRecoveryServicesBackupStatus -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Type 'AzureVM'
if ($recoveryVaultInfo.BackedUp -eq $true)
{
Write-Host "$($vm.Name) - BackedUp : Yes"
#Backup Recovery Vault Information
$vmBackupVault = $backupVaults | Where-Object {$_.ID -eq $recoveryVaultInfo.VaultId}
#Backup recovery Vault policy Information
$container = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVM -VaultId $vmBackupVault.ID -FriendlyName $vm.Name #-Status "Registered"
$backupItem = Get-AzRecoveryServicesBackupItem -Container $container -WorkloadType AzureVM -VaultId $vmBackupVault.ID
} #if ($recoveryVaultInfo.BackedUp -eq $true)
else
{
Write-Host "$($vm.Name) - BackedUp : No" -BackgroundColor DarkRed
$vmBackupVault = $null
$container = $null
$backupItem = $null
} #else if ($recoveryVaultInfo.BackedUp -eq $true)
[void]$vmBackupReport.Add([PSCustomObject]#{
VM_Name = $vm.Name
VM_Location = $vm.Location
VM_ResourceGroupName = $vm.ResourceGroupName
VM_BackedUp = $recoveryVaultInfo.BackedUp
VM_RecoveryVaultName = $vmBackupVault.Name
VM_RecoveryVaultPolicy = $backupItem.ProtectionPolicyName
VM_BackupHealthStatus = $backupItem.HealthStatus
VM_BackupProtectionStatus = $backupItem.ProtectionStatus
VM_LastBackupStatus = $backupItem.LastBackupStatus
VM_LastBackupTime = $backupItem.LastBackupTime
VM_BackupDeleteState = $backupItem.DeleteState
VM_BackupLatestRecoveryPoint = $backupItem.LatestRecoveryPoint
VM_Id = $vm.Id
RecoveryVault_ResourceGroupName = $vmBackupVault.ResourceGroupName
RecoveryVault_Location = $vmBackupVault.Location
RecoveryVault_SubscriptionId = $vmBackupVault.ID
}) #[void]$vmBackupReport.Add([PSCustomObject]#{
} #foreach ($vm in $vms)
} #Process
end
{
$vmBackupReport
} #end
You can try this sample script from the MS doc for looping through multiple subscriptions.
Connect-AzAccount
$SubscriptionList = Get-AzSubscription
foreach ($Id in $SubscriptionList)
{
#Provide the subscription Id where the VMs reside
$subscriptionId = $Id
#Provide the name of the csv file to be exported
$reportName = "myReport.csv"
Select-AzSubscription $subscriptionId
$report = #()
$vms = Get-AzVM
$publicIps = Get-AzPublicIpAddress
$nics = Get-AzNetworkInterface | ?{ $_.VirtualMachine -NE $null}
foreach ($nic in $nics)
{
$info = "" | Select VmName, ResourceGroupName, Region, VmSize, VirtualNetwork, Subnet, PrivateIpAddress, OsType, PublicIPAddress, NicName, ApplicationSecurityGroup, subscriptionId
$vm = $vms | ? -Property Id -eq $nic.VirtualMachine.id
foreach($publicIp in $publicIps)
{
if($nic.IpConfigurations.id -eq $publicIp.ipconfiguration.Id)
{
$info.PublicIPAddress = $publicIp.ipaddress
}
}
$info.subscriptionId = $subscriptionId
$info.OsType = $vm.StorageProfile.OsDisk.OsType
$info.VMName = $vm.Name
$info.ResourceGroupName = $vm.ResourceGroupName
$info.Region = $vm.Location
$info.VmSize = $vm.HardwareProfile.VmSize
$info.VirtualNetwork = $nic.IpConfigurations.subnet.Id.Split("/")[-3]
$info.Subnet = $nic.IpConfigurations.subnet.Id.Split("/")[-1]
$info.PrivateIpAddress = $nic.IpConfigurations.PrivateIpAddress
$info.NicName = $nic.Name
$info.ApplicationSecurityGroup = $nic.IpConfigurations.ApplicationSecurityGroups.Id
$report+=$info
}
$report | ft subscriptionId, VmName, ResourceGroupName, Region, VmSize, VirtualNetwork, Subnet, PrivateIpAddress, OsType, PublicIPAddress, NicName, ApplicationSecurityGroup
$report | Export-CSV "$home/$reportName"
}
References: Collect details about all VMs in a subscription with PowerShell - Azure Virtual Machines | Microsoft Docs , Iterate through subscriptions using an Array to avoid manual work · Issue #50670 · MicrosoftDocs/azure-docs · GitHub and powershell - How to loop through multiple Azure subscriptions on Azure Pipelines Yaml? - Stack Overflow

How to create an Azure Network Security Group Flow log with Azure PowerShell

I want to create a NSG flow log for the network security group of a given Virtual Machine and link to a given Storage Account with PowerShell.
How can I achieve this?
This can be achieved with this sequence of operations:
determine the NSG linked to a Virtual Machine
get or create a `NetworkWatcher for the location of the NSG
find a suitable storage account
set a Flow Log configuration, if there is none existing
param(
# RegEx pattern to find your first VM in your current subscription
[Parameter(Mandatory = $true, Position = 1)]
[string]$vmNamePattern,
# RegEx pattern to find a storage account in your current subscription
[Parameter(Mandatory = $true, Position = 2)]
[string]$storageNamePattern
)
$vm = Get-AzVM | Where-Object { $_.Name -match $vmNamePattern } | Select-Object -First 1
$nic = Get-AzNetworkInterface -ResourceId $vm.NetworkProfile.NetworkInterfaces[0].Id
$sn = Get-AzVirtualNetworkSubnetConfig -ResourceId $nic.IpConfigurations[0].Subnet.Id
$nsgRes = Get-AzResource -ResourceId $sn.NetworkSecurityGroup.Id
$nsg = Get-AzNetworkSecurityGroup -ResourceGroupName $nsgRes.ResourceGroupName -Name $nsgRes.ResourceName
# create or get NetworkWatcher
$nw = Get-AzNetworkWatcher -ResourceGroupName NetworkWatcherRg | ? { $_.Location -eq $nsg.Location }
if (!$nw) {
New-AzNetworkWatcher -ResourceGroupName NetworkWatcherRg -Location $nsg.Location -Name $("NetworkWatcher_" + $nsg.Location)
$nw = Get-AzNetworkWatcher -ResourceGroupName NetworkWatcherRg | ? { $_.Location -eq $nsg.Location }
}
# detect first viable storage account
$storageAccount = Get-AzStorageAccount | Where-Object { $_.StorageAccountName -match $storageNamePattern -and $_.PrimaryEndpoints.Blob -match "^http" } | Select-Object -First 1
# get or set NSG flow log if not yet established
$fl = Get-AzNetworkWatcherFlowLogStatus -NetworkWatcher $nw -TargetResourceId $nsg.Id
if (!$fl) {
# https://learn.microsoft.com/de-de/azure/network-watcher/network-watcher-nsg-flow-logging-powershell
Set-AzNetworkWatcherConfigFlowLog -NetworkWatcher $nw -TargetResourceId $nsg.Id -StorageAccountId $storageAccount.Id -EnableFlowLog $true -FormatType Json -FormatVersion 2
}

List all Storage Accounts and containers in Aure w/Powershell

I am a novice at Powershell. I have been tasked with listing all storage accounts, along with all the underlying containers, for one of our Azure subscriptions. So I looked to see if a script existed, but couldn't find one. I then set about heavily modifying one that was originally for something different. Figured it would be a good learning exercise.
So what I am wanting my script to do is to work through the subscription, spit out all the storage accounts, and then go through each storage account to list all the containers within them. There are dozens of accounts to go through, each with multiple containers. Once done, throw it into a formatted CSV.
So far I can get the script to output the storage accounts, but nothing more than that. I am running this on my own test environment before hitting the live one, just in case.
Hoping that someone can throw some pointers as to what I'm doing wrong.
Script as below:
##################################################
# Gather storage account information
# across all subscriptions
##################################################
Write-Host "Gathering storage account information...`n"
[System.Collections.ArrayList]$saUsage = New-Object -TypeName System.Collections.ArrayList
# Loop through each subscription
foreach ($subscriptionId in $SubscriptionIDs) {
# Set context to the subscription
Select-AzSubscription -SubscriptionId $subscriptionID | Out-Null
$context = Get-AzContext
Write-Host "The subscription context is set to: $($context.Name)`n"
$storageAccounts = Get-AzResource -ResourceType 'Microsoft.Storage/storageAccounts'
$containers = Get-AzResource -ResourceType
'Microsoft.Storage/storageAccounts/blobServices/containers'
}
# Check the account can access storage accounts within the subscription
if (!$storageAccounts) {
Write-Host -ForegroundColor Red "Account '$($context.Account.Id)' does not have access to any
storage accounts in subscription '$($context.Name)'"
$storageAccounts | Format-Table StorageAccountName, ResourceGroupName, Location
continue
}
Write-Host "Progress Status:"
[int]$i = 1
Loop through each storage account and gather usage information
foreach ($storageAccount in $storageAccounts) {
Write-Host "[$i of $($storageAccounts.Count)] $($storageAccount.Name)"
$i++
Gather storage account details and store as a PS custom object
$StorageAccountDetails = [ordered]#{
SubscriptionName = $context.Subscription.Name
SubscrpitionID = $context.Subscription.Id
StorageAccountName = $storageAccount.Name
ContainerName = $container.containerName
ResourceGroup = $storageAccount.ResourceGroupName
Location = $storageAccount.Location
}
$saUsage.add((New-Object psobject -Property $StorageAccountDetails)) | Out-Null
}
foreach($container in $storageAccount.BlobContainersOperationsExtensions.get) {
if($container.containerName) {
# Gather storage account container details and store as a PS custom object
$StorageAccountDetails = [ordered]#{
SubscriptionName = $context.Subscription.Name
SubscrpitionID = $context.Subscription.Id
StorageAccountName = $storageAccount.Name
ContainerName = $container.containerName
ResourceGroup = $storageAccount.ResourceGroupName
Location = $storageAccount.Location
}
}
$saUsage.add((New-Object psobject -Property $StorageAccountDetails)) | Out-Null
}
# Output storage account usage results to .CSV
if($saUsage) {
# Output to CSV
$saUsage | Export-Csv -Path $SAOutputPath -NoTypeInformation
Write-Output "`nExported storage account usage report at $SAOutputPath`n"
}
Regarding the issue, please refer to the following script
$context = Get-AzContext
$storageAccounts = Get-AzResource -ResourceType 'Microsoft.Storage/storageAccounts'
[System.Collections.ArrayList]$saUsage = New-Object -TypeName System.Collections.ArrayList
foreach ($storageAccount in $storageAccounts) {
#list containers
$conatiners= Get-AzRmStorageContainer -ResourceGroupName $storageAccount.ResourceGroupName -StorageAccountName $storageAccount.Name
if($conatiners -ne $null){
foreach($container in $conatiners){
$StorageAccountDetails = [ordered]#{
SubscriptionName = $context.Subscription.Name
SubscrpitionID = $context.Subscription.Id
StorageAccountName = $storageAccount.Name
ContainerName = $container.Name
ResourceGroup = $storageAccount.ResourceGroupName
Location = $storageAccount.Location
}
$saUsage.add((New-Object psobject -Property $StorageAccountDetails)) | Out-Null
}
}else{
$StorageAccountDetails = [ordered]#{
SubscriptionName = $context.Subscription.Name
SubscrpitionID = $context.Subscription.Id
StorageAccountName = $storageAccount.Name
ContainerName = $null
ResourceGroup = $storageAccount.ResourceGroupName
Location = $storageAccount.Location
}
$saUsage.add((New-Object psobject -Property $StorageAccountDetails)) | Out-Null
}
}
$saUsage | Export-Csv -Path e:\test.csv -NoTypeInformation

Multiple Azure VM base images with the same name

When i use a script to create a VM in Azure and select as the base image "Windows 10, Pro Version 1903" I get the following error: "Found more than 1 image with name 'Windows 10 Pro, Version 1903'. Please pick one from ['Windows 10 Pro, Version 1903', 'Windows 10 Pro, Version 1903']"
If I create a VM from the portal there are two base images with exactly the same name.
az lab vm create --resource-group MyTestRG --lab-name MyTestLab --name 'MyScriptVM' --image "Windows 10 Pro, Version 1903" --image-type gallery --size 'Standard_B2s' --admin-username '****' --admin-password '****'
How are you supposed to use that base image if you can't tell it exactly which one to use?
When you filter the image via CLI command: az lab gallery-image list --lab-name mytestlab --resource-group myrg --query "[?name == 'Windows 10 Pro, Version 1903']", you will find the similar image reference except for the SKU.
However, there is no SKU parameter for Azure CLI az lab vm create. As a workaround, you could create a VM with DevTest Labs using Azure PowerShell.
The sample PowerShell script:
[CmdletBinding()]
Param(
[Parameter(Mandatory = $false)] $SubscriptionId,
[Parameter(Mandatory = $true)] $LabResourceGroup,
[Parameter(Mandatory = $true)] $LabName,
[Parameter(Mandatory = $true)] $NewVmName,
[Parameter(Mandatory = $true)] $UserName,
[Parameter(Mandatory = $true)] $Password
)
pushd $PSScriptRoot
try {
if ($SubscriptionId -eq $null) {
$SubscriptionId = (Get-AzContext).Subscription.SubscriptionId
}
$API_VERSION = '2016-05-15'
$lab = Get-AzResource -ResourceId "/subscriptions/$SubscriptionId/resourceGroups/$LabResourceGroup/providers/Microsoft.DevTestLab/labs/$LabName"
if ($lab -eq $null) {
throw "Unable to find lab $LabName resource group $LabResourceGroup in subscription $SubscriptionId."
}
#For this example, we are getting the first allowed subnet in the first virtual network
# for the lab.
#If a specific virtual network is needed use | to find it.
#ie $virtualNetwork = #(Get-AzResource -ResourceType 'Microsoft.DevTestLab/labs/virtualnetworks' -ResourceName $LabName -ResourceGroupName $lab.ResourceGroupName -ApiVersion $API_VERSION) | Where-Object Name -EQ "SpecificVNetName"
$virtualNetwork = #(Get-AzResource -ResourceType 'Microsoft.DevTestLab/labs/virtualnetworks' -ResourceName $LabName -ResourceGroupName $lab.ResourceGroupName -ApiVersion $API_VERSION)[0]
$labSubnetName = $virtualNetwork.properties.allowedSubnets[0].labSubnetName
#Prepare all the properties needed for the createEnvironment
# call used to create the new VM.
# The properties will be slightly different depending on the base of the vm
# (a marketplace image, custom image or formula).
# The setup of the virtual network to be used may also affect the properties.
# This sample includes the properties to add an additional disk under dataDiskParameters
$parameters = #{
"name" = $NewVmName;
"location" = $lab.Location;
"properties" = #{
"labVirtualNetworkId" = $virtualNetwork.ResourceId;
"labSubnetName" = $labSubnetName;
"notes" = "Windows Server 2016 Datacenter";
"osType" = "windows"
"expirationDate" = "2019-12-01"
"galleryImageReference" = #{
"offer" = "WindowsServer";
"publisher" = "MicrosoftWindowsServer";
"sku" = "2016-Datacenter";
"osType" = "Windows";
"version" = "latest"
};
"size" = "Standard_DS2_v2";
"userName" = $UserName;
"password" = $Password;
"disallowPublicIpAddress" = $true;
"dataDiskParameters" = #(#{
"attachNewDataDiskOptions" = #{
"diskName" = "adddatadisk"
"diskSizeGiB" = "1023"
"diskType" = "Standard"
}
"hostCaching" = "ReadWrite"
})
}
}
#The following line is the same as invoking
# https://azure.github.io/projects/apis/#!/Labs/Labs_CreateEnvironment rest api
Invoke-AzResourceAction -ResourceId $lab.ResourceId -Action 'createEnvironment' -Parameters $parameters -ApiVersion $API_VERSION -Force -Verbose
}
finally {
popd
}
The following command provides an example of running the script saved in a file name: Create-LabVirtualMachine.ps1.
PS> .\Create-LabVirtualMachine.ps1 -ResourceGroupName 'MyLabResourceGroup' -LabName 'MyLab' -userName 'AdminUser' -password 'Password1!' -VMName 'MyLabVM'

Resources