Looking for a way to optimze this script as it take 15-20 mins to complete

$date = get-date -Format MM-dd-yy
$customername = read-host -Prompt "Enter Customer Name"
$reportName = "$customername-VMinfo-$date.xls"
$path = "c:\temp"
$rpttemp = "c:\temp\rpttemp\"
$nics = Get-AzNetworkInterface | ? { $_.VirtualMachine -NE $null}
$azstraccts = Get-AzStorageAccount
$vmsizelist = Get-AzVMSize -Location 'EASTUS'
write-host "1 VMinfo, 2 DiskInfo, 3 NSGInfo, 4 Detail Report contains 1 through 4 + users"
$num = Read-Host -Prompt "Enter a number"
Switch ($num)
1 {
if (Test-Path $rpttemp -ne $null) {
write-host "Report Folder Found" -ForegroundColor Green}
else { (Test-Path $reporttmp -eq $null )
write-host "Creating Report Folder " -ForegroundColor Yellow
New-Item -ItemType "directory" -Path $rpttemp --ForegroundColor Yellow}
if (Test-Path $rpttemp\nsgnames\ -ne $null) {
write-host "NSG folder Path Found" -ForegroundColor Green}
else { (Test-Path $reporttmp\nsgnames -eq $null)
write-host "Creating NsgName folder" -ForegroundColor Yellow
New-Item -ItemType "directory" -Path $rpttemp\nsgnames}
$vminfo = @()
Write-Host "Start Collection of VMinfo details" -ForegroundColor Green
foreach ($nic in $nics) {
$vm = $nic.VirtualMachine.Id.Split("/")[-1]
$rg = $nic.ResourceGroupName
$VMDiskname = ((get-azvm -resourcegroupname $rg -name $vm).StorageProfile).OsDisk.name
$VMDiskInfo = Get-AzDisk -ResourceGroupName $rg -DiskName $VMDiskName
$VMCreatedDate = $VMDiskInfo.TimeCreated
$size = (get-azvm -name $vm -ResourceGroupName $rg).HardwareProfile.VmSize
$os = (get-azvm -name $vm -ResourceGroupName $rg).StorageProfile.OsDisk.OsType
$status = get-azvm -ResourceGroupName $rg -name $vm -status
#Secureity Group Check
if( $null -eq (Get-AzNetworkInterface -name $nic.name).NetworkSecurityGroup.Id)
{ $nsg ="NSG Group Not Set"}
else { $nsg = (Get-AzNetworkInterface -name $nic.name).NetworkSecurityGroup.Id.Split("/")[-1] -join ", "}
#Azure Hybrid Benifit Check
if( $null -eq $os )
{$azhb = "Disabled"}
elseif("Linux"-eq $os)
{$azhb = "Linux Not Required"}
else {$azhb = "Enabled"}
#check for Antimalware Extension
if( $null -eq (Get-AzVMExtension -ResourceGroupName $rg -VMName $vm -Name IaaSAntimalware ))
{ $vmext ="Antimalware Extension Not installed"}
else {$vmext = "Antimalware Extension installed" }
$vminfo += (
[pscustomobject][ordered] @{
VMName = $vm
"VM Build Date (UTC)" = $VMCreatedDate
Status = $status.Statuses[1].DisplayStatus
VMSize = $size
"CPU(S)" = ($vmsizelist | ? {$_.name -eq $size}).numberOfCores
Memory = ($vmsizelist | ? {$_.name -eq $size}).memoryinmb
OsType = $os
"Azure hybrid benefit" = $azhb
"Azure VM Extentions" = $vmext
ResourceGroupName = $rg
Region = (get-azvm -name $vm -ResourceGroupName $rg).Location
NicName = $nic.Name -join ", "
PrivateIpAddress = $nic.IpConfigurations.PrivateIpAddress -join ", "
"IP Allocation" = (Get-AzNetworkInterface -Name $nic.name).IpConfigurations.PrivateIpAllocationMethod
VirtualNetwork = $nic.IpConfigurations.subnet.Id.Split("/")[-3]
Subnet = $nic.IpConfigurations.subnet.Id.Split("/")[-1]
NSG = $nsg})}
$vminfo | Export-Excel -Show `</div> <div> -AutoSize `
-AutoFilter `</div> <div> -AutoNameRange `
-TableName VMINFO `</div> <div> -WorksheetName VMINFO `
-ConditionalFormat $(
New-ConditionalText "Dynamic" -ConditionalTextColor red #color check for dynamic IP address
New-ConditionalText "Antimalware Extension Not installed" -ConditionalTextColor red #color Antimalware Not Set Red if not set
New-ConditionalText "NSG Group Not Set" -ConditionalTextColor red #color NSG Group Not Set Red if not set
New-ConditionalText "Disabled" -ConditionalTextColor red #color Azure hybrid benefit Red if not set
New-ConditionalText "VM deallocated" -ConditionalTextColor red #color Azure hybrid benefit Red if not set
) `
-path $path\$reportName}

The biggest thing I see is you are making this same query to get different statistics:

get-azvm -resourcegroupname $rg -name $vm

Not personally used the cmdlet, but typically they return all of the information you would need for all of the -Status calls and everything else, so rather than 4+ GET calls, you would do something like this:

$vmInfo = get-azvm -name $vm -ResourceGroupName $rg
$size = $vmInfo.HardwareProfile.VmSize
$os = $vminfo.StorageProfile.OsDisk.OsType

The same thing for Get-AzNetworkInterface, call it once and then parse.

Hello sreed7743,

The performance issues lie in += operator.

Try using ArrayList it should improve you performance drastically.

So you would need to do something like this:

$vminfo=New-Object System.Collections.ArrayList
#instead of your

$vminfo.Add( <#your code to initialize PS Custom object goes here#>)

#insted of your $vminfo+=…

Hope that helps.

Please do not use an arraylist, they are deprecated. If you do, be sure to use

$null = $vminfo.add(...)
because it outputs the index where it's inserted and can cause unexpected issues/headaches. Instead use a generic list
$vminfo = [System.Collections.Generic.List[object]]::new()


This combined with Rob’s suggestion should speed it up for sure!

Thanks @andysvints and @KrzyDoug these changes made a over 50% increase in the speed.