Windows 10 Image Series – Part 1 – Create The VM

In this series I am going to show you how build a Windows 10 Image via Azure Pipelines and DevOps without 3rd party tooling, welcome to part 1!

Part 1 is about building the Windows 10 machine, sysprepping it and creating an image from it.

Prerequisites

There are some prerequisites.

Firstly, I am assuming that you have knowledge of Azure DevOps. These are the parts that already need be setup:

In addition, if you don’t have knowledge about Azure DevOps and still want to follow this series please let me know. I might write a blog about the preparing Azure DevOps.

Checkout/Skip to the other parts

0. Windows 10 Image Series – Part 0 (Preparing Azure/Azure DevOps)

2. Windows 10 Image Series – Part 2 (Artifacts & Application Installation)

3. Windows 10 Image Series – Part 3 (Shared Image Gallery)

3.1 Windows 10 Image Series – Part 3.1 (Create test VM from Shared Image Gallery)

4. Windows 10 Image Series – Part 4 (SessionHost Deployment from Image)

5. Windows 10 Image Series – Part 5 (Convert the Image Build pipeline to YAML)

6. Windows 10 Image Series – Part 6 (Deploy Sessionhosts with Bicep and YAML)

Building the Windows 10 Image Pipeline

The pipeline consist of 3 parts:

  • Building a Windows 10 machine using an ARM Template
  • Sysprepping the Windows 10 machine that was just created
  • Creating an image from the just created machine

We are starting with creating the pipeline.

Creating the pipeline

Firstly, log on to the Azure portal.

After that, create a resource group, for example:

  • RG_WE_GoldenImage_WVD

This resourcegroup is for storing the Windows 10 images.

Windows 10 Image Series - Part 1 - Resource Group

Log on to Azure DevOps.

After that, go to your repository and add a new folder:

Windows 10 Image Series - Part 1 - Creating the pipeline

Call the folder ARM templates and put the following file in the folder:

  • Windows10Template.json

Furthermore, you can find this file in my github. Your repo should look like this:

This ARM Template build the Windows 10 Virtual Machine.

Now go to pipelines:

Windows 10 Image Series - Part 1 - Creating the pipeline add

Create a new pipeline:

Windows 10 Image Series - Part 1 - adding the pipeline

Pick “Use the classic editor”:

Windows 10 Image Series - Part 1 - Classic git repo

Select your repository where you have put the ARM Template folder and file:

Windows 10 Image Series - Part 1 - Selecting a source

Lastly, start with an “Empty Job”:

Windows 10 Image Series - Part 1 - Selecting empty job

Name the pipeline and select your agent pool:

Windows 10 Image Series - Part 1 - Naming pipeline and agents

Click on save:

saving  Azure pipeline

The pipeline for Windows 10 Image Series – Part 1 has been created! Let’s go on to the next chapter.

Variable Groups

Next, go to “Library” in the pipelines section:

We are now going to create a variable group where we specify our variables for our build later on. That makes it easier to use the same variables through different scripts and templates.

Please click on “+ Variable Group”:

Name it and add the following variables:

ImageName –> Windows10Image_$(Build.DefinitionName)_$(Build.BuildId) – This is name that the image is going to have
ImageRGName –> RG_WE_GoldenImage_WVD – ResourceGroup where the image is going to land
Location –> WestEurope – Location for all the builds
RGName –> RG_WE_Win10ImageBuild_Temp – Resource Group where the VM is going to build and deleted afterwards
Subnet –> WVD-Build – Subnet where the VM is going to be build in
VMName –> Windows10VM_$(Build.DefinitionName)_$(Build.BuildId) – Generic Name for the VM
VNetResourceID –> Put the resource id of your VNET here

After that, click on save!

Next up, go to your Azure Key Vault in the Azure Portal. For example:

Add a secret to this key vault:

Name it: LocalAdminPassword and put a generated password in here:

Go back to Azure DevOps, pipelines, library and add a new variable group:

Name the variable group,

Choose “Link secret from an Azure Key vault as variables”

Pick your service connection and vault

Lastly, add the variables:

Go back to your azure pipeline:

Edit the pipeline:

Click on variables:

And link both variable groups to the pipeline:

This is what it should look like after that:

