Two-tier software deployment model using Group Policy: baseline MSIs that install on every domain workstation, plus per-request approved programs filtered by computer security group membership. Scoped via a dedicated Workstations OU rather than linked at the domain root. End-to-end working deployment of five applications — 7-Zip, Chrome, VLC (baseline), PuTTY, and Wireshark (approved) — verified on a domain-joined Windows 11 client.
- Two-tier deployment design: baseline (all workstations) vs approved (per-request via security groups)
- OU-based GPO scoping — workstation-targeted policies linked to a dedicated Workstations OU rather than the domain root
- Share and NTFS permission layering for a deployment share (Domain Computers, Authenticated Users, Domain Admins)
- GPO Software Installation with MSI packages, UNC path requirements, and Assigned deployment
- Security filtering mechanics — including the Authenticated Users Read-on-Delegation requirement when restricting Security Filtering to a specific group
- Event Viewer troubleshooting (Event 6035 — Software Installation deferred processing and the two-restart requirement)
- Real-world limitations honestly documented — MSI-only constraint, Wireshark's Npcap dependency, and when to migrate to Intune or SCCM
- Design iteration — refactoring from domain-root linking + DC Deny exclusion to OU-scoped linking
| Component | Detail |
|---|---|
| Domain controller | WS2022.mylab.local (Windows Server 2022 Datacenter) |
| Client | WIN11-TEST01 (Windows 11 Pro, domain-joined, in Workstations OU) |
| Platform | VMware Workstation |
| Domain | mylab.local |
| Deployment share | \\WS2022\SoftwareDeploy$ (on DC E:\Software Deploy) |
| Baseline MSIs deployed | 7-Zip 26.00, Google Chrome 147.0, VLC 3.0 |
| Approved MSIs deployed | PuTTY 0.83, Wireshark 4.6.4 |
This lab deploys software to domain-joined workstations via Group Policy using two distinct patterns:
Baseline deployment — software every workstation should have (archivers, media players, browsers). One GPO, linked to the Workstations OU, filtered to Authenticated Users.
Approved program deployment — specialist or per-request software (PuTTY for admin teams, Wireshark for network analysts). Each application gets its own GPO plus its own security group. Computers are added to the group as requests come in.
Both tiers are linked at the Workstations OU, not the domain root. The DC sits in its own Domain Controllers OU and is naturally out of scope — no explicit Deny exclusions required.
E:\Software Deploy\
├── Baseline\ ← MSIs that go on every workstation
└── Approved Programs\ ← MSIs deployed per-request via security groups
| Type | GPO Name | Security Group | Security Filter |
|---|---|---|---|
| Baseline | SW-Baseline-AllPCs |
— | Authenticated Users |
| Approved | SW-[AppName]-Approved |
SW-[AppName] |
SW-[AppName] group |
All GPOs reference this same share. Set it up once.
On the DC, create E:\Software Deploy\ with Baseline\ and Approved Programs\ subfolders.
- Right-click
E:\Software Deploy→ Properties → Sharing tab. - Click Advanced Sharing → tick Share this folder.
- Set share name to SoftwareDeploy$ (the
$hides it from casual network browsing).
Share name vs folder name: The folder on disk is
E:\Software Deploy(with a space) but the share name isSoftwareDeploy$(no space). All UNC paths use the share name, not the folder name. Clients never see or care about the folder name on the E: drive.
Click Permissions. Remove Everyone, then add:
| Principal | Permission |
|---|---|
| Domain Computers | Read |
| Domain Admins | Full Control |
Why Domain Computers and not individual PCs? Domain Computers is a built-in group that automatically includes every computer that joins the domain. Adding individual computer objects (e.g.,
WIN11-TEST01$) doesn't scale — you'd have to add every new PC manually.
Why Read, not Change? Clients only need to pull MSI files during installation. They never write back to this share. Change would be excessive.
Right-click E:\Software Deploy → Properties → Security tab → Edit.
| Principal | Permission |
|---|---|
| Authenticated Users | Read & Execute |
| Domain Admins | Full Control |
The permissions set on E:\Software Deploy need to cascade to Baseline and Approved Programs.
- Navigate into
E:\Software Deploy\Baseline→ right-click → Properties → Security → Advanced. - In the permissions list, confirm Authenticated Users and Domain Admins appear with Inherited from showing
E:\Software Deploy. - At the bottom, confirm Include inheritable permissions from this object's parent is ticked.
- Cancel (no changes needed). Repeat on
Approved Programs.
If inheritance is disabled, click Enable inheritance → choose Convert when prompted → Apply.
What inheritance means here: Any permission set on
E:\Software Deployautomatically cascades to every subfolder and file inside it. Baseline and Approved Programs don't need permissions configured separately — they inherit from the parent.
| Software type | Location |
|---|---|
| Baseline (7-Zip, VLC, Chrome, etc.) | E:\Software Deploy\Baseline\ |
| Approved (PuTTY, Wireshark, etc.) | E:\Software Deploy\Approved Programs\ |
Critical — MSI only: GPO Software Installation only works with
.msifiles..exeinstallers are silently ignored. Always download the MSI version from the vendor's website where available. Many commercial vendors do not publish public MSI installers; see the "Real-world limitations" section below for how this is handled in practice.
On the client, open CMD and run:
dir \\WS2022\SoftwareDeploy$\Baseline
dir "\\WS2022\SoftwareDeploy$\Approved Programs"
Both must return MSI files successfully. If either fails, the GPO will never work — fix share or NTFS permissions before proceeding.
Before building the deployment GPOs, the OU structure needs two dedicated OUs: one for workstation computer objects, one for the security groups used in approved program filtering. This structure determines where GPOs are linked and how they're scoped.
- Open Active Directory Users and Computers (
dsa.msc). - Right-click mylab.local → New → Organizational Unit.
- Name it Workstations OU.
- Move
WIN11-TEST01from the default Computers container into this new OU.
- Right-click mylab.local → New → Organizational Unit.
- Name it Software Groups.
- Inside it, create two Global Security groups:
SW-PuTTYandSW-Wireshark. Don't add members yet.
Why separate OUs for workstations and software groups? Keeping computer objects and security groups in different OUs makes delegation cleaner later — helpdesk staff can be given rights to manage security group memberships without touching computer objects, and vice versa. In a larger environment you'd also have separate OUs for servers, service accounts, and admin accounts following a tiered admin model.
All workstation-targeted deployment GPOs are linked to the Workstations OU, not the domain root. This design decision is driven by three practical concerns:
Cleaner GPMC view. At 10+ approved programs, linking each GPO to the domain root creates a wall of text under mylab.local. Clicking on the domain root in GPMC should show policies that genuinely apply domain-wide (firewall baseline, password policy) — not a crowded list of workstation-specific software GPOs.
No DC exclusion needed. When GPOs are linked at the domain root, every computer in the domain is in scope by default — including the DC. Workstation software has no business on a DC, so an explicit Deny on Apply group policy for WS2022$ was required on every new GPO. Easy to forget, and a forgotten Deny means the DC accidentally receives workstation software. With OU-scoped linking, the DC sits in its own Domain Controllers OU and is naturally out of scope.
Scoping through structure, not exceptions. Expressing "this policy applies to workstations" through OU placement is cleaner than expressing it through Security Filtering plus Deny entries. The intent is visible from the GPMC tree, not buried in a GPO's Delegation tab.
See the Design iteration section at the end of this README for the original domain-root design and how it was refactored.
For software every workstation should have. One GPO can contain multiple MSI packages.
- In GPMC, right-click the Workstations OU → Create a GPO in this domain, and Link it here.
- Name it SW-Baseline-AllPCs.
- Right-click SW-Baseline-AllPCs → Edit.
- Navigate to: Computer Configuration → Policies → Software Settings → Software Installation.
- Right-click in the right pane → New → Package.
- In the file dialog, type the UNC path directly:
\\WS2022\SoftwareDeploy$\Baseline\7z2301-x64.msi
- When prompted, select Assigned → OK.
- Repeat for each baseline MSI (Chrome, VLC, etc.). All go into this one GPO.
Critical — UNC path only: Do NOT browse via
C:\orE:\. You must use the UNC path (\\servername\sharename\...). If you use a local path, the GPO stores that local path and the client will look for the file on its own hard drive — which doesn't exist. This is the single most common cause of software deployment failures.
Assigned vs Published: Assigned = installs automatically at computer startup. Published = shows up in "Add or Remove Programs" for users to install optionally (user-assigned only). Baseline deployments are always Assigned.
Under the Scope tab, Security Filtering should show Authenticated Users. Leave as is — combined with the OU link, this ensures every computer in the Workstations OU processes this GPO.
After both tiers are built (this section plus Part 4), the Workstations OU should have all deployment GPOs linked:
For specialist software that only specific workstations should receive. Each approved application gets its own GPO and its own security group. This section walks through PuTTY end-to-end; Wireshark follows the identical pattern.
- In GPMC, right-click the Workstations OU → Create a GPO in this domain, and Link it here.
- Name it SW-PuTTY-Approved.
- Right-click SW-PuTTY-Approved → Edit.
- Navigate to: Computer Configuration → Policies → Software Settings → Software Installation.
- New → Package → UNC path:
\\WS2022\SoftwareDeploy$\Approved Programs\PuTTY.msi
- Select Assigned → OK.
This is the key difference from baseline deployment.
- In GPMC, click on SW-PuTTY-Approved under the Workstations OU.
- Under the Scope tab → Security Filtering:
- Select Authenticated Users → Remove.
- Click Add → type
SW-PuTTY→ Check Names → OK.
When Authenticated Users is removed from Security Filtering, it is also removed from Delegation entirely. This must be added back with Read-only permission — otherwise the GPO fails silently.
- Go to the Delegation tab → click Add.
- Type
Authenticated Users→ Check Names → OK. - In the Permissions dropdown, select Read (not Edit settings).
- Click OK.
Why keep Authenticated Users with Read in Delegation? If Authenticated Users has no permission at all on the GPO, computers can't read the GPO to determine whether they should apply it. The GPO becomes invisible to all machines and fails silently — no event, no error, no deployment. Authenticated Users needs Read so every computer can discover the GPO; only members of SW-PuTTY actually apply it. This is the most commonly misunderstood part of security filtering, and was reinforced by MS16-072 which changed how GPO reads are authenticated. Every approved program GPO needs this check.
Same pattern as 4.1 through 4.4, with these substitutions:
- GPO name:
SW-Wireshark-Approved - MSI path:
\\WS2022\SoftwareDeploy$\Approved Programs\Wireshark.msi - Security Filtering group:
SW-Wireshark
- In ADUC, find
WIN11-TEST01→ right-click → Properties → Member Of tab → Add. - Click Object Types → tick Computers → OK. (Easy to miss — by default Computers object type isn't selected, so typing a computer name fails with "object not found" until this is enabled.)
- Type
SW-PuTTY→ Check Names → OK. - Repeat: Add → type
SW-Wireshark→ OK.
- Restart the client — twice. See the troubleshooting section below for why.
- After login, open Programs and Features. All five applications should appear.
From an elevated CMD:
gpresult /r
Under Computer Settings → Applied Group Policy Objects, all three software GPOs should be listed alongside Firewall Baseline and Default Domain Policy.
And Programs and Features on the client:
Each new approved application follows the same pattern:
| Security Group | GPO Name | MSI |
|---|---|---|
SW-PuTTY |
SW-PuTTY-Approved |
PuTTY.msi |
SW-Wireshark |
SW-Wireshark-Approved |
Wireshark.msi |
SW-[NewApp] |
SW-[NewApp]-Approved |
[NewApp].msi |
To deploy a new app on a workstation: add the computer object to the relevant security group and restart twice.
The most common "it's not working" scenario. gpresult /r shows the GPO under Applied Group Policy Objects, but Programs and Features doesn't show the software.
Cause: Windows uses fast logon optimisation by default — Group Policy processes asynchronously at boot so users can log in quickly. But Software Installation requires synchronous foreground processing because it must run before any user session exists. When a new Software Installation policy is detected, Windows defers the actual install until the next synchronous foreground boot.
Evidence: Event Viewer → Applications and Services Logs → Microsoft → Windows → GroupPolicy → Operational → Event ID 6035: "Software Installation Extension deferred processing until next synchronous foreground."
Fix: Restart the client a second time. The software installs before login on the second boot.
Prevention for future deployments: Enable Computer Configuration → Policies → Administrative Templates → System → Logon → Always wait for the network at computer startup and logon in a machine-baseline GPO. This forces synchronous foreground processing every boot, so Software Installation policies install on the first boot after policy changes. Trade-off: slightly slower boot times because the machine waits for the domain to be contactable before showing the login screen. Standard practice in enterprise environments.
Work through these in order:
1. Did you use the UNC path? Check the package properties inside the GPO. Source path must start with \\WS2022\SoftwareDeploy$\... — not C:\ or E:\. Number one failure cause.
2. Is it actually an MSI? GPO Software Installation only supports .msi files. .exe installers are silently ignored.
3. Can the client reach the share? From an admin CMD on the client: dir "\\WS2022\SoftwareDeploy$\Approved Programs". If this fails, it's a share permission, NTFS permission, DNS, or firewall issue.
4. Is the GPO applied? gpresult /r. Check under Computer Settings → Applied Group Policy Objects. If not listed, check the "filtered out" section for the reason. Common causes: computer not in the right security group, Authenticated Users missing Read on Delegation, WMI filter blocking it.
5. Check Event Viewer. Applications and Services Logs → Microsoft → Windows → GroupPolicy → Operational. Look for the most recent boot. Common errors:
- Event 6035 — Deferred processing. Restart again.
- Event 101 — Failed to access the GPO. Share permission or DNS issue.
- Software Installation errors — Usually corrupt MSI or UNC path issue.
6. Group membership refreshes at boot. After adding a computer to a security group, the computer needs to restart to pick up the new group membership. gpupdate /force alone won't refresh the Kerberos ticket that carries group memberships.
Cause: Wireshark requires Npcap (packet capture driver) for live traffic capture. The Wireshark EXE installer bundles Npcap and installs it interactively. The MSI installer — which is what GPO Software Installation requires — does not install Npcap. Wireshark opens and can read existing .pcap files, but the interface list is empty for live capture.
Why not deploy Npcap via GPO too? Npcap ships as an EXE-only installer from Nmap Project. GPO Software Installation cannot deploy EXE installers. Free Npcap is also capped at 5 systems per the licence.
Practical handling options:
- Lab / small deployment: Install Npcap manually on each workstation that needs live capture. Documented as a known limitation.
- GPO startup script: Deploy Npcap via a computer startup script calling
npcap.exe /Sfor silent install. Works but sits outside GPO Software Installation's management model. - Enterprise: Move Wireshark deployment to Intune Win32 apps or SCCM Application model, where both the MSI and its EXE-based Npcap dependency can be packaged together (typically using PSAppDeployToolkit wrapping).
This limitation is representative of the broader problem outlined below.
GPO Software Installation is a valid tool for basic MSI-based baseline deployment in small AD environments. At scale, it hits ceilings:
- MSI-only. Many commercial vendors ship EXE installers (Adobe, Autodesk) or have dependencies that ship as EXE (like Wireshark's Npcap). GPO Software Installation cannot handle these without supplementary startup scripts.
- GPMC sprawl. At 10+ approved programs, even with OU-scoping, GPMC lacks folder or grouping features for GPOs. The naming convention (
SW-[App]-Approved) helps alphabetical sorting, but visibility remains limited. - No supersedence, dependencies, or maintenance windows. Assigned MSIs install at boot with no staging, no dependency resolution, no rollback, and no way to target a maintenance window.
- Poor observability. Failure modes are visible only through Event Viewer on each client. No central reporting.
Modern enterprise alternatives:
- Intune Win32 apps — each application is a discrete object in a catalogue, assigned via Entra ID groups. Handles MSI, EXE, PowerShell scripts, complex detection logic, and per-user or per-device targeting. Works over the internet without VPN. Where most organisations with Microsoft 365 are heading.
- SCCM Application model — on-prem enterprise standard. Proper application catalogue with supersedence, dependencies, maintenance windows, and central deployment reporting.
- PSAppDeployToolkit (PSADT) — PowerShell framework for wrapping EXE installers with logging, user UI, and proper exit code handling. Commonly used inside SCCM or Intune packages.
In a production environment with more than a handful of applications, the deployment pattern demonstrated in this lab would typically be used only for foundational baseline software, with everything else managed through Intune or SCCM.
This repo went through one significant design iteration worth documenting. The original design worked but didn't scale; the refactor fixes the scaling problem and simplifies the scoping model.
All software deployment GPOs linked at the domain root (mylab.local). Baseline scoped to every domain-joined computer, with the DC explicitly excluded via Deny on Apply group policy on the WS2022$ computer object in the GPO's Delegation tab.
Functionally correct — Deny overrides Allow, so the DC was successfully excluded from baseline software. But the design surfaced problems:
- Domain root clutter. Every new approved program GPO added another link under
mylab.local. At 10+ approved programs, the domain root becomes a wall of text in GPMC, mixing workstation-specific software with genuinely domain-wide policies like firewall and password baselines. - Deny exclusion was fragile. Each new workstation-targeted GPO required remembering to add the DC Deny entry. Forgetting it meant the DC would receive workstation software — a real risk in larger environments where server admins and workstation admins might be different people.
- Scoping expressed through exceptions, not structure. "This policy applies to workstations only" was encoded in a Security Filtering exception rather than an OU boundary. The intent was hidden in the Delegation tab rather than visible in the GPMC tree.
- Created a Workstations OU at the domain root.
- Moved
WIN11-TEST01from the default Computers container into the Workstations OU. - Unlinked
SW-Baseline-AllPCsandWindows Update Settingsfrom the domain root. - Re-linked both to the Workstations OU.
- New approved program GPOs (
SW-PuTTY-Approved,SW-Wireshark-Approved) created directly under the Workstations OU. - Removed the DC Deny entry from
SW-Baseline-AllPCs— no longer needed, since the DC sits in the Domain Controllers OU and is naturally out of scope.
The domain root now shows only truly domain-wide policies: Default Domain Policy, Firewall Baseline. All workstation-specific deployment GPOs live under the Workstations OU where they belong.
- Drop the MSI into
E:\Software Deploy\Baseline\on the DC. - Edit
SW-Baseline-AllPCsGPO → Software Installation → New → Package → UNC path. - All workstations install it at their next second-boot-after-change.
- Drop the MSI into
E:\Software Deploy\Approved Programs\on the DC. - Create security group
SW-[AppName]in the Software Groups OU. - Create GPO
SW-[AppName]-Approvedlinked to the Workstations OU. - Add the MSI under Software Installation.
- In Security Filtering, replace Authenticated Users with
SW-[AppName]. - In Delegation, add Authenticated Users back with Read permission.
- Add target computer objects to
SW-[AppName]. - Restart target workstations (twice — see troubleshooting).
For approved programs: remove the computer object from the security group and restart. Depending on the GPO package's Deployment tab options, the software may be automatically uninstalled on next boot.
Edit SW-Baseline-AllPCs → Software Installation → right-click the package → All Tasks → Remove. Choose whether to immediately uninstall from all workstations or allow users to continue using it.
| Concept | Where it appears |
|---|---|
| Two-tier deployment model | Baseline (all workstations) vs Approved (per-request via security groups) |
| OU-based scoping through structure | All deployment GPOs linked to Workstations OU rather than domain root |
| Share vs NTFS permission layering | Domain Computers Read on share, Authenticated Users R&E on NTFS |
| UNC path dependency | GPO stores whatever path you enter — local paths fail silently on clients |
| Computer-assigned software runs at boot | Restart required, not gpupdate /force |
| Two-restart requirement | Software Installation defers to next synchronous foreground boot (Event 6035) |
| Security filtering mechanics | Authenticated Users needs Read on Delegation even when removed from Security Filtering |
| Group membership refreshes at boot | Adding a computer to a security group requires restart to take effect |
| MSI-only limitation | .exe installers silently ignored; workarounds via startup scripts or modern tooling |
| Design iteration | Refactored from domain-root linking + DC Deny to OU-scoped linking |
| When to move beyond GPO | Intune Win32 apps or SCCM for EXE handling, supersedence, reporting, and scale |














