0

Attempting to add an extension when not detected but keep failing to find the secret sauce to get this to work. Mind you I am a BASH guy and this is a first foray into PowerShell..

#requires -version 2

# Required parameter $subscription: name of the subscription to enable Custom Script Extensions in
param (
  # NOTE: See below for reason...
  #  [Parameter(Mandatory = $true)] [String] $subscription

  # NOTE: Prompting is great for using the script interactively, but if this will also be executed
  #       from a build server or ...

  # NOTE: Once the parameter is marked as mandatory PowerShell it will prompt for value. That said,
  #       if you remove the mandatory attribute then you can set a default value as a T_THROW ...

  # NOTE: This _does_ contain shortcomings if this will be used as a pipeline param ...
  #       https://stackoverflow.com/questions/33600279/is-it-possible-to-force-powershell-script-to-throw-if-a-required-pipeline-para

  [Parameter()]
  [ValidateNotNullOrEmpty()]
  [String]$SubscriptionName=$(Throw "`SubscriptionName` is mandatory, please provide a value...")
)

# Connect to the current Azure account
Write-Output "Pulling Azure account credentials..."
Start-Process "https://microsoft.com/devicelogin" # steals focus...

# Login to Azure account
Connect-AzAccount

# Set the active subscription
$null = Get-AzSubscription -SubscriptionName "$SubscriptionName" |Set-AzContext

# TODO: error handling
$vms = Get-AzVM
$cseName = "VulnerabilityManagementTools"

ForEach ($vm in $vms) {
  try {
    $cseStatus = Get-AzVMCustomScriptExtension `
      -ResourceGroupName $vm.ResourceGroupName `
      -VMName $vm.Name `
      -Name $cseName `
      -Status
  }
  catch {
    Write-Output "Enabling Custom Script Extension for $vm."

    Set-AzVMCustomScriptExtension `
      -ResourceGroupName $vm.ResourceGroup `
      -Location $vm.Location `
      -VMName $vm.Name `
      -Name $cseName `
      -TypeHandlerVersion "1.1" `
      -StorageAccountName "VulnerabilityManagementTools" `
      -FileName "VulnerabilityManagementInstaller.ps1" `
      -ContainerName "VulnerabilityManagementTools"
  }
}

End up err'ing out with

PS /.../automation-scripts> ./EnableCustomScriptExtension.ps1 SubscriptionName
Pulling Azure account credentials...
WARNING: To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXX to authenticate.

Account                     SubscriptionName      TenantId                             Environment
-------                     ----------------      --------                             -----------
XXXX@analytics.com          SubName               XXXXXX-XXXX                           AzureCloud
Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{NAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{NAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+     $cseStatus = Get-AzVMCustomScriptExtension `
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand

Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/XXXXX/extensions/VulnerabilityManagementTools' under resource group '{RESOURCE_GROUPNAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{RESOURCE_GROUPNAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+     $cseStatus = Get-AzVMCustomScriptExtension `
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand

Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/{VMName}/extensions/VulnerabilityManagementTools' under resource group '{RESOURCEX_GROUPNAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/{VMName}/extensions/VulnerabilityManagementTools' under resource group '{RESOURCEX_GROUPNAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+     $cseStatus = Get-AzVMCustomScriptExtension `
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand`
Robert Dyjas
  • 4,979
  • 3
  • 19
  • 34
ehime
  • 8,025
  • 14
  • 51
  • 110

2 Answers2

2

In your case, you just need to use the if(){}else{} statement, try the script as below instead of the ForEach part of yours, it works fine on my side.

ForEach ($vm in $vms) {
$cseStatus = Get-AzVMCustomScriptExtension `
      -ResourceGroupName $vm.ResourceGroupName `
      -VMName $vm.Name `
      -Name $cseName `
      -Status `
      -ErrorAction SilentlyContinue

if ($cseStatus){
    Write-Host "The extension has been set for" $vm.Name
}else{
    Write-Host "Enabling Custom Script Extension for" $vm.Name

    Set-AzVMCustomScriptExtension `
      -ResourceGroupName $vm.ResourceGroup `
      -Location $vm.Location `
      -VMName $vm.Name `
      -Name $cseName `
      -TypeHandlerVersion "1.1" `
      -StorageAccountName "VulnerabilityManagementTools" `
      -FileName "VulnerabilityManagementInstaller.ps1" `
      -ContainerName "VulnerabilityManagementTools"
    }
}

Test result:

enter image description here

enter image description here

Joy Wang
  • 39,905
  • 3
  • 30
  • 54
1

You'll need to create an Azure AD Service Principal using password authentication and use the credentials of this to pass to the Connect-AzAccount cmdlet as follows:

$credentials = Get-Credential
Connect-AzAccount -ServicePrincipal -Credentials $credentials

The service account will need to have the necessary permissions to use the Set-AzVMCustomScriptExtensions cmdlet.

More information on creating the service account here:

https://learn.microsoft.com/en-us/powershell/azure/create-azure-service-principal-azureps?view=azps-2.8.0

Architect Jamie
  • 1,621
  • 4
  • 18