Skip to content

Installation

HGPM is a PowerShell module. It needs PowerShell 7.4 or later on every platform; what else it needs depends on what you do with it and where.

The module

Install it from the PowerShell Gallery, or build it from the repository (the branch master):

With PSResourceGet, the module of PowerShell 7.4 and later that replaces PowerShellGet (Install-Module):

Install-PSResource -Name HGPM -Scope CurrentUser
Import-Module HGPM

Since 0.2.0, HGPM has releases: no -Prerelease. An alpha version installed before (0.1.x-alpha, with -Prerelease) goes to the release with Update-PSResource -Name HGPM, which also installs the newer versions later (updates).

git clone https://github.com/JM2K69/PSGPOTools.git
cd PSGPOTools
pwsh -File CI/03_Build.ps1          # builds HGPM/HGPM.psm1 from Code/
Import-Module ./HGPM/HGPM.psd1

The Avalonia runtime

The window runs on Avalonia 11. Its assemblies are not shipped with the module: the first time a window opens, the console downloads the 21 NuGet packages of Resources/AvaloniaPackages.json for the runtime of the computer (win-x64, win-arm64, linux-x64, linux-arm64, osx), checks each one against its pinned SHA-512 (the hash of the nuget.org catalog) before extracting anything, then each file of the runtime against its pinned SHA-256, and puts them in place at once. The console checks these files again each time it loads them, and refuses a library added next to them.

  • They go into the module folder when it can be written to, else into the data folder of the user.
  • PSGPOTOOLS_AVALONIA_NO_DOWNLOAD=1 forbids the download (offline computers: the offline archives of each release have the runtime).
  • PSGPOTOOLS_NUGET_SOURCE takes them from an internal NuGet feed, or a folder of .nupkg files, instead of nuget.org; the pinned hashes apply all the same (offline installation). A download is tried three times, two minutes each.
  • Avalonia/Get-AvaloniaBinaries.ps1 installs them beforehand, or for another computer. It loads the module: from the repository, build it first (CI/03_Build.ps1).
./HGPM/Avalonia/Get-AvaloniaBinaries.ps1 -Rid linux-x64

The commands that do not open a window (backups, drift, approval...) never need Avalonia.

The ADMX files

The module does not ship ADMX files: the console reads those of the central store of the domain (\domain\SYSVOL\domain\Policies\PolicyDefinitions), of Windows (%windir%\PolicyDefinitions) or of the SYSVOL of a Samba domain controller, else asks for a folder. As GPMC, it takes the central store of the domain it shows when it holds ADMX files, unless another folder was chosen in its window, which proposes the central store first; Initialize-PSGPOAdmx without -Path takes the central store too. The files of a folder are parsed once, then read from a cache of the user while they keep their names, sizes and dates (%LOCALAPPDATA%\PSGPOTools\Admx on Windows; $XDG_CACHE_HOME/PSGPOTools/Admx, else ~/.cache/PSGPOTools/Admx elsewhere; -NoCache parses them). Where there are none (a Linux computer, a domain without a central store), Install-PSGPOAdmx installs those of Windows from the package of Microsoft, Administrative Templates (.admx) for Windows 11 (an .msi of download.microsoft.com: 236 .admx files, their .adml files in 22 languages). HGPM neither ships nor redistributes them: they are the files of Microsoft, under its terms. The command extracts the package without installing it (msiexec /a on Windows; on Linux and macOS msiextract, of the package msitools: sudo apt install msitools, sudo dnf install msitools, brew install msitools). The module pins the package (its size and SHA-256) and each set of its files (the .admx files, each language): a package or files that differ are refused before anything is written.

Install-PSGPOAdmx                                    # en-US and the language of the session, next to the module
Install-PSGPOAdmx -UICulture en-US, fr-FR            # the languages chosen
Install-PSGPOAdmx -AllLanguages -Path ~/PolicyDefinitions
Install-PSGPOAdmx -CentralStore -Server dc.hardenbox.labo -UICulture en-US, fr-FR   # the central store of the domain
Install-PSGPOAdmx -MsiPath './Administrative Templates (.admx) for Windows 11 Sep 2026 Update.msi'   # without internet

Without -Path, the files go next to the module when it can be written to, else into the data folder of the user (PSGPOTools/PolicyDefinitions): the console finds them there. With -CentralStore, they go into SYSVOL\<domain>\Policies\PolicyDefinitions of the domain controller (an account allowed to write SYSVOL: a domain administrator), as for GPMC: every console of the domain then reads them. The ADMX files already there are kept, those of the same name replaced; with files already there, give -Force. A computer without internet: download the package on another one (the page of Microsoft is in the error of a failed download) and give it with -MsiPath; it is checked as a download is.

The cache of the ADMX files

Parsing a PolicyDefinitions folder takes a few seconds, and each console of the launcher opens in a process of its own: what a load reads is kept in a cache of the user, one file for each folder and language (%LOCALAPPDATA%\PSGPOTools\Admx on Windows; $XDG_CACHE_HOME/PSGPOTools/Admx, else ~/.cache/PSGPOTools/Admx elsewhere).

  • When it is written: the first time a folder is loaded in a language, by whatever loads it: the GPO console the first time it needs the policies (the editor, the Settings and History tabs, a report; never for the links, the delegation or the approval), or before it opens with -PolicyDefinitions; the editor alone (-NoDirectory) and Policy Analyzer when they start; Load in the ADMX window; Initialize-PSGPOAdmx. It is written aside, then renamed: a console opening meanwhile reads the former file or the new one, never half of one.
  • When it is read: while the .admx files, and the .adml files of the language and of en-US, keep their names, sizes and dates, with the same version of HGPM. A file added, changed or removed (a new template in the central store), or an update of HGPM, and the next load parses the files again and writes the cache again: a few seconds once more.
  • When it is not written: with -NoCache, after an error, or when a file was left out for a reason that may pass (the network, the rights): the next load parses the files again rather than keep a load that misses some of them. A cache that cannot be written only makes the next load slower.
  • Clearing it: delete its folder, nothing else is lost; the next load writes it again.
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\PSGPOTools\Admx"   # Windows
Remove-Item -Recurse -Force ~/.cache/PSGPOTools/Admx              # Linux, without XDG_CACHE_HOME

