Identity, Authentication, and Access Management Questions
Designing and operating identity and access control systems. Covers authentication protocols and standards (OAuth, SAML, OIDC, MFA), authorization models (RBAC, ABAC), identity lifecycle and privilege management, IAM architecture and automation, and access control across cloud and on-premises environments. The 'who can do what' control plane, distinct from cryptographic key management.
Define Privileged Access Management (PAM). List common PAM controls such as vaulted credentials, just-in-time access, session recording, and bastion hosts, and explain how PAM integrates into the identity lifecycle and supports emergency break-glass workflows.
Sample Answer
Direct answer
Privileged Access Management (PAM) is the set of tools and processes specifically for securing, controlling, and monitoring access to accounts that carry outsized power, such as root, domain administrator, database administrator, or cloud organization-administrator accounts, because a compromise of one of these does far more damage than a compromise of an ordinary user account. Its four common controls are vaulted credentials (nobody memorizes or directly holds the actual password), just-in-time (JIT) elevation (privileged access exists only for the duration it is actually needed, not standing indefinitely), session recording (every privileged session is logged and auditable), and bastion hosts (a single hardened, monitored gateway that all privileged access must pass through, rather than direct network access to sensitive systems).
Structured elaboration
Vaulted credentials. Passwords or keys for privileged accounts are stored in a secure vault rather than known to, or memorized by, the administrator who needs them. When access is required, the vault checks out the credential (or injects it directly into a session without ever displaying it to the user) and can automatically rotate it after each use, so a privileged credential is never a static, reusable secret sitting in someone's memory or a password manager.
Just-in-time elevation. Rather than a standing administrator account that exists at full privilege all the time, a user requests elevated access for a specific task, often through an approval workflow, and receives it for a bounded time window that expires automatically afterward. This shrinks the amount of time a privileged account's risk actually exists in the environment, since most of the time, nobody holds standing elevated access at all.
Session recording. A PAM system brokers the actual connection to the target system rather than letting the user connect directly with their own credential, and it records what happens during that session, keystrokes, commands, or a full screen recording depending on the tool, producing a forensic record of exactly what a privileged session did. This matters both for after-the-fact investigation and as a deterrent: a session known to be recorded is less likely to be misused.
Bastion hosts. A single hardened, closely monitored gateway machine is the only path through which privileged access can reach sensitive internal systems, rather than administrators connecting directly over the network. Concentrating access at one narrow chokepoint is what makes the vaulting and session-recording controls above practical to enforce consistently: there is one place to apply them, rather than dozens of direct paths to secure individually.
Integration into the identity lifecycle. PAM enrollment is not a separate, disconnected system; it is provisioned and deprovisioned alongside a person's broader identity lifecycle. When someone is granted a privileged role (promoted to an on-call role, hired as a database administrator), their PAM eligibility, vault access, and just-in-time elevation permissions are provisioned as part of that same onboarding step. The more consequential direction is offboarding: when someone leaves a privileged role or the organization, their PAM access has to be revoked immediately, because standing privileged access left behind after someone's role changes is exactly the highest-risk kind of orphaned access to leave lingering. Because of that risk, privileged entitlements are also typically reviewed and re-certified more frequently than ordinary access, as part of the organization's periodic access-review process.
Emergency break-glass workflows. Break-glass access exists for the specific scenario where the normal control plane itself is unavailable or too slow, the identity provider or multi-factor authentication (MFA) system is down, or an incident is severe enough that waiting for a standard just-in-time approval would cause unacceptable harm. A break-glass credential is vaulted under tighter controls than routine privileged access, often requiring two people to jointly retrieve it or an out-of-band physical retrieval step, and its use triggers immediate, high-visibility alerting to the security team. Critically, break-glass deliberately bypasses the normal approval workflow, which is exactly why its use has to be rare, loudly alerted on the moment it happens, and always followed by a mandatory post-use review and credential rotation, regardless of whether the underlying emergency turns out to have been genuine.
Worked example
A database administrator (DBA) needs emergency read access to a production database during an incident. Walking through all four controls together: the DBA requests just-in-time elevation for the specific production system, naming the incident as justification; an on-call approver grants it for a two-hour window. The DBA connects through the organization's bastion host, the only network path into the production environment, rather than directly to the database server. The PAM system checks a vaulted database credential out on the DBA's behalf and injects it into the session without ever displaying the actual password, and the entire session is recorded. Two hours later, the elevation expires automatically and the checked-out credential is rotated, closing the window. If instead the identity provider itself were down during a severe outage and no one could complete the normal just-in-time approval flow, the on-call lead would use the break-glass procedure instead: retrieving a specially vaulted emergency credential (requiring a second approver to also confirm the retrieval), which immediately pages the security team, and after the incident, a mandatory review confirms the break-glass use was legitimate before the emergency credential is rotated and re-vaulted.
Trade-offs and pitfalls
- A PAM program that only covers well-known accounts (root, a handful of domain admins) but misses newer privileged surfaces, such as a cloud console's organization-admin role or a Kubernetes cluster-admin binding, leaves real gaps. Privileged access keeps expanding into new platforms faster than a PAM rollout typically covers them, so the inventory of "what counts as privileged" needs to be revisited regularly, not defined once.
- Just-in-time elevation only reduces risk if the approval step is genuinely meaningful. An approval workflow that rubber-stamps every request without real scrutiny provides the audit trail of a JIT system without the actual risk reduction, which is a common way JIT programs quietly become theater.
- Break-glass access that is never tested is a real operational risk, not just a security one. If the emergency procedure is only ever exercised during an actual crisis, the first real use may reveal that the vaulted credential has expired, the retrieval process is broken, or the people who know the procedure have since left, exactly when there is no time to fix it.
- Session recording without a review process only helps after an incident is already known to have happened. Recordings that are stored but never sampled or reviewed do not provide the early-warning value they could; some organizations pair session recording with automated anomaly detection over the recorded activity, not just passive storage.
An attacker has replaced a user's ~/.ssh/authorized_keys across multiple servers to maintain persistent access. Describe how you would identify which keys were added and when, what logs and artefacts you would inspect across systems (including auditd, filesystem timestamps, configuration management), and how you would coordinate an automated, auditable rotation of that user's keys across the fleet.
Sample Answer
Direct answer
Because file timestamps and the authorized_keys file's own content can both be altered by whoever already has write access to them, the trustworthy evidence has to come from sources the attacker cannot also silently edit: auditd records (if file-integrity watches were configured before the compromise), your configuration-management tool's own run history (which independently records what it last confirmed was correct, on its own schedule, not the file's), and centralized authentication logs showing which key fingerprint was actually used to log in and when. Once you know which keys are illegitimate and roughly when they were added, coordinate rotation as one auditable, fleet-wide change rather than fixing hosts one at a time as you find them.
Structured elaboration
Identifying which keys were added, and when
auditd, if a watch rule was already in place on~/.ssh/authorized_keys(-w /home/*/.ssh/authorized_keys -p wa), gives you the actual write events with timestamps and the process/user that performed them; this is the strongest evidence because it is generated at the time of the change, not reconstructed afterward.- Filesystem timestamps (
staton the file) are useful corroboration but are the weakest evidence on their own: an attacker who can write the file can also often touch it to alter its recorded modification time, and a legitimate later edit by anyone else will also update the same timestamp, so timestamps alone cannot distinguish a legitimate change from the attacker's. - Configuration-management run history (Ansible, Puppet, Chef, Salt) records the LAST TIME the tool confirmed the file matched its managed state, independent of the file's own metadata; a gap between the tool's last confirmed-good run and now, combined with the file no longer matching what the tool manages, brackets the window during which the unauthorized change happened.
- Centralized SSH authentication logs (aggregated via your SIEM, not just each host's local
/var/log/auth.log) show the key fingerprint presented on each login; comparing fingerprints against your known-good key inventory identifies exactly which key the attacker added and every host where it was subsequently used to log in.
Scoping which hosts are affected
Before assuming only the hosts with direct evidence of a modified authorized_keys are compromised, trace how the attacker obtained write access to that file in the first place (a stolen credential, a vulnerable service, a compromised configuration-management control plane). If the entry point could plausibly reach other hosts (for example, a compromised configuration-management server that pushes to the whole fleet, or a shared jump host), those hosts need the same evidence review even without a directly observed modified file yet, since the absence of evidence on a host you haven't checked is not evidence of absence.
Coordinating an automated, auditable rotation
- Generate a fresh keypair for the affected user, distributed through the same configuration-management system that manages
authorized_keysnormally (so the distribution itself is logged and auditable), rather than manually editing files on each host. - Push the new key to the entire fleet in one coordinated run, then explicitly remove ALL previously trusted keys for that user (not just the one identified as the attacker's addition), since a targeted user's other keys may also have been copied or otherwise compromised during the same incident.
- Force a reconciliation run of the configuration-management tool immediately after, so any host where the attacker's key was manually re-added out-of-band (bypassing the normal management path) gets flagged as drifted rather than silently keeping the stale malicious key.
- Record the whole rotation (which hosts, which keys removed, which key added, timestamps) as its own auditable change, both to close out the incident and to have a clean baseline if the same investigation needs to be repeated later.
Trade-offs and pitfalls
The pitfall that extends an incident longest is scoping the fix to only the hosts where you happened to find direct evidence, when the actual exposure is defined by how the attacker got write access in the first place, not by which hosts you got around to checking. A close second is rotating the compromised key without also removing the user's OTHER existing keys, on the assumption only the newly discovered key is malicious; if the initial compromise came from a stolen credential or workstation, any key that existed at the same time should be treated as suspect, not just the one you can directly attribute.
Design detection and alerting rules (for auditd + SIEM like Splunk/ELK) to detect suspicious user-administration activity: additions to /etc/sudoers or /etc/sudoers.d, changes to group 'sudo' membership, new SSH keys written to home directories, and creation of UID 0 users. Provide example auditd rules or file watches and high-level SIEM query patterns and thresholds to reduce false positives.
Sample Answer
Direct answer
auditd (the Linux kernel's auditing subsystem daemon) can watch a fixed set of file paths for reads, writes, and attribute changes and tag each event with a searchable key, which covers three of the four things this question asks for directly: sudoers edits, group-file changes, and passwd/UID-0 creation all show up as writes to a small number of well-known files. The fourth, new SSH keys, is the one that needs a design decision rather than a single rule, because auditd watches paths, not filename patterns, and an authorized_keys file can live inside any user's home directory.
Structured elaboration
Additions to /etc/sudoers or /etc/sudoers.d. A direct write-watch on both catches any edit, whether made through visudo or a direct file write:
-w /etc/sudoers -p wa -k sudoers_changes
-w /etc/sudoers.d/ -p wa -k sudoers_changes
-p wa watches for writes and attribute changes (not reads), and -k attaches a key string so the SIEM can query on sudoers_changes directly instead of matching on the raw path.
Changes to sudo group membership. Local group membership lives in /etc/group (and the shadowed password half in /etc/gshadow), so watching both catches a direct edit to the sudo group's member list:
-w /etc/group -p wa -k group_changes
-w /etc/gshadow -p wa -k group_changes
This only catches membership stored locally. If the environment resolves group membership through a directory service (an LDAP- or Active-Directory-integrated NSS module), the authoritative change happens on the directory side, not in a local file, and this rule sees nothing; that gap has to be closed by the directory's own audit logging, not by auditd on the Linux host.
New SSH keys written to home directories. auditd watches a fixed path, not a glob, so there is no single rule for "any authorized_keys file under any home directory." The practical options are a broad directory watch on the home-directory root, accepting that it fires on any write anywhere under it and needs a downstream filename filter, or enumerating each known home directory into its own watch, accepting the maintenance burden of updating rules as accounts are added:
-w /home -p wa -k home_dir_writes
The SIEM-side query then narrows the resulting stream to events whose path ends in .ssh/authorized_keys or .ssh/authorized_keys2, since that filtering has to happen after the event is captured, not in the auditd rule itself.
Creation of UID 0 users. auditd records that /etc/passwd was written, not what changed inside it, so detecting a new UID 0 account needs two complementary signals: a write-watch on the file itself, and a syscall-level rule on the command that creates or modifies accounts, so the SIEM can inspect the actual arguments:
-w /etc/passwd -p wa -k passwd_changes
-a always,exit -F arch=b64 -S execve -F exe=/usr/sbin/useradd -k user_admin_exec
-a always,exit -F arch=b64 -S execve -F exe=/usr/sbin/usermod -k user_admin_exec
The SIEM then correlates a user_admin_exec event whose captured arguments include -u 0 (or -o -u 0, since -o allows a duplicate/non-unique UID) with the following passwd_changes write, and treats a resulting UID field of 0 for any account other than the pre-existing root line as a near-certain finding, since a legitimate second UID-0 account is created vanishingly rarely in ordinary operations.
High-level SIEM query patterns and thresholds. For sudoers_changes and group_changes, correlate the event with whether it happened through the organization's change-management tooling (a known automation service account, during a recorded maintenance window) versus an interactive human session outside one; alert immediately on the latter and suppress or batch the former, since routine configuration-management-driven edits are common and a threshold based on volume alone would either miss a single unauthorized edit or drown the analyst in expected noise. For home_dir_writes filtered to authorized_keys paths, apply the same actor-based filter: a key rotation performed by the known configuration-management identity is routine, while the same file written by an interactively logged-in session is comparatively rare and worth a low-volume, near-zero-tolerance alert threshold. For the UID-0 correlation, the threshold is effectively "greater than zero, ever," since there is essentially no legitimate volume of new UID-0 account creation to distinguish from noise.
Worked example
Consider a host where the configuration-management agent rotates SSH keys under every user's ~/.ssh/authorized_keys every night as part of routine key hygiene, generating dozens of home_dir_writes events tagged to that agent's own service-account identity. One evening, a home_dir_writes event fires for /home/deploy/.ssh/authorized_keys attributed to an interactive session under a human user's login, not the configuration-management agent. That single event, filtered by the actor-identity rule above, is exactly the rare, high-signal case the design is built to surface: the routine nightly rotations from the known automation identity are suppressed from paging anyone, while this one write from an unexpected actor triggers an immediate alert, because "someone logged in interactively and wrote to a deploy account's authorized_keys file" has essentially no benign explanation in an environment where key management is otherwise fully automated.
Trade-offs and pitfalls
The biggest limitation to be explicit about is that auditd observes local file-system events, not directory-service events; in any environment where account and group management is centralized (LDAP, Active Directory, or a configuration-management system that is itself the source of truth), the local watches above catch only changes made directly on that one host, which is a real but partial view, and the directory service's own change auditing has to cover the rest.
A second pitfall is inode-based watch fragility: a file watch in auditd is tied to the underlying inode at the time the rule was loaded, so a file that gets deleted and recreated (rather than edited in place) can silently stop being watched until the rules are reloaded; periodically re-applying the rule set (or watching the parent directory instead of the file itself where that trade-off is acceptable) avoids a watch quietly going stale without anyone noticing.
A third pitfall is threshold design that ignores actor identity: alerting on raw event volume for home_dir_writes would either miss a single malicious key addition buried among routine automated rotations, or generate so many alerts from the automation itself that analysts learn to ignore the queue; filtering by which identity performed the write, as in the worked example, is what actually makes the threshold usable rather than just present.
Design an audit and monitoring architecture to detect improper privilege escalations and lateral movement originating from compromised Windows user accounts. Specify telemetry sources (AD change logs, Kerberos events, SMB/file access), alerting logic, retention, and how to integrate with a SIEM for automated playbooks.
Sample Answer
Direct answer
Detecting privilege escalation and lateral movement from a compromised Windows account means correlating three telemetry sources that each catch a different stage of the attack: Active Directory (AD) change logs catch the escalation itself (an account gaining privilege it did not have), Kerberos events catch credential harvesting and impersonation (an account requesting access it should not be requesting), and SMB (the Windows file-sharing protocol) and file-access logs catch the spread across machines. No single source reliably distinguishes an attacker from a busy administrator having an unusual day; the detection logic has to baseline each account against its own normal behavior and alert on combinations, not on any one source crossing a threshold alone.
Structured elaboration
Telemetry sources. AD change logs capture privileged-group membership changes (an account added to Domain Admins or another sensitive group), group policy object (GPO) changes, and changes to security-sensitive attributes, all of which are the direct evidence of an escalation having occurred. Kerberos events capture ticket-granting-ticket (TGT) and service-ticket (TGS) requests; a burst of TGS requests for many distinct service principal names (SPNs) in a short window is the signature of an attacker harvesting service-account credentials to crack offline (commonly called Kerberoasting), and a TGT requested with unusual encryption parameters or from an unexpected source can indicate a forged ticket. SMB and file-access logs capture which hosts an account has touched; an account authenticating to the administrative share (admin$ or C$) on many machines in a short window is the classic signature of lateral movement, since a legitimate administrator's normal day rarely looks like that.
Alerting logic. Baseline each account against its own historical pattern (typical number of distinct hosts touched per day, typical SPNs requested, typical logon hours) rather than a single global threshold, since a backup service account and a helpdesk technician have very different normal footprints. Alert on combinations that reinforce each other: a privileged-group addition made outside business hours, or a TGS-request burst followed within minutes by SMB access to several new hosts, is a materially stronger signal than either alone, because each individually has a plausible innocent explanation (an emergency change, a scheduled batch job) that the combination makes much less likely.
Retention. Advanced, patient attackers can dwell inside a network for a long time (weeks to months) before an escalation or lateral-movement step is even attempted, so retention has to support retro-hunting over that full dwell window, not only real-time alerting; a design that only keeps 30 days of Kerberos and SMB telemetry cannot answer "was this account doing anything unusual two months before the incident we just found," which is often exactly the question an investigation needs answered.
SIEM integration for automated playbooks. Feed all three telemetry sources into a security information and event management (SIEM) platform with a shared identity and timestamp so events can be correlated across sources, not just within one. Above a defined severity threshold, the SIEM should trigger an automated playbook, not only a human alert: disable the account, force a password or Kerberos-ticket reset (invalidating any tickets the attacker already harvested), and isolate the source host from the network, with a human security analyst confirming or rolling back the automated action rather than being the one who has to take it under time pressure during an active incident.
Worked example
flowchart LR
AD[AD change logs: group membership and GPO changes] --> COR[Correlation Engine]
KRB[Kerberos events: ticket requests and unusual SPNs] --> COR
SMB[SMB and file access logs] --> COR
COR --> BASE[Baseline and peer-group comparison]
BASE --> SCORE[Anomaly score]
SCORE -->|above threshold| ALERT[SIEM alert]
ALERT --> PLAY[Automated playbook: contain, rotate, notify]
SCORE -->|below threshold| RET[Retained for retro-hunting]
Concretely: an account's 90-day baseline shows a typical day touching the admin$ share on 1 to 2 distinct hosts. On one day, the same account authenticates to admin$ on 15 distinct hosts within an 8-minute window, a 7 to 15 times increase over its own established baseline, which alone crosses a reasonable "distinct-host-count-per-window" threshold for that account. The correlation engine checks the same window for Kerberos activity and finds a burst of TGS requests for 12 distinct SPNs in the preceding 6 minutes, consistent with credential harvesting immediately before the lateral movement. Neither signal alone is unambiguous (a patch deployment can legitimately touch many hosts quickly; a monitoring tool can legitimately request many service tickets), but the combination, specifically the SPN-harvesting burst immediately followed by a sharp spike in distinct-host admin$ access from the same account, exceeds the combined threshold and triggers the automated playbook: the account is disabled, its Kerberos tickets are invalidated, and the source host is flagged for isolation, all before a human analyst has finished reading the alert.
Trade-offs and pitfalls
The central trade-off is sensitivity versus false-positive load: a threshold tight enough to catch a fast, deliberate lateral-movement burst will also catch legitimate bulk administrative activity (a patch rollout, a fleet-wide configuration push), and a threshold loose enough to avoid flagging those will miss a more patient attacker who spreads the same footprint across days instead of minutes. Per-account baselining (rather than a single global threshold) narrows this gap but does not eliminate it, since a genuinely new administrative task will always look anomalous against an account's own history the first time it happens.
A common pitfall is alerting on any one telemetry source in isolation: an AD-change-only detector will miss lateral movement that never touches AD (an attacker who only harvests and reuses credentials across file shares), and a Kerberos-only detector will miss an attacker who already has valid, unexpired credentials and only needs to move laterally, not harvest new ones. A second pitfall is retention that is sized to the alerting window rather than the realistic dwell-time window: a system tuned only to catch the fast, obvious burst will have nothing to look back on when an incident is discovered weeks after the actual escalation happened. A third pitfall is an automated playbook with no human-confirmable rollback: disabling the wrong account or isolating a critical production host on a false positive is itself an outage, so the playbook needs a fast, well-rehearsed reversal path, not just a fast trigger.
Create a PowerShell solution (outline or code) to collect the local 'Administrators' group membership from every domain-joined computer in an OU, identify non-approved users, and produce a CSV report with computer name, account, SID, and whether the account is a domain or local account. Describe remoting and permission requirements.
Sample Answer
Direct answer
Enumerate the computers in the target organizational unit (OU) from Active Directory, remotely query each machine's local "Administrators" group membership, resolve each member to a security identifier (SID, the unique identifier Windows uses to represent an account, independent of its display name) so renamed or ambiguous accounts cannot slip past a name-only comparison, classify each member as a domain or local account, and compare against an explicit allowlist before writing the CSV. The part that is easy to get wrong is the comparison itself: checking only by name misses an account that has been renamed, so the allowlist check has to match on SID as well as name.
Structured elaboration
Approach. For each computer, remotely enumerate local group membership (in production, via Invoke-Command calling the WinNT ADSI provider, Get-LocalGroupMember on modern Windows, or the Win32_Group/Win32_GroupUser WMI classes), translate each member's account name to a SID, classify domain versus local by whether the account's prefix matches the local computer name or BUILTIN, and flag any member whose name and SID both fail to match the allowlist. Offline or unreachable computers are caught and reported as an explicit error row rather than silently omitted from the CSV, so a gap in the report is visible instead of looking like a clean result.
Key points.
- Compare against the allowlist by both name and SID, not name alone: a domain account that has been renamed keeps the same SID, so a name-only check can both miss a renamed unapproved account and false-flag a renamed approved one.
BUILTIN\Administratorand any account prefixed with the target computer's own name are local accounts; anything else is a domain account, which matters for triage (a local account added directly on one machine bypasses group-policy-managed domain group membership entirely).- An unreachable computer must produce a visible error row, not a silent gap, since "the report has fewer rows than expected because three machines were offline" and "three machines are clean" look identical unless the report says otherwise.
$AllowList = @("CONTOSO\CorpAdmin", "S-1-5-32-544", "BUILTIN\Administrator", "S-1-5-32-544-500")
# Fixed SID lookup table standing in for NTAccount.Translate([SecurityIdentifier]);
# real deployments resolve these from the domain/local SAM, not a literal map.
$SidTable = @{
"CONTOSO\CorpAdmin" = "S-1-5-21-111-222-333-1001"
"BUILTIN\Administrator" = "S-1-5-32-544-500"
"CONTOSO\jdoe" = "S-1-5-21-111-222-333-1042"
"CONTOSO\svc-backup" = "S-1-5-21-111-222-333-2099"
}
# In production: $computers = Get-ADComputer -SearchBase $OU -Filter * | Select -Expand Name
# then Invoke-Command -ComputerName $c -ScriptBlock { (Get-LocalGroupMember Administrators) }
# Below, MockFleet models exactly that per-computer result for three representative machines,
# including one offline host to exercise the error-handling branch.
$MockFleet = @(
[pscustomobject]@{ Computer="WKS01"; Reachable=$true; Members=@("CONTOSO\CorpAdmin","BUILTIN\Administrator","CONTOSO\jdoe") }
[pscustomobject]@{ Computer="WKS02"; Reachable=$true; Members=@("CONTOSO\CorpAdmin","BUILTIN\Administrator","CONTOSO\svc-backup") }
[pscustomobject]@{ Computer="WKS03"; Reachable=$false; Members=@() }
)
function Get-AccountType {
param([string]$Account, [string]$ComputerName)
if ($Account -like "$ComputerName\*") { return "Local" }
if ($Account -like "BUILTIN\*") { return "Local" }
return "Domain"
}
$Results = foreach ($host_ in $MockFleet) {
if (-not $host_.Reachable) {
[pscustomobject]@{ Computer=$host_.Computer; Account="ERROR"; SID=""
AccountType=""; Approved="Error: WinRM connect failed (host unreachable)" }
continue
}
foreach ($m in $host_.Members) {
$sid = if ($SidTable.ContainsKey($m)) { $SidTable[$m] } else { $null }
$type = Get-AccountType -Account $m -ComputerName $host_.Computer
$approved = (($AllowList -contains $m) -or ($sid -and ($AllowList -contains $sid)))
[pscustomobject]@{ Computer=$host_.Computer; Account=$m; SID=$sid
AccountType=$type; Approved=if ($approved) { "Yes" } else { "No" } }
}
}
$csvPath = "./LocalAdminsReport.csv"
$Results | Export-Csv -Path $csvPath -NoTypeInformation
Get-Content $csvPath
$flagged = $Results | Where-Object { $_.Approved -eq "No" }
Write-Output "Flagged (non-approved) accounts: $($flagged.Count)"
$flagged | ForEach-Object { Write-Output (" {0}\{1}" -f $_.Computer, $_.Account) }
Worked example
Run unmodified with pwsh, this produces:
"Computer","Account","SID","AccountType","Approved"
"WKS01","CONTOSO\CorpAdmin","S-1-5-21-111-222-333-1001","Domain","Yes"
"WKS01","BUILTIN\Administrator","S-1-5-32-544-500","Local","Yes"
"WKS01","CONTOSO\jdoe","S-1-5-21-111-222-333-1042","Domain","No"
"WKS02","CONTOSO\CorpAdmin","S-1-5-21-111-222-333-1001","Domain","Yes"
"WKS02","BUILTIN\Administrator","S-1-5-32-544-500","Local","Yes"
"WKS02","CONTOSO\svc-backup","S-1-5-21-111-222-333-2099","Domain","No"
"WKS03","ERROR","","","Error: WinRM connect failed (host unreachable)"
Flagged (non-approved) accounts: 2
WKS01\CONTOSO\jdoe
WKS02\CONTOSO\svc-backup
WKS01\CONTOSO\jdoe and WKS02\CONTOSO\svc-backup are correctly flagged as non-approved, a domain account added to local admins on one machine without going through the approved-group process; CONTOSO\CorpAdmin and BUILTIN\Administrator correctly pass on both machines that report in; and WKS03, which is offline, produces an explicit ERROR row rather than silently vanishing from the CSV, exactly the visible-gap behavior the "key points" section calls for. Note that if the SID lookup for CONTOSO\jdoe had, purely hypothetically, matched an entry in $AllowList by SID even though the name did not, the account would correctly show Approved=Yes, which is precisely why the comparison checks both name and SID rather than either alone.
Complexity. For c computers with an average of m local admin members each, the remote enumeration is O(c) round-trips (one per computer, each returning its own membership in one call), and the allowlist comparison is O(c⋅m) simple lookups against a hash-backed allowlist, which is cheap even for a large OU; the actual bottleneck in a real environment is network round-trip latency across potentially thousands of computers, not the comparison logic.
Edge cases. An unreachable computer must be caught and reported, not allowed to throw and abort the whole run; a member whose SID cannot be resolved (a deleted domain account still listed in a local group) should still appear in the report with a blank or best-effort SID rather than being silently skipped, since an orphaned SID in a privileged local group is itself a finding worth surfacing; and a renamed approved account must still resolve as approved via its SID even though its current display name no longer matches the allowlist's name entry.
Trade-offs and pitfalls
Remoting to every computer in an OU serially does not scale past a few hundred machines in a reasonable window; production runs typically parallelize with a bounded throttle (Invoke-Command -ThrottleLimit) or route through an existing management channel (SCCM, Intune, or a similar endpoint-management tool) rather than opening a fresh WinRM session to every host from a single script.
Remoting and permission requirements. PowerShell Remoting (WinRM) must be enabled and reachable on every target computer, and the account running the script needs rights to query local group membership on each target, typically local administrator rights or a delegated equivalent. Watch for the Kerberos "double hop" problem: if the remote command itself needs to reach back out to Active Directory (for example, to resolve a SID against the domain rather than a local cache), the credential used to connect does not automatically carry forward to that second hop unless you use CredSSP, resource-based constrained delegation, or a CIM session with an explicitly provided credential.
A common pitfall is trusting name-only comparison against the allowlist, which both of the flagged accounts above would still be correctly caught by, but which would wrongly clear a renamed unapproved account or wrongly flag a renamed approved one; matching on SID as well is what makes the comparison correct under renames. A second pitfall is letting an unreachable computer fail silently: a script that throws and stops on the first offline host, or one that simply omits offline hosts from the output, produces a report that looks complete but is not, which is worse than an explicit error row because nobody investigating the gap knows to look for it.
Unlock Full Question Bank
Get access to all 22 Identity, Authentication, and Access Management interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.