【问题标题】:Optimize PowerShell code to avoid calling the cmdlet multiple times inside calculated properties?优化 PowerShell 代码以避免在计算属性中多次调用 cmdlet?
【发布时间】:2022-08-18 18:44:48
【问题描述】:

我需要一些建议和帮助来优化下面的代码,以避免在计算的属性下两次调用相同的命令。

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

https://docs.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 } }

上面的脚本适用于提取各种不同的 Azure VM。

如果有人知道如何做得更好,请建议更新的代码。

谢谢。

    标签: azure powershell azure-powershell


    【解决方案1】:

    虽然calculated properties的脚本块是按顺序执行的,但对于每个输入对象,它们都各自运行孩子范围相对于调用者,这使它们之间的共享状态变得复杂。

    但是,您可以简单地创建一个要在父母范围,在脚本中最简单的情况下是 $script: 范围,如以下简化示例所示(它使用对 Get-Date 的调用代替对 Azure cmdlet 的调用作为您不想要的调用的示例重复):

    # Share the result of the `Get-Date` call between calculated properties.
    'foo' | Select-Object `
      @{ n='Month'; e = { $script:dt = Get-Date; $dt.Month } },
      @{ n='Year'; e = { $dt.Year } }
    

    输出:

    Month Year
    ----- ----
        8 2022
    

    这证明$script:-scoped $dt 变量在第二个计算属性中被成功使用。

    如果您想可靠地定位父母范围,如果您在嵌套函数调用中运行,它可能与 $script: 范围不同,例如,将 $script:dt = Get-Date 替换为
    Set-Variable -Scope 1 dt (Get-Date)

    笔记:

    • 计算属性的脚本块以及延迟绑定脚本块在孩子范围可能令人惊讶,因为它与传递给 ForEach-ObjectWhere-Object 的脚本块的行为形成对比,例如 - 有关讨论,请参阅 GitHub issue #7157

    【讨论】:

    • 酷,感谢@mklement0 的分享和解释
    【解决方案2】:

    这可能无法完全回答您最初的问题,但是当代码变得过于复杂时,您可能会考虑删除计算的属性。相反,在 ForEach-Object 脚本块中使用 [pscustomobject]@{…} 文字。这样,您可以将公共代码从属性移到脚本块的开头。

    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  
        } 
    }
    

    附带说明一下,SomeCommand | Select-Object -Expand PropertyName 效率不高,可以用成员访问权限代替,就像我对 ip 属性所做的那样。关键是将命令括在括号中。

    【讨论】:

    • 太好了,谢谢@zett42 的分享和解释。
    猜你喜欢
    • 2018-06-22
    • 2017-06-04
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 2010-11-14
    • 2019-04-07
    • 2018-09-09
    相关资源
    最近更新 更多