Filling the pipeline with jobs

It is now time to fill the pipeline with the jobs that handle these tasks:

  • Building a Windows 10 machine using an ARM Template
  • Sysprepping the Windows 10 machine that was just created
  • Creating an image from the just created machine
Building a Windows 10 machine using an ARM Template

Firstly, add the ARM Template job by clicking on this icon:

Adding pipeline jobs

After that, search for “ARM Template deployment” and click on add:

Windows 10 Image Series - Part 1 - Add ARM templatejob

Rename the task and select the deployment scope:

After that, select the “Azure Resource Manager Connection”, “Subscription” and “Action”:

Next, enter a Resource Group name and a location. NOTE: The Resource Group should not exist! This will be automatically cleaned up when the machine has been converted to an image.

It is now time to pick the ARM template to deploy the Windows 10 VM.

Firstly, select “Linked Artifact”:

At the template section select the ARM template we added earlier on in the process. The Windows10template.json file:

Now click on “Override Template Parameters” and make sure to add the following parameters from the variable group created earlier:

Sysprepping the Windows 10 machine that was just created

Add a second job and search for Azure CLI:

Name the task, choos a resource manager connection, script type and a script location:

After that, put the following script in the “Inline Script section”:

$FileUri = "https://raw.githubusercontent.com/Ruthhl3ss/public/main/AzureVMExtensions/SysPrepScript.ps1"

Set-AzVMCustomScriptExtension -ResourceGroupName $(RGName) -VMName $(VMName) -Location $(Location) -FileUri $FileUri -Run 'SysPrepScript.ps1' -Name SysPrep

Get-AzVMExtension -ResourceGroupName $(RGName) -VMName $(VMName) | where {$_.ExtensionType -eq "CustomScriptExtension"} | Remove-AzVMExtension -Force

This script downloads a sysprep script from my github repository and applies it to the VM. If you are not comfortable using this public script you can also put the sysprep script in a storage account (more information).

Afterwards the ‘CustomScriptExtension’ is removed so you can apply another one later on if you want to.

After this step the VM is sysprepped and ready to be captured.

Creating an image from the just created machine

Add another Azure CLI Job to the pipeline:

Name the task, choos a resource manager connection, script type and a script location:

After that, put the following script in the “Inline Script section”:

#  Capture Image

$vmName = '$(VMName)'
$rgName = '$(RGName)'
$location = '$(Location)'
$imageName = '$(ImageName)'
$ImagergName = '$(ImageRGName)'


$VMStatus = Get-AzVM -ResourceGroupName $rgName -Name $vmName -Status

if ($VMStatus.Statuses[1].DisplayStatus -eq 'VM Running') {
    
    Write-Host 'VM is Running and will be turned off'

    Stop-AzVM -ResourceGroupName $rgName -Name $vmName -Force    

    Set-AzVm -ResourceGroupName $rgName -Name $vmName -Generalized

    $vm = Get-AzVM -Name $vmName -ResourceGroupName $rgName

    $ImageConfiguration = New-AzImageConfig -Location $location -SourceVirtualMachineId $vm.Id

    New-AzImage -Image $ImageConfiguration -ImageName $imageName -ResourceGroupName $ImagergName

}
else {
    Write-Host 'VM is not running, capturing image will start immediatly'

    Set-AzVm -ResourceGroupName $rgName -Name $vmName -Generalized

    $vm = Get-AzVM -Name $vmName -ResourceGroupName $rgName

    $ImageConfiguration = New-AzImageConfig -Location $location -SourceVirtualMachineId $vm.Id

    New-AzImage -Image $ImageConfiguration -ImageName $imageName -ResourceGroupName $ImagergName
}

## Removing VM  Resource Group
$ExistingImages = Get-AzResource -ResourceGroupName $ImagergName | Where-Object ResourceType -eq 'Microsoft.Compute/images'

if ($ExistingImages.Name -contains $imageName) {
    
    Remove-AzResourceGroup -Name $rgName -Force

}

This script turns the VM off if it is running and creates a managed image from it. After that, the resource group where the VM was build is removed by this script.

Run the Pipeline

When you are finished creating the pipeline you can click on queue:

The pipeline will start creating the job:

This is the temporary resource group:

These are the temporary resources:

