azure 为什么Powershell ForEach循环给出不正确的输出

im9ewurl  于 2023-06-06  发布在  Shell
关注(0)|答案(1)|浏览(167)

我计划在我们的一个应用程序代理版本上生成一个报告,所以我想写一个管道,它将通过每个订阅中的每个VM,并将自定义脚本扩展部署到每个VM资源,检索CSE输出值并放入表中,稍后我想在电子邮件中以CSV文件的形式发送。脚本代码如下所示:

# ... variable initializations omitted

$subscriptions | ForEach-Object {
  Select-AzSubscription -Subscription $_.Name
  $vms = Get-AzVm -Status | Where-Object {$_.StorageProfile.OsDisk.OsType -eq "Windows" -and $_.Name -notlike "azbecdns*" -and $_.Name -notlike "SF160SV0*" -and $_.PowerState -eq "VM running"}
  forEach ($vm in $vms) {

      $CSEvalidation = Get-AzVmExtension -VmName $vm.name -ResourceGroupName $vm.resourceGroupName | where-object {$_.Extensiontype -like "CustomScript*"} 
      if ($CSEvalidation -ne $null)
      {
        Remove-AzVmExtension -VmName $vm.name -ResourceGroupName $vm.resourceGroupName -Name $CSEvalidation.name -Force -ErrorAction Continue
      }
      Set-AzVMCustomScriptExtension -TypeHandlerVersion 1.10 `
              -ResourceGroupName $vm.resourceGroupName `
              -VMName $vm.Name `
              -FileName $fileName `
              -ContainerName $containerName `
              -StorageAccountName $storageAccountName `
              -StorageAccountKey $storageAccountKey `
              -Run $fileName `
              -Location "West Europe" `
              -Name "CustomScriptExtension"

      #this var parse works and lists all vms
      $cseOutput = "test"

      #this doesn't work and only list last vm instance like in the very beginning
      $cseOutput = ((Get-AzVm -VmName $vm.name -ResourceGroupName $vm.resourceGroupName -Status).Extensions | Where {$_.Type -eq 'Microsoft.Compute.CustomScriptExtension'}).SubStatuses.Message[0]

      [PSCustomObject] @{
          VmName = $vm.name
          AgentVer = $cseOutput
        }
  }
} | Select-Object -Property VmName, AgentVer | Where-Object {$_.VmName -ne $null} | export-csv -NoTypeInformation -delimiter ';' -Path $(Pipeline.Workspace)\***.csv

CSV文件只包含最后一个输入,但是当我在循环中检查$hash变量的内容时,它显示了每个VM及其对应值的列表。我已经想了好几天了,还是得不到我想要的结果。我还使用了一个数组对象,但这并不是一个足够的方法,因为它是一个非常耗时的方法,但结果仍然是相同的- csv文件只包含最后一个输入。我应该如何修改脚本来获得我想要的结果-是一个CSV文件,有两列-所有订阅的所有VM名称列表和CSE子状态消息。

sgtfey8w

sgtfey8w1#

更新

  • $cseOutput值中的 * 隐藏控制字符 * 导致了这个问题,用$cseOutput = $cseOutput -replace '\W'消除它们解决了这个问题。
  • 请注意,这个基于正则表达式的-replace操作从字符串中删除了所有不是 word 字符的字符,即任何东西都不是字母数字字符或_
  • 要将删除限制为仅删除 * 控制字符 * 和 * 隐藏格式字符 *(请参阅正则表达式中的字符类),请用途:

$cseOutput = $cseOutput -replace '[\p{Cc}\p{Cf}]'

原始答案:

你的症状有点神秘如果hashtable有多个条目,您 * 应该 * 看到多个行,尽管具有固定的列名"Name","Key","Value";以@{ one = 1; two = 2; three = 3 }.GetEnumerator() | ConvertTo-Csv为例。
我应该如何修改脚本来获得我想要的结果-是一个CSV文件,有两列-所有订阅的所有VM名称列表和CSE子状态消息。
注:此问题已更新,包括以下代码,并进行了修改。
foreach循环中发出具有以所需CSV列名命名的属性的[pscustomobject]示例,并让PowerShell将它们收集到数组中-或者,更可取的是-切换到ForEach-Object并将这些对象直接传递到Export-Csv

# ... variable initializations omitted

$subscriptions |
  ForEach-Object {
    Select-AzSubscription -Subscription $_.Name
    $vms = Get-AzVm -Status | Where-Object { $_.StorageProfile.OsDisk.OsType -eq 'Windows' -and $_.PowerState -eq 'VM running' }
    forEach ($vm in $vms) {
      $CSEvalidation = Get-AzVmExtension -VmName $vm.name -ResourceGroupName $vm.resourceGroupName -ErrorAction Continue | Where-Object { $_.Extensiontype -like 'CustomScript*' } 
      if ($CSEvalidation -ne $null) {
        $null = Remove-AzVmExtension -VmName $vm.name -ResourceGroupName $vm.resourceGroupName -Name $CSEvalidation.name -Force -ErrorAction Continue
      }

      $null = Set-AzVMCustomScriptExtension -TypeHandlerVersion 1.10 `
        -ResourceGroupName $vm.resourceGroupName `
        -VMName $vm.Name `
        -FileName $fileName `
        -ContainerName $containerName `
        -StorageAccountName $storageAccountName `
        -StorageAccountKey $storageAccountKey `
        -Run $fileName `
        -Location 'West Europe' `
        -Name 'CustomScriptExtension' `
        -ErrorAction Continue

      $cseOutput = ((Get-AzVm -VmName $vm.name -ResourceGroupName $vm.resourceGroupName -Status).Extensions | where { $_.Type -eq 'Microsoft.Compute.CustomScriptExtension' }).SubStatuses.Message[0]
      
      # Construct and output a [pscustomobject] instance with the desired
      # properties. The property names will become the CSV colum names.
      [pscustomobject] @{
        VmName = $vm.Name
        CseSubstatus = $cseOutput
      }

    }
  } | 
  Export-Csv -Delimiter ';' -NoTypeInformation -Path $(Pipeline.Workspace)\***.csv

相关问题