[{"data":1,"prerenderedAt":2458},["ShallowReactive",2],{"post:\u002F2025\u002F10\u002F08\u002Fpowershell-windows-discover-local-admins-across-every-workstation\u002F":3},{"post":4,"newer":2413,"older":2423,"related":2431,"series":2456},{"id":5,"title":6,"body":7,"canonical":2393,"categories":2394,"date":2397,"description":2398,"extension":2399,"featured":2400,"hero":2401,"image":2401,"meta":2402,"navigation":324,"path":2403,"readingTime":415,"seo":2404,"series":2401,"seriesOrder":2401,"sites":2405,"source":2401,"stem":2406,"tags":2407,"updated":2401,"url":2411,"__hash__":2412},"blog\u002Fblog\u002F2025\u002F10\u002F08\u002Fpowershell-windows-discover-local-admins-across-every-workstation.md","PowerShell: Windows – Discover Local Admins Across Every Workstation",{"type":8,"value":9,"toc":2385},"minimark",[10,14,38,43,77,81,209,213,216,269,272,361,364,372,375,381,385,2243,2247,2335,2339,2381],[11,12,13],"p",{},"Local admin sprawl is one of those problems that accumulates quietly. A help desk tech adds themselves to the local Administrators group to fix one thing during a busy incident, a former contractor's personal account never got removed, an old imaging process baked in an account nobody remembers the purpose of. None of it looks dangerous in isolation, and all of it adds up to lateral movement paths an attacker will find faster than you will. This script walks the local Administrators group on every workstation you point it at and flags any member that isn't on your approved allowlist, so cleanup becomes a list to work through instead of a mystery to solve.",[11,15,16,17,21,22,25,26,29,30,33,34,37],{},"Two things make this harder than a one-line ",[18,19,20],"code",{},"Get-LocalGroupMember -Group \"Administrators\"",". The group name is localized (it isn't \"Administrators\" on a German or French build), so the script asks for the group by its well-known SID, ",[18,23,24],{},"S-1-5-32-544",". And ",[18,27,28],{},"Get-LocalGroupMember"," has a long-standing bug, tracked in the PowerShell repository as issues #2996, #7105 and #21617, where a member SID that no longer resolves makes the whole call throw ",[18,31,32],{},"Failed to compare two elements in the array."," That's common on machines that were moved between domains or joined to Microsoft Entra ID, which are exactly the machines you most want to audit. When that happens the script falls back to ",[18,35,36],{},"net.exe localgroup"," for that computer and marks the rows so you know which method produced them.",[39,40,42],"h2",{"id":41},"requirements","Requirements",[44,45,46,54,65],"ul",{},[47,48,49,50,53],"li",{},"PowerShell 5.1 or later on the machine running the script; PowerShell remoting (WinRM) enabled and reachable on every target. Windows client editions don't enable remoting by default, so push it with ",[18,51,52],{},"Enable-PSRemoting"," or Group Policy first.",[47,55,56,57,60,61,64],{},"Windows 10 \u002F Server 2016 or later on targets for the built-in ",[18,58,59],{},"Microsoft.PowerShell.LocalAccounts"," module. It's not available in 32-bit PowerShell on a 64-bit system, which doesn't matter here because remoting lands in the 64-bit ",[18,62,63],{},"Microsoft.PowerShell"," endpoint.",[47,66,67,68,72,73,76],{},"An account in the ",[69,70,71],"strong",{},"Administrators"," or ",[69,74,75],{},"Remote Management Users"," group on each target (the default endpoint only admits Administrators). In practice that means a dedicated audit account, not your daily one.",[39,78,80],{"id":79},"parameters","Parameters",[82,83,84,103],"table",{},[85,86,87],"thead",{},[88,89,90,94,97,100],"tr",{},[91,92,93],"th",{},"Name",[91,95,96],{},"Type",[91,98,99],{},"Required",[91,101,102],{},"Description",[104,105,106,130,143,174,191],"tbody",{},[88,107,108,114,120,123],{},[109,110,111],"td",{},[18,112,113],{},"-ComputerName",[109,115,116,117],{},"String",[118,119],"span",{},[109,121,122],{},"No",[109,124,125,126,129],{},"One or more computer names to check. If omitted, ",[18,127,128],{},"-ComputerListPath"," is used instead.",[88,131,132,136,138,140],{},[109,133,134],{},[18,135,128],{},[109,137,116],{},[109,139,122],{},[109,141,142],{},"Path to a text file with one computer name per line.",[88,144,145,150,154,156],{},[109,146,147],{},[18,148,149],{},"-ExpectedAdmins",[109,151,116,152],{},[118,153],{},[109,155,122],{},[109,157,158,159,162,163,166,167,170,171,173],{},"Approved members. Each entry can be a short name (",[18,160,161],{},"Domain Admins","), a qualified name (",[18,164,165],{},"CORP\\Domain Admins",") or a SID. Short names are compared against the part after the backslash. Defaults to ",[18,168,169],{},"Administrator"," and ",[18,172,161],{},".",[88,175,176,181,183,185],{},[109,177,178],{},[18,179,180],{},"-OutputPath",[109,182,116],{},[109,184,122],{},[109,186,187,188,173],{},"Path to the CSV of flagged (unapproved) members. Defaults to ",[18,189,190],{},".\\unapproved-local-admins.csv",[88,192,193,198,201,203],{},[109,194,195],{},[18,196,197],{},"-ThrottleLimit",[109,199,200],{},"Int",[109,202,122],{},[109,204,205,206,173],{},"Maximum number of concurrent remote connections. Defaults to ",[18,207,208],{},"32",[39,210,212],{"id":211},"usage","Usage",[11,214,215],{},"Check a handful of workstations against the default allowlist:",[217,218,223],"pre",{"className":219,"code":220,"language":221,"meta":222,"style":222},"language-powershell shiki shiki-themes github-dark",".\\Find-UnapprovedLocalAdmins.ps1 -ComputerName WKS-0142, WKS-0198, WKS-0203\n","powershell","",[18,224,225],{"__ignoreMap":222},[118,226,229,232,236,240,243,246,249,252,255,257,260,262,264,266],{"class":227,"line":228},"line",1,[118,230,173],{"class":231},"s95oV",[118,233,235],{"class":234},"sDLfK","\\Find-UnapprovedLocalAdmins.ps1",[118,237,239],{"class":238},"snl16"," -",[118,241,242],{"class":231},"ComputerName WKS",[118,244,245],{"class":238},"-",[118,247,248],{"class":234},"0142",[118,250,251],{"class":238},",",[118,253,254],{"class":231}," WKS",[118,256,245],{"class":238},[118,258,259],{"class":234},"0198",[118,261,251],{"class":238},[118,263,254],{"class":231},[118,265,245],{"class":238},[118,267,268],{"class":234},"0203\n",[11,270,271],{},"Check every enabled workstation in an OU, with your own approved accounts (including a Windows LAPS-managed account and a workstation admin group):",[217,273,275],{"className":219,"code":274,"language":221,"meta":222,"style":222},"$workstations = Get-ADComputer -Filter 'Enabled -eq $true' -SearchBase \"OU=Workstations,DC=corp,DC=example,DC=com\" |\n    Select-Object -ExpandProperty Name\n\n.\\Find-UnapprovedLocalAdmins.ps1 -ComputerName $workstations -ExpectedAdmins \"Administrator\", \"Domain Admins\", \"CORP\\Workstation Admins\", \"lapsadmin\"\n",[18,276,277,308,319,326],{"__ignoreMap":222},[118,278,279,282,285,288,290,293,297,299,302,305],{"class":227,"line":228},[118,280,281],{"class":231},"$workstations ",[118,283,284],{"class":238},"=",[118,286,287],{"class":234}," Get-ADComputer",[118,289,239],{"class":238},[118,291,292],{"class":231},"Filter ",[118,294,296],{"class":295},"sU2Wk","'Enabled -eq $true'",[118,298,239],{"class":238},[118,300,301],{"class":231},"SearchBase ",[118,303,304],{"class":295},"\"OU=Workstations,DC=corp,DC=example,DC=com\"",[118,306,307],{"class":238}," |\n",[118,309,311,314,316],{"class":227,"line":310},2,[118,312,313],{"class":234},"    Select-Object",[118,315,239],{"class":238},[118,317,318],{"class":231},"ExpandProperty Name\n",[118,320,322],{"class":227,"line":321},3,[118,323,325],{"emptyLinePlaceholder":324},true,"\n",[118,327,329,331,333,335,338,340,343,346,348,351,353,356,358],{"class":227,"line":328},4,[118,330,173],{"class":231},[118,332,235],{"class":234},[118,334,239],{"class":238},[118,336,337],{"class":231},"ComputerName $workstations ",[118,339,245],{"class":238},[118,341,342],{"class":231},"ExpectedAdmins ",[118,344,345],{"class":295},"\"Administrator\"",[118,347,251],{"class":238},[118,349,350],{"class":295}," \"Domain Admins\"",[118,352,251],{"class":238},[118,354,355],{"class":295}," \"CORP\\Workstation Admins\"",[118,357,251],{"class":238},[118,359,360],{"class":295}," \"lapsadmin\"\n",[11,362,363],{},"Sample console output:",[217,365,370],{"className":366,"code":368,"language":369,"meta":222},[367],"language-text","Checking 3 computer(s) with a throttle limit of 32 ...\nWKS-0142: 1 unapproved member(s) found\nWKS-0198: no unapproved members (net.exe fallback)\nWARNING: Failed WKS-0203: Connecting to remote server WKS-0203 failed with the following error message : WinRM cannot complete the operation...\nFlagged members written to .\\unapproved-local-admins.csv\nWARNING: Unreachable or failed computers: WKS-0203\n","text",[18,371,368],{"__ignoreMap":222},[11,373,374],{},"And the CSV row behind the first line:",[217,376,379],{"className":377,"code":378,"language":369,"meta":222},[367],"\"ComputerName\",\"Name\",\"SID\",\"ObjectClass\",\"PrincipalSource\",\"Method\"\n\"WKS-0142\",\"CORP\\jsmith\",\"S-1-5-21-\u003Cdomain>-4127\",\"User\",\"ActiveDirectory\",\"Get-LocalGroupMember\"\n",[18,380,378],{"__ignoreMap":222},[39,382,384],{"id":383},"script","Script",[217,386,388],{"className":219,"code":387,"language":221,"meta":222,"style":222},"\u003C#\n.SYNOPSIS\n    Enumerates the local Administrators group on a list of Windows computers and\n    flags members that are not on an approved allowlist.\n.DESCRIPTION\n    Over PowerShell remoting, reads the members of the built-in Administrators group\n    by its well-known SID (S-1-5-32-544) so it works on localized builds. If\n    Get-LocalGroupMember throws (for example on the orphaned-SID bug, \"Failed to\n    compare two elements in the array\"), falls back to net.exe localgroup on that\n    computer. Compares each member with -ExpectedAdmins and writes unapproved members\n    to a CSV.\n.PARAMETER ComputerName\n    One or more computer names to check.\n.PARAMETER ComputerListPath\n    Path to a text file with one computer name per line, used when -ComputerName\n    is not supplied.\n.PARAMETER ExpectedAdmins\n    Approved members as short names, DOMAIN\\name, or SIDs.\n.PARAMETER OutputPath\n    Path to the CSV of flagged members. Defaults to .\\unapproved-local-admins.csv.\n.PARAMETER ThrottleLimit\n    Maximum number of concurrent remote connections. Defaults to 32.\n.EXAMPLE\n    .\\Find-UnapprovedLocalAdmins.ps1 -ComputerListPath C:\\Lists\\workstations.txt -ExpectedAdmins \"Administrator\", \"Domain Admins\"\n.NOTES\n    Author  : Thomas Lasswell (https:\u002F\u002Fwww.techcolumnist.com)\n    Version : 1.0 (2025-10-08)\n    Requires: PowerShell remoting on targets; Windows 10 \u002F Server 2016+ for Get-LocalGroupMember\n#>\n[CmdletBinding()]\nparam(\n    [string[]]$ComputerName,\n\n    [string]$ComputerListPath,\n\n    [string[]]$ExpectedAdmins = @(\"Administrator\", \"Domain Admins\"),\n\n    [string]$OutputPath = \".\\unapproved-local-admins.csv\",\n\n    [int]$ThrottleLimit = 32\n)\n\nif (-not $ComputerName) {\n    if (-not $ComputerListPath -or -not (Test-Path -Path $ComputerListPath)) {\n        throw \"Supply -ComputerName or a valid -ComputerListPath.\"\n    }\n\n    $ComputerName = Get-Content -Path $ComputerListPath | Where-Object { $_.Trim() -ne \"\" } | ForEach-Object { $_.Trim() }\n}\n\n$ComputerName = @($ComputerName | Sort-Object -Unique)\nWrite-Host \"Checking $($ComputerName.Count) computer(s) with a throttle limit of $ThrottleLimit ...\"\n\n# The script block that runs on each remote computer.\n$membershipScript = {\n    $adminSid = \"S-1-5-32-544\"\n\n    try {\n        Get-LocalGroupMember -SID $adminSid -ErrorAction Stop | ForEach-Object {\n            [pscustomobject]@{\n                ComputerName    = $env:COMPUTERNAME\n                Name            = $_.Name\n                SID             = $_.SID.Value\n                ObjectClass     = $_.ObjectClass\n                PrincipalSource = \"$($_.PrincipalSource)\"\n                Method          = \"Get-LocalGroupMember\"\n            }\n        }\n    } catch {\n        # Fallback: resolve the localized group name from the SID and parse net.exe output.\n        $sidObject = New-Object System.Security.Principal.SecurityIdentifier($adminSid)\n        $groupName = ($sidObject.Translate([System.Security.Principal.NTAccount]).Value -split \"\\\\\")[-1]\n        $output = @(& net.exe localgroup \"$groupName\")\n\n        $dashIndex = -1\n        for ($i = 0; $i -lt $output.Count; $i++) {\n            if ($output[$i] -match \"^-{5,}\") {\n                $dashIndex = $i\n                break\n            }\n        }\n\n        if ($dashIndex -ge 0) {\n            # Members follow the dashed line; the last non-empty line is the completion message.\n            $output[($dashIndex + 1)..($output.Count - 1)] |\n                Where-Object { $_.Trim() -ne \"\" } |\n                Select-Object -SkipLast 1 |\n                ForEach-Object {\n                    [pscustomobject]@{\n                        ComputerName    = $env:COMPUTERNAME\n                        Name            = $_.Trim()\n                        SID             = $null\n                        ObjectClass     = $null\n                        PrincipalSource = $null\n                        Method          = \"net.exe\"\n                    }\n                }\n        }\n    }\n}\n\n# Return $true when a member matches any allowlist entry by SID, full name or short name.\nfunction Test-Approved {\n    param (\n        $Member,\n        [string[]]$Allowlist\n    )\n\n    $shortName = ($Member.Name -split \"\\\\\")[-1]\n\n    foreach ($entry in $Allowlist) {\n        if ($Member.SID -and $entry -eq $Member.SID) { return $true }\n        if ($entry -eq $Member.Name) { return $true }\n        if ($entry -notlike \"*\\*\" -and $entry -eq $shortName) { return $true }\n    }\n\n    return $false\n}\n\n$parentJob = Invoke-Command -ComputerName $ComputerName -ScriptBlock $membershipScript -AsJob -ThrottleLimit $ThrottleLimit\n$parentJob | Wait-Job | Out-Null\n\n$flagged = New-Object System.Collections.Generic.List[object]\n$failures = New-Object System.Collections.Generic.List[string]\n\nforeach ($child in $parentJob.ChildJobs) {\n    $target = $child.Location\n\n    if ($child.State -eq \"Failed\") {\n        $failures.Add($target)\n        Write-Warning \"Failed $target`: $($child.JobStateInfo.Reason.Message)\"\n        continue\n    }\n\n    $members = @(Receive-Job -Job $child -ErrorAction SilentlyContinue |\n        Select-Object -Property ComputerName, Name, SID, ObjectClass, PrincipalSource, Method)\n    $unapproved = @($members | Where-Object { -not (Test-Approved -Member $_ -Allowlist $ExpectedAdmins) })\n    $note = if ($members.Count -gt 0 -and $members[0].Method -eq \"net.exe\") { \" (net.exe fallback)\" } else { \"\" }\n\n    if ($unapproved.Count -gt 0) {\n        $flagged.AddRange([object[]]$unapproved)\n        Write-Host \"$target`: $($unapproved.Count) unapproved member(s) found$note\"\n    } else {\n        Write-Host \"$target`: no unapproved members$note\"\n    }\n}\n\nRemove-Job -Job $parentJob -Force\n\n$flagged | Export-Csv -Path $OutputPath -NoTypeInformation\nWrite-Host \"Flagged members written to $OutputPath\"\n\nif ($failures.Count -gt 0) {\n    Write-Warning \"Unreachable or failed computers: $($failures -join ', ')\"\n}\n",[18,389,390,396,403,408,413,421,427,433,439,445,451,457,468,474,484,490,496,506,512,522,528,538,544,552,558,566,572,578,584,590,602,611,626,631,643,648,677,682,699,704,720,726,731,746,775,784,790,795,847,853,858,881,909,914,920,931,942,947,955,977,995,1012,1026,1039,1052,1077,1088,1094,1100,1111,1117,1131,1163,1194,1199,1210,1239,1256,1267,1273,1278,1283,1288,1304,1310,1340,1360,1376,1384,1398,1412,1425,1436,1446,1456,1467,1473,1479,1484,1489,1494,1499,1505,1517,1526,1534,1545,1551,1556,1577,1582,1597,1626,1644,1673,1678,1683,1692,1697,1702,1733,1749,1754,1772,1788,1793,1807,1818,1823,1838,1844,1870,1876,1881,1886,1913,1949,1987,2040,2045,2059,2070,2099,2108,2124,2129,2134,2139,2155,2160,2180,2193,2198,2212,2238],{"__ignoreMap":222},[118,391,392],{"class":227,"line":228},[118,393,395],{"class":394},"sAwPA","\u003C#\n",[118,397,398,400],{"class":227,"line":310},[118,399,173],{"class":234},[118,401,402],{"class":238},"SYNOPSIS\n",[118,404,405],{"class":227,"line":321},[118,406,407],{"class":394},"    Enumerates the local Administrators group on a list of Windows computers and\n",[118,409,410],{"class":227,"line":328},[118,411,412],{"class":394},"    flags members that are not on an approved allowlist.\n",[118,414,416,418],{"class":227,"line":415},5,[118,417,173],{"class":234},[118,419,420],{"class":238},"DESCRIPTION\n",[118,422,424],{"class":227,"line":423},6,[118,425,426],{"class":394},"    Over PowerShell remoting, reads the members of the built-in Administrators group\n",[118,428,430],{"class":227,"line":429},7,[118,431,432],{"class":394},"    by its well-known SID (S-1-5-32-544) so it works on localized builds. If\n",[118,434,436],{"class":227,"line":435},8,[118,437,438],{"class":394},"    Get-LocalGroupMember throws (for example on the orphaned-SID bug, \"Failed to\n",[118,440,442],{"class":227,"line":441},9,[118,443,444],{"class":394},"    compare two elements in the array\"), falls back to net.exe localgroup on that\n",[118,446,448],{"class":227,"line":447},10,[118,449,450],{"class":394},"    computer. Compares each member with -ExpectedAdmins and writes unapproved members\n",[118,452,454],{"class":227,"line":453},11,[118,455,456],{"class":394},"    to a CSV.\n",[118,458,460,462,465],{"class":227,"line":459},12,[118,461,173],{"class":234},[118,463,464],{"class":238},"PARAMETER",[118,466,467],{"class":238}," ComputerName\n",[118,469,471],{"class":227,"line":470},13,[118,472,473],{"class":394},"    One or more computer names to check.\n",[118,475,477,479,481],{"class":227,"line":476},14,[118,478,173],{"class":234},[118,480,464],{"class":238},[118,482,483],{"class":238}," ComputerListPath\n",[118,485,487],{"class":227,"line":486},15,[118,488,489],{"class":394},"    Path to a text file with one computer name per line, used when -ComputerName\n",[118,491,493],{"class":227,"line":492},16,[118,494,495],{"class":394},"    is not supplied.\n",[118,497,499,501,503],{"class":227,"line":498},17,[118,500,173],{"class":234},[118,502,464],{"class":238},[118,504,505],{"class":238}," ExpectedAdmins\n",[118,507,509],{"class":227,"line":508},18,[118,510,511],{"class":394},"    Approved members as short names, DOMAIN\\name, or SIDs.\n",[118,513,515,517,519],{"class":227,"line":514},19,[118,516,173],{"class":234},[118,518,464],{"class":238},[118,520,521],{"class":238}," OutputPath\n",[118,523,525],{"class":227,"line":524},20,[118,526,527],{"class":394},"    Path to the CSV of flagged members. Defaults to .\\unapproved-local-admins.csv.\n",[118,529,531,533,535],{"class":227,"line":530},21,[118,532,173],{"class":234},[118,534,464],{"class":238},[118,536,537],{"class":238}," ThrottleLimit\n",[118,539,541],{"class":227,"line":540},22,[118,542,543],{"class":394},"    Maximum number of concurrent remote connections. Defaults to 32.\n",[118,545,547,549],{"class":227,"line":546},23,[118,548,173],{"class":234},[118,550,551],{"class":238},"EXAMPLE\n",[118,553,555],{"class":227,"line":554},24,[118,556,557],{"class":394},"    .\\Find-UnapprovedLocalAdmins.ps1 -ComputerListPath C:\\Lists\\workstations.txt -ExpectedAdmins \"Administrator\", \"Domain Admins\"\n",[118,559,561,563],{"class":227,"line":560},25,[118,562,173],{"class":234},[118,564,565],{"class":238},"NOTES\n",[118,567,569],{"class":227,"line":568},26,[118,570,571],{"class":394},"    Author  : Thomas Lasswell (https:\u002F\u002Fwww.techcolumnist.com)\n",[118,573,575],{"class":227,"line":574},27,[118,576,577],{"class":394},"    Version : 1.0 (2025-10-08)\n",[118,579,581],{"class":227,"line":580},28,[118,582,583],{"class":394},"    Requires: PowerShell remoting on targets; Windows 10 \u002F Server 2016+ for Get-LocalGroupMember\n",[118,585,587],{"class":227,"line":586},29,[118,588,589],{"class":394},"#>\n",[118,591,593,596,599],{"class":227,"line":592},30,[118,594,595],{"class":231},"[",[118,597,598],{"class":234},"CmdletBinding",[118,600,601],{"class":231},"()]\n",[118,603,605,608],{"class":227,"line":604},31,[118,606,607],{"class":238},"param",[118,609,610],{"class":231},"(\n",[118,612,614,617,620,623],{"class":227,"line":613},32,[118,615,616],{"class":231},"    [",[118,618,619],{"class":238},"string",[118,621,622],{"class":231},"[]]$ComputerName",[118,624,625],{"class":238},",\n",[118,627,629],{"class":227,"line":628},33,[118,630,325],{"emptyLinePlaceholder":324},[118,632,634,636,638,641],{"class":227,"line":633},34,[118,635,616],{"class":231},[118,637,619],{"class":238},[118,639,640],{"class":231},"]$ComputerListPath",[118,642,625],{"class":238},[118,644,646],{"class":227,"line":645},35,[118,647,325],{"emptyLinePlaceholder":324},[118,649,651,653,655,658,660,663,666,668,670,672,675],{"class":227,"line":650},36,[118,652,616],{"class":231},[118,654,619],{"class":238},[118,656,657],{"class":231},"[]]$ExpectedAdmins ",[118,659,284],{"class":238},[118,661,662],{"class":238}," @",[118,664,665],{"class":231},"(",[118,667,345],{"class":295},[118,669,251],{"class":238},[118,671,350],{"class":295},[118,673,674],{"class":231},")",[118,676,625],{"class":238},[118,678,680],{"class":227,"line":679},37,[118,681,325],{"emptyLinePlaceholder":324},[118,683,685,687,689,692,694,697],{"class":227,"line":684},38,[118,686,616],{"class":231},[118,688,619],{"class":238},[118,690,691],{"class":231},"]$OutputPath ",[118,693,284],{"class":238},[118,695,696],{"class":295}," \".\\unapproved-local-admins.csv\"",[118,698,625],{"class":238},[118,700,702],{"class":227,"line":701},39,[118,703,325],{"emptyLinePlaceholder":324},[118,705,707,709,712,715,717],{"class":227,"line":706},40,[118,708,616],{"class":231},[118,710,711],{"class":238},"int",[118,713,714],{"class":231},"]$ThrottleLimit ",[118,716,284],{"class":238},[118,718,719],{"class":234}," 32\n",[118,721,723],{"class":227,"line":722},41,[118,724,725],{"class":231},")\n",[118,727,729],{"class":227,"line":728},42,[118,730,325],{"emptyLinePlaceholder":324},[118,732,734,737,740,743],{"class":227,"line":733},43,[118,735,736],{"class":238},"if",[118,738,739],{"class":231}," (",[118,741,742],{"class":238},"-not",[118,744,745],{"class":231}," $ComputerName) {\n",[118,747,749,752,754,756,759,762,765,767,770,772],{"class":227,"line":748},44,[118,750,751],{"class":238},"    if",[118,753,739],{"class":231},[118,755,742],{"class":238},[118,757,758],{"class":231}," $ComputerListPath ",[118,760,761],{"class":238},"-or",[118,763,764],{"class":238}," -not",[118,766,739],{"class":231},[118,768,769],{"class":234},"Test-Path",[118,771,239],{"class":238},[118,773,774],{"class":231},"Path $ComputerListPath)) {\n",[118,776,778,781],{"class":227,"line":777},45,[118,779,780],{"class":238},"        throw",[118,782,783],{"class":295}," \"Supply -ComputerName or a valid -ComputerListPath.\"\n",[118,785,787],{"class":227,"line":786},46,[118,788,789],{"class":231},"    }\n",[118,791,793],{"class":227,"line":792},47,[118,794,325],{"emptyLinePlaceholder":324},[118,796,798,801,803,806,808,811,814,817,820,823,826,829,832,835,837,840,842,844],{"class":227,"line":797},48,[118,799,800],{"class":231},"    $ComputerName ",[118,802,284],{"class":238},[118,804,805],{"class":234}," Get-Content",[118,807,239],{"class":238},[118,809,810],{"class":231},"Path $ComputerListPath ",[118,812,813],{"class":238},"|",[118,815,816],{"class":234}," Where-Object",[118,818,819],{"class":231}," { ",[118,821,822],{"class":234},"$_",[118,824,825],{"class":231},".Trim() ",[118,827,828],{"class":238},"-ne",[118,830,831],{"class":295}," \"\"",[118,833,834],{"class":231}," } ",[118,836,813],{"class":238},[118,838,839],{"class":234}," ForEach-Object",[118,841,819],{"class":231},[118,843,822],{"class":234},[118,845,846],{"class":231},".Trim() }\n",[118,848,850],{"class":227,"line":849},49,[118,851,852],{"class":231},"}\n",[118,854,856],{"class":227,"line":855},50,[118,857,325],{"emptyLinePlaceholder":324},[118,859,861,864,866,868,871,873,876,878],{"class":227,"line":860},51,[118,862,863],{"class":231},"$ComputerName ",[118,865,284],{"class":238},[118,867,662],{"class":238},[118,869,870],{"class":231},"($ComputerName ",[118,872,813],{"class":238},[118,874,875],{"class":234}," Sort-Object",[118,877,239],{"class":238},[118,879,880],{"class":231},"Unique)\n",[118,882,884,887,890,893,895,898,900,903,906],{"class":227,"line":883},52,[118,885,886],{"class":234},"Write-Host",[118,888,889],{"class":295}," \"Checking ",[118,891,892],{"class":238},"$",[118,894,665],{"class":295},[118,896,897],{"class":231},"$ComputerName.Count",[118,899,674],{"class":295},[118,901,902],{"class":295}," computer(s) with a throttle limit of ",[118,904,905],{"class":231},"$ThrottleLimit",[118,907,908],{"class":295}," ...\"\n",[118,910,912],{"class":227,"line":911},53,[118,913,325],{"emptyLinePlaceholder":324},[118,915,917],{"class":227,"line":916},54,[118,918,919],{"class":394},"# The script block that runs on each remote computer.\n",[118,921,923,926,928],{"class":227,"line":922},55,[118,924,925],{"class":231},"$membershipScript ",[118,927,284],{"class":238},[118,929,930],{"class":231}," {\n",[118,932,934,937,939],{"class":227,"line":933},56,[118,935,936],{"class":231},"    $adminSid ",[118,938,284],{"class":238},[118,940,941],{"class":295}," \"S-1-5-32-544\"\n",[118,943,945],{"class":227,"line":944},57,[118,946,325],{"emptyLinePlaceholder":324},[118,948,950,953],{"class":227,"line":949},58,[118,951,952],{"class":238},"    try",[118,954,930],{"class":231},[118,956,958,961,963,966,968,971,973,975],{"class":227,"line":957},59,[118,959,960],{"class":234},"        Get-LocalGroupMember",[118,962,239],{"class":238},[118,964,965],{"class":231},"SID $adminSid ",[118,967,245],{"class":238},[118,969,970],{"class":231},"ErrorAction Stop ",[118,972,813],{"class":238},[118,974,839],{"class":234},[118,976,930],{"class":231},[118,978,980,983,986,989,992],{"class":227,"line":979},60,[118,981,982],{"class":231},"            [",[118,984,985],{"class":238},"pscustomobject",[118,987,988],{"class":231},"]",[118,990,991],{"class":238},"@",[118,993,994],{"class":231},"{\n",[118,996,998,1001,1003,1006,1009],{"class":227,"line":997},61,[118,999,1000],{"class":231},"                ComputerName    ",[118,1002,284],{"class":238},[118,1004,1005],{"class":231}," $",[118,1007,1008],{"class":234},"env:",[118,1010,1011],{"class":231},"COMPUTERNAME\n",[118,1013,1015,1018,1020,1023],{"class":227,"line":1014},62,[118,1016,1017],{"class":231},"                Name            ",[118,1019,284],{"class":238},[118,1021,1022],{"class":234}," $_",[118,1024,1025],{"class":231},".Name\n",[118,1027,1029,1032,1034,1036],{"class":227,"line":1028},63,[118,1030,1031],{"class":231},"                SID             ",[118,1033,284],{"class":238},[118,1035,1022],{"class":234},[118,1037,1038],{"class":231},".SID.Value\n",[118,1040,1042,1045,1047,1049],{"class":227,"line":1041},64,[118,1043,1044],{"class":231},"                ObjectClass     ",[118,1046,284],{"class":238},[118,1048,1022],{"class":234},[118,1050,1051],{"class":231},".ObjectClass\n",[118,1053,1055,1058,1060,1063,1065,1067,1069,1072,1074],{"class":227,"line":1054},65,[118,1056,1057],{"class":231},"                PrincipalSource ",[118,1059,284],{"class":238},[118,1061,1062],{"class":295}," \"",[118,1064,892],{"class":238},[118,1066,665],{"class":295},[118,1068,822],{"class":234},[118,1070,1071],{"class":231},".PrincipalSource",[118,1073,674],{"class":295},[118,1075,1076],{"class":295},"\"\n",[118,1078,1080,1083,1085],{"class":227,"line":1079},66,[118,1081,1082],{"class":231},"                Method          ",[118,1084,284],{"class":238},[118,1086,1087],{"class":295}," \"Get-LocalGroupMember\"\n",[118,1089,1091],{"class":227,"line":1090},67,[118,1092,1093],{"class":231},"            }\n",[118,1095,1097],{"class":227,"line":1096},68,[118,1098,1099],{"class":231},"        }\n",[118,1101,1103,1106,1109],{"class":227,"line":1102},69,[118,1104,1105],{"class":231},"    } ",[118,1107,1108],{"class":238},"catch",[118,1110,930],{"class":231},[118,1112,1114],{"class":227,"line":1113},70,[118,1115,1116],{"class":394},"        # Fallback: resolve the localized group name from the SID and parse net.exe output.\n",[118,1118,1120,1123,1125,1128],{"class":227,"line":1119},71,[118,1121,1122],{"class":231},"        $sidObject ",[118,1124,284],{"class":238},[118,1126,1127],{"class":234}," New-Object",[118,1129,1130],{"class":231}," System.Security.Principal.SecurityIdentifier($adminSid)\n",[118,1132,1134,1137,1139,1142,1145,1148,1151,1154,1157,1160],{"class":227,"line":1133},72,[118,1135,1136],{"class":231},"        $groupName ",[118,1138,284],{"class":238},[118,1140,1141],{"class":231}," ($sidObject.Translate([",[118,1143,1144],{"class":238},"System.Security.Principal.NTAccount",[118,1146,1147],{"class":231},"]).Value ",[118,1149,1150],{"class":238},"-split",[118,1152,1153],{"class":295}," \"\\\\\"",[118,1155,1156],{"class":231},")[",[118,1158,1159],{"class":234},"-1",[118,1161,1162],{"class":231},"]\n",[118,1164,1166,1169,1171,1173,1175,1178,1181,1184,1187,1190,1192],{"class":227,"line":1165},73,[118,1167,1168],{"class":231},"        $output ",[118,1170,284],{"class":238},[118,1172,662],{"class":238},[118,1174,665],{"class":231},[118,1176,1177],{"class":238},"&",[118,1179,1180],{"class":234}," net.exe",[118,1182,1183],{"class":231}," localgroup ",[118,1185,1186],{"class":295},"\"",[118,1188,1189],{"class":231},"$groupName",[118,1191,1186],{"class":295},[118,1193,725],{"class":231},[118,1195,1197],{"class":227,"line":1196},74,[118,1198,325],{"emptyLinePlaceholder":324},[118,1200,1202,1205,1207],{"class":227,"line":1201},75,[118,1203,1204],{"class":231},"        $dashIndex ",[118,1206,284],{"class":238},[118,1208,1209],{"class":234}," -1\n",[118,1211,1213,1216,1219,1221,1224,1227,1230,1233,1236],{"class":227,"line":1212},76,[118,1214,1215],{"class":238},"        for",[118,1217,1218],{"class":231}," ($i ",[118,1220,284],{"class":238},[118,1222,1223],{"class":234}," 0",[118,1225,1226],{"class":231},"; $i ",[118,1228,1229],{"class":238},"-lt",[118,1231,1232],{"class":231}," $output.Count; $i",[118,1234,1235],{"class":238},"++",[118,1237,1238],{"class":231},") {\n",[118,1240,1242,1245,1248,1251,1254],{"class":227,"line":1241},77,[118,1243,1244],{"class":238},"            if",[118,1246,1247],{"class":231}," ($output[$i] ",[118,1249,1250],{"class":238},"-match",[118,1252,1253],{"class":295}," \"^-{5,}\"",[118,1255,1238],{"class":231},[118,1257,1259,1262,1264],{"class":227,"line":1258},78,[118,1260,1261],{"class":231},"                $dashIndex ",[118,1263,284],{"class":238},[118,1265,1266],{"class":231}," $i\n",[118,1268,1270],{"class":227,"line":1269},79,[118,1271,1272],{"class":238},"                break\n",[118,1274,1276],{"class":227,"line":1275},80,[118,1277,1093],{"class":231},[118,1279,1281],{"class":227,"line":1280},81,[118,1282,1099],{"class":231},[118,1284,1286],{"class":227,"line":1285},82,[118,1287,325],{"emptyLinePlaceholder":324},[118,1289,1291,1294,1297,1300,1302],{"class":227,"line":1290},83,[118,1292,1293],{"class":238},"        if",[118,1295,1296],{"class":231}," ($dashIndex ",[118,1298,1299],{"class":238},"-ge",[118,1301,1223],{"class":234},[118,1303,1238],{"class":231},[118,1305,1307],{"class":227,"line":1306},84,[118,1308,1309],{"class":394},"            # Members follow the dashed line; the last non-empty line is the completion message.\n",[118,1311,1313,1316,1319,1322,1324,1327,1330,1332,1334,1337],{"class":227,"line":1312},85,[118,1314,1315],{"class":231},"            $output[($dashIndex ",[118,1317,1318],{"class":238},"+",[118,1320,1321],{"class":234}," 1",[118,1323,674],{"class":231},[118,1325,1326],{"class":238},"..",[118,1328,1329],{"class":231},"($output.Count ",[118,1331,245],{"class":238},[118,1333,1321],{"class":234},[118,1335,1336],{"class":231},")] ",[118,1338,1339],{"class":238},"|\n",[118,1341,1343,1346,1348,1350,1352,1354,1356,1358],{"class":227,"line":1342},86,[118,1344,1345],{"class":234},"                Where-Object",[118,1347,819],{"class":231},[118,1349,822],{"class":234},[118,1351,825],{"class":231},[118,1353,828],{"class":238},[118,1355,831],{"class":295},[118,1357,834],{"class":231},[118,1359,1339],{"class":238},[118,1361,1363,1366,1368,1371,1374],{"class":227,"line":1362},87,[118,1364,1365],{"class":234},"                Select-Object",[118,1367,239],{"class":238},[118,1369,1370],{"class":231},"SkipLast ",[118,1372,1373],{"class":234},"1",[118,1375,307],{"class":238},[118,1377,1379,1382],{"class":227,"line":1378},88,[118,1380,1381],{"class":234},"                ForEach-Object",[118,1383,930],{"class":231},[118,1385,1387,1390,1392,1394,1396],{"class":227,"line":1386},89,[118,1388,1389],{"class":231},"                    [",[118,1391,985],{"class":238},[118,1393,988],{"class":231},[118,1395,991],{"class":238},[118,1397,994],{"class":231},[118,1399,1401,1404,1406,1408,1410],{"class":227,"line":1400},90,[118,1402,1403],{"class":231},"                        ComputerName    ",[118,1405,284],{"class":238},[118,1407,1005],{"class":231},[118,1409,1008],{"class":234},[118,1411,1011],{"class":231},[118,1413,1415,1418,1420,1422],{"class":227,"line":1414},91,[118,1416,1417],{"class":231},"                        Name            ",[118,1419,284],{"class":238},[118,1421,1022],{"class":234},[118,1423,1424],{"class":231},".Trim()\n",[118,1426,1428,1431,1433],{"class":227,"line":1427},92,[118,1429,1430],{"class":231},"                        SID             ",[118,1432,284],{"class":238},[118,1434,1435],{"class":234}," $null\n",[118,1437,1439,1442,1444],{"class":227,"line":1438},93,[118,1440,1441],{"class":231},"                        ObjectClass     ",[118,1443,284],{"class":238},[118,1445,1435],{"class":234},[118,1447,1449,1452,1454],{"class":227,"line":1448},94,[118,1450,1451],{"class":231},"                        PrincipalSource ",[118,1453,284],{"class":238},[118,1455,1435],{"class":234},[118,1457,1459,1462,1464],{"class":227,"line":1458},95,[118,1460,1461],{"class":231},"                        Method          ",[118,1463,284],{"class":238},[118,1465,1466],{"class":295}," \"net.exe\"\n",[118,1468,1470],{"class":227,"line":1469},96,[118,1471,1472],{"class":231},"                    }\n",[118,1474,1476],{"class":227,"line":1475},97,[118,1477,1478],{"class":231},"                }\n",[118,1480,1482],{"class":227,"line":1481},98,[118,1483,1099],{"class":231},[118,1485,1487],{"class":227,"line":1486},99,[118,1488,789],{"class":231},[118,1490,1492],{"class":227,"line":1491},100,[118,1493,852],{"class":231},[118,1495,1497],{"class":227,"line":1496},101,[118,1498,325],{"emptyLinePlaceholder":324},[118,1500,1502],{"class":227,"line":1501},102,[118,1503,1504],{"class":394},"# Return $true when a member matches any allowlist entry by SID, full name or short name.\n",[118,1506,1508,1511,1515],{"class":227,"line":1507},103,[118,1509,1510],{"class":238},"function",[118,1512,1514],{"class":1513},"svObZ"," Test-Approved",[118,1516,930],{"class":231},[118,1518,1520,1523],{"class":227,"line":1519},104,[118,1521,1522],{"class":238},"    param",[118,1524,1525],{"class":231}," (\n",[118,1527,1529,1532],{"class":227,"line":1528},105,[118,1530,1531],{"class":231},"        $Member",[118,1533,625],{"class":238},[118,1535,1537,1540,1542],{"class":227,"line":1536},106,[118,1538,1539],{"class":231},"        [",[118,1541,619],{"class":238},[118,1543,1544],{"class":231},"[]]$Allowlist\n",[118,1546,1548],{"class":227,"line":1547},107,[118,1549,1550],{"class":231},"    )\n",[118,1552,1554],{"class":227,"line":1553},108,[118,1555,325],{"emptyLinePlaceholder":324},[118,1557,1559,1562,1564,1567,1569,1571,1573,1575],{"class":227,"line":1558},109,[118,1560,1561],{"class":231},"    $shortName ",[118,1563,284],{"class":238},[118,1565,1566],{"class":231}," ($Member.Name ",[118,1568,1150],{"class":238},[118,1570,1153],{"class":295},[118,1572,1156],{"class":231},[118,1574,1159],{"class":234},[118,1576,1162],{"class":231},[118,1578,1580],{"class":227,"line":1579},110,[118,1581,325],{"emptyLinePlaceholder":324},[118,1583,1585,1588,1591,1594],{"class":227,"line":1584},111,[118,1586,1587],{"class":238},"    foreach",[118,1589,1590],{"class":231}," ($entry ",[118,1592,1593],{"class":238},"in",[118,1595,1596],{"class":231}," $Allowlist) {\n",[118,1598,1600,1602,1605,1608,1611,1614,1617,1620,1623],{"class":227,"line":1599},112,[118,1601,1293],{"class":238},[118,1603,1604],{"class":231}," ($Member.SID ",[118,1606,1607],{"class":238},"-and",[118,1609,1610],{"class":231}," $entry ",[118,1612,1613],{"class":238},"-eq",[118,1615,1616],{"class":231}," $Member.SID) { ",[118,1618,1619],{"class":238},"return",[118,1621,1622],{"class":234}," $true",[118,1624,1625],{"class":231}," }\n",[118,1627,1629,1631,1633,1635,1638,1640,1642],{"class":227,"line":1628},113,[118,1630,1293],{"class":238},[118,1632,1590],{"class":231},[118,1634,1613],{"class":238},[118,1636,1637],{"class":231}," $Member.Name) { ",[118,1639,1619],{"class":238},[118,1641,1622],{"class":234},[118,1643,1625],{"class":231},[118,1645,1647,1649,1651,1654,1657,1660,1662,1664,1667,1669,1671],{"class":227,"line":1646},114,[118,1648,1293],{"class":238},[118,1650,1590],{"class":231},[118,1652,1653],{"class":238},"-notlike",[118,1655,1656],{"class":295}," \"*\\*\"",[118,1658,1659],{"class":238}," -and",[118,1661,1610],{"class":231},[118,1663,1613],{"class":238},[118,1665,1666],{"class":231}," $shortName) { ",[118,1668,1619],{"class":238},[118,1670,1622],{"class":234},[118,1672,1625],{"class":231},[118,1674,1676],{"class":227,"line":1675},115,[118,1677,789],{"class":231},[118,1679,1681],{"class":227,"line":1680},116,[118,1682,325],{"emptyLinePlaceholder":324},[118,1684,1686,1689],{"class":227,"line":1685},117,[118,1687,1688],{"class":238},"    return",[118,1690,1691],{"class":234}," $false\n",[118,1693,1695],{"class":227,"line":1694},118,[118,1696,852],{"class":231},[118,1698,1700],{"class":227,"line":1699},119,[118,1701,325],{"emptyLinePlaceholder":324},[118,1703,1705,1708,1710,1713,1715,1718,1720,1723,1725,1728,1730],{"class":227,"line":1704},120,[118,1706,1707],{"class":231},"$parentJob ",[118,1709,284],{"class":238},[118,1711,1712],{"class":234}," Invoke-Command",[118,1714,239],{"class":238},[118,1716,1717],{"class":231},"ComputerName $ComputerName ",[118,1719,245],{"class":238},[118,1721,1722],{"class":231},"ScriptBlock $membershipScript ",[118,1724,245],{"class":238},[118,1726,1727],{"class":231},"AsJob ",[118,1729,245],{"class":238},[118,1731,1732],{"class":231},"ThrottleLimit $ThrottleLimit\n",[118,1734,1736,1738,1740,1743,1746],{"class":227,"line":1735},121,[118,1737,1707],{"class":231},[118,1739,813],{"class":238},[118,1741,1742],{"class":234}," Wait-Job",[118,1744,1745],{"class":238}," |",[118,1747,1748],{"class":234}," Out-Null\n",[118,1750,1752],{"class":227,"line":1751},122,[118,1753,325],{"emptyLinePlaceholder":324},[118,1755,1757,1760,1762,1764,1767,1770],{"class":227,"line":1756},123,[118,1758,1759],{"class":231},"$flagged ",[118,1761,284],{"class":238},[118,1763,1127],{"class":234},[118,1765,1766],{"class":231}," System.Collections.Generic.List[",[118,1768,1769],{"class":238},"object",[118,1771,1162],{"class":231},[118,1773,1775,1778,1780,1782,1784,1786],{"class":227,"line":1774},124,[118,1776,1777],{"class":231},"$failures ",[118,1779,284],{"class":238},[118,1781,1127],{"class":234},[118,1783,1766],{"class":231},[118,1785,619],{"class":238},[118,1787,1162],{"class":231},[118,1789,1791],{"class":227,"line":1790},125,[118,1792,325],{"emptyLinePlaceholder":324},[118,1794,1796,1799,1802,1804],{"class":227,"line":1795},126,[118,1797,1798],{"class":238},"foreach",[118,1800,1801],{"class":231}," ($child ",[118,1803,1593],{"class":238},[118,1805,1806],{"class":231}," $parentJob.ChildJobs) {\n",[118,1808,1810,1813,1815],{"class":227,"line":1809},127,[118,1811,1812],{"class":231},"    $target ",[118,1814,284],{"class":238},[118,1816,1817],{"class":231}," $child.Location\n",[118,1819,1821],{"class":227,"line":1820},128,[118,1822,325],{"emptyLinePlaceholder":324},[118,1824,1826,1828,1831,1833,1836],{"class":227,"line":1825},129,[118,1827,751],{"class":238},[118,1829,1830],{"class":231}," ($child.State ",[118,1832,1613],{"class":238},[118,1834,1835],{"class":295}," \"Failed\"",[118,1837,1238],{"class":231},[118,1839,1841],{"class":227,"line":1840},130,[118,1842,1843],{"class":231},"        $failures.Add($target)\n",[118,1845,1847,1850,1853,1856,1859,1861,1863,1866,1868],{"class":227,"line":1846},131,[118,1848,1849],{"class":234},"        Write-Warning",[118,1851,1852],{"class":295}," \"Failed ",[118,1854,1855],{"class":231},"$target",[118,1857,1858],{"class":295},"`: ",[118,1860,892],{"class":238},[118,1862,665],{"class":295},[118,1864,1865],{"class":231},"$child.JobStateInfo.Reason.Message",[118,1867,674],{"class":295},[118,1869,1076],{"class":295},[118,1871,1873],{"class":227,"line":1872},132,[118,1874,1875],{"class":238},"        continue\n",[118,1877,1879],{"class":227,"line":1878},133,[118,1880,789],{"class":231},[118,1882,1884],{"class":227,"line":1883},134,[118,1885,325],{"emptyLinePlaceholder":324},[118,1887,1889,1892,1894,1896,1898,1901,1903,1906,1908,1911],{"class":227,"line":1888},135,[118,1890,1891],{"class":231},"    $members ",[118,1893,284],{"class":238},[118,1895,662],{"class":238},[118,1897,665],{"class":231},[118,1899,1900],{"class":234},"Receive-Job",[118,1902,239],{"class":238},[118,1904,1905],{"class":231},"Job $child ",[118,1907,245],{"class":238},[118,1909,1910],{"class":231},"ErrorAction SilentlyContinue ",[118,1912,1339],{"class":238},[118,1914,1916,1919,1921,1924,1926,1929,1931,1934,1936,1939,1941,1944,1946],{"class":227,"line":1915},136,[118,1917,1918],{"class":234},"        Select-Object",[118,1920,239],{"class":238},[118,1922,1923],{"class":231},"Property ComputerName",[118,1925,251],{"class":238},[118,1927,1928],{"class":231}," Name",[118,1930,251],{"class":238},[118,1932,1933],{"class":231}," SID",[118,1935,251],{"class":238},[118,1937,1938],{"class":231}," ObjectClass",[118,1940,251],{"class":238},[118,1942,1943],{"class":231}," PrincipalSource",[118,1945,251],{"class":238},[118,1947,1948],{"class":231}," Method)\n",[118,1950,1952,1955,1957,1959,1962,1964,1966,1968,1970,1972,1975,1977,1980,1982,1984],{"class":227,"line":1951},137,[118,1953,1954],{"class":231},"    $unapproved ",[118,1956,284],{"class":238},[118,1958,662],{"class":238},[118,1960,1961],{"class":231},"($members ",[118,1963,813],{"class":238},[118,1965,816],{"class":234},[118,1967,819],{"class":231},[118,1969,742],{"class":238},[118,1971,739],{"class":231},[118,1973,1974],{"class":234},"Test-Approved",[118,1976,239],{"class":238},[118,1978,1979],{"class":231},"Member ",[118,1981,822],{"class":234},[118,1983,239],{"class":238},[118,1985,1986],{"class":231},"Allowlist $ExpectedAdmins) })\n",[118,1988,1990,1993,1995,1998,2001,2004,2006,2008,2011,2014,2017,2019,2022,2025,2028,2030,2033,2035,2038],{"class":227,"line":1989},138,[118,1991,1992],{"class":231},"    $note ",[118,1994,284],{"class":238},[118,1996,1997],{"class":238}," if",[118,1999,2000],{"class":231}," ($members.Count ",[118,2002,2003],{"class":238},"-gt",[118,2005,1223],{"class":234},[118,2007,1659],{"class":238},[118,2009,2010],{"class":231}," $members[",[118,2012,2013],{"class":234},"0",[118,2015,2016],{"class":231},"].Method ",[118,2018,1613],{"class":238},[118,2020,2021],{"class":295}," \"net.exe\"",[118,2023,2024],{"class":231},") { ",[118,2026,2027],{"class":295},"\" (net.exe fallback)\"",[118,2029,834],{"class":231},[118,2031,2032],{"class":238},"else",[118,2034,819],{"class":231},[118,2036,2037],{"class":295},"\"\"",[118,2039,1625],{"class":231},[118,2041,2043],{"class":227,"line":2042},139,[118,2044,325],{"emptyLinePlaceholder":324},[118,2046,2048,2050,2053,2055,2057],{"class":227,"line":2047},140,[118,2049,751],{"class":238},[118,2051,2052],{"class":231}," ($unapproved.Count ",[118,2054,2003],{"class":238},[118,2056,1223],{"class":234},[118,2058,1238],{"class":231},[118,2060,2062,2065,2067],{"class":227,"line":2061},141,[118,2063,2064],{"class":231},"        $flagged.AddRange([",[118,2066,1769],{"class":238},[118,2068,2069],{"class":231},"[]]$unapproved)\n",[118,2071,2073,2076,2078,2080,2082,2084,2086,2089,2091,2094,2097],{"class":227,"line":2072},142,[118,2074,2075],{"class":234},"        Write-Host",[118,2077,1062],{"class":295},[118,2079,1855],{"class":231},[118,2081,1858],{"class":295},[118,2083,892],{"class":238},[118,2085,665],{"class":295},[118,2087,2088],{"class":231},"$unapproved.Count",[118,2090,674],{"class":295},[118,2092,2093],{"class":295}," unapproved member(s) found",[118,2095,2096],{"class":231},"$note",[118,2098,1076],{"class":295},[118,2100,2102,2104,2106],{"class":227,"line":2101},143,[118,2103,1105],{"class":231},[118,2105,2032],{"class":238},[118,2107,930],{"class":231},[118,2109,2111,2113,2115,2117,2120,2122],{"class":227,"line":2110},144,[118,2112,2075],{"class":234},[118,2114,1062],{"class":295},[118,2116,1855],{"class":231},[118,2118,2119],{"class":295},"`: no unapproved members",[118,2121,2096],{"class":231},[118,2123,1076],{"class":295},[118,2125,2127],{"class":227,"line":2126},145,[118,2128,789],{"class":231},[118,2130,2132],{"class":227,"line":2131},146,[118,2133,852],{"class":231},[118,2135,2137],{"class":227,"line":2136},147,[118,2138,325],{"emptyLinePlaceholder":324},[118,2140,2142,2145,2147,2150,2152],{"class":227,"line":2141},148,[118,2143,2144],{"class":234},"Remove-Job",[118,2146,239],{"class":238},[118,2148,2149],{"class":231},"Job $parentJob ",[118,2151,245],{"class":238},[118,2153,2154],{"class":231},"Force\n",[118,2156,2158],{"class":227,"line":2157},149,[118,2159,325],{"emptyLinePlaceholder":324},[118,2161,2163,2165,2167,2170,2172,2175,2177],{"class":227,"line":2162},150,[118,2164,1759],{"class":231},[118,2166,813],{"class":238},[118,2168,2169],{"class":234}," Export-Csv",[118,2171,239],{"class":238},[118,2173,2174],{"class":231},"Path $OutputPath ",[118,2176,245],{"class":238},[118,2178,2179],{"class":231},"NoTypeInformation\n",[118,2181,2183,2185,2188,2191],{"class":227,"line":2182},151,[118,2184,886],{"class":234},[118,2186,2187],{"class":295}," \"Flagged members written to ",[118,2189,2190],{"class":231},"$OutputPath",[118,2192,1076],{"class":295},[118,2194,2196],{"class":227,"line":2195},152,[118,2197,325],{"emptyLinePlaceholder":324},[118,2199,2201,2203,2206,2208,2210],{"class":227,"line":2200},153,[118,2202,736],{"class":238},[118,2204,2205],{"class":231}," ($failures.Count ",[118,2207,2003],{"class":238},[118,2209,1223],{"class":234},[118,2211,1238],{"class":231},[118,2213,2215,2218,2221,2223,2225,2228,2231,2234,2236],{"class":227,"line":2214},154,[118,2216,2217],{"class":234},"    Write-Warning",[118,2219,2220],{"class":295}," \"Unreachable or failed computers: ",[118,2222,892],{"class":238},[118,2224,665],{"class":295},[118,2226,2227],{"class":231},"$failures",[118,2229,2230],{"class":238}," -join",[118,2232,2233],{"class":295}," ', '",[118,2235,674],{"class":295},[118,2237,1076],{"class":295},[118,2239,2241],{"class":227,"line":2240},155,[118,2242,852],{"class":231},[39,2244,2246],{"id":2245},"notes","Notes",[44,2248,2249,2264,2281,2308,2321,2326],{},[47,2250,2251,2253,2254,72,2256,2259,2260,2263],{},[18,2252,28],{}," returns the group's direct members. If ",[18,2255,161],{},[18,2257,2258],{},"CORP\\Workstation Admins"," is a member, the report shows the group, not the people in it. Resolve those separately with ",[18,2261,2262],{},"Get-ADGroupMember -Identity \"Workstation Admins\" -Recursive","; that's usually where the real sprawl hides.",[47,2265,2266,2267,2270,2271,2274,2275,2277,2278,2280],{},"Rows marked ",[18,2268,2269],{},"net.exe"," have no SID or ",[18,2272,2273],{},"PrincipalSource",", only the name as ",[18,2276,2269],{}," prints it. A computer that needed the fallback almost certainly has an unresolvable member in the group; find it, confirm the old domain or account is really gone, and remove it; the GitHub reports tie the error to unresolvable members, so ",[18,2279,28],{}," should work again once they're gone.",[47,2282,2283,2285,2286,2289,2290,2289,2293,2296,2297,2300,2301,2304,2305,2307],{},[18,2284,2273],{}," tells you where a member comes from. The CSV holds the enum value: ",[18,2287,2288],{},"Local",", ",[18,2291,2292],{},"ActiveDirectory",[18,2294,2295],{},"AzureAD"," (Microsoft Entra ID), ",[18,2298,2299],{},"MicrosoftAccount",", or ",[18,2302,2303],{},"Unknown"," (documented for Windows 10 \u002F Server 2016 and later). A ",[18,2306,2299],{}," admin on a corporate workstation is almost always worth a conversation.",[47,2309,2310,2311,2313,2314,2317,2318,2320],{},"Short-name matching is convenient but loose: an allowlisted ",[18,2312,169],{}," also matches a same-named account in a different domain. Use ",[18,2315,2316],{},"DOMAIN\\name"," or SIDs in ",[18,2319,149],{}," when that distinction matters.",[47,2322,2323,2324,173],{},"The built-in local Administrator account shouldn't have the same password everywhere. Windows LAPS is built into Windows 11 23H2 and later (and earlier builds with the April 11, 2023 update), backs the password up to Active Directory or Microsoft Entra ID, and rotates it. The legacy Microsoft LAPS MSI is deprecated and blocked from installing on Windows 11 23H2 and later. If you use a custom LAPS-managed account name, add it to ",[18,2325,149],{},[47,2327,2328,2329,2334],{},"I run this monthly and diff the output against the previous run rather than treating every flagged account as new. A shrinking diff is the real signal that the cleanup is working. The ",[2330,2331,2333],"a",{"href":2332},"\u002F2025\u002F08\u002F27\u002Fpowershell-windows-inventory-installed-software-across-a-domain\u002F","software inventory script"," uses the same fan-out pattern.",[39,2336,2338],{"id":2337},"source","Source",[44,2340,2341,2348,2360,2367,2374],{},[47,2342,2343],{},[2330,2344,28],{"href":2345,"rel":2346},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Fmicrosoft.powershell.localaccounts\u002Fget-localgroupmember?view=powershell-5.1",[2347],"nofollow",[47,2349,2350,170,2355],{},[2330,2351,2354],{"href":2352,"rel":2353},"https:\u002F\u002Fgithub.com\u002FPowerShell\u002FPowerShell\u002Fissues\u002F2996",[2347],"PowerShell issue #2996: Failed to compare two elements in the array",[2330,2356,2359],{"href":2357,"rel":2358},"https:\u002F\u002Fgithub.com\u002FPowerShell\u002FPowerShell\u002Fissues\u002F21617",[2347],"#21617",[47,2361,2362],{},[2330,2363,2366],{"href":2364,"rel":2365},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Fmicrosoft.powershell.core\u002Fabout\u002Fabout_remote_requirements",[2347],"about_Remote_Requirements",[47,2368,2369],{},[2330,2370,2373],{"href":2371,"rel":2372},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Fmicrosoft.powershell.core\u002Finvoke-command",[2347],"Invoke-Command",[47,2375,2376],{},[2330,2377,2380],{"href":2378,"rel":2379},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fwindows-server\u002Fidentity\u002Flaps\u002Flaps-overview",[2347],"Windows LAPS overview",[2382,2383,2384],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":222,"searchDepth":310,"depth":310,"links":2386},[2387,2388,2389,2390,2391,2392],{"id":41,"depth":310,"text":42},{"id":79,"depth":310,"text":80},{"id":211,"depth":310,"text":212},{"id":383,"depth":310,"text":384},{"id":2245,"depth":310,"text":2246},{"id":2337,"depth":310,"text":2338},"techcolumnist",[2395,2396],"ps","scripts","2025-10-08T14:00:00Z","A script that reads the local Administrators group on every workstation by SID, survives orphaned-SID errors, and flags members outside an approved allowlist.","md",false,null,{},"\u002Fblog\u002F2025\u002F10\u002F08\u002Fpowershell-windows-discover-local-admins-across-every-workstation",{"title":6,"description":2398},[2393],"blog\u002F2025\u002F10\u002F08\u002Fpowershell-windows-discover-local-admins-across-every-workstation",[221,2408,2409,2410],"windows","discovery","active-directory","\u002F2025\u002F10\u002F08\u002Fpowershell-windows-discover-local-admins-across-every-workstation\u002F","TZA9_Uw90FvRN-yc62xe_w-i6tEZ_WFwqsje6jEWsYU",{"title":2414,"description":2415,"date":2416,"url":2417,"categories":2418,"tags":2419,"image":2401,"readingTime":328,"canonical":2393,"sites":2422,"series":2401,"seriesOrder":2401},"PowerShell: Hyper-V – Automate VM Checkpoints Before Patch Tuesday","A script that takes dated production checkpoints of running Hyper-V VMs on hosts or a whole cluster before patching, prunes its own old ones and plugs into CAU.","2025-10-15T14:00:00Z","\u002F2025\u002F10\u002F15\u002Fpowershell-hyper-v-automate-vm-checkpoints-before-patch-tuesday\u002F",[2395,2396],[221,2420,2421],"hyper-v","cluster",[2393],{"title":2424,"description":2425,"date":2426,"url":2427,"categories":2428,"tags":2429,"image":2401,"readingTime":415,"canonical":2393,"sites":2430,"series":2401,"seriesOrder":2401},"PowerShell: Active Directory – Bulk Password Reset with Forced Change","Reset a list of AD accounts to random, policy-length passwords, force a change at next logon, handle never-expires and lockouts, and write a report.","2025-10-01T14:00:00Z","\u002F2025\u002F10\u002F01\u002Fpowershell-active-directory-bulk-reset-passwords-with-a-forced-change\u002F",[2395,2396],[221,2410],[2393],[2432,2439,2447],{"title":2433,"description":2434,"date":2435,"url":2332,"categories":2436,"tags":2437,"image":2401,"readingTime":321,"canonical":2393,"sites":2438,"series":2401,"seriesOrder":2401},"PowerShell: Windows – Inventory Installed Software Across a Domain","A script that reads the Uninstall registry keys on many Windows computers in parallel over PowerShell remoting and writes one CSV, without touching Win32_Product.","2025-08-27T14:00:00Z",[2395,2396],[221,2408,2409,2410],[2393],{"title":2440,"description":2441,"date":2442,"url":2443,"categories":2444,"tags":2445,"image":2401,"readingTime":328,"canonical":2393,"sites":2446,"series":2401,"seriesOrder":2401},"PowerShell: Active Directory – Find and Disable Stale Computers","Find AD computer accounts that stopped authenticating using lastLogonTimestamp and pwdLastSet, report them, then disable and quarantine them with a note for rollback.","2025-06-30T14:00:00Z","\u002F2025\u002F06\u002F30\u002Fpowershell-active-directory-find-and-disable-stale-computer-accounts\u002F",[2395,2396],[221,2410,2408],[2393],{"title":2448,"description":2449,"date":2450,"url":2451,"categories":2452,"tags":2453,"image":2401,"readingTime":415,"canonical":2393,"sites":2455,"series":2401,"seriesOrder":2401},"PowerShell: Active Directory – Report Group Membership Sprawl","Rank AD security groups by nesting depth, transitive member count, ownership and staleness for an access review, plus a per-user Kerberos token size estimate.","2025-12-03T14:00:00Z","\u002F2025\u002F12\u002F03\u002Fpowershell-active-directory-report-group-membership-sprawl\u002F",[2395,2396],[221,2410,2454],"reporting",[2393],{"doc":2401,"posts":2457},[],1790052513194]