Search code examples
azurepowershellazure-powershell

Optimize PowerShell code to avoid calling the cmdlet multiple times inside calculated properties?


I am looking to optimize the code below to avoid calling the same command twice under the calculated properties.

https://learn.microsoft.com/en-us/powershell/module/az.compute/get-azvm

https://learn.microsoft.com/en-us/powershell/module/az.compute/get-azvmsize

Get-AzVM | Select-Object-Object Name,
    @{ l = 'osdiskingb'; e = { ($_.StorageProfile.OsDisk.DiskSizeGB) } }, `
    @{ l = 'memory'; e = { $size = $_.HardwareProfile.VmSize; Get-AzVMSize -vmname $_.Name -ResourceGroupName $_.ResourceGroupName | Where-Object { $_.name -eq $size } | Select-Object -expand MemoryInMB } }, `
    @{ l = 'cpu'; e = { $size = $_.HardwareProfile.VmSize; Get-AzVMSize -vmname $_.Name -ResourceGroupName $_.ResourceGroupName | Where-Object { $_.name -eq $size } | Select-Object -expand NumberOfCores } }, `
    @{ l = 'nic'; e = { $_.NetworkProfile.NetworkInterfaces.id.split('/') | Select-Object -Last 1 } }, `
    @{ l = 'ip'; e = { $nic = $_.NetworkProfile.NetworkInterfaces.id.split('/') | Select-Object -Last 1; Get-AzNetworkInterface -Name $nic | Select-Object -expand ipconfigurations | Select-Object -expand privateipaddress } }

The script above works for pulling various different Azure VMs.

What can I try next?


Solution

  • This might not exactly answer your original question, but you might consider dropping calculated properties when the code becomes too complicated. Instead, use a [pscustomobject]@{…} literal in a ForEach-Object script block. This way you can move common code out of the properties to the begin of the script block.

    Get-AzVM | ForEach-Object {
        $size = $_.HardwareProfile.VmSize
        $vmsize = Get-AzVMSize -vmname $_.Name -ResourceGroupName $_.ResourceGroupName | Where-Object { $_.name -eq $size }
        $nic = $_.NetworkProfile.NetworkInterfaces.id.split('/') | Select-Object -Last 1
    
        # Implicitly outputs an object with the given properties
        [pscustomobject]@{
            Name       = $_.Name
            osdiskingb = $_.StorageProfile.OsDisk.DiskSizeGB
            memory     = $vmsize.MemoryInMB
            cpu        = $vmsize.NumberOfCores
            nic        = $nic
            ip         = (Get-AzNetworkInterface -Name $nic).ipconfigurations.privateipaddress  
        } 
    }
    

    On a side note, SomeCommand | Select-Object -Expand PropertyName isn't very efficient and can be replaced by member access, as I did for the ip property. The key is to enclose the command in parentheses.