Help with WinRM timeout issue

Hey guys, racking my brain trying to work out why my packer build is timing out at the winrm step, here is my HCL file config:

packer {

required_plugins {

azure = {

  version = ">= 2.0.0"

  source  = "github.com/hashicorp/azure"

}

}

}

source “azure-arm” “autogenerated_1” {

azure_tags = {

dept       = "Build"

task       = "Image deployment"

created-by = "Packer" 

OS_Version = "Windows 2019"

Release    = "Latest"

}

# Azure Details

build_resource_group_name = “RESOURCE NAME”

client_id = “ID”

client_secret = “SECRET”

subscription_id = “SUB”

tenant_id = “TENANT”

vm_size = “Standard_D2_v2”

# Source Image Details

os_type = “Windows”

image_offer = “WindowsServer”

image_publisher = “MicrosoftWindowsServer”

image_sku = “2019-Datacenter”

# Managed Image Details

managed_image_name = “Win-2019-{{timestamp}}”

managed_image_resource_group_name = “RESOURCE GROUP”

# Network Settings

virtual_network_name = “VNET”

virtual_network_resource_group_name = “VNET_GROUP”

virtual_network_subnet_name = “SUBNET”

# Communicator Settings

communicator = “winrm”

winrm_insecure = true

winrm_timeout = “30m”

winrm_use_ssl = true

winrm_username = “packer”

winrm_password = “ComplexP@ssw0rd123!” "#This is an example#

custom_data = base64encode(<<-EOF

<powershell>

\# Configure WinRM

Write-Host "Configuring WinRM..."



\# Create self-signed certificate for HTTPS

$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:\\LocalMachine\\My

$thumbprint = $cert.Thumbprint



\# Configure WinRM HTTPS listener

winrm create winrm/config/Listener?Address=\*+Transport=HTTPS "@{Hostname=\`"$env:COMPUTERNAME\`"; CertificateThumbprint=\`"$thumbprint\`"}"



\# Configure WinRM service

winrm set winrm/config/service '@{AllowUnencrypted="false"}'

winrm set winrm/config/service/auth '@{Basic="true"}'

winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="2048"}'



\# Configure firewall

New-NetFirewallRule -DisplayName "WinRM HTTPS" -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow



\# Restart WinRM service

Restart-Service WinRM

</powershell>

EOF

)

}

build {

sources = [“source.azure-arm.autogenerated_1”]

provisioner “powershell” {

inline = \[

  "Write-Host 'Installing IIS...'",

  "Add-WindowsFeature Web-Server",

  "Write-Host 'Waiting for Azure services...'",

  "while ((Get-Service RdAgent -ErrorAction SilentlyContinue).Status -ne 'Running') { Start-Sleep -s 5 }",

  "while ((Get-Service WindowsAzureGuestAgent -ErrorAction SilentlyContinue).Status -ne 'Running') { Start-Sleep -s 5 }"

\]

}

provisioner “powershell” {

inline = \[

  "Write-Host 'Running Sysprep...'",

  "& $env:SystemRoot\\\\System32\\\\Sysprep\\\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm",

  "while($true) { $imageState = Get-ItemProperty HKLM:\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Setup\\\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10 } else { break } }"

\]

}

}

The output get to just Waiting for VM to respond via WinRM. I have also tried via SSH, tried with and without SSL.

I tried with the “Administrator” account but that’s the default admin and can’t be used. Going to have gone grey at the end of this project.

Any insights would be greatly appreciated..

Does it work fine with the default Administrator account?

No, I tried to configure the Administrator account and it error’d also.

I’m guessing the WinRM service isn’t configured or running properly to let packer connect later.

Could you try experimenting with the custom_data and refer this doc.

Also to ensure if the custom_data runs successfully, you can try to login into the VM and find the logs of this startup script to confirm no issues there.

1 Like

The VM cleans itself up and deletes itself at the end or when it’s cancelled.

Let me try play with the custom_data and revert.

Set the winrm_timeout to 1h to give yourself some time to debug.

If I try and use Administrator as the username, if fails with this error:

==> azure-arm.autogenerated_1: ERROR: → InvalidParameter : The Admin Username specified is not allowed. For more information about disallowed usernames, see Virtual Machines - Create Or Update - REST API (Azure Compute) | Microsoft Learn

Is the packer user created in the startup script? If no, then its probably why its failing.
You can try this.

# Create a new local administrator for Packer.
$username = “packer”
$password = ConvertTo-SecureString -String ‘password-here’ -AsPlainText -Force
New-LocalUser $username -Password $password -FullName “Packer User” -Description “Temporary user for Packer”
Add-LocalGroupMember -Group “Administrators” -Member $username

It looks like it’s having trouble with this part of the code:

provisioner “powershell” {

inline = \[

  "New-LocalUser -Name 'packer' -Password 'PASSWORD' -FullName 'Packer User' -Description 'User for Packer build'",

  "Add-LocalGroupMember -Group 'Administrators' -Member 'packer'",

  "Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope LocalMachine",

  "Write-Host 'Configuring WinRM...'",

  "winrm quickconfig -q",

  **"winrm set winrm/config/service '@{AllowUnencrypted=\\"true\\"}'",**

  **"winrm set winrm/config/service/auth '@{Basic=\\"true\\"}'",**

  "netsh advfirewall firewall add rule name =\\"WinRM-HTTP\\" dir=in action=allow protocol=TCP localport=5985",

  "netsh advfirewall firewall add rule name =\\"WinRM-HTTPS\\" dir=in action=allow protocol=TCP localport=5986",

  "Add-WindowsFeature Web-Server",

  "while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }",

  "while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }",

  "& $env:SystemRoot\\\\System32\\\\Sysprep\\\\Sysprep.exe /oobe /generalize /quiet /quit",

  "while($true) { $imageState = Get-ItemProperty HKLM:\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Setup\\\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10  } else { break } }"

\]

}

The AllowUnencrypted and Basic authentication are both false when the VM is built. Is there a better syntax to do this?

Create the user during the startup script i.e inside the custom_data . The WinRM setup should also be done there.

The provisioning will take place only when the initial handshake with the VM has been successful.

The user is being created and winrm set during the source part:

# Communicator Settings

communicator = “winrm”

winrm_insecure = true

winrm_timeout = “60m”

winrm_use_ssl = false

winrm_username = “Packer”

winrm_password = “PASSWORD”

winrm_port = “5985”

I don’t have a custom_data area setup in my config yet.

source, then build and then provisioner. Where should I slot the custom_data part in and how should that look as an example?

I can see this as part of your hcl file, here’s where the winrm setup and account creation should be done.

Yeah, found it, sorry, made so many adjustments, so something like this then?

custom_data = base64encode(<<-EOF

<powershell>

#Configure WinRM

Write-Host "Configuring WinRM..."



New-LocalUser -Name 'packer' -Password 'PASSWORD' -FullName 'Packer User' -Description 'User for Packer build'

Add-LocalGroupMember -Group 'Administrators' -Member 'packer'



#Configure WinRM HTTP listener

winrm create winrm/config/Listener?Address=\*+Transport=HTTP "@{Hostname=\`"$env:COMPUTERNAME\`"; CertificateThumbprint=\`"$thumbprint\`"}"



#Configure WinRM service

winrm quickconfig -q

winrm set winrm/config/service '@{AllowUnencrypted="true"}'

winrm set winrm/config/service/auth '@{Basic="true"}'

 

#Configure firewall

New-NetFirewallRule -DisplayName "WinRM HTTP" -Direction Inbound -Protocol TCP -LocalPort 5985 -Action Allow



#Restart WinRM service

Restart-Service WinRM

</powershell>

EOF

)