The Local A-DEM I Mean, Admin Paradox


*Since vb.net does not exist as syntax here i used basic not optimal but best i can do.
When elevation just doesn't cut it.
You know the deal:
You get DEM elevation, launch something as admin... and still get blocked.
Because SYSTEM ≠ user, and elevation ≠ local admin.
Apps running under SYSTEM, installers, services they don’t care about your nice little “run elevated” badge from DEM.
But here’s the mind blowing thing and the paradox:
Quote
You can use that limited DEM elevation to give yourself real local admin rights.
Let that sink in.
The elevation might not let you install the thing, but it will let you add your domain account to the local administrators group after which, yes, you can install the thing. We still have some legacy which unfortunately cannot be solved in an other way.
So I built a small VB.NET utility in 2020 to do exactly that (and it still works in W11 in 2025):
Only runs on whitelisted domains
Grabs the real logged-in user
Adds that user to the local admin group
Cleans up after itself
And politely exits stage left
Because when elevation gives you lemons, you might as well use them to rewrite your access level.
For example :
1. Registering COM Components or DLLs
Why DEM elevation fails:
Registering with regsvr32
modifies system-wide settings under HKLM\Software\Classes
and may copy files to C:\Windows\System32
both actions require full local administrator rights, not just an elevated user token.
Example:
regsvr32 somecontrol.dll
Result:
Fails silently or throws Access Denied unless the user is a member of the local Administrators group with a full token.
Real-world impact:
Some legacy or enterprise applications attempt on-the-fly COM registration during runtime, especially if:
They're repairing broken file associations,
They're verifying component registration on launch,
Or they self-register plugins dynamically (e.g., older .NET, VB6, or Delphi apps).
Symptoms:
App crashes at startup
Features silently disabled
"ActiveX component can't create object" errors
Missing right-click menu entries or Office add-ins
Why this breaks with DEM elevation:
Because even though the process is elevated, the HKLM hive and System32 folder reject write access from anything other than a full local admin token.
The Token Fuzz: Why DEM Elevation ≠ Full Admin
When you elevate a process (like with DEM), you're not becoming an admin you're just getting a filtered copy of the admin token. Windows politely lets you think you have power, but behind the scenes, you're still fenced in.
User Tokens: Standard vs. Elevated
Every Windows process runs with an access token it defines what you're allowed to do.
Standard Token → what you get by default, even if you're in the Administrators group
Elevated Token → what you get when you click "Run as Administrator" or respond to a UAC prompt
Even if you're technically a local admin, UAC ensures that you don't run with full privileges unless you explicitly elevate.
The DEM Limitation
DEM (and most user environment tools) "elevate" by launching the process in an elevated user context but:
It's not SYSTEM
It doesn’t have all Se privileges*
It gives you an elevated user token, not a full administrative one
Result?
You're still blocked from doing things that require true machine-level control.
SYSTEM Context ≠ Elevated User
Here’s the kicker and the fuzz:
Tools like
regsvr32
, service installers, or driver writers don’t care if you’re "elevated"They check your token:
“Are you SYSTEM?”
“Do you have full local admin privileges?”
If the answer is no access denied.
Even though DEM says you’re elevated, Windows knows better.
The Paradox in Action
Let’s say you launch an installer from DEM:
It tries to write to
HKLM\Software
It needs to copy files to
C:\Program Files
It might register a COM component or start a service
You’re elevated but not enough.
Windows checks → sees a filtered token → denies the write.
But here’s the paradox:
Quote
That same fuzzy token can still be used to add yourself to the local Administrators group granting you full rights
Run as Administrator
.
LCLGRP.Invoke("Add", New Object() {DOMUSR.Path.ToString})
More about this line of code later but first some drawbacks :
If you use Run as Administrator after your user was added to the local Administrators group, you don’t need to log off and back on to gain elevated access in that new process. But here’s the nuance:
What Works Immediately
Once you're added to the local Administrators group:
Any process launched with Run as Administrator will get a full admin token.
You can now register COM components, install services, write to
HKLM
, etc.You don’t need to log off to use
regsvr32
, installers, or system tools if you launch them elevated after being added.
What Still Requires a Logoff/Login (so no luck in non persistent use cases)
Your current Explorer shell (taskbar, file explorer, etc.) is still running under your old token.
Any already-running tools (Command Prompt, PowerShell, etc.) keep using the non-admin token.
You may not see permission changes reflected in Explorer or apps started before elevation unless you:
Restart them with Run as Admin, or
Log off and back on (or restart Explorer cleanly).
So DEM can’t help you install the app,
…but it can help you become the kind of admin who can.
Before doing the deep dive in a very short code snippet , yep it really isn't much let's look at the requirements:
Requirements
Before using the code below, make sure your environment meets the following:
Environment Prerequisites
Windows client or server with .NET Framework 4.x
Domain-joined machine
Domain user running the app (must be able to see the domain via
WinNT://
)DEM or UEM tool capable of launching an executable with "elevated rights"
Code Dependencies
System.Management.dll
(for WMI call to get current user)System.DirectoryServices.dll
(for modifying local groups via WinNT provider)
These are standard .NET libraries and don’t require additional NuGet packages.
Execution Rights
Run via a tool like DEM with elevation configured
The executing user must have permission to add domain users to local groups (in practice: this script adds the current domain user, so no impersonation or credentials are needed)
**To program it yourself you need the following:
1. Project Type**
Windows Forms App (.NET Framework)
Target framework: .NET Framework 4.7.2 or higher (recommended for modern Windows compatibility)
2. Required Imports
These namespaces must be imported at the top of your form:
Imports System.Management
Imports System.DirectoryServices
3. Project References
Ensure your project references the following assemblies (they are included by default in WinForms projects targeting .NET Framework):
Reference | Purpose |
System.Management.dll | Used for WMI queries to get the logged-in user |
System.DirectoryServices.dll | Used to access and manipulate local/domain user and group objects |
Quote
In Visual Studio:
Right-click References → Add Reference → Assemblies → Check:
System.Management
System.DirectoryServices
4. UI Components (Windows Form)
Minimal UI required (since it closes itself). You can keep:
One default form:
Form1
FormBorderStyle = None
(optional, makes it fully silent)ShowInTaskbar = False
(optional, hides it)StartPosition = CenterScreen
(or manual)
You don’t need any controls on the form.
5. Application Settings
In Project Properties
:
Set Output type to:
Windows Application
Enable "Enable application framework"
Optionally check "Make single instance application"
The code explained followed by the full code :
Imports System.Management
Imports System.DirectoryServices
Purpose:
System.Management
: Used to query WMI for the currently logged-on user.System.DirectoryServices
: Used to access and modify local and domain group membership.
Const AllowedDomain As String = "YOURDOMAIN" ' NetBIOS domain name
Const WinNTDomainPath As String = "WinNT://YOURDOMAIN"
Purpose:
This defines your domain name in one place to avoid hardcoding it twice.
AllowedDomain: The domain this tool is allowed to run in (from %USERDOMAIN%).
WinNTDomainPath: Used by DirectoryEntry to find users in the domain.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Executes when the form loads (application starts)
In this case three things are done :
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If Environment.UserDomainName.ToUpper() = AllowedDomain Then
Me.Visible = False
adduserasadmin()
Dim strAppdata As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
Try
System.IO.File.Delete(strAppdata & "\Microsoft\Windows\Start Menu\Programs\Startup\Add addlocaladmin shortcut.lnk")
Catch
' Ignore file delete errors
End Try
Me.Close()
Else
MsgBox("This program can only run within the whitelisted domain.", vbInformation, "I shall not run :)")
Me.Close()
End If
End Sub
check if the domain of the user is an allowed domain to execute more of the code
run the adduserasadmin() routine
Delete the shortcut set by DEM in startup to run after login : System.IO.File.Delete(strAppdata & "\Microsoft\Windows\Start Menu\Programs\Startup\Add addlocaladmin shortcut.lnk") the program assumes the startup folder of the logged on user : "shell:starup" location when run with win+r
adduserasadmin()
The Core Action Block
This is the function that does the actual work: adding the current domain user to the local "Administrators" group on the machine.
Here’s what each part does:
Try
Wraps the logic in a Try/Catch
block to avoid crashing the app on permission or lookup errors.
Dim UserName As String = get_user()
Calls the get_user()
function to retrieve the username of the actual user logged into the machine (not the one running the process if elevated via DEM).
Example return: "j.smith"
Dim PCNAME As String = Environment.MachineName
Gets the local computer name, needed to construct the WinNT://
path for the local machine context.
Example: "PC-0237"
Dim localusrname As String = UserName
Assigns the username to a new variable.
Dim LCL As New DirectoryEntry("WinNT://" & PCNAME & ",computer")
Creates a DirectoryEntry
object targeting the local computer. This object allows us to query and modify local users and groups.
Example:"WinNT://PC-0237,computer"
Dim DOM As New DirectoryEntry(WinNTDomainPath)
Creates a DirectoryEntry
for your domain (e.g., "WinNT://NKI"
), so you can search for domain users.
WinNTDomainPath
is a constant you define earlier in the code.
Dim DOMUSR As DirectoryEntry = DOM.Children.Find(localusrname, "user")
Finds the user object in the domain by name.
If "j.smith"
exists in the domain and is a valid user, this returns the full domain user entry.
Fails silently if:
The user doesn’t exist in the domain.
The domain is unreachable.
Dim LCLGRP As DirectoryEntry = LCL.Children.Find("Administrators", "group")
Finds the local Administrators group on the computer.
This is where we want to add the domain user.
LCLGRP.Invoke("Add", New Object() {DOMUSR.Path.ToString})
Calls the Add
method on the local Administrators group and passes the full AD path of the domain user.
This is equivalent to running:
net localgroup administrators "DOMAIN\j.smith" /add
But done programmatically using the legacy WinNT://
provider.
Catch ex As Exception
' Silently fail
End Try
Catches any exceptions without throwing an error.
This avoids breaking the form or showing a stack trace if:
The user is already in the group
The domain is unavailable
The app lacks permission to modify group memberships
get_user()
Getting the Real Logged-On User
In some cases (especially with DEM or UEM tools), using Environment.UserName
or WindowsIdentity.GetCurrent()
won’t give you the actual desktop user it may return SYSTEM
, LOCAL SERVICE
, or the launching context.
This function solves that by asking WMI who is actually logged on at the console.
Code Explanation
Public Function get_user() As String
Declares a public function that returns the currently logged-on username (just the short name no domain prefix).
Dim username As String = "test"
Initializes the username
variable with a dummy value. This gets overwritten in the loop, but avoids uninitialized errors.
Dim searcher As New ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem")
Creates a WMI query to retrieve the UserName
property from the Win32_ComputerSystem
class which tells you who's logged on to the console session.
This is the most reliable way to get the real desktop user.
Dim collection As ManagementObjectCollection = searcher.Get()
Executes the query and returns a collection of results. Usually only one object is returned, but it's still a collection.
For Each oReturn As ManagementObject In collection username = oReturn("UserName") Next
Loops over the returned objects (normally just one) and assigns the UserName
property to our variable.
The format is:
DOMAIN\username
Dim parts() As String = Split(username, "\")
Splits the DOMAIN\username
string into two parts:
parts(0)
= domainparts(1)
= username
If parts.Length > 1 Then username = parts(1) End If
Ensures the array contains both domain and username before grabbing just the username part. This is the value we want to add to the local admin group.
Return username End Function
Returns the cleaned-up short username (e.g., "j.smith"
), which is used in the next function to find the domain user.
Why Not Just Use Environment.UserName
?
Because that can return:
SYSTEM
LOCAL SERVICE
Or the wrong user in elevated or background sessions
This WMI method tells you who’s actually logged on to the system the person sitting at the keyboard.
Full Code :
Imports System.Management
Imports System.DirectoryServices
Public Class Form1
' === EDIT THESE VALUES ===
Const AllowedDomain As String = "YOURDOMAIN" ' NetBIOS name, e.g. "DOM1"
Const WinNTDomainPath As String = "WinNT://YOURDOMAIN" ' No trailing slash
' =========================
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If Environment.UserDomainName.ToUpper() = AllowedDomain Then
Me.Visible = False
adduserasadmin()
Dim strAppdata As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
Try
System.IO.File.Delete(strAppdata & "\Microsoft\Windows\Start Menu\Programs\Startup\Add addlocaladmin shortcut.lnk")
Catch
' Ignore file delete errors
End Try
Me.Close()
Else
MsgBox("This program can only run within the whitelisted domain.", vbInformation, "I shall not run :)")
Me.Close()
End If
End Sub
Public Function get_user() As String
Dim username As String = "test"
Dim searcher As New ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem")
Dim collection As ManagementObjectCollection = searcher.Get()
For Each oReturn As ManagementObject In collection
username = oReturn("UserName")
Next
Dim parts() As String = Split(username, "\")
If parts.Length > 1 Then
username = parts(1)
End If
Return username
End Function
Private Sub adduserasadmin()
Try
Dim UserName As String = get_user()
Dim PCNAME As String = Environment.MachineName
Dim localusrname As String = UserName
Dim LCL As New DirectoryEntry("WinNT://" & PCNAME & ",computer")
Dim DOM As New DirectoryEntry(WinNTDomainPath)
Dim DOMUSR As DirectoryEntry = DOM.Children.Find(localusrname, "user")
Dim LCLGRP As DirectoryEntry = LCL.Children.Find("Administrators", "group")
LCLGRP.Invoke("Add", New Object() {DOMUSR.Path.ToString})
Catch ex As Exception
' Silently fail
End Try
End Sub
End Class
Quick Note on DEM Elevation
I won’t go into too much detail here if you're reading this post, I assume you already know how to wrangle DEM.
But in short, here’s what works:
Create a domain group like
DL_DEM_LA
and throw your legacy power users in there.Store the compiled
.exe
on a shared location your DEM config share is perfect.Create a DEM Shortcut rule scoped to that AD group.
Create an Elevation rule:
Match by path, filename, or signature whatever fits your setup.
Optionally add a condition for the same AD group to scope elevation even further.
That’s it. Clean, scoped, and no GPO gymnastics required.
Why This Approach Works So Well
User-scoped: You control who sees the shortcut and who gets elevation with a simple AD group.
Stateless-friendly: No need to touch the base image or rely on persistent local config.
No OU dependency: No loopback processing, no item-level targeting, no Group Policy wizardry.
Works with instant clones: Because DEM is session-based, it naturally fits non-persistent environments.
Reversible: The shortcut disappears when the user leaves the group nothing baked in, nothing to clean up.
The Alternatives (and Why They Suck in VDI my humble opinion)
Option 2: Group Policy (GPO)–Based Local Admin Rights
Use a GPO to add users or groups to the local “Administrators” group.
Scope the policy via OU or security filtering.
It applies at user logon.
But GPO elevation is harder to scope per user.
GPOs are typically applied to computers or OUs, not individual users.
If you want to give just one person local admin rights on just one machine (or session type), you’ll end up juggling:
Item-Level Targeting
Security Filtering
Potential GPO conflicts
Complex loopback configurations
And all of that has to reapply at every logon in a non-persistent environment making it brittle, inconsistent, and hard to manage cleanly.
Quote
Bottom line:
GPOs can work but in fast-booting, non-persistent VDIs, you’re trusting a lot of moving parts to line up perfectly. That’s rarely a good idea.
Option 3: Baking a Domain Group into the Base Image
This is the "default admin everywhere" method and the one most likely to bite you later.
You add a global domain group (e.g.
DOMAIN\LocalAdmins
) to the local Administrators group in your base image.Now, every user in that group is local admin on every VM that uses that image.
The problem?
No scoping. No per-session logic. No way to control who is admin where. You’re giving broad, persistent admin rights across the entire fleet.
Quote
Great for testing.
Terrible for production.
Even worse for incident response.
What About Commercial Tools ?
Yes there are commercial solutions out there that offer just-in-time admin access with approval workflows, logging, and revocation after use. Think:
Admin By Request
MakeMeAdmin
CyberArk Endpoint Privilege Manager
...and a few others
These tools are great if:
You need audit trails for compliance.
You want time-limited or approval-based elevation.
You support a large fleet with delegated admin needs.
But they come with:
Licensing costs
Agent / service installations
Infrastructure overhead
If you already have DEM in place and just need to cover a handful of legacy apps, engineers, or use cases, then combining DEM + this lightweight tool gives you 90% of the benefit with 0% of the cost.
Final Thoughts
This little tool gets the job done and does it cleanly.
But let’s be real:
Quote
Local admin always carries risk.
It should never be the default only the exception.
Use it only when:
DEM elevation isn’t enough to register a COM component, install a service, or bypass a SYSTEM-owned install blocker.
EUC engineers need real admin rights under their own user account for testing, debugging, or running config scripts without jumping through GPO hoops or logging in as someone else.
If you’re going to hand out admin rights, this method at least lets you:
Scope it to the right users
Trigger it only when needed
Audit and reverse it easily
Download the Source
I’ve included a .zip
file with the full VB.NET source code no compiled executable, no funny business.
You'll need to open it in Visual Studio and build it yourself.
Also, don’t forget to update:
Const AllowedDomain As String = "YOURDOMAIN"
Const WinNTDomainPath As String = "WinNT://YOURDOMAIN"
…to match your actual NetBIOS domain name.
Otherwise, the tool will politely refuse to run
Feedback Welcome (Really)
If you like the tool give me a heads-up, drop a comment, or just steal the idea and pretend it was yours.
If you hate it, or think my reasoning is total bogus even better. Tell me why.
This kind of stuff only gets better when people call out the rough edges.
So don't hold back. I’m all ears and apparently, also local admin now.
Enjoy,
Mark
Subscribe to my newsletter
Read articles from Mark Platte directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Mark Platte
Mark Platte
Mark Platte Born in January, 1984.I currently work as an IT architect in a hospital environment, with a career shaped by hands-on experience in application development, storage engineering, and infrastructure design. My roots are in software, but over time I moved deeper into system architecture, working closely with storage platforms, virtualization, and security especially in regulated and research-intensive environments. I have a strong focus on building stable, secure, and manageable IT solutions, particularly in complex environments where clinical systems, research data, and compliance requirements intersect. I’m especially experienced in enterprise storage design, backup strategies, and performance tuning, often acting as the bridge between engineering teams and long-term architectural planning. I enjoy solving difficult problems and still believe most issues in IT can be fixed with enough determination, focus, and sometimes budget. It’s that drive to find solutions that keeps me motivated.