[
  {
    "path": ".devcontainer/Dockerfile",
    "content": "# syntax=docker.io/docker/dockerfile:1.23\n\n# see https://github.com/devcontainers/images/blob/main/src/base-debian/manifest.json\nFROM mcr.microsoft.com/devcontainers/base:2.1.7-trixie\n\nRUN <<'EOF'\n#!/usr/bin/bash\nset -euxo pipefail\nexport DEBIAN_FRONTEND=noninteractive\napt-get update\napt-get -y install --no-install-recommends \\\n    bash-completion \\\n    curl \\\n    git \\\n    openssh-client \\\n    pylint \\\n    python3-argcomplete \\\n    python3-openssl \\\n    python3-pip \\\n    python3-venv \\\n    python3-yaml \\\n    qemu-system-x86 \\\n    qemu-utils \\\n    sudo \\\n    unzip \\\n    wget\napt-get clean\nrm -rf /var/lib/apt/lists/*\nactivate-global-python-argcomplete\npython3 -m venv --system-site-packages /opt/venv\nEOF\nENV PATH=\"/opt/venv/bin:$PATH\"\n\n# disable the packer telemetry.\nENV CHECKPOINT_DISABLE=1\n\nRUN <<'EOF'\n#!/usr/bin/bash\nset -euxo pipefail\n# ensure /etc/profile is called at the top of the file, when running in a\n# login shell.\nsed -i '0,/esac/s/esac/&\\n\\nsource \\/etc\\/profile/' /home/vscode/.bashrc\nEOF\nCOPY .devcontainer/inputrc /etc/inputrc\nCOPY .devcontainer/login.sh /etc/profile.d/login.sh\n"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "{\n  \"name\": \"Packer\",\n  \"dockerFile\": \"Dockerfile\",\n  \"context\": \"..\",\n  \"runArgs\": [\n    \"--group-add=108\", // 108 is the id of the kvm group.\n    \"-v=${localEnv:HOME}/.ssh/id_rsa:/home/vscode/.ssh/id_rsa:ro\",\n    \"-v=${localEnv:HOME}/.ssh/id_rsa.pub:/home/vscode/.ssh/id_rsa.pub:ro\",\n    \"-v=${localEnv:HOME}/.vagrant.d:/home/vscode/.vagrant.d:ro\",\n    \"-v=/usr/share/ovmf:/usr/share/ovmf:ro\",\n    \"--device=/dev/kvm\"\n  ],\n  \"postCreateCommand\": \"bash .devcontainer/setup.sh\",\n  \"features\": {\n    \"ghcr.io/devcontainers/features/go:1\": {\n      \"version\": \"1.26.1\"\n    },\n    \"ghcr.io/devcontainers-extra/features/packer-asdf:2\": {\n      \"version\": \"1.15.1\"\n    }\n  },\n  \"customizations\": {\n    \"vscode\": {\n      \"extensions\": [\n        \"hashicorp.hcl\",\n        \"streetsidesoftware.code-spell-checker\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": ".devcontainer/inputrc",
    "content": "set input-meta on\nset output-meta on\nset show-all-if-ambiguous on\nset completion-ignore-case on\n\n\"\\e[A\": history-search-backward\n\"\\e[B\": history-search-forward\n\"\\eOD\": backward-word\n\"\\eOC\": forward-word\n"
  },
  {
    "path": ".devcontainer/login.sh",
    "content": "export EDITOR=code\nexport PAGER=less\n\nalias l='ls -lF --color'\nalias ll='l -a'\nalias h='history 25'\nalias j='jobs -l'\n"
  },
  {
    "path": ".devcontainer/setup.sh",
    "content": "#!/bin/bash\nset -euxo pipefail\n\npushd /home/vscode\nsudo chown vscode:vscode .ssh && sudo chmod 700 .ssh\npopd\n"
  },
  {
    "path": ".gitattributes",
    "content": "/update/*.ps1 -text\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\non: [push, pull_request]\njobs:\n  build:\n    name: Build\n    runs-on: windows-2022\n    steps:\n      - name: Configure git\n        run: git config --global core.autocrlf false\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-go@v6\n        with:\n          go-version: '1.26.1'\n      - name: Set up msys2\n        uses: msys2/setup-msys2@v2\n        with:\n          install: make tar zip unzip\n          path-type: inherit\n      - name: Import GPG key\n        id: import_gpg\n        uses: crazy-max/ghaction-import-gpg@v7\n        with:\n          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}\n          passphrase: ${{ secrets.GPG_PASSPHRASE }}\n      - name: Build\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}\n        run: msys2 ./ci-release.sh\n      - name: Archive\n        uses: actions/upload-artifact@v7\n        with:\n          name: artifacts\n          path: |\n            dist/\n            !dist/*/*\n"
  },
  {
    "path": ".gitignore",
    "content": "dist/\npacker-plugin-windows-update\npacker-plugin-windows-update.exe\ntmp*\n.idea/\noutput-*/\n*.log\n"
  },
  {
    "path": ".goreleaser.yml",
    "content": "version: 2\nbuilds:\n  - env:\n      - CGO_ENABLED=0\n    goos:\n      - linux\n      - darwin\n      - windows\n    goarch:\n      - amd64\n      - arm64\n    flags:\n      - -v\n      - -trimpath\n    ldflags:\n      - -s\n      - -w\n      - -X main.version={{ .Version }}\n      - -X main.commit={{ .Commit }}\n      - -X main.date={{ .CommitDate }}\n    mod_timestamp: '{{ .CommitTimestamp }}'\n    binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}'\nchangelog:\n  sort: asc\n  filters:\n    exclude:\n      - '^docs:'\n      - '^test:'\nsnapshot:\n  version_template: '{{ .Version }}-SNAPSHOT-{{ .ShortCommit }}'\nrelease:\n  draft: true\n  prerelease: auto\narchives:\n  - formats:\n      - zip\n    name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}'\nchecksum:\n  name_template: '{{ .ProjectName }}_v{{ .Version }}_SHA256SUMS'\n  algorithm: sha256\nsigns:\n  - artifacts: checksum\n    args:\n      - --batch\n      - --local-user\n      - \"{{ .Env.GPG_FINGERPRINT }}\"\n      - --output\n      - ${signature}\n      - --detach-sign\n      - ${artifact}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"cSpell.words\": [\n        \"devcontainers\"\n    ]\n}"
  },
  {
    "path": "LICENSE.txt",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in\n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "Makefile",
    "content": "GOPATH := $(shell go env GOPATH | tr '\\\\' '/')\nGOEXE := $(shell go env GOEXE)\nGOHOSTOS := $(shell go env GOHOSTOS)\nGOHOSTARCH := $(shell go env GOHOSTARCH)\nGOHOSTARCHVERSION := $(shell go env \"GO$(shell go env GOHOSTARCH | tr '[:lower:]' '[:upper:]')\")\nGORELEASER := $(GOPATH)/bin/goreleaser\nSOURCE_FILES := *.go update/* update/provisioner.hcl2spec.go\nPLUGIN_PATH := dist/packer-plugin-windows-update_$(GOHOSTOS)_$(GOHOSTARCH)_$(GOHOSTARCHVERSION)/packer-plugin-windows-update_*_$(GOHOSTOS)_$(GOHOSTARCH)$(GOEXE)\n\n# see https://github.com/goreleaser/goreleaser\n# renovate: datasource=github-releases depName=goreleaser/goreleaser extractVersion=^v?(?<version>2\\..+)\nGORELEASER_VERSION := 2.15.2\n\nall: clean build\n\ninit:\n\tgo mod download\n\n$(GORELEASER):\n\tgo install github.com/goreleaser/goreleaser/v2@v$(GORELEASER_VERSION)\n\nbuild: init $(GORELEASER) $(SOURCE_FILES)\n\tAPI_VERSION=\"$(shell go run . describe 2>/dev/null | jq -r .api_version)\" \\\n\t\t$(GORELEASER) build --skip=validate --clean --single-target\n\nrelease-snapshot: init $(GORELEASER) $(SOURCE_FILES)\n\tAPI_VERSION=\"$(shell go run . describe 2>/dev/null | jq -r .api_version)\" \\\n\t\t$(GORELEASER) release --snapshot --skip=publish --clean\n\nrelease: init $(GORELEASER) $(SOURCE_FILES)\n\tAPI_VERSION=\"$(shell go run . describe 2>/dev/null | jq -r .api_version)\" \\\n\t\t$(GORELEASER) release --clean\n\n# see https://www.packer.io/guides/hcl/component-object-spec/\nupdate/provisioner.hcl2spec.go: update/provisioner.go\n\tgo install github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc@$(shell go list -m -f '{{.Version}}' github.com/hashicorp/packer-plugin-sdk)\n\tgo generate ./...\n\nclean:\n\trm -rf update/provisioner.hcl2spec.go dist tmp* output-test *.log\n\ntest: build\n\t./test.sh\n\n.PHONY: all init build release release-snapshot install uninstall clean test\n"
  },
  {
    "path": "README.md",
    "content": "# Packer Windows Update Provisioner\n\n[![Build status](https://github.com/rgl/packer-plugin-windows-update/workflows/Build/badge.svg)](https://github.com/rgl/packer-plugin-windows-update/actions?query=workflow%3ABuild)\n\nThis is a Packer plugin for installing Windows updates (akin to [rgl/vagrant-windows-update](https://github.com/rgl/vagrant-windows-update)).\n\n**NB** This was only tested with Packer 1.15.1 and the images at [rgl/windows-vagrant](https://github.com/rgl/windows-vagrant), so YMMV.\n\n# Usage\n\nConfigure your packer template to require a [release version of the plugin](https://github.com/rgl/packer-plugin-windows-update/releases), e.g.:\n\n```hcl\npacker {\n  required_plugins {\n    windows-update = {\n      version = \"0.18.1\"\n      source  = \"github.com/rgl/windows-update\"\n    }\n  }\n}\n```\n\nInitialize your packer template (it will install the plugin):\n\n```bash\npacker init your-template.pkr.hcl\n```\n\nUse this provisioner plugin from your packer template file, e.g. like in [rgl/windows-vagrant](https://github.com/rgl/windows-vagrant):\n\n```hcl\nbuild {\n  provisioner \"windows-update\" {\n    filters = [\n      # exclude KB5007651:\n      #   Update for Windows Security platform - KB5007651 (Version 10.0.29510.1001)\n      # NB it can only be applied while the user is logged in.\n      \"exclude:$_.Title -like '*KB5007651*'\",\n      \"include:$true\",\n    ]\n  }\n}\n```\n\nNote, the plugin automatically restarts the machine after Windows Updates are applied and repeats until all updates are installed. The reboots occur similar to the windows-restart provisioner built into packer where packer is aware that a shutdown is in progress.\n\n## Search Criteria, Filters and Update Limit\n\nYou can select which Windows Updates are installed by defining the search criteria, a set of filters, and how many updates are installed at a time.\n\nNormally you would use one of the following settings:\n\n| Name          | `search_criteria`                           | `filters`       |\n|---------------|---------------------------------------------|-----------------|\n| Important     | `AutoSelectOnWebSites=1 and IsInstalled=0`  | `$true`         |\n| Recommended   | `BrowseOnly=0 and IsInstalled=0`            | `$true`         |\n| All           | `IsInstalled=0`                             | `$true`         |\n| Optional Only | `AutoSelectOnWebSites=0 and IsInstalled=0`  | `$_.BrowseOnly` |\n\n**NB** `Recommended` is the default setting.\n\nBut you can customize them, e.g.:\n\n```hcl\nbuild {\n  provisioner \"windows-update\" {\n    search_criteria = \"IsInstalled=0\"\n    filters = [\n      \"exclude:$_.Title -like '*Preview*'\",\n      \"include:$true\",\n    ]\n    update_limit = 25\n  }\n}\n```\n\n**NB** For more information about the search criteria see the [IUpdateSearcher::Search method](https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesearcher-search) documentation and the [xWindowsUpdateAgent DSC resource source](https://github.com/dsccommunity/xWindowsUpdate/tree/master/source/DSCResources/MSFT_xWindowsUpdateAgent).\n\n**NB** If the `update_limit` attribute is not declared, it defaults to `1000`.\n\nThe general filter syntax is:\n\n    ACTION:EXPRESSION\n\n`ACTION` is a string that can have one of the following values:\n\n| action    | description                                                  |\n| --------- | ------------------------------------------------------------ |\n| `include` | includes the update when the expression evaluates to `$true` |\n| `exclude` | excludes the update when the expression evaluates to `$true` |\n\n**NB** If no `ACTION` evaluates to `$true` the update will **NOT** be installed.\n\n`EXPRESSION` is a PowerShell expression. When it returns `$true`, the\n`ACTION` is executed and no further filters are evaluated.\n\nInside an expression, the Windows Update [IUpdate interface](https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdate) can be referenced by the `$_` variable.\n\n# Development\n\nInstall the dependencies:\n\n* [Docker](https://docs.docker.com/engine/install/).\n* [Visual Studio Code](https://code.visualstudio.com).\n* [Dev Container plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).\n* [`windows-2022-amd64` vagrant box](https://github.com/rgl/windows-vagrant).\n\nOpen this directory with the Dev Container plugin.\n\nOpen `bash` inside the Visual Studio Code Terminal.\n\nBuild:\n\n```bash\nmake\n```\n\nTest with QEMU:\n\n```bash\nmake test\n```\n"
  },
  {
    "path": "ci-release.sh",
    "content": "#!/bin/bash\nset -euxo pipefail\n\n# ensure provisioner.hcl2spec.go is updated by re-generate it. if there are\n# differences, abort the build.\nrm -f update/provisioner.hcl2spec.go\nmake update/provisioner.hcl2spec.go\ngit diff --exit-code update/provisioner.hcl2spec.go \\\n  || (echo 'ERROR: You must re-generate update/provisioner.hcl2spec.go and commit the changes.' && exit 1)\n\n# point the msys2 user gpg home to the one managed by the crazy-max/ghaction-import-gpg github action.\nln -s /c/Users/runneradmin/.gnupg ~/.gnupg\n\n# do the release.\nif [[ $GITHUB_REF == refs/tags/v* ]]; then\n  make release\nelse\n  make release-snapshot\nfi\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/rgl/packer-plugin-windows-update\n\ngo 1.26.1\n\nrequire (\n\tgithub.com/hashicorp/hcl/v2 v2.24.0\n\tgithub.com/hashicorp/packer-plugin-sdk v0.6.7\n\tgithub.com/zclconf/go-cty v1.18.0\n)\n\nrequire (\n\tgithub.com/agext/levenshtein v1.2.3 // indirect\n\tgithub.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect\n\tgithub.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect\n\tgithub.com/armon/go-metrics v0.4.1 // indirect\n\tgithub.com/aws/aws-sdk-go-v2 v1.41.5 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/config v1.32.14 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/credentials v1.19.14 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sso v1.30.15 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sts v1.41.10 // indirect\n\tgithub.com/aws/smithy-go v1.24.3 // indirect\n\tgithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect\n\tgithub.com/cenkalti/backoff/v4 v4.3.0 // indirect\n\tgithub.com/fatih/color v1.19.0 // indirect\n\tgithub.com/go-jose/go-jose/v4 v4.1.4 // indirect\n\tgithub.com/go-viper/mapstructure/v2 v2.5.0 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/hashicorp/consul/api v1.33.7 // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2 // indirect\n\tgithub.com/hashicorp/go-getter/v2 v2.2.3 // indirect\n\tgithub.com/hashicorp/go-hclog v1.6.3 // indirect\n\tgithub.com/hashicorp/go-immutable-radix v1.3.1 // indirect\n\tgithub.com/hashicorp/go-metrics v0.5.4 // indirect\n\tgithub.com/hashicorp/go-multierror v1.1.1 // indirect\n\tgithub.com/hashicorp/go-retryablehttp v0.7.8 // indirect\n\tgithub.com/hashicorp/go-rootcerts v1.0.2 // indirect\n\tgithub.com/hashicorp/go-safetemp v1.0.0 // indirect\n\tgithub.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect\n\tgithub.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect\n\tgithub.com/hashicorp/go-sockaddr v1.0.7 // indirect\n\tgithub.com/hashicorp/go-version v1.9.0 // indirect\n\tgithub.com/hashicorp/golang-lru v1.0.2 // indirect\n\tgithub.com/hashicorp/hcl v1.0.1-vault-7 // indirect\n\tgithub.com/hashicorp/serf v0.10.2 // indirect\n\tgithub.com/hashicorp/vault/api v1.23.0 // indirect\n\tgithub.com/hashicorp/yamux v0.1.2 // indirect\n\tgithub.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect\n\tgithub.com/klauspost/compress v1.18.5 // indirect\n\tgithub.com/mattn/go-colorable v0.1.14 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/mitchellh/go-testing-interface v1.14.1 // indirect\n\tgithub.com/mitchellh/go-wordwrap v1.0.1 // indirect\n\tgithub.com/mitchellh/iochan v1.0.0 // indirect\n\tgithub.com/mitchellh/mapstructure v1.5.0 // indirect\n\tgithub.com/mitchellh/reflectwalk v1.0.2 // indirect\n\tgithub.com/ryanuber/go-glob v1.0.0 // indirect\n\tgithub.com/ugorji/go/codec v1.3.1 // indirect\n\tgithub.com/ulikunitz/xz v0.5.15 // indirect\n\tgithub.com/vmihailenco/msgpack/v5 v5.4.1 // indirect\n\tgithub.com/vmihailenco/tagparser/v2 v2.0.0 // indirect\n\tgolang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect\n\tgolang.org/x/mod v0.34.0 // indirect\n\tgolang.org/x/net v0.52.0 // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n\tgolang.org/x/sys v0.42.0 // indirect\n\tgolang.org/x/text v0.35.0 // indirect\n\tgolang.org/x/time v0.15.0 // indirect\n\tgolang.org/x/tools v0.43.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.11 // indirect\n)\n\nreplace github.com/zclconf/go-cty => github.com/nywilken/go-cty v1.13.3 // added by packer-sdc fix as noted in github.com/hashicorp/packer-plugin-sdk/issues/187\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=\ngithub.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=\ngithub.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=\ngithub.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=\ngithub.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=\ngithub.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=\ngithub.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=\ngithub.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.14 h1:opVIRo/ZbbI8OIqSOKmpFaY7IwfFUOCCXBsUpJOwDdI=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.14/go.mod h1:U4/V0uKxh0Tl5sxmCBZ3AecYny4UNlVmObYjKuuaiOo=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.14 h1:n+UcGWAIZHkXzYt87uMFBv/l8THYELoX6gVcUvgl6fI=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA=\ngithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5 h1:z2ayoK3pOvf8ODj/vPR0FgAS5ONruBq0F94SRoW/BIU=\ngithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5/go.mod h1:mpZB5HAl4ZIISod9qCi12xZ170TbHX9CCJV5y7nb7QU=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.15 h1:lFd1+ZSEYJZYvv9d6kXzhkZu07si3f+GQ1AaYwa2LUM=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.15/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 h1:dzztQ1YmfPrxdrOiuZRMF6fuOwWlWpD2StNLTceKpys=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw=\ngithub.com/aws/smithy-go v1.24.3 h1:XgOAaUgx+HhVBoP4v8n6HCQoTRDhoMghKqw4LNHsDNg=\ngithub.com/aws/smithy-go v1.24.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=\ngithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=\ngithub.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=\ngithub.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=\ngithub.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=\ngithub.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=\ngithub.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=\ngithub.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=\ngithub.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=\ngithub.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=\ngithub.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=\ngithub.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=\ngithub.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/hashicorp/consul/api v1.33.7 h1:apLZVzX7O7BLgHyh4pvczcsBzPmYSVXGKZQbOaA1ae0=\ngithub.com/hashicorp/consul/api v1.33.7/go.mod h1:SjR3cjwCUSLLDfVw5dFg76rnnKjOySxr8W8lC5s01C8=\ngithub.com/hashicorp/consul/sdk v0.17.3 h1:oZMMxzQGSsiT+ToOH50y3Qcs0nc9Ud+7L5lRx+EmMU0=\ngithub.com/hashicorp/consul/sdk v0.17.3/go.mod h1:jnOmYjiNfVRpBaujQ1DFFVs0N6g3S1y6wygSjLTzYfc=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-getter/v2 v2.2.3 h1:6CVzhT0KJQHqd9b0pK3xSP0CM/Cv+bVhk+jcaRJ2pGk=\ngithub.com/hashicorp/go-getter/v2 v2.2.3/go.mod h1:hp5Yy0GMQvwWVUmwLs3ygivz1JSLI323hdIE9J9m7TY=\ngithub.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=\ngithub.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=\ngithub.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY=\ngithub.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI=\ngithub.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=\ngithub.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0=\ngithub.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=\ngithub.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=\ngithub.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=\ngithub.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=\ngithub.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=\ngithub.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=\ngithub.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=\ngithub.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM=\ngithub.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0=\ngithub.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=\ngithub.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=\ngithub.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw=\ngithub.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=\ngithub.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=\ngithub.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=\ngithub.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=\ngithub.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=\ngithub.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE=\ngithub.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=\ngithub.com/hashicorp/memberlist v0.5.2 h1:rJoNPWZ0juJBgqn48gjy59K5H4rNgvUoM1kUD7bXiuI=\ngithub.com/hashicorp/memberlist v0.5.2/go.mod h1:Ri9p/tRShbjYnpNf4FFPXG7wxEGY4Nrcn6E7jrVa//4=\ngithub.com/hashicorp/packer-plugin-sdk v0.6.7 h1:R6xO8j5GUT1AC+1CmDvXCjjiCDndWbIA1O7jJ3MeTVs=\ngithub.com/hashicorp/packer-plugin-sdk v0.6.7/go.mod h1:J+hZE+SdN0MPCZLmoRPSrqg4YuP/mXTuuVqiAYbDVfw=\ngithub.com/hashicorp/serf v0.10.2 h1:m5IORhuNSjaxeljg5DeQVDlQyVkhRIjJDimbkCa8aAc=\ngithub.com/hashicorp/serf v0.10.2/go.mod h1:T1CmSGfSeGfnfNy/w0odXQUR1rfECGd2Qdsp84DjOiY=\ngithub.com/hashicorp/vault/api v1.23.0 h1:gXgluBsSECfRWTSW9niY2jwg2e9mMJc4WoHNv4g3h6A=\ngithub.com/hashicorp/vault/api v1.23.0/go.mod h1:zransKiB9ftp+kgY8ydjnvCU7Wk8i9L0DYWpXeMj9ko=\ngithub.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=\ngithub.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=\ngithub.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4=\ngithub.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=\ngithub.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=\ngithub.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=\ngithub.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=\ngithub.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=\ngithub.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=\ngithub.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=\ngithub.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=\ngithub.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=\ngithub.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=\ngithub.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=\ngithub.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/nywilken/go-cty v1.13.3 h1:03U99oXf3j3g9xgqAE3YGpixCjM8Mg09KZ0Ji9LzX0o=\ngithub.com/nywilken/go-cty v1.13.3/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=\ngithub.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=\ngithub.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=\ngithub.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=\ngithub.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=\ngithub.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=\ngithub.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=\ngithub.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=\ngithub.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=\ngithub.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=\ngithub.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=\ngithub.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=\ngithub.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=\ngolang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=\ngolang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=\ngolang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=\ngolang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=\ngolang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=\ngolang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=\ngolang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=\ngolang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\n\t\"github.com/hashicorp/packer-plugin-sdk/plugin\"\n\tv \"github.com/hashicorp/packer-plugin-sdk/version\"\n\t\"github.com/rgl/packer-plugin-windows-update/update\"\n)\n\nvar (\n\tversion = \"0.0.0\"\n\tcommit  = \"unknown\"\n\tdate    = \"unknown\"\n)\n\nfunc main() {\n\tlog.Printf(\"Starting packer-plugin-windows-update (version %s; commit %s; date %s)\", version, commit, date)\n\tpps := plugin.NewSet()\n\tpps.RegisterProvisioner(plugin.DEFAULT_NAME, new(update.Provisioner))\n\tpps.SetVersion(v.InitializePluginVersion(version, \"\"))\n\terr := pps.Run()\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to start: %v\", err)\n\t}\n}\n"
  },
  {
    "path": "renovate.json5",
    "content": "// see https://docs.renovatebot.com/templates/\n// see https://docs.renovatebot.com/modules/manager/\n// see https://docs.renovatebot.com/modules/manager/regex/\n// see https://docs.renovatebot.com/configuration-options/\n{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"regexManagers\": [\n    // default datasources.\n    {\n      \"fileMatch\": [\n        \"\\\\.yml$\",\n        \"\\\\.sh$\",\n        \"Makefile\",\n      ],\n      \"matchStrings\": [\n        \"# renovate: datasource=(?<datasource>[^:]+?) depName=(?<depName>.+?)( versioning=(?<versioning>.+?))?( extractVersion=(?<extractVersion>.+?))?( registryUrl=(?<registryUrl>.+?))?\\\\s.+?(:=|:|=)\\\\s*[\\\"']?(?<currentValue>.+?)[\\\"']?\\\\s\"\n      ],\n      \"versioningTemplate\": \"{{#if versioning}}{{{versioning}}}{{else}}semver-coerced{{/if}}\",\n      \"extractVersionTemplate\": \"{{#if extractVersion}}{{{extractVersion}}}{{else}}^v?(?<version>.+)${{/if}}\"\n    },\n    // nuget:powershellgallery datasource.\n    {\n      \"fileMatch\": [\n        \"\\\\.yml$\",\n        \"\\\\.sh$\",\n        \"Makefile\",\n      ],\n      \"matchStrings\": [\n        \"# renovate: datasource=(?<datasource>nuget):powershellgallery depName=(?<depName>.+?)( versioning=(?<versioning>.+?))?( extractVersion=(?<extractVersion>.+?))?( registryUrl=(?<registryUrl>.+?))?\\\\s.+?(:=|:|=)\\\\s*[\\\"']?(?<currentValue>.+?)[\\\"']?\\\\s\"\n      ],\n      \"registryUrlTemplate\": \"{{#if registryUrl}}{{{registryUrl}}}{{else}}https://www.powershellgallery.com/api/v2{{/if}}\",\n      \"versioningTemplate\": \"{{#if versioning}}{{{versioning}}}{{else}}nuget{{/if}}\",\n      \"extractVersionTemplate\": \"{{#if extractVersion}}{{{extractVersion}}}{{else}}^v?(?<version>.+)${{/if}}\"\n    }\n  ]\n}"
  },
  {
    "path": "renovate.sh",
    "content": "#!/bin/bash\nset -euo pipefail\n\n# this executes renovate against the local repository.\n# NB this uses a temporary gitea instance because running renovate against a\n#    local directory not (yet?) supported.\n#    see https://github.com/renovatebot/renovate/issues/3609\n\nexport RENOVATE_USERNAME='renovate'\nexport RENOVATE_NAME='Renovate Bot'\nexport RENOVATE_PASSWORD='password'\ngitea_container_name=\"$(basename \"$(dirname \"$(realpath \"${BASH_SOURCE[0]}\")\")\")-renovate-gitea\"\n\n# see https://hub.docker.com/r/gitea/gitea/tags\n# renovate: datasource=docker depName=gitea/gitea\ngitea_version='1.25.5'\n\n# see https://hub.docker.com/r/renovate/renovate/tags\n# see https://github.com/renovatebot/renovate/releases\n# renovate: datasource=docker depName=renovate/renovate\nrenovate_version='43.104.1'\n\n# clean.\necho 'Deleting existing Gitea...'\ndocker rm --force \"$gitea_container_name\" >/dev/null 2>&1\necho 'Deleting existing temporary files...'\nrm -f tmp/renovate-*\ninstall -d tmp\n\n# start gitea in background.\n# see https://docs.gitea.io/en-us/config-cheat-sheet/\n# see https://github.com/go-gitea/gitea/releases\n# see https://github.com/go-gitea/gitea/blob/v1.25.5/docker/root/etc/s6/gitea/setup\necho 'Starting Gitea...'\ndocker run \\\n    --detach \\\n    --name \"$gitea_container_name\" \\\n    -v /etc/timezone:/etc/timezone:ro \\\n    -v /etc/localtime:/etc/localtime:ro \\\n    -e SECRET_KEY=opensesame \\\n    -p 3000 \\\n    \"gitea/gitea:$gitea_version\" \\\n    >/dev/null\ngitea_addr=\"$(docker port \"$gitea_container_name\" 3000 | head -1)\"\ngitea_url=\"http://$gitea_addr\"\nexport RENOVATE_ENDPOINT=\"$gitea_url\"\nexport GIT_PUSH_REPOSITORY=\"http://$RENOVATE_USERNAME:$RENOVATE_PASSWORD@$gitea_addr/$RENOVATE_USERNAME/test.git\"\n\n# wait for gitea to be ready.\necho \"Waiting for Gitea to be ready at $gitea_url...\"\nGITEA_URL=\"$gitea_url\" bash -euc 'while [ -z \"$(wget -qO- \"$GITEA_URL/api/v1/version\" | jq -r \".version | select(.!=null)\")\" ]; do sleep 5; done'\n\n# create user in gitea.\necho \"Creating Gitea $RENOVATE_USERNAME user...\"\ndocker exec --user git \"$gitea_container_name\" gitea admin user create \\\n    --admin \\\n    --email \"$RENOVATE_USERNAME@example.com\" \\\n    --username \"$RENOVATE_USERNAME\" \\\n    --password \"$RENOVATE_PASSWORD\"\ncurl \\\n    --silent \\\n    --show-error \\\n    --fail-with-body \\\n    -u \"$RENOVATE_USERNAME:$RENOVATE_PASSWORD\" \\\n    -X 'PATCH' \\\n    -H 'Accept: application/json' \\\n    -H 'Content-Type: application/json' \\\n    -d \"{\\\"full_name\\\":\\\"$RENOVATE_NAME\\\"}\" \\\n    \"$gitea_url/api/v1/user/settings\" \\\n    | jq \\\n    > /dev/null\n\n# create the user personal access token.\n# see https://docs.gitea.io/en-us/api-usage/\n# see https://docs.gitea.io/en-us/oauth2-provider/#scopes\n# see https://try.gitea.io/api/swagger#/user/userCreateToken\necho \"Creating Gitea $RENOVATE_USERNAME user personal access token...\"\ncurl \\\n    --silent \\\n    --show-error \\\n    --fail-with-body \\\n    -u \"$RENOVATE_USERNAME:$RENOVATE_PASSWORD\" \\\n    -X POST \\\n    -H \"Content-Type: application/json\" \\\n    -d '{\"name\": \"renovate\", \"scopes\": [\"read:user\", \"write:issue\", \"write:repository\"]}' \\\n    \"$gitea_url/api/v1/users/$RENOVATE_USERNAME/tokens\" \\\n    | jq -r .sha1 \\\n    >tmp/renovate-gitea-token.txt\n\n# try the token.\necho \"Trying the Gitea $RENOVATE_USERNAME user personal access token...\"\nRENOVATE_TOKEN=\"$(cat tmp/renovate-gitea-token.txt)\"\nexport RENOVATE_TOKEN\ncurl \\\n    --silent \\\n    --show-error \\\n    --fail-with-body \\\n    -H \"Authorization: token $RENOVATE_TOKEN\" \\\n    -H 'Accept: application/json' \\\n    \"$gitea_url/api/v1/version\" \\\n    | jq \\\n    > /dev/null\n\n# create remote repository in gitea.\necho \"Creating Gitea $RENOVATE_USERNAME test repository...\"\ncurl \\\n    --silent \\\n    --show-error \\\n    --fail-with-body \\\n    -u \"$RENOVATE_USERNAME:$RENOVATE_PASSWORD\" \\\n    -X POST \\\n    -H 'Accept: application/json' \\\n    -H 'Content-Type: application/json' \\\n    -d '{\"name\": \"test\"}' \\\n    \"$gitea_url/api/v1/user/repos\" \\\n    | jq \\\n    > /dev/null\n\n# push the code to local gitea repository.\n# NB running renovate locally is not yet supported.\n#    see https://github.com/renovatebot/renovate/issues/3609\necho \"Pushing local repository to Gitea $RENOVATE_USERNAME test repository...\"\ngit push --force \"$GIT_PUSH_REPOSITORY\"\n\n# see https://docs.renovatebot.com/modules/platform/gitea/\n# see https://docs.renovatebot.com/self-hosted-configuration/#dryrun\n# see https://github.com/renovatebot/renovate/blob/main/docs/usage/examples/self-hosting.md\n# see https://github.com/renovatebot/renovate/tree/main/lib/modules/datasource\n# see https://github.com/renovatebot/renovate/tree/main/lib/modules/versioning\nRENOVATE_TOKEN=\"$(cat tmp/renovate-gitea-token.txt)\"\nexport RENOVATE_TOKEN\n# NB these can also be passed as raw positional arguments to docker run.\nexport RENOVATE_REPOSITORIES=\"$RENOVATE_USERNAME/test\"\n# see https://docs.github.com/en/rest/rate-limit#get-rate-limit-status-for-the-authenticated-user\n# see https://github.com/settings/tokens\n# NB this is only used for authentication. the token should not have any scope enabled.\n#export GITHUB_COM_TOKEN='TODO-YOUR-TOKEN'\n# let renovate create all the required pull requests.\n# see https://docs.renovatebot.com/configuration-options/#prhourlylimit\n# see https://docs.renovatebot.com/configuration-options/#prconcurrentlimit\nexport RENOVATE_PR_HOURLY_LIMIT='0'\nexport RENOVATE_PR_CONCURRENT_LIMIT='0'\necho 'Running renovate...'\n# NB to capture the traffic using mitmproxy, start mitmweb in a different\n#    shell, then enable the following if (i.e. true).\ndocker_extra_args=()\nif false; then\n    docker_extra_args+=(\n        --env http_proxy=http://127.0.0.1:8080\n        --env https_proxy=http://127.0.0.1:8080\n        --env no_proxy=\n        --env SSL_CERT_FILE=/usr/local/shared/ca-certificates/mitmproxy-ca.crt\n        --volume \"$HOME/.mitmproxy/mitmproxy-ca-cert.pem:/usr/local/shared/ca-certificates/mitmproxy-ca.crt:ro\"\n    )\nfi\n# NB use --dry-run=lookup for not modifying the repository (e.g. for not\n#    creating pull requests).\ndocker run \\\n  --rm \\\n  --tty \\\n  --interactive \\\n  --net host \\\n  --env GITHUB_COM_TOKEN \\\n  --env RENOVATE_ENDPOINT \\\n  --env RENOVATE_TOKEN \\\n  --env RENOVATE_REPOSITORIES \\\n  --env RENOVATE_PR_HOURLY_LIMIT \\\n  --env RENOVATE_PR_CONCURRENT_LIMIT \\\n  --env LOG_LEVEL=debug \\\n  --env LOG_FORMAT=json \\\n  \"${docker_extra_args[@]}\" \\\n  \"renovate/renovate:$renovate_version\" \\\n  --platform=gitea \\\n  --git-url=endpoint \\\n  >tmp/renovate-log.txt\n grep -E '^{' \\\n    tmp/renovate-log.txt \\\n    >tmp/renovate-log.json\n\necho 'Getting results...'\n# extract the errors.\njq 'select(.err)' tmp/renovate-log.json >tmp/renovate-errors.json\n# extract the result from the renovate log.\njq 'select(.msg == \"packageFiles with updates\") | .config' tmp/renovate-log.json >tmp/renovate-result.json\n# extract all the dependencies.\njq 'to_entries[].value[] | {packageFile,dep:.deps[]}' tmp/renovate-result.json >tmp/renovate-dependencies.json\n# extract the dependencies that have updates.\njq 'select((.dep.updates | length) > 0)' tmp/renovate-dependencies.json >tmp/renovate-dependencies-updates.json\n\n# helpers.\nfunction show-title {\n    echo\n    echo '#'\n    echo \"# $1\"\n    echo '#'\n    echo\n}\n\n# show errors.\nif [ \"$(jq --slurp length tmp/renovate-errors.json)\" -ne '0' ]; then\n    show-title errors\n    jq . tmp/renovate-errors.json\nfi\n\n# show dependencies.\nfunction show-dependencies {\n    show-title \"$1\"\n    (\n        printf 'packageFile\\tdatasource\\tdepName\\tcurrentValue\\tnewVersions\\tskipReason\\twarnings\\n'\n        jq \\\n            -r \\\n            '[\n                .packageFile,\n                .dep.datasource,\n                .dep.depName,\n                .dep.currentValue,\n                (.dep | select(.updates) | .updates | map(.newVersion) | join(\" | \")),\n                .dep.skipReason,\n                (.dep | select(.warnings) | .warnings | map(.message) | join(\" | \"))\n            ] | @tsv' \\\n            \"$2\" \\\n            | sort\n    ) | column -t -s \"$(printf \\\\t)\"\n}\nshow-dependencies 'Dependencies' tmp/renovate-dependencies.json\nshow-dependencies 'Dependencies Updates' tmp/renovate-dependencies-updates.json\n\n# show the gitea project.\nshow-title \"See PRs at $gitea_url/$RENOVATE_USERNAME/test/pulls (you can login as $RENOVATE_USERNAME:$RENOVATE_PASSWORD)\"\n"
  },
  {
    "path": "test.pkr.hcl",
    "content": "packer {\n  required_plugins {\n    # see https://github.com/hashicorp/packer-plugin-qemu\n    qemu = {\n      version = \"1.1.4\"\n      source  = \"github.com/hashicorp/qemu\"\n    }\n    # see https://github.com/rgl/packer-plugin-windows-update\n    windows-update = {\n      version = \">= 0.0.0\"\n      source  = \"github.com/rgl/windows-update\"\n    }\n  }\n}\n\nvariable \"disk_size\" {\n  type    = string\n  default = \"61440\"\n}\n\nvariable \"disk_image\" {\n  type = string\n}\n\nsource \"qemu\" \"test\" {\n  headless     = true\n  accelerator  = \"kvm\"\n  machine_type = \"q35\"\n  cpus         = 2\n  memory       = 4096\n  qemuargs = [\n    strcontains(var.disk_image, \"uefi\") ? [\"-bios\", \"/usr/share/ovmf/OVMF.fd\"] : null,\n    [\"-cpu\", \"host\"],\n  ]\n  disk_interface   = \"virtio-scsi\"\n  disk_cache       = \"unsafe\"\n  disk_discard     = \"unmap\"\n  disk_image       = true\n  use_backing_file = true\n  disk_size        = var.disk_size\n  iso_url          = var.disk_image\n  iso_checksum     = \"none\"\n  net_device       = \"virtio-net\"\n  shutdown_command = \"shutdown /s /t 0 /f /d p:4:1 /c \\\"Packer Shutdown\\\"\"\n  communicator     = \"winrm\"\n  winrm_username   = \"vagrant\"\n  winrm_password   = \"vagrant\"\n  winrm_timeout    = \"4h\"\n}\n\nbuild {\n  sources = [\n    \"source.qemu.test\",\n  ]\n  provisioner \"windows-update\" {\n  }\n  provisioner \"powershell\" {\n    use_pwsh = true\n    inline = [\n      <<-EOF\n      $p = 'c:/packer.delete.me.to.end.test.wait.txt'\n      Set-Content $p 'delete this file to end the packer test wait'\n      Write-Host \"ATTENTION To end this test wait, login into the machine and delete the $p file. Or just press Ctrl+C.\"\n      while (Test-Path $p) {\n        Start-Sleep -Seconds 5\n      }\n      EOF\n    ]\n  }\n}\n"
  },
  {
    "path": "test.sh",
    "content": "#!/usr/bin/bash\nset -euo pipefail\n\nGOHOSTOS=\"$(go env GOHOSTOS)\"\nGOHOSTARCH=\"$(go env GOHOSTARCH)\"\nPLUGIN_PATH=\"$(\n    jq -r \\\n        --arg goos \"$GOHOSTOS\" \\\n        --arg goarch \"$GOHOSTARCH\" \\\n        '.[] | select(.goos == $goos and .goarch == $goarch and .extra.ID == \"packer-plugin-windows-update\") | .path' \\\n        dist/artifacts.json)\"\nPLUGIN_BASE_NAME=\"$(basename \"$PLUGIN_PATH\")\"\nPLUGIN_TEST_PATH=\"dist/test/plugins/github.com/rgl/windows-update/$PLUGIN_BASE_NAME\"\n\n# see https://developer.hashicorp.com/packer/docs/plugins/creation/plugin-load-spec\nrm -rf output-test test.log dist/test\ninstall -d dist/test/plugins/github.com/rgl/windows-update\ninstall \"$PLUGIN_PATH\" \"$PLUGIN_TEST_PATH\"\n(cd \"$(dirname \"$PLUGIN_TEST_PATH\")\" && \\\n    sha256sum \"$PLUGIN_BASE_NAME\" >\"${PLUGIN_BASE_NAME}_SHA256SUM\")\n\nexport CHECKPOINT_DISABLE=1\nexport PACKER_LOG=1\nexport PACKER_LOG_PATH=test.log\nexport PACKER_CONFIG_DIR=\"$PWD/dist/test\"\nexport PACKER_PLUGIN_PATH=\"$PWD/dist/test/plugins\"\n\n#export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-11-24h2-amd64/0.0.0/libvirt/box_0.img\n#export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-2022-amd64/0.0.0/libvirt/box_0.img\n#export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-2025-amd64/0.0.0/libvirt/box_0.img\n#export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-11-24h2-uefi-amd64/0.0.0/libvirt/box_0.img\nexport PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-2022-uefi-amd64/0.0.0/libvirt/box_0.img\n#export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-2025-uefi-amd64/0.0.0/libvirt/box_0.img\n\npacker init -only=qemu.test test.pkr.hcl\npacker build -only=qemu.test -on-error=abort test.pkr.hcl\n"
  },
  {
    "path": "update/elevated-template.ps1",
    "content": "Set-StrictMode -Version Latest\r\n$ErrorActionPreference = 'Stop'\r\n$ProgressPreference = 'SilentlyContinue'\r\ntrap {\r\n    Write-Output \"ERROR: $_\"\r\n    Write-Output (($_.ScriptStackTrace -split '\\r?\\n') -replace '^(.*)$','ERROR: $1')\r\n    Write-Output (($_.Exception.ToString() -split '\\r?\\n') -replace '^(.*)$','ERROR EXCEPTION: $1')\r\n    Exit 1\r\n}\r\n$name = \"{{.TaskName}}\"\r\n$log = \"$env:SystemRoot\\Temp\\$name.out\"\r\n$s = New-Object -ComObject \"Schedule.Service\"\r\n$s.Connect()\r\n$t = $s.NewTask($null)\r\n$t.XmlText = @'\r\n<Task version=\"1.2\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\">\r\n    <RegistrationInfo>\r\n        <Description>{{.TaskDescription}}</Description>\r\n    </RegistrationInfo>\r\n    <Principals>\r\n        <Principal id=\"Author\">\r\n            <RunLevel>HighestAvailable</RunLevel>\r\n        </Principal>\r\n    </Principals>\r\n    <Settings>\r\n        <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>\r\n        <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>\r\n        <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>\r\n        <AllowHardTerminate>true</AllowHardTerminate>\r\n        <StartWhenAvailable>false</StartWhenAvailable>\r\n        <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>\r\n        <IdleSettings>\r\n            <StopOnIdleEnd>false</StopOnIdleEnd>\r\n            <RestartOnIdle>false</RestartOnIdle>\r\n        </IdleSettings>\r\n        <AllowStartOnDemand>true</AllowStartOnDemand>\r\n        <Enabled>true</Enabled>\r\n        <Hidden>false</Hidden>\r\n        <RunOnlyIfIdle>false</RunOnlyIfIdle>\r\n        <WakeToRun>false</WakeToRun>\r\n        <ExecutionTimeLimit>PT24H</ExecutionTimeLimit>\r\n        <Priority>4</Priority>\r\n    </Settings>\r\n    <Actions Context=\"Author\">\r\n        <Exec>\r\n            <Command>cmd</Command>\r\n            <Arguments>/c {{.Command}} &gt;%SYSTEMROOT%\\Temp\\{{.TaskName}}.out 2&gt;&amp;1</Arguments>\r\n        </Exec>\r\n    </Actions>\r\n</Task>\r\n'@\r\n$username = \"{{.Username}}\"\r\n$password = \"{{.Password}}\"\r\nif (!$password) {\r\n    $password = $null\r\n}\r\n$f = $s.GetFolder(\"\\\")\r\n$f.RegisterTaskDefinition($name, $t, 6, $username, $password, 1, $null) | Out-Null\r\n$t = $f.GetTask(\"\\$name\")\r\n$t.Run($null) | Out-Null\r\n$timeout = 10\r\n$sec = 0\r\nwhile ((!($t.state -eq 4)) -and ($sec -lt $timeout)) {\r\n    Start-Sleep -Seconds 1\r\n    $sec++\r\n}\r\n# Windows PowerShell 2 on Windows 7 does not have Get-CimInstance.\r\n# PowerShell 6 does not have Get-WmiObject.\r\nif (!(Get-Command Get-CimInstance -ErrorAction:SilentlyContinue)) {\r\n    function Get-CimInstance {\r\n        [CmdletBinding()]\r\n        param(\r\n            [Parameter(Mandatory = $True, Position = 0)]\r\n            [string]\r\n            $ClassName\r\n        )\r\n        Get-WmiObject -Class $ClassName\r\n    }\r\n}\r\n$reportProgressInterval = New-TimeSpan -Minutes 1\r\n$startDate = Get-Date\r\n$line = 0\r\ndo {\r\n    Start-Sleep -Seconds 5\r\n    if (Test-Path $log) {\r\n        Get-Content $log | Select-Object -skip $line | ForEach-Object {\r\n            ++$line\r\n            Write-Output $_\r\n        }\r\n    }\r\n    $currentDate = Get-Date\r\n    if ($currentDate.Subtract($startDate) -ge $reportProgressInterval) {\r\n        $startDate = $currentDate\r\n        $cpuUsage = (Get-CimInstance CIM_Processor | Measure-Object -Property LoadPercentage -Average).Average / 100\r\n        $os = Get-CimInstance Win32_OperatingSystem\r\n        $memoryUsage = 1 - $os.FreePhysicalMemory / $os.TotalVisibleMemorySize\r\n        Write-Output (\"Waiting for operation to complete (system performance: {0:P0} cpu; {1:P0} memory)...\" -f $cpuUsage,$memoryUsage)\r\n    }\r\n} while (!($t.state -eq 3))\r\n$result = $t.LastTaskResult\r\nif (Test-Path $log) {\r\n    Remove-Item $log -Force -ErrorAction SilentlyContinue | Out-Null\r\n}\r\n\r\n# delete scheduled task\r\n$f.DeleteTask(\"\\$name\", 0)\r\n\r\n[System.Runtime.Interopservices.Marshal]::ReleaseComObject($s) | Out-Null\r\nexit $result\r\n"
  },
  {
    "path": "update/elevated.go",
    "content": "// NB this code was based on https://github.com/hashicorp/packer/blob/370b67497e90785b71be1b6fcc6430de487d644e/provisioner/powershell/elevated.go\n\npackage update\n\nimport (\n\t_ \"embed\" // this is needed for using the go:embed directive\n\t\"text/template\"\n)\n\ntype elevatedOptions struct {\n\tUsername        string\n\tPassword        string\n\tTaskName        string\n\tTaskDescription string\n\tCommand         string\n}\n\n//go:embed elevated-template.ps1\nvar elevatedTemplatePs1 string\n\nvar elevatedTemplate = template.Must(\n\ttemplate.New(\"Elevated\").Parse(\n\t\televatedTemplatePs1))\n"
  },
  {
    "path": "update/provisioner.go",
    "content": "//go:generate packer-sdc mapstructure-to-hcl2 -type Config\n\n// NB this code was based on https://github.com/hashicorp/packer/blob/81522dced0b25084a824e79efda02483b12dc7cd/provisioner/windows-restart/provisioner.go\n\npackage update\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\" // this is needed for using the go:embed directive\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode/utf16\"\n\n\t\"github.com/hashicorp/hcl/v2/hcldec\"\n\t\"github.com/hashicorp/packer-plugin-sdk/common\"\n\t\"github.com/hashicorp/packer-plugin-sdk/packer\"\n\t\"github.com/hashicorp/packer-plugin-sdk/retry\"\n\t\"github.com/hashicorp/packer-plugin-sdk/template/config\"\n\t\"github.com/hashicorp/packer-plugin-sdk/template/interpolate\"\n\t\"github.com/hashicorp/packer-plugin-sdk/uuid\"\n)\n\nconst (\n\televatedPath                 = \"C:/Windows/Temp/packer-windows-update-elevated.ps1\"\n\televatedCommand              = \"PowerShell -ExecutionPolicy Bypass -OutputFormat Text -File C:/Windows/Temp/packer-windows-update-elevated.ps1\"\n\twindowsUpdatePath            = \"C:/Windows/Temp/packer-windows-update.ps1\"\n\tpendingRebootElevatedPath    = \"C:/Windows/Temp/packer-windows-update-pending-reboot-elevated.ps1\"\n\tpendingRebootElevatedCommand = \"PowerShell -ExecutionPolicy Bypass -OutputFormat Text -File C:/Windows/Temp/packer-windows-update-pending-reboot-elevated.ps1\"\n\trestartCommand               = \"shutdown.exe -f -r -t 0 -c \\\"packer restart\\\"\"\n\ttestRestartCommand           = \"shutdown.exe -f -r -t 60 -c \\\"packer restart test\\\"\"\n\tabortTestRestartCommand      = \"shutdown.exe -a\"\n\tretryableDelay               = 5 * time.Second\n\tuploadTimeout                = 5 * time.Minute\n)\n\n//go:embed windows-update.ps1\nvar windowsUpdatePs1 []byte\n\ntype Config struct {\n\tcommon.PackerConfig `mapstructure:\",squash\"`\n\n\t// The timeout for waiting for the machine to restart\n\tRestartTimeout time.Duration `mapstructure:\"restart_timeout\"`\n\n\t// Instructs the communicator to run the remote script as a\n\t// Windows scheduled task, effectively elevating the remote\n\t// user by impersonating a logged-in user.\n\tUsername string `mapstructure:\"username\"`\n\tPassword string `mapstructure:\"password\"`\n\n\t// The updates search criteria.\n\t// See the IUpdateSearcher::Search method at https://docs.microsoft.com/en-us/windows/desktop/api/wuapi/nf-wuapi-iupdatesearcher-search.\n\tSearchCriteria string `mapstructure:\"search_criteria\"`\n\n\t// Filters the installed Windows updates. If no filter is\n\t// matched the update is NOT installed.\n\tFilters []string `mapstructure:\"filters\"`\n\n\t// Adds a limit to how many updates are installed at a time\n\tUpdateLimit int `mapstructure:\"update_limit\"`\n\n\t// Max times the provisioner will try install the updates\n\t// in case of failure.\n\tUpdateMaxRetries int `mapstructure:\"update_max_retries\"`\n\n\tctx interpolate.Context\n}\n\ntype Provisioner struct {\n\tconfig Config\n}\n\nfunc (b *Provisioner) ConfigSpec() hcldec.ObjectSpec {\n\treturn b.config.FlatMapstructure().HCL2Spec()\n}\n\nfunc (p *Provisioner) Prepare(raws ...interface{}) error {\n\terr := config.Decode(&p.config, &config.DecodeOpts{\n\t\tInterpolate:        true,\n\t\tInterpolateContext: &p.config.ctx,\n\t\tInterpolateFilter: &interpolate.RenderFilter{\n\t\t\tExclude: []string{\n\t\t\t\t\"execute_command\",\n\t\t\t},\n\t\t},\n\t}, raws...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif p.config.RestartTimeout == 0 {\n\t\tp.config.RestartTimeout = 4 * time.Hour\n\t}\n\n\tif p.config.Username == \"\" {\n\t\tp.config.Username = \"SYSTEM\"\n\t}\n\n\tvar errs error\n\n\tif p.config.Username == \"\" {\n\t\terrs = packer.MultiErrorAppend(errs,\n\t\t\terrors.New(\"Must supply an 'username'\"))\n\t}\n\n\tif p.config.UpdateLimit == 0 {\n\t\tp.config.UpdateLimit = 1000\n\t}\n\n\tif p.config.UpdateMaxRetries == 0 {\n\t\tp.config.UpdateMaxRetries = 5\n\t}\n\n\treturn errs\n}\n\nfunc (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.Communicator, _ map[string]interface{}) error {\n\tui.Say(\"Uploading the Windows update elevated script...\")\n\tvar buffer bytes.Buffer\n\terr := elevatedTemplate.Execute(&buffer, elevatedOptions{\n\t\tUsername:        p.config.Username,\n\t\tPassword:        p.config.Password,\n\t\tTaskDescription: \"Packer Windows update elevated task\",\n\t\tTaskName:        fmt.Sprintf(\"packer-windows-update-%s\", uuid.TimeOrderedUUID()),\n\t\tCommand:         p.windowsUpdateCommand(),\n\t})\n\tif err != nil {\n\t\tfmt.Printf(\"Error creating elevated template: %s\", err)\n\t\treturn err\n\t}\n\terr = retry.Config{StartTimeout: uploadTimeout}.Run(ctx, func(context.Context) error {\n\t\tif err := comm.Upload(\n\t\t\televatedPath,\n\t\t\tbytes.NewReader(buffer.Bytes()),\n\t\t\tnil); err != nil {\n\t\t\treturn fmt.Errorf(\"Error uploading the Windows update elevated script: %s\", err)\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tui.Say(\"Uploading the Windows update check for reboot required elevated script...\")\n\tbuffer.Reset()\n\terr = elevatedTemplate.Execute(&buffer, elevatedOptions{\n\t\tUsername:        p.config.Username,\n\t\tPassword:        p.config.Password,\n\t\tTaskDescription: \"Packer Windows update pending reboot elevated task\",\n\t\tTaskName:        fmt.Sprintf(\"packer-windows-update-pending-reboot-%s\", uuid.TimeOrderedUUID()),\n\t\tCommand:         p.windowsUpdateCheckForRebootRequiredCommand(),\n\t})\n\tif err != nil {\n\t\tfmt.Printf(\"Error creating elevated template: %s\", err)\n\t\treturn err\n\t}\n\terr = retry.Config{StartTimeout: uploadTimeout}.Run(ctx, func(context.Context) error {\n\t\tif err := comm.Upload(\n\t\t\tpendingRebootElevatedPath,\n\t\t\tbytes.NewReader(buffer.Bytes()),\n\t\t\tnil); err != nil {\n\t\t\treturn fmt.Errorf(\"Error uploading the Windows update check for reboot required elevated script: %s\", err)\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tui.Say(\"Uploading the Windows update script...\")\n\terr = comm.Upload(\n\t\twindowsUpdatePath,\n\t\tbytes.NewReader(windowsUpdatePs1),\n\t\tnil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\trestartPending, err := p.update(ctx, ui, comm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !restartPending {\n\t\t\treturn nil\n\t\t}\n\n\t\terr = p.restart(ctx, ui, comm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (p *Provisioner) update(ctx context.Context, ui packer.Ui, comm packer.Communicator) (bool, error) {\n\tui.Say(\"Running Windows update...\")\n\tvar restartPending bool\n\terr := retry.Config{\n\t\tRetryDelay: func() time.Duration { return retryableDelay },\n\t\tTries:      p.config.UpdateMaxRetries,\n\t}.Run(ctx, func(ctx context.Context) error {\n\t\tui := NewUpdateUi(ui)\n\t\tcmd := &packer.RemoteCmd{Command: elevatedCommand}\n\t\terr := cmd.RunWithUi(ctx, comm, ui)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvar exitStatus = cmd.ExitStatus()\n\t\tif !ui.finished {\n\t\t\treturn fmt.Errorf(\"Windows update script did not finish\")\n\t\t}\n\t\tswitch exitStatus {\n\t\tcase 0:\n\t\t\treturn nil\n\t\tcase 101:\n\t\t\trestartPending = true\n\t\t\treturn nil\n\t\tcase 2147942501: //windows 2012\n\t\t\trestartPending = true\n\t\t\treturn nil\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"Windows update script exited with non-zero exit status: %d\", exitStatus)\n\t\t}\n\t})\n\treturn restartPending, err\n}\n\nfunc (p *Provisioner) restart(ctx context.Context, ui packer.Ui, comm packer.Communicator) error {\n\trestartPending := true\n\tfor restartPending {\n\t\tui.Say(\"Restarting the machine...\")\n\t\terr := p.retryable(ctx, func(ctx context.Context) error {\n\t\t\tcmd := &packer.RemoteCmd{Command: restartCommand}\n\t\t\terr := cmd.RunWithUi(ctx, comm, ui)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\texitStatus := cmd.ExitStatus()\n\t\t\tif exitStatus != 0 {\n\t\t\t\treturn fmt.Errorf(\"Failed to restart the machine with exit status: %d\", exitStatus)\n\t\t\t}\n\t\t\treturn err\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tui.Say(\"Waiting for machine to become available...\")\n\t\terr = p.retryable(ctx, func(ctx context.Context) error {\n\t\t\t// wait for the machine to reboot.\n\t\t\tcmd := &packer.RemoteCmd{Command: testRestartCommand}\n\t\t\terr := cmd.RunWithUi(ctx, comm, ui)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\texitStatus := cmd.ExitStatus()\n\t\t\tif exitStatus != 0 {\n\t\t\t\treturn fmt.Errorf(\"Machine not yet available (exit status %d)\", exitStatus)\n\t\t\t}\n\t\t\tcmd = &packer.RemoteCmd{Command: abortTestRestartCommand}\n\t\t\terr = cmd.RunWithUi(ctx, comm, ui)\n\n\t\t\treturn err\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tui.Say(\"Checking for pending restart...\")\n\t\terr = p.retryable(ctx, func(ctx context.Context) error {\n\t\t\tui := NewUpdateUi(ui)\n\t\t\tcmd := &packer.RemoteCmd{Command: pendingRebootElevatedCommand}\n\t\t\terr = cmd.RunWithUi(ctx, comm, ui)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif !ui.finished {\n\t\t\t\treturn fmt.Errorf(\"Windows update script did not finish\")\n\t\t\t}\n\n\t\t\texitStatus := cmd.ExitStatus()\n\t\t\tswitch exitStatus {\n\t\t\tcase 0:\n\t\t\t\trestartPending = false\n\t\t\tcase 101:\n\t\t\t\trestartPending = true\n\t\t\tcase 2147942501: //windows 2012\n\t\t\t\trestartPending = true\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"Machine not yet available (exit status %d)\", exitStatus)\n\t\t\t}\n\n\t\t\treturn err\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif restartPending {\n\t\t\tui.Say(\"Restart is still pending...\")\n\t\t} else {\n\t\t\tui.Say(\"Restart complete\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// retryable will retry the given function over and over until a\n// non-error is returned, RestartTimeout expires, or ctx is\n// cancelled.\nfunc (p *Provisioner) retryable(ctx context.Context, f func(ctx context.Context) error) error {\n\treturn retry.Config{\n\t\tRetryDelay:   func() time.Duration { return retryableDelay },\n\t\tStartTimeout: p.config.RestartTimeout,\n\t}.Run(ctx, f)\n}\n\nfunc (p *Provisioner) windowsUpdateCommand() string {\n\treturn fmt.Sprintf(\n\t\t\"PowerShell -ExecutionPolicy Bypass -OutputFormat Text -EncodedCommand %s\",\n\t\tbase64.StdEncoding.EncodeToString(\n\t\t\tencodeUtf16Le(fmt.Sprintf(\n\t\t\t\t\"%s%s%s -UpdateLimit %d\",\n\t\t\t\twindowsUpdatePath,\n\t\t\t\tsearchCriteriaArgument(p.config.SearchCriteria),\n\t\t\t\tfiltersArgument(p.config.Filters),\n\t\t\t\tp.config.UpdateLimit))))\n}\n\nfunc (p *Provisioner) windowsUpdateCheckForRebootRequiredCommand() string {\n\treturn fmt.Sprintf(\n\t\t\"PowerShell -ExecutionPolicy Bypass -OutputFormat Text -EncodedCommand %s\",\n\t\tbase64.StdEncoding.EncodeToString(\n\t\t\tencodeUtf16Le(fmt.Sprintf(\n\t\t\t\t\"%s -OnlyCheckForRebootRequired\",\n\t\t\t\twindowsUpdatePath))))\n}\n\nfunc encodeUtf16Le(s string) []byte {\n\td := utf16.Encode([]rune(s))\n\tb := make([]byte, len(d)*2)\n\tfor i, r := range d {\n\t\tb[i*2] = byte(r)\n\t\tb[i*2+1] = byte(r >> 8)\n\t}\n\treturn b\n}\n\nfunc searchCriteriaArgument(searchCriteria string) string {\n\tif searchCriteria == \"\" {\n\t\treturn \"\"\n\t}\n\n\tvar buffer bytes.Buffer\n\n\tbuffer.WriteString(\" -SearchCriteria \")\n\tbuffer.WriteString(escapePowerShellString(searchCriteria))\n\n\treturn buffer.String()\n}\n\nfunc filtersArgument(filters []string) string {\n\tif filters == nil {\n\t\treturn \"\"\n\t}\n\n\tvar buffer bytes.Buffer\n\n\tbuffer.WriteString(\" -Filters \")\n\n\tfor i, filter := range filters {\n\t\tif i > 0 {\n\t\t\tbuffer.WriteString(\",\")\n\t\t}\n\t\tbuffer.WriteString(escapePowerShellString(filter))\n\t}\n\n\treturn buffer.String()\n}\n\nfunc escapePowerShellString(value string) string {\n\treturn fmt.Sprintf(\n\t\t\"'%s'\",\n\t\t// escape single quotes with another single quote.\n\t\tstrings.ReplaceAll(value, \"'\", \"''\"))\n}\n"
  },
  {
    "path": "update/provisioner.hcl2spec.go",
    "content": "// Code generated by \"packer-sdc mapstructure-to-hcl2\"; DO NOT EDIT.\n\npackage update\n\nimport (\n\t\"github.com/hashicorp/hcl/v2/hcldec\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\n// FlatConfig is an auto-generated flat version of Config.\n// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.\ntype FlatConfig struct {\n\tPackerBuildName     *string           `mapstructure:\"packer_build_name\" cty:\"packer_build_name\" hcl:\"packer_build_name\"`\n\tPackerBuilderType   *string           `mapstructure:\"packer_builder_type\" cty:\"packer_builder_type\" hcl:\"packer_builder_type\"`\n\tPackerCoreVersion   *string           `mapstructure:\"packer_core_version\" cty:\"packer_core_version\" hcl:\"packer_core_version\"`\n\tPackerDebug         *bool             `mapstructure:\"packer_debug\" cty:\"packer_debug\" hcl:\"packer_debug\"`\n\tPackerForce         *bool             `mapstructure:\"packer_force\" cty:\"packer_force\" hcl:\"packer_force\"`\n\tPackerOnError       *string           `mapstructure:\"packer_on_error\" cty:\"packer_on_error\" hcl:\"packer_on_error\"`\n\tPackerUserVars      map[string]string `mapstructure:\"packer_user_variables\" cty:\"packer_user_variables\" hcl:\"packer_user_variables\"`\n\tPackerSensitiveVars []string          `mapstructure:\"packer_sensitive_variables\" cty:\"packer_sensitive_variables\" hcl:\"packer_sensitive_variables\"`\n\tRestartTimeout      *string           `mapstructure:\"restart_timeout\" cty:\"restart_timeout\" hcl:\"restart_timeout\"`\n\tUsername            *string           `mapstructure:\"username\" cty:\"username\" hcl:\"username\"`\n\tPassword            *string           `mapstructure:\"password\" cty:\"password\" hcl:\"password\"`\n\tSearchCriteria      *string           `mapstructure:\"search_criteria\" cty:\"search_criteria\" hcl:\"search_criteria\"`\n\tFilters             []string          `mapstructure:\"filters\" cty:\"filters\" hcl:\"filters\"`\n\tUpdateLimit         *int              `mapstructure:\"update_limit\" cty:\"update_limit\" hcl:\"update_limit\"`\n\tUpdateMaxRetries    *int              `mapstructure:\"update_max_retries\" cty:\"update_max_retries\" hcl:\"update_max_retries\"`\n}\n\n// FlatMapstructure returns a new FlatConfig.\n// FlatConfig is an auto-generated flat version of Config.\n// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.\nfunc (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {\n\treturn new(FlatConfig)\n}\n\n// HCL2Spec returns the hcl spec of a Config.\n// This spec is used by HCL to read the fields of Config.\n// The decoded values from this spec will then be applied to a FlatConfig.\nfunc (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {\n\ts := map[string]hcldec.Spec{\n\t\t\"packer_build_name\":          &hcldec.AttrSpec{Name: \"packer_build_name\", Type: cty.String, Required: false},\n\t\t\"packer_builder_type\":        &hcldec.AttrSpec{Name: \"packer_builder_type\", Type: cty.String, Required: false},\n\t\t\"packer_core_version\":        &hcldec.AttrSpec{Name: \"packer_core_version\", Type: cty.String, Required: false},\n\t\t\"packer_debug\":               &hcldec.AttrSpec{Name: \"packer_debug\", Type: cty.Bool, Required: false},\n\t\t\"packer_force\":               &hcldec.AttrSpec{Name: \"packer_force\", Type: cty.Bool, Required: false},\n\t\t\"packer_on_error\":            &hcldec.AttrSpec{Name: \"packer_on_error\", Type: cty.String, Required: false},\n\t\t\"packer_user_variables\":      &hcldec.AttrSpec{Name: \"packer_user_variables\", Type: cty.Map(cty.String), Required: false},\n\t\t\"packer_sensitive_variables\": &hcldec.AttrSpec{Name: \"packer_sensitive_variables\", Type: cty.List(cty.String), Required: false},\n\t\t\"restart_timeout\":            &hcldec.AttrSpec{Name: \"restart_timeout\", Type: cty.String, Required: false},\n\t\t\"username\":                   &hcldec.AttrSpec{Name: \"username\", Type: cty.String, Required: false},\n\t\t\"password\":                   &hcldec.AttrSpec{Name: \"password\", Type: cty.String, Required: false},\n\t\t\"search_criteria\":            &hcldec.AttrSpec{Name: \"search_criteria\", Type: cty.String, Required: false},\n\t\t\"filters\":                    &hcldec.AttrSpec{Name: \"filters\", Type: cty.List(cty.String), Required: false},\n\t\t\"update_limit\":               &hcldec.AttrSpec{Name: \"update_limit\", Type: cty.Number, Required: false},\n\t\t\"update_max_retries\":         &hcldec.AttrSpec{Name: \"update_max_retries\", Type: cty.Number, Required: false},\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "update/update_ui.go",
    "content": "package update\n\nimport (\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/packer-plugin-sdk/packer\"\n)\n\ntype UpdateUi struct {\n\tui       packer.Ui\n\tfinished bool\n}\n\nfunc NewUpdateUi(ui packer.Ui) *UpdateUi {\n\treturn &UpdateUi{\n\t\tui:       ui,\n\t\tfinished: false,\n\t}\n}\n\nfunc (u *UpdateUi) Askf(s string, args ...any) (string, error) {\n\treturn u.ui.Askf(s, args...)\n}\n\nfunc (u *UpdateUi) Ask(s string) (string, error) {\n\treturn u.ui.Ask(s)\n}\n\nfunc (u *UpdateUi) Sayf(s string, args ...any) {\n\tu.ui.Sayf(s, args...)\n}\n\nfunc (u *UpdateUi) Say(s string) {\n\tif strings.HasPrefix(s, \"Exiting with code \") {\n\t\tu.finished = true\n\t\treturn\n\t}\n\tu.ui.Say(s)\n}\n\nfunc (u *UpdateUi) Message(s string) {\n\tu.Say(s)\n}\n\nfunc (u *UpdateUi) Errorf(s string, args ...any) {\n\tu.ui.Errorf(s, args...)\n}\n\nfunc (u *UpdateUi) Error(s string) {\n\tu.ui.Error(s)\n}\n\nfunc (u *UpdateUi) Machine(t string, args ...string) {\n\tu.ui.Machine(t, args...)\n}\n\nfunc (u *UpdateUi) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser) {\n\treturn u.ui.TrackProgress(src, currentSize, totalSize, stream)\n}\n"
  },
  {
    "path": "update/windows-update.ps1",
    "content": "# see Using the Windows Update Agent API | Searching, Downloading, and Installing Updates\r\n#     at https://learn.microsoft.com/en-us/windows/win32/wua_sdk/searching--downloading--and-installing-updates\r\n# see ISystemInformation interface\r\n#     at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-isysteminformation\r\n# see IUpdateSession interface\r\n#     at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdatesession\r\n# see IUpdateSearcher interface\r\n#     at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdatesearcher\r\n# see IUpdateSearcher::Search method\r\n#     at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesearcher-search\r\n# see IUpdateDownloader interface\r\n#     at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdatedownloader\r\n# see IUpdateCollection interface\r\n#     at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdatecollection\r\n# see IUpdate interface\r\n#     at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdate\r\n# see xWindowsUpdateAgent DSC resource\r\n#     at https://github.com/dsccommunity/xWindowsUpdate/tree/master/source/DSCResources/MSFT_xWindowsUpdateAgent\r\n# NB you can install common sets of updates with one of these settings:\r\n#       | Name          | SearchCriteria                            | Filters       |\r\n#       |---------------|-------------------------------------------|---------------|\r\n#       | Important     | AutoSelectOnWebSites=1 and IsInstalled=0  | $true         |\r\n#       | Recommended   | BrowseOnly=0 and IsInstalled=0            | $true         |\r\n#       | All           | IsInstalled=0                             | $true         |\r\n#       | Optional Only | AutoSelectOnWebSites=0 and IsInstalled=0  | $_.BrowseOnly |\r\n\r\nparam(\r\n    [string]$SearchCriteria = 'BrowseOnly=0 and IsInstalled=0',\r\n    [string[]]$Filters = @('include:$true'),\r\n    [int]$UpdateLimit = 1000,\r\n    [switch]$OnlyCheckForRebootRequired = $false\r\n)\r\n\r\n$mock = $false\r\n\r\nfunction ExitWithCode($exitCode) {\r\n    $host.SetShouldExit($exitCode)\r\n    Write-Output \"Exiting with code $exitCode\"\r\n    Exit\r\n}\r\n\r\nSet-StrictMode -Version Latest\r\n$ErrorActionPreference = 'Stop'\r\n$ProgressPreference = 'SilentlyContinue'\r\ntrap {\r\n    Write-Output \"ERROR: $_\"\r\n    Write-Output (($_.ScriptStackTrace -split '\\r?\\n') -replace '^(.*)$','ERROR: $1')\r\n    Write-Output (($_.Exception.ToString() -split '\\r?\\n') -replace '^(.*)$','ERROR EXCEPTION: $1')\r\n    ExitWithCode 1\r\n}\r\n\r\nif ($mock) {\r\n    $mockWindowsUpdatePath = 'C:\\Windows\\Temp\\windows-update-count-mock.txt'\r\n    if (!(Test-Path $mockWindowsUpdatePath)) {\r\n        Set-Content $mockWindowsUpdatePath 10\r\n    }\r\n    $count = [int]::Parse((Get-Content $mockWindowsUpdatePath).Trim())\r\n    if ($count) {\r\n        Write-Output \"Synthetic reboot countdown counter is at $count\"\r\n        Set-Content $mockWindowsUpdatePath (--$count)\r\n        ExitWithCode 101\r\n    }\r\n    Write-Output 'No Windows updates found'\r\n    ExitWithCode 0\r\n}\r\n\r\nAdd-Type @'\r\nusing System;\r\nusing System.Runtime.InteropServices;\r\n\r\npublic static class Windows\r\n{\r\n    [DllImport(\"kernel32\", SetLastError=true)]\r\n    public static extern UInt64 GetTickCount64();\r\n\r\n    public static TimeSpan GetUptime()\r\n    {\r\n        return TimeSpan.FromMilliseconds(GetTickCount64());\r\n    }\r\n}\r\n'@\r\n\r\nfunction Wait-Condition {\r\n    param(\r\n      [scriptblock]$Condition,\r\n      [int]$DebounceSeconds=15\r\n    )\r\n    process {\r\n        $begin = [Windows]::GetUptime()\r\n        do {\r\n            Start-Sleep -Seconds 1\r\n            try {\r\n              $result = &$Condition\r\n            } catch {\r\n              $result = $false\r\n            }\r\n            if (-not $result) {\r\n                $begin = [Windows]::GetUptime()\r\n                continue\r\n            }\r\n        } while ((([Windows]::GetUptime()) - $begin).TotalSeconds -lt $DebounceSeconds)\r\n    }\r\n}\r\n\r\n$operationResultCodes = @{\r\n    0 = \"NotStarted\";\r\n    1 = \"InProgress\";\r\n    2 = \"Succeeded\";\r\n    3 = \"SucceededWithErrors\";\r\n    4 = \"Failed\";\r\n    5 = \"Aborted\"\r\n}\r\n\r\nfunction LookupOperationResultCode($code) {\r\n    if ($operationResultCodes.ContainsKey($code)) {\r\n        return $operationResultCodes[$code]\r\n    }\r\n    return \"Unknown Code $code\"\r\n}\r\n\r\nfunction ExitWhenRebootRequired($rebootRequired = $false) {\r\n    # check for pending Windows Updates.\r\n    if (!$rebootRequired) {\r\n        $systemInformation = New-Object -ComObject 'Microsoft.Update.SystemInfo'\r\n        $rebootRequired = $systemInformation.RebootRequired\r\n    }\r\n\r\n    # check for pending Windows Features.\r\n    if (!$rebootRequired) {\r\n        $pendingPackagesKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\PackagesPending'\r\n        $pendingPackagesCount = (Get-ChildItem -ErrorAction SilentlyContinue $pendingPackagesKey | Measure-Object).Count\r\n        $rebootRequired = $pendingPackagesCount -gt 0\r\n    }\r\n\r\n    if ($rebootRequired) {\r\n        Write-Output 'Waiting for the Windows Modules Installer to exit...'\r\n        Wait-Condition {(Get-Process -ErrorAction SilentlyContinue TiWorker | Measure-Object).Count -eq 0}\r\n        ExitWithCode 101\r\n    }\r\n}\r\n\r\n# try to repair the windows update settings to work in non-preview mode.\r\n# see https://github.com/rgl/packer-plugin-windows-update/issues/144\r\n# see https://learn.microsoft.com/en-sg/answers/questions/1791668/powershell-command-outputting-system-comobject-on\r\nfunction Repair-WindowsUpdate {\r\n    $settingsPath = 'C:\\ProgramData\\Microsoft\\Windows\\OneSettings\\UusSettings.json'\r\n    if (!(Test-Path $settingsPath)) {\r\n        throw 'the windows update api is in an invalid state. see https://github.com/rgl/packer-plugin-windows-update/issues/144.'\r\n    }\r\n    $version = (New-Object -ComObject Microsoft.Update.AgentInfo).GetInfo('ProductVersionString')\r\n    $settings = Get-Content -Raw $settingsPath | ConvertFrom-Json\r\n    if ($settings.settings.EXCLUSIONS -notcontains $version) {\r\n        $settings.settings.EXCLUSIONS += $version\r\n        Write-Output 'Repairing the windows update settings to work in non-preview mode...'\r\n        Copy-Item $settingsPath \"$settingsPath.backup.json\" -Force\r\n        [System.IO.File]::WriteAllText(\r\n            $settingsPath,\r\n            ($settings | ConvertTo-Json -Compress -Depth 100),\r\n            (New-Object System.Text.UTF8Encoding $false))\r\n    }\r\n    Write-Output 'Restarting the machine to retry a new windows update round...'\r\n    ExitWithCode 101\r\n}\r\n\r\nExitWhenRebootRequired\r\n\r\nif ($OnlyCheckForRebootRequired) {\r\n    Write-Output \"$env:COMPUTERNAME restarted.\"\r\n    ExitWithCode 0\r\n}\r\n\r\n$updateFilters = $Filters | ForEach-Object {\r\n    $action, $expression = $_ -split ':',2\r\n    New-Object PSObject -Property @{\r\n        Action = $action\r\n        Expression = [ScriptBlock]::Create($expression)\r\n    }\r\n}\r\n\r\nfunction Test-IncludeUpdate($filters, $update) {\r\n    foreach ($filter in $filters) {\r\n        if (Where-Object -InputObject $update $filter.Expression) {\r\n            return $filter.Action -eq 'include'\r\n        }\r\n    }\r\n    return $false\r\n}\r\n\r\n$windowsOsVersion = [System.Environment]::OSVersion.Version\r\n\r\nWrite-Output 'Searching for Windows updates...'\r\n$updatesToDownloadSize = 0\r\n$updatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'\r\n$updatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'\r\nwhile ($true) {\r\n    try {\r\n        $updateSession = New-Object -ComObject 'Microsoft.Update.Session'\r\n        $updateSession.ClientApplicationID = 'packer-windows-update'\r\n        $updateSearcher = $updateSession.CreateUpdateSearcher()\r\n        $searchResult = $updateSearcher.Search($SearchCriteria)\r\n        if ($searchResult.ResultCode -eq 2) {\r\n            break\r\n        }\r\n        $searchStatus = LookupOperationResultCode($searchResult.ResultCode)\r\n    } catch {\r\n        $searchStatus = $_.ToString()\r\n    }\r\n    Write-Output \"Search for Windows updates failed with '$searchStatus'. Retrying...\"\r\n    Start-Sleep -Seconds 5\r\n}\r\n$rebootRequired = $false\r\nfor ($i = 0; $i -lt $searchResult.Updates.Count; ++$i) {\r\n    $update = $searchResult.Updates.Item($i)\r\n\r\n    # when the windows update api returns an invalid update object, repair\r\n    # windows update and signal a reboot to try again.\r\n    # see https://github.com/rgl/packer-plugin-windows-update/issues/144\r\n    # see The June 2024 preview update might impact applications using Windows Update APIs\r\n    #     https://learn.microsoft.com/en-us/windows/release-health/status-windows-11-23h2#3351msgdesc\r\n    $expectedProperties = @(\r\n        'Title'\r\n        'MaxDownloadSize'\r\n        'LastDeploymentChangeTime'\r\n        'InstallationBehavior'\r\n        'AcceptEula'\r\n    )\r\n    $properties = $update `\r\n        | Get-Member $expectedProperties `\r\n        | Select-Object -ExpandProperty Name\r\n    if (!$properties -or (Compare-Object $expectedProperties $properties)) {\r\n        Repair-WindowsUpdate\r\n    }\r\n\r\n    $updateTitle = $update.Title\r\n    $updateMaxDownloadSize = $update.MaxDownloadSize\r\n    $updateDate = $update.LastDeploymentChangeTime.ToString('yyyy-MM-dd')\r\n    $updateSize = ($updateMaxDownloadSize/1024/1024).ToString('0.##')\r\n    $updateSummary = \"Windows update ($updateDate; $updateSize MB): $updateTitle\"\r\n\r\n    if (!(Test-IncludeUpdate $updateFilters $update)) {\r\n        Write-Output \"Skipped (filter) $updateSummary\"\r\n        continue\r\n    }\r\n\r\n    if ($update.InstallationBehavior.CanRequestUserInput) {\r\n        Write-Output \"Warning The update '$updateTitle' has the CanRequestUserInput flag set (if the install hangs, you might need to exclude it with the filter 'exclude:`$_.InstallationBehavior.CanRequestUserInput' or 'exclude:`$_.Title -like '*$updateTitle*'')\"\r\n    }\r\n\r\n    if (($updatesToInstall | Select-Object -ExpandProperty Title) -contains $updateTitle) {\r\n        Write-Output \"Warning, Skipping queueing the duplicated titled update '$updateTitle'.\"\r\n        continue\r\n    }\r\n\r\n    Write-Output \"Found $updateSummary\"\r\n\r\n    $update.AcceptEula() | Out-Null\r\n\r\n    $updatesToDownloadSize += $updateMaxDownloadSize\r\n    $updatesToDownload.Add($update) | Out-Null\r\n\r\n    $updatesToInstall.Add($update) | Out-Null\r\n    if ($updatesToInstall.Count -ge $UpdateLimit) {\r\n        $rebootRequired = $true\r\n        break\r\n    }\r\n}\r\n\r\nif ($updatesToDownload.Count) {\r\n    $updateSize = ($updatesToDownloadSize/1024/1024).ToString('0.##')\r\n    Write-Output \"Downloading Windows updates ($($updatesToDownload.Count) updates; $updateSize MB)...\"\r\n    $updateDownloader = $updateSession.CreateUpdateDownloader()\r\n    # see https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa#remarks\r\n    if (($windowsOsVersion.Major -eq 6 -and $windowsOsVersion.Minor -gt 1) -or ($windowsOsVersion.Major -gt 6)) {\r\n        $updateDownloader.Priority = 4 # 1 (dpLow), 2 (dpNormal), 3 (dpHigh), 4 (dpExtraHigh).\r\n    } else {\r\n        # For versions lower then 6.2 highest prioirty is 3\r\n        $updateDownloader.Priority = 3 # 1 (dpLow), 2 (dpNormal), 3 (dpHigh).\r\n    }\r\n    $updateDownloader.Updates = $updatesToDownload\r\n    while ($true) {\r\n        $downloadResult = $updateDownloader.Download()\r\n        if ($downloadResult.ResultCode -eq 2) {\r\n            break\r\n        }\r\n        if ($downloadResult.ResultCode -eq 3) {\r\n            Write-Output \"Download Windows updates succeeded with errors. Will retry after the next reboot.\"\r\n            $rebootRequired = $true\r\n            break\r\n        }\r\n        $downloadStatus = LookupOperationResultCode($downloadResult.ResultCode)\r\n        Write-Output \"Download Windows updates failed with $downloadStatus. Retrying...\"\r\n        Start-Sleep -Seconds 5\r\n    }\r\n}\r\n\r\nif ($updatesToInstall.Count) {\r\n    Write-Output 'Installing Windows updates...'\r\n    $updateInstaller = $updateSession.CreateUpdateInstaller()\r\n    $updateInstaller.Updates = $updatesToInstall\r\n\r\n    $installRebootRequired = $false\r\n    try {\r\n        $installResult = $updateInstaller.Install()\r\n        Write-Output \"Windows update installation completed. Checking for more updates after a reboot...\"\r\n        $installRebootRequired = $installResult.RebootRequired -or $true\r\n    } catch {\r\n        Write-Warning \"Windows update installation failed with error:\"\r\n        Write-Warning $_.Exception.ToString()\r\n\r\n        # Windows update install failed for some reason\r\n        # restart the machine and try again\r\n        $rebootRequired = $true\r\n    }\r\n    ExitWhenRebootRequired ($installRebootRequired -or $rebootRequired)\r\n} else {\r\n    ExitWhenRebootRequired $rebootRequired\r\n    Write-Output 'No Windows updates found'\r\n}\r\n\r\nExitWithCode 0\r\n"
  }
]