Windows

Need Why How
A domain account the console reads the domain with the identity of the session (Kerberos) log on with it, or -Credential with -UseSsl
RSAT Group Policy Management tools create and delete GPOs (New-GPO, Remove-GPO) Add-WindowsCapability -Online -Name 'Rsat.GroupPolicy.Management.Tools~~~~0.0.1.0' (Windows 10/11), Install-WindowsFeature GPMC (Server)
RSAT Active Directory tools optional: only the test scripts use them Add-WindowsCapability -Online -Name 'Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0'

The GroupPolicy module is a Windows PowerShell module: PowerShell 7 hides it from Get-Module -ListAvailable and loads it through its Windows PowerShell compatibility. The console finds it with -SkipEditionCheck.

SYSVOL is read and written through its UNC path (\\dc\SYSVOL\domain\Policies\{GUID}), with the identity of the session.

A session opened by SSH with a key

An OpenSSH session opened with a key has no network credentials (S4U logon): LDAP binds fail and SYSVOL cannot be reached. Run the console in an interactive session, or over SSH with a password.

Linux

Need Why Debian / Ubuntu RHEL / Fedora
OpenLDAP client library LDAP from .NET apt install libldap2 dnf install openldap
SASL GSSAPI module Kerberos over LDAP apt install libsasl2-modules-gssapi-mit dnf install cyrus-sasl-gssapi
Kerberos client the ticket the console uses apt install krb5-user dnf install krb5-workstation
smbclient read and write SYSVOL apt install smbclient dnf install samba-client
samba-tool, Samba Python bindings create and delete GPOs, SYSVOL permissions apt install python3-samba samba-common-bin dnf install samba-tools python3-samba
A graphical session the window (X11 or Wayland with XWayland)

The console authenticates with Kerberos: get a ticket first, and give the domain controller by its DNS name (Kerberos needs the name, not the IP address).

kinit administrator@HARDENBOX.LABO
klist

A password is never given to samba-tool or smbclient, and never sent over plain LDAP: with -Credential, use -UseSsl (LDAPS), and the changes still need a Kerberos ticket.

-Credential on Windows

On Windows, a domain read with -Credential (and -UseSsl) is changed with that account in the directory and in SYSVOL: the console opens an SMB connection to \\<dc>\SYSVOL with it, as net use \\<dc>\SYSVOL /user:... does. Windows has one account per server in a session: if the session already reaches that server with another account, the console says so (net use \\<dc>\* /delete closes those connections). Creating and deleting a GPO use RSAT, which only knows the identity of the session: they are refused with -Credential.

Check the installation

Import-Module HGPM
Get-Command -Module HGPM        # the public commands
Get-PSGPODirectory -Server dc.hardenbox.labo | Select-Object DomainName, Account, Source

The status bar of the window also says what the console found: this computer, its domain, the domain controller and its directory service.

Updates

The import of the module says its version, and the command that installs a newer one when the PowerShell Gallery has it:

PS> Import-Module HGPM
HGPM 0.2.0
HGPM 0.2.1 is available on the PowerShell Gallery: Update-PSResource -Name HGPM, then open a new PowerShell session.

The import reads the Gallery at most once a day (UpdateCheck.json in the local data folder of the user, PSGPOTools), and waits 8 seconds at most: without network, it gives the version only, and does not try again for an hour. It does not read it in a CI, in a session started with -NonInteractive, nor with PSGPOTOOLS_SKIP_UPDATE_CHECK=1. The new version is used by a new PowerShell session: the one running keeps the module it imported.

Test-PSGPOUpdate tells whether a newer version of HGPM is published on the PowerShell Gallery, and gives the command that installs it. It compares the version loaded with the latest of the Gallery as semantic versions: 0.1.4-alpha comes before 0.1.4-beta, itself before 0.1.4. The prereleases count when the version loaded is one (or with -Prerelease).

Test-PSGPOUpdate
# Name             : HGPM
# InstalledVersion : 0.2.0
# LatestVersion    : 0.2.1
# UpdateAvailable  : True
# UpdateCommand    : Update-PSResource -Name HGPM

if (Test-PSGPOUpdate -Quiet) { Update-PSResource -Name HGPM }

Update HGPM

  1. Close the consoles (Show-GPOManagerAvalonia, Show-PSOManagerAvalonia) and the PowerShell sessions that imported HGPM: a session keeps the module it imported.
  2. Install the new version, as the module was installed:

    Update-PSResource -Name HGPM
    

    The new version goes beside the old one (a folder per version in Modules/HGPM). A module installed for all users (-Scope AllUsers) is updated as an administrator, with -Scope AllUsers (sudo pwsh on Linux). Installed with PowerShellGet (Install-Module): Update-Module -Name HGPM.

    cd PSGPOTools
    git pull
    pwsh -File CI/03_Build.ps1
    

    The import of a checkout then suggests Install-PSResource: it installs the version of the Gallery beside the checkout, which keeps its own.

  3. Check in a new PowerShell session: the import gives the new version, without the line is available, and the dot of the status bar of the consoles is green.

    Import-Module HGPM
    Get-PSResource -Name HGPM          # the versions installed
    
  4. Optionally, remove an old version: Uninstall-PSResource -Name HGPM -Version <version>.

The changes of each version are in the changelog.