And last but not least there is the image being created:

And the resource group has been removed!

This was Windows 10 Image Series – Part 1, check out the other parts:

0. Windows 10 Image Series – Part 0 (Preparing Azure/Azure DevOps)

2. Windows 10 Image Series – Part 2 (Artifacts & Application Installation)

3. Windows 10 Image Series – Part 3 (Shared Image Gallery)

3.1 Windows 10 Image Series – Part 3.1 (Create test VM from Shared Image Gallery)

4. Windows 10 Image Series – Part 4 (SessionHost Deployment from Image)

5. Windows 10 Image Series – Part 5 (Convert the Image Build pipeline to YAML)

6. Windows 10 Image Series – Part 6 (Deploy Sessionhosts with Bicep and YAML)

Windows 10 Image Series

References

Other posts:

Autopilot Device info menu script
Powershell function for creating Hostpools

References
Microsoft Docs about AZExtensions

69 thoughts on “Windows 10 Image Series – Part 1 – Create The VM”

  1. Great post. I am on the path of learning Azure DevOps and pipelines so if your able to do the prep Azure DevOps article I certainly be interested in viewing it!

    Reply
  2. hi Niels,
    Great ready i want to setup a pipeline on my sub am on step “Name the pipeline and select your agent pool:”
    the Agent pool you did make NOK Agents, I don’t have that option did mist a step ?

    Reply
  3. Hello Niels,

    Thanks for part 0, it helped a lot. Now I am stuck in building the image from part 1. On the Windows Server that is used as the Agent I needed to install Azure CLI and Az (powershell).

    The first part works creating the VM, but the Azure CLI keeps failing with these errors:

    ##
    Set-AzVMCustomScriptExtension : No subscription found in the context. Please ensure that the credentials you provided
    ##

    I have a clean Azure VM as agent (PAT) without any previous logged in Az sessions so that cannot be the problem.

    Hope you can point me in the right direction!

    Thx
    Stefan

    ### ERRORS ###
    C:\Windows\system32\cmd.exe /D /S /C “”C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd” account set –subscription 5cbcb620-6216-432c-b48e-ed16e65c70a9″
    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command “. ‘C:\DevOps\_work\_temp\azureclitaskscript1630149469753.ps1′”
    Set-AzVMCustomScriptExtension : No subscription found in the context. Please ensure that the credentials you provided
    are authorized to access an Azure subscription, then run Connect-AzAccount to login.
    At C:\DevOps\_work\_temp\azureclitaskscript1630149469753_inlinescript.ps1:3 char:1
    + Set-AzVMCustomScriptExtension -ResourceGroupName RG_WE_Win10ImageBuil …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : CloseError: (:) [Set-AzVMCustomScriptExtension], AzPSApplicationException
    + FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.SetAzureVMCustomScriptExtensionCommand

    ##[error]Script failed with exit code: 1
    C:\Windows\system32\cmd.exe /D /S /C “”C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd” account clear”

    Reply
    • Hi Stefan,

      Thanks for reading my blog and trying it for yourself. On which part does the pipeline fail? On the sysprep script or? The error that you are getting states that your Az CLI session has no context. That means that you need to select a subscription prior to running the script. This should be handeld by the Azure DevOps Pipeline task when selecting your service connection. Could you please state at which step you are getting this error?

      Thanks,

      Niels

      Reply
      • Hi Niels,

        I’m receiving the same error with the SysPrep task. The strange thing is that the connection to the tenant is present in the task. Do you know a solution to fix this?

        Thanks,
        Mark

        Reply
        • Yeah, that is strange.

          Does your Service Principal have Owner permissions or contributor permissions?

          You could add an addition authentication step in the inline script section to make sure you are connected with the proper permissions and selected the proper permissions. This sometimes works for me. After that the script is able to run. I don’t know why that is the case. I need to do some further investigation on this part.

          The additional authentication step in powershell is:

          $secret = ConvertTo-SecureString -String (YOUR SECRET for your Service Principal) -AsPlainText -Force
          $username = (App ID for your Service Principal)
          $Credential = New-Object -TypeName “System.Management.Automation.PSCredential” -ArgumentList $username, $secret
          Connect-AzAccount -Credential $Credential -Tenant <> -ServicePrincipal
          Start-Sleep 5
          Select-AzSubscription -SubscriptionId <> | Set-AzContext

          I will investigate this further. Thanks for letting me know.

          Niels

          Reply
          • Hi Niels,

            The Service Principal has Owner permissions on the subscription.

            I have implemented your suggestion about the authentication step and that worked once.
            At the moment i’m still using the buildin agent pool, so maybe that has something to do with that. The job will timeout around 60 minutes.

            I did found another workaround yesterday and that was using azure cli:

            $customScriptUri = “https://raw.githubusercontent.com/Ruthhl3ss/public/main/AzureVMExtensions/SysPrepScript.ps1″
            $customScriptSettings=”{`\`”fileUris`\`”:[`\`”$customScriptUri`\`”], `\`”commandToExecute`\`”:`\`”powershell.exe ./SysPrepScript.ps1`\`”}”

            az vm extension set `
            –name CustomScriptExtension `
            –publisher Microsoft.Compute `
            –vm-name $(VMName) `
            –resource-group $(RGName) `
            –settings $customScriptSettings

            Also the CaptureImage task needs the authentication part to be successfull. I needed to install the correct PowerShell Modules because some Modules aren’t loaded by default.
            But the task didn’t need a rebuild to azure cli commands.

            Mark

          • Hello Niel,

            You are correct it is in the Azure CLI part, your extra lines of PowerShell fixed the problem. The sysprep script now runs without error.

            Unfortunately the next script “Azure CLI – Capture Image” fails with a strange error:
            2021-09-04T20:55:50.4587841Z
            2021-09-04T20:55:51.4822694Z Windows10VM_WVDImageBuild_30 : The term ‘Windows10VM_WVDImageBuild_30’ is not recognized as the name of a cmdlet,
            2021-09-04T20:55:51.4823675Z function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the
            2021-09-04T20:55:51.4824275Z path is correct and try again.
            2021-09-04T20:55:51.4824981Z At C:\DevOps\_work\_temp\azureclitaskscript1630788938020_inlinescript.ps1:9 char:11
            2021-09-04T20:55:51.4825605Z + $vmName = Windows10VM_WVDImageBuild_30
            2021-09-04T20:55:51.4826099Z + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            2021-09-04T20:55:51.4827213Z + CategoryInfo : ObjectNotFound: (Windows10VM_WVDImageBuild_30:String) [], ParentContainsErrorRecordExcep
            2021-09-04T20:55:51.4828175Z tion
            2021-09-04T20:55:51.4831565Z + FullyQualifiedErrorId : CommandNotFoundException
            2021-09-04T20:55:51.4832877Z
            2021-09-04T20:55:51.5275943Z ##[error]Script failed with exit code: 1

            It is complaining about this line in the inline script (line 9):
            $vmName = $(VMName)

            Also I head to remove all the “&nbsp;=&nbsp;” from this script, else it wouldn’t run at all.

            Hope you can help me with the last part!

            Thx
            Stefan

          • Hello Niels,

            Sorry my previous post was full of typos 🙂

            You are correct it is in the Azure CLI part, your extra lines of PowerShell fixed the problem. The sysprep script now runs without error.

            Unfortunately the next script “Azure CLI – Capture Image” fails with a strange error:
            2021-09-04T20:55:50.4587841Z
            2021-09-04T20:55:51.4822694Z Windows10VM_WVDImageBuild_30 : The term ‘Windows10VM_WVDImageBuild_30’ is not recognized as the name of a cmdlet,
            2021-09-04T20:55:51.4823675Z function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the
            2021-09-04T20:55:51.4824275Z path is correct and try again.
            2021-09-04T20:55:51.4824981Z At C:\DevOps\_work\_temp\azureclitaskscript1630788938020_inlinescript.ps1:9 char:11
            2021-09-04T20:55:51.4825605Z + $vmName = Windows10VM_WVDImageBuild_30
            2021-09-04T20:55:51.4826099Z + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            2021-09-04T20:55:51.4827213Z + CategoryInfo : ObjectNotFound: (Windows10VM_WVDImageBuild_30:String) [], ParentContainsErrorRecordExcep
            2021-09-04T20:55:51.4828175Z tion
            2021-09-04T20:55:51.4831565Z + FullyQualifiedErrorId : CommandNotFoundException
            2021-09-04T20:55:51.4832877Z
            2021-09-04T20:55:51.5275943Z ##[error]Script failed with exit code: 1

            It is complaining about this line in the inline script (line 9):
            $vmName = $(VMName)

            Also I had to remove all the “ = ” from this script, else it wouldn’t run at all.

            Update; Fixed it:
            $vmName = $(VMName) <—- wrong.
            the ' where lost in copy/paste and removing the " = "
            $vmName = '$(VMName)' <—- correct.

            Last part now fixed, mayby you can put the scripts on github for download, that save some copy/past errors perhaps.

            Thx
            Stefan

  4. Hi Niel

    QQ not sure where to get this
    VNetResourceID –> Put the resource id of your VNET here
    As in the RG i did created any event as I did see any step to do so

    Reply
    • Hi Roni,

      I assumed that you already have a VNet available in your Azure subscription. If this is not the case, please create one. In the properties blade of the VNet, you can find the resource ID. Please use this value as requested.

      I will put this in the prerequisites.

      Niels

      Reply
      • i created i vnet in the RG_WE_goldennimage_WVD RG
        add the vnet id to the liberty but now

        2021-09-03T08:25:40.2525238Z There were errors in your deployment. Error code: DeploymentFailed.
        2021-09-03T08:25:40.2555353Z ##[error]At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.
        2021-09-03T08:25:40.2567810Z ##[error]Details:
        2021-09-03T08:25:40.2574886Z ##[error]LinkedInvalidPropertyId: Property id ‘$)VNetResourceID)/subnets/WVD-Build’ at path ‘properties.ipConfigurations[0].properties.subnet.id’ is invalid. Expect fully qualified resource Id that start with ‘/subscriptions/{subscriptionId}’ or ‘/providers/{resourceProviderNamespace}/’.

        Reply
          • Hi Niels

            just that one

            Set-AzVMCustomScriptExtension : The term ‘Set-AzVMCustomScriptExtension’ is not recognized as the name of a cmdlet,
            function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the
            path is correct and try again.
            At C:\Agents\_work\_temp\azureclitaskscript1630660070868_inlinescript.ps1:3 char:1
            + Set-AzVMCustomScriptExtension -ResourceGroupName RG_WE_Win10ImageBuil …
            + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            + CategoryInfo : ObjectNotFound: (Set-AzVMCustomScriptExtension:String) [], ParentContainsErrorRecordExce
            ption
            + FullyQualifiedErrorId : CommandNotFoundException

            ##[error]Script failed with exit code: 1
            C:\Windows\system32\cmd.exe /D /S /C “”C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd” account clea

  5. Hi Niels
    when i try to do Choose “Link secret from an Azure Key vault as variables”
    i get
    Specified Azure service connection needs to have “Get, List” secret management permissions on the selected key vault. Set these secret permissions in Azure portal or run the following commands in powershell window.

    Reply
  6. sorry again me when i run the pipline i get
    ##[error]Deployment template validation failed: ‘The value for the template parameter ‘virtualNetworkId’ at line ‘1’ and column ‘337’ is not provided

    what step did I miss?

    Reply
  7. sorry to be a pain 🙂

    Set-AzVMCustomScriptExtension : The term ‘Set-AzVMCustomScriptExtension’ is not recognized as the name of a cmdlet,
    function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the
    path is correct and try again.
    At C:\Agents\_work\_temp\azureclitaskscript1630660070868_inlinescript.ps1:3 char:1
    + Set-AzVMCustomScriptExtension -ResourceGroupName RG_WE_Win10ImageBuil …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (Set-AzVMCustomScriptExtension:String) [], ParentContainsErrorRecordExce
    ption
    + FullyQualifiedErrorId : CommandNotFoundException

    ##[error]Script failed with exit code: 1
    C:\Windows\system32\cmd.exe /D /S /C “”C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd” account clea

    Reply
  8. hi

    Am still stuck on
    Set-AzVMCustomScriptExtension : The term ‘Set-AzVMCustomScriptExtension’ is not recognized as the name of a cmdlet,

    in the sysprem task could any one help? what did I miss ?

    Reply
      • hi Niels

        yes I did install them on the VM that I use to run the agent
        I did all the steps in the post but I get this error.:(

        In part 0 I did see that as a reqieremnt

        Reply
        • Hi Dave,

          At the end of the post, it is a pipeline. You can also check out the Packer YAML series which is a lot easier.

          Thanks,
          Niels

          Reply
          • Hi Niels
            Thanks I will check that one. I have an error on this one. I created an extra azure powershell step because I got an error on the Set-AzVMCustomScriptExtension. Now I have this. Can you help.
            My pipeline is now
            Arm template deployment
            Azure PowerShell V5 (install module az.compute and import it )
            azure cli sys prep
            azure cli – capture image

            C:\Windows\system32\cmd.exe /D /S /C “”C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd” account set –subscription 20b6fe01-31f4-489b-ac13-f25e7fd83c68″
            C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command “. ‘D:\a\_temp\azureclitaskscript1652728818980.ps1′”
            C:\Program Files\WindowsPowerShell\Modules\Az.Compute\4.26.0\Compute.Autorest\Az.Compute.psm1 :
            This module requires Az.Accounts version 2.2.3 or greater. For installation instructions, please see:
            https://docs.microsoft.com/powershell/azure/install-az-ps
            At D:\a\_temp\azureclitaskscript1652728818976_inlinescript.ps1:3 char:1
            + Import-Module Az.Compute
            + ~~~~~~~~~~~~~~~~~~~~~~~~
            + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
            + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Az.Compute.psm1

            ##[error]Script failed with exit code: 1
            C:\Windows\system32\cmd.exe /D /S /C “”C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin\az.cmd” account clear”
            Finishing: Azure CLI – Sysprep

          • Hi Dave,

            You need to update or install Azure CLI on the machine where the script is running.

            If you have more questions, don’t hesitate to ask.

            Thanks,
            Niels

  9. Hi Niels
    I did recreated all and now i get

    Set-AzVMCustomScriptExtension : The Resource ‘Microsoft.Compute/virtualMachines/Windows10VM_WVDImageBuilder_8’ under re
    source group ‘RG_WE_Win10ImageBuild_Temp’ was not found. For more details please go to https://aka.ms/ARMResourceNotFou
    ndFix
    ErrorCode: ResourceNotFound
    ErrorMessage: The Resource ‘Microsoft.Compute/virtualMachines/Windows10VM_WVDImageBuilder_8’ under resource group ‘RG_W
    E_Win10ImageBuild_Temp’ was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix

    I see that the machines NIc are created in RG_WE_GoldenImage_WVD and in RG_WE_GoldenImage_WVD_temp and RG_WE_GoldenImage_WVD_teamp is not created.
    I did look over all the step I done see that did a wrong any ideas?

    thank you

    Reply
    • Hi Roni.

      Did you properly name this variable:

      VMName –> Windows10VM_$(Build.DefinitionName)_$(Build.BuildId) – Generic Name for the VM

      What is the Virtual Machine name of the VM in the Azure Resource Group?

      This should equal:

      Windows10VM_$(Build.DefinitionName)_$(Build.BuildId)

      Goodluck!

      Niels

      Reply
      • Hi Niels

        yes the property are correct set

        the VM name is Windows10VM_WVDImageBuilder_9 its in RG_WE_GoldenImage_WVD
        after the syspre try to find in RG_WE_GoldenImage_WVD_temp
        ErrorMessage: The Resource ‘Microsoft.Compute/virtualMachines/Windows10VM_WVDImageBuilder_9’ under resource group ‘RG_W
        E_Win10ImageBuild_Temp’ was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix
        ErrorTarget:
        StatusCode: 404

        Reply
    • I think it the bast post about packer and I want to learn it,

      I hope the last issue 🙂

      in the image capture i get

      Unexpected token ‘&’ in expression or statement.
      At C:\packer\_work\_temp\azureclitaskscript1632924474235_inlinescript.ps1:3 char:19
      + $vmName&nbsp;=&nbsp;’Windows10VM_WVDImageBuilder_13′
      The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quot
      ation marks (“&”) to pass it as part of a string.
      At C:\packer\_work\_temp\azureclitaskscript1632924474235_inlinescript.ps1:4 char:8
      + $rgName&nbsp;=&nbsp;’RG_WE_Win10ImageBuild_Temp’

      Reply
      • hi Niels

        the fun never stops is did copy the code for your blog but I get this in the image capture

        At C:\packer\_work\_temp\azureclitaskscript1632994667955_inlinescript.ps1:3 char:8
        + $vmName&nbsp;=&nbsp;’Windows10VM_WVDImageBuilder_17′
        + ~
        Unexpected token ‘&’ in expression or statement.
        At C:\packer\_work\_temp\azureclitaskscript1632994667955_inlinescript.ps1:3 char:19
        + $vmName&nbsp;=&nbsp;’Windows10VM_WVDImageBuilder_17′
        + ~
        The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quot
        ation marks (“&”) to pass it as part of a string.
        At C:\packer\_work\_temp\azureclitaskscript1632994667955_inlinescript.ps1:4 char:8
        + $rgName&nbsp;=&nbsp;’RG_WE_Win10ImageBuild_Temp’

        Reply
          • no

            just that code

            #&nbsp;&nbsp;Capture&nbsp;Image

            $vmName&nbsp;=&nbsp;’$(VMName)’
            $rgName&nbsp;=&nbsp;’$(RGName)’
            $location&nbsp;=&nbsp;’$(Location)’
            $imageName&nbsp;=&nbsp;’$(ImageName)’
            $ImagergName&nbsp;=&nbsp;’$(ImageRGName)’

            $VMStatus&nbsp;=&nbsp;Get-AzVM&nbsp;-ResourceGroupName&nbsp;$rgName&nbsp;-Name&nbsp;$vmName&nbsp;-Status

            if&nbsp;($VMStatus.Statuses[1].DisplayStatus&nbsp;-eq&nbsp;’VM&nbsp;Running’)&nbsp;{
            &nbsp;&nbsp;&nbsp;&nbsp;
            &nbsp;&nbsp;&nbsp;&nbsp;Write-Host&nbsp;’VM&nbsp;is&nbsp;Running&nbsp;and&nbsp;will&nbsp;be&nbsp;turned&nbsp;off’

            &nbsp;&nbsp;&nbsp;&nbsp;Stop-AzVM&nbsp;-ResourceGroupName&nbsp;$rgName&nbsp;-Name&nbsp;$vmName&nbsp;-Force&nbsp;&nbsp;&nbsp;&nbsp;

            &nbsp;&nbsp;&nbsp;&nbsp;Set-AzVm&nbsp;-ResourceGroupName&nbsp;$rgName&nbsp;-Name&nbsp;$vmName&nbsp;-Generalized

            &nbsp;&nbsp;&nbsp;&nbsp;$vm&nbsp;=&nbsp;Get-AzVM&nbsp;-Name&nbsp;$vmName&nbsp;-ResourceGroupName&nbsp;$rgName

            &nbsp;&nbsp;&nbsp;&nbsp;$ImageConfiguration&nbsp;=&nbsp;New-AzImageConfig&nbsp;-Location&nbsp;$location&nbsp;-SourceVirtualMachineId&nbsp;$vm.Id

            &nbsp;&nbsp;&nbsp;&nbsp;New-AzImage&nbsp;-Image&nbsp;$ImageConfiguration&nbsp;-ImageName&nbsp;$imageName&nbsp;-ResourceGroupName&nbsp;$ImagergName

            }
            else&nbsp;{
            &nbsp;&nbsp;&nbsp;&nbsp;Write-Host&nbsp;’VM&nbsp;is&nbsp;not&nbsp;running,&nbsp;capturing&nbsp;image&nbsp;will&nbsp;start&nbsp;immediatly’

            &nbsp;&nbsp;&nbsp;&nbsp;Set-AzVm&nbsp;-ResourceGroupName&nbsp;$rgName&nbsp;-Name&nbsp;$vmName&nbsp;-Generalized

            &nbsp;&nbsp;&nbsp;&nbsp;$vm&nbsp;=&nbsp;Get-AzVM&nbsp;-Name&nbsp;$vmName&nbsp;-ResourceGroupName&nbsp;$rgName

            &nbsp;&nbsp;&nbsp;&nbsp;$ImageConfiguration&nbsp;=&nbsp;New-AzImageConfig&nbsp;-Location&nbsp;$location&nbsp;-SourceVirtualMachineId&nbsp;$vm.Id

            &nbsp;&nbsp;&nbsp;&nbsp;New-AzImage&nbsp;-Image&nbsp;$ImageConfiguration&nbsp;-ImageName&nbsp;$imageName&nbsp;-ResourceGroupName&nbsp;$ImagergName
            }

            ##&nbsp;Removing&nbsp;VM&nbsp;&nbsp;Resource&nbsp;Group
            $ExistingImages&nbsp;=&nbsp;Get-AzResource&nbsp;-ResourceGroupName&nbsp;$ImagergName&nbsp;|&nbsp;Where-Object&nbsp;ResourceType&nbsp;-eq&nbsp;’Microsoft.Compute/images’

            if&nbsp;($ExistingImages.Name&nbsp;-contains&nbsp;$imageName)&nbsp;{
            &nbsp;&nbsp;&nbsp;&nbsp;
            &nbsp;&nbsp;&nbsp;&nbsp;Remove-AzResourceGroup&nbsp;-Name&nbsp;$rgName&nbsp;-Force

            }

  10. ok it works but i need to edit your code

    that’s the code that works for me I this some did wrong past in the blog post

    # Capture Image

    $vmName = ‘$(VMName)’
    $rgName = ‘$(RGName)’
    $location = ‘$(Location)’
    $imageName = ‘$(ImageName)’
    $ImagergName = ‘$(ImageRGName)’

    $VMStatus = Get-AzVM -ResourceGroupName $rgName -Name $vmName -Status

    if ($VMStatus.Statuses[1].DisplayStatus -eq ‘VM Running’) {

    Write-Host ‘VM is Running and will be turned off’

    Stop-AzVM -ResourceGroupName $rgName -Name $vmName -Force

    Set-AzVm -ResourceGroupName $rgName -Name $vmName -Generalized

    $vm = Get-AzVM -Name $vmName -ResourceGroupName $rgName

    $ImageConfiguration = New-AzImageConfig -Location $location -SourceVirtualMachineId $vm.Id

    New-AzImage -Image $ImageConfiguration -ImageName $imageName -ResourceGroupName $ImagergName

    }
    else {
    Write-Host ‘VM is not running, capturing image will start immediatly’

    Set-AzVm -ResourceGroupName $rgName -Name $vmName -Generalized

    $vm = Get-AzVM -Name $vmName -ResourceGroupName $rgName

    $ImageConfiguration = New-AzImageConfig -Location $location -SourceVirtualMachineId $vm.Id

    New-AzImage -Image $ImageConfiguration -ImageName $imageName -ResourceGroupName $ImagergName
    }

    ## Removing VM Resource Group
    $ExistingImages = Get-AzResource -ResourceGroupName $ImagergName | Where-Object ResourceType -eq ‘Microsoft.Compute/images’

    if ($ExistingImages.Name -contains $imageName) {

    Remove-AzResourceGroup -Name $rgName -Force

    }

    Reply
    • Hi Roni,

      Thanks for the update. The WordPress plugin does something strange with the code snippets. I have updated the code.

      Thanks,

      Niels

      Reply
  11. Hi Niels,
    I am also getting the following error:
    Set-AzVMCustomScriptExtension : The term ‘Set-AzVMCustomScriptExtension’ is not recognized as the name of a cmdlet
    I have configured the self hosted agent and installed AZURE CLI
    https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli
    And installed the the AZ module for All users
    Install-Module -Name Az -Scope AllUsers -Repository PSGallery -Force
    On the self hosted agent server I can connect to the az account and run az commands:
    PS C:\windows\system32> Get-AzVMExtension
    cmdlet Get-AzVMExtension at command pipeline position 1
    Supply values for the following parameters:
    (Type !? for Help.)
    ResourceGroupName:
    I have restarted the server and tried reinstalling the modules. Do you know what I overlooked? Alvast bedankt!

    Reply
    • Hi Dirk,

      I am a little confused, why don’t you test the set-azvmcustomscriptextension on the agent?

      Furthermore, I currently like the packer approach. You can check out these in blogs also!

      Thanks,
      Niels

      Reply

Leave a Comment