[{"data":1,"prerenderedAt":1941},["ShallowReactive",2],{"post:\u002F2025\u002F08\u002F27\u002Fpowershell-windows-inventory-installed-software-across-a-domain\u002F":3},{"post":4,"newer":1896,"older":1906,"related":1915,"series":1939},{"id":5,"title":6,"body":7,"canonical":1876,"categories":1877,"date":1880,"description":1881,"extension":1882,"featured":1883,"hero":1884,"image":1884,"meta":1885,"navigation":662,"path":1886,"readingTime":388,"seo":1887,"series":1884,"seriesOrder":1884,"sites":1888,"source":1884,"stem":1889,"tags":1890,"updated":1884,"url":1894,"__hash__":1895},"blog\u002Fblog\u002F2025\u002F08\u002F27\u002Fpowershell-windows-inventory-installed-software-across-a-domain.md","PowerShell: Windows – Inventory Installed Software Across a Domain",{"type":8,"value":9,"toc":1868},"minimark",[10,31,36,69,73,176,180,183,236,239,265,268,324,327,335,338,428,432,1732,1736,1816,1820,1864],[11,12,13,14,18,19,22,23,26,27,30],"p",{},"Software inventory questions come up constantly: which machines still have an old Java runtime, who has a vulnerable version of some agent installed, how many endpoints are actually running the app a vendor wants to renew. The query everyone reaches for first, ",[15,16,17],"code",{},"Get-WmiObject Win32_Product"," (or ",[15,20,21],{},"Get-CimInstance","), is the one not to run fleet-wide. Microsoft's support article on it (KB 974524) explains that enumerating ",[15,24,25],{},"Win32_Product"," goes through the MSI provider and \"starts a consistency check of packages installed, verifying, and repairing the install\". The visible symptom is an ",[15,28,29],{},"MsiInstaller"," event 1035, \"Windows Installer reconfigured the product\", logged for every installed MSI, plus slow startups and sign-ins if a GPO WMI filter does it. So I read the same Uninstall registry keys that Programs and Features reads, in parallel, across every machine on the list.",[32,33,35],"h2",{"id":34},"requirements","Requirements",[37,38,39,43,50,66],"ul",{},[40,41,42],"li",{},"Windows PowerShell 5.1 or PowerShell 7 on the machine running the script.",[40,44,45,46,49],{},"PowerShell remoting (WinRM) enabled and reachable on every target. Windows Server 2012 and later have it on by default; Windows client editions don't, so enable it with ",[15,47,48],{},"Enable-PSRemoting"," or the equivalent Group Policy (WinRM service, listener, and firewall rule).",[40,51,52,53,57,58,61,62,65],{},"An account in the ",[54,55,56],"strong",{},"Administrators"," or ",[54,59,60],{},"Remote Management Users"," group on each target. The default ",[15,63,64],{},"Microsoft.PowerShell"," endpoint only admits Administrators unless you've changed its security descriptor.",[40,67,68],{},"The Active Directory module (RSAT) only if you want to source the computer list from AD.",[32,70,72],{"id":71},"parameters","Parameters",[74,75,76,95],"table",{},[77,78,79],"thead",{},[80,81,82,86,89,92],"tr",{},[83,84,85],"th",{},"Name",[83,87,88],{},"Type",[83,90,91],{},"Required",[83,93,94],{},"Description",[96,97,98,122,135,153],"tbody",{},[80,99,100,106,112,115],{},[101,102,103],"td",{},[15,104,105],{},"-ComputerName",[101,107,108,109],{},"String",[110,111],"span",{},[101,113,114],{},"No",[101,116,117,118,121],{},"One or more computer names to inventory. If omitted, ",[15,119,120],{},"-ComputerListPath"," is used instead.",[80,123,124,128,130,132],{},[101,125,126],{},[15,127,120],{},[101,129,108],{},[101,131,114],{},[101,133,134],{},"Path to a text file with one computer name per line.",[80,136,137,142,144,146],{},[101,138,139],{},[15,140,141],{},"-OutputPath",[101,143,108],{},[101,145,114],{},[101,147,148,149,152],{},"Path to the consolidated CSV. Defaults to ",[15,150,151],{},".\\software-inventory.csv",".",[80,154,155,160,163,165],{},[101,156,157],{},[15,158,159],{},"-ThrottleLimit",[101,161,162],{},"Int",[101,164,114],{},[101,166,167,168,171,172,175],{},"Maximum number of concurrent remote connections. Defaults to ",[15,169,170],{},"32",", the same default ",[15,173,174],{},"Invoke-Command"," uses.",[32,177,179],{"id":178},"usage","Usage",[11,181,182],{},"Inventory a short list of computers directly:",[184,185,190],"pre",{"className":186,"code":187,"language":188,"meta":189,"style":189},"language-powershell shiki shiki-themes github-dark",".\\Get-SoftwareInventory.ps1 -ComputerName SRV-APP01, SRV-APP02, SRV-SQL01\n","powershell","",[15,191,192],{"__ignoreMap":189},[110,193,196,199,203,207,210,213,216,219,222,224,227,229,231,233],{"class":194,"line":195},"line",1,[110,197,152],{"class":198},"s95oV",[110,200,202],{"class":201},"sDLfK","\\Get-SoftwareInventory.ps1",[110,204,206],{"class":205},"snl16"," -",[110,208,209],{"class":198},"ComputerName SRV",[110,211,212],{"class":205},"-",[110,214,215],{"class":198},"APP01",[110,217,218],{"class":205},",",[110,220,221],{"class":198}," SRV",[110,223,212],{"class":205},[110,225,226],{"class":198},"APP02",[110,228,218],{"class":205},[110,230,221],{"class":198},[110,232,212],{"class":205},[110,234,235],{"class":198},"SQL01\n",[11,237,238],{},"Inventory every computer name in a text file and write the results somewhere specific:",[184,240,242],{"className":186,"code":241,"language":188,"meta":189,"style":189},".\\Get-SoftwareInventory.ps1 -ComputerListPath C:\\Lists\\workstations.txt -OutputPath C:\\Reports\\software-inventory.csv\n",[15,243,244],{"__ignoreMap":189},[110,245,246,248,250,252,255,257,260,262],{"class":194,"line":195},[110,247,152],{"class":198},[110,249,202],{"class":201},[110,251,206],{"class":205},[110,253,254],{"class":198},"ComputerListPath C:\\Lists\\workstations.txt ",[110,256,212],{"class":205},[110,258,259],{"class":198},"OutputPath C:\\Reports\\software",[110,261,212],{"class":205},[110,263,264],{"class":198},"inventory.csv\n",[11,266,267],{},"Pull enabled computer accounts from Active Directory and feed them in directly:",[184,269,271],{"className":186,"code":270,"language":188,"meta":189,"style":189},"$computers = Get-ADComputer -Filter 'Enabled -eq $true' | Select-Object -ExpandProperty Name\n.\\Get-SoftwareInventory.ps1 -ComputerName $computers -ThrottleLimit 64\n",[15,272,273,304],{"__ignoreMap":189},[110,274,275,278,281,284,286,289,293,296,299,301],{"class":194,"line":195},[110,276,277],{"class":198},"$computers ",[110,279,280],{"class":205},"=",[110,282,283],{"class":201}," Get-ADComputer",[110,285,206],{"class":205},[110,287,288],{"class":198},"Filter ",[110,290,292],{"class":291},"sU2Wk","'Enabled -eq $true'",[110,294,295],{"class":205}," |",[110,297,298],{"class":201}," Select-Object",[110,300,206],{"class":205},[110,302,303],{"class":198},"ExpandProperty Name\n",[110,305,307,309,311,313,316,318,321],{"class":194,"line":306},2,[110,308,152],{"class":198},[110,310,202],{"class":201},[110,312,206],{"class":205},[110,314,315],{"class":198},"ComputerName $computers ",[110,317,212],{"class":205},[110,319,320],{"class":198},"ThrottleLimit ",[110,322,323],{"class":201},"64\n",[11,325,326],{},"Sample console output:",[184,328,333],{"className":329,"code":331,"language":332,"meta":189},[330],"language-text","Querying 3 computer(s) with a throttle limit of 32 ...\nCompleted SRV-APP01 (231 entries)\nCompleted SRV-APP02 (187 entries)\nWARNING: Failed SRV-SQL01: Connecting to remote server SRV-SQL01 failed with the following error message : WinRM cannot process the request...\nInventory written to .\\software-inventory.csv (418 rows from 2 of 3 computers)\nWARNING: Unreachable or failed computers: SRV-SQL01\n","text",[15,334,331],{"__ignoreMap":189},[11,336,337],{},"Answer the common questions from the CSV afterwards, for example every machine with a Java runtime and its version:",[184,339,341],{"className":186,"code":340,"language":188,"meta":189,"style":189},"Import-Csv -Path .\\software-inventory.csv |\n    Where-Object { $_.DisplayName -like \"*Java*\" } |\n    Sort-Object -Property ComputerName |\n    Format-Table ComputerName, DisplayName, DisplayVersion, Scope -AutoSize\n",[15,342,343,361,386,399],{"__ignoreMap":189},[110,344,345,348,350,353,355,358],{"class":194,"line":195},[110,346,347],{"class":201},"Import-Csv",[110,349,206],{"class":205},[110,351,352],{"class":198},"Path .\\software",[110,354,212],{"class":205},[110,356,357],{"class":198},"inventory.csv ",[110,359,360],{"class":205},"|\n",[110,362,363,366,369,372,375,378,381,384],{"class":194,"line":306},[110,364,365],{"class":201},"    Where-Object",[110,367,368],{"class":198}," { ",[110,370,371],{"class":201},"$_",[110,373,374],{"class":198},".DisplayName ",[110,376,377],{"class":205},"-like",[110,379,380],{"class":291}," \"*Java*\"",[110,382,383],{"class":198}," } ",[110,385,360],{"class":205},[110,387,389,392,394,397],{"class":194,"line":388},3,[110,390,391],{"class":201},"    Sort-Object",[110,393,206],{"class":205},[110,395,396],{"class":198},"Property ComputerName ",[110,398,360],{"class":205},[110,400,402,405,408,410,413,415,418,420,423,425],{"class":194,"line":401},4,[110,403,404],{"class":201},"    Format-Table",[110,406,407],{"class":198}," ComputerName",[110,409,218],{"class":205},[110,411,412],{"class":198}," DisplayName",[110,414,218],{"class":205},[110,416,417],{"class":198}," DisplayVersion",[110,419,218],{"class":205},[110,421,422],{"class":198}," Scope ",[110,424,212],{"class":205},[110,426,427],{"class":198},"AutoSize\n",[32,429,431],{"id":430},"script","Script",[184,433,435],{"className":186,"code":434,"language":188,"meta":189,"style":189},"\u003C#\n.SYNOPSIS\n    Remotely enumerates installed software from the registry across a list of\n    Windows computers and consolidates the results into one CSV.\n.DESCRIPTION\n    Reads the 64-bit and 32-bit (WOW6432Node) Uninstall keys under HKLM, plus the\n    Uninstall key of every user hive currently loaded under HKEY_USERS, on each target\n    over PowerShell remoting. One Invoke-Command call fans out to all computers; each\n    computer runs as a child job, so failures are reported per computer. Never queries\n    Win32_Product.\n.PARAMETER ComputerName\n    One or more computer names to inventory.\n.PARAMETER ComputerListPath\n    Path to a text file with one computer name per line, used when -ComputerName\n    is not supplied.\n.PARAMETER OutputPath\n    Path to the consolidated CSV. Defaults to .\\software-inventory.csv.\n.PARAMETER ThrottleLimit\n    Maximum number of concurrent remote connections. Defaults to 32.\n.EXAMPLE\n    .\\Get-SoftwareInventory.ps1 -ComputerListPath C:\\Lists\\workstations.txt\n.NOTES\n    Author  : Thomas Lasswell (https:\u002F\u002Fwww.techcolumnist.com)\n    Version : 1.0 (2025-08-27)\n    Requires: PowerShell remoting (WinRM) on every target; Administrators or\n              Remote Management Users membership on each target\n#>\n[CmdletBinding()]\nparam(\n    [string[]]$ComputerName,\n\n    [string]$ComputerListPath,\n\n    [string]$OutputPath = \".\\software-inventory.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)\nif ($ComputerName.Count -eq 0) {\n    throw \"No computer names to query. Check -ComputerName or the contents of -ComputerListPath.\"\n}\nWrite-Host \"Querying $($ComputerName.Count) computer(s) with a throttle limit of $ThrottleLimit ...\"\n\n# The script block that runs on each remote computer.\n$inventoryScript = {\n    $sources = @(\n        @{ Scope = \"Machine64\"; Path = \"HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\" },\n        @{ Scope = \"Machine32\"; Path = \"HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\" },\n        @{ Scope = \"User\"; Path = \"Registry::HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\" }\n    )\n\n    foreach ($source in $sources) {\n        Get-ItemProperty -Path $source.Path -ErrorAction SilentlyContinue |\n            Where-Object { $_.DisplayName } |\n            ForEach-Object {\n                [pscustomobject]@{\n                    ComputerName    = $env:COMPUTERNAME\n                    Scope           = $source.Scope\n                    DisplayName     = $_.DisplayName\n                    DisplayVersion  = $_.DisplayVersion\n                    Publisher       = $_.Publisher\n                    InstallDate     = $_.InstallDate\n                    SystemComponent = $_.SystemComponent\n                    KeyName         = $_.PSChildName\n                }\n            }\n    }\n}\n\n$parentJob = Invoke-Command -ComputerName $ComputerName -ScriptBlock $inventoryScript -AsJob -ThrottleLimit $ThrottleLimit\n$parentJob | Wait-Job | Out-Null\n\n$results = New-Object System.Collections.Generic.List[object]\n$failures = New-Object System.Collections.Generic.List[string]\n\n# One child job per computer: read each separately so one failure doesn't hide the rest.\nforeach ($child in $parentJob.ChildJobs) {\n    $target = $child.Location\n\n    if ($child.State -eq \"Failed\") {\n        $reason = $child.JobStateInfo.Reason.Message\n        $failures.Add($target)\n        Write-Warning \"Failed $target`: $reason\"\n        continue\n    }\n\n    $rows = @(Receive-Job -Job $child -ErrorAction SilentlyContinue |\n        Select-Object -Property ComputerName, Scope, DisplayName, DisplayVersion, Publisher, InstallDate, SystemComponent, KeyName)\n    $results.AddRange([object[]]$rows)\n    Write-Host \"Completed $target ($($rows.Count) entries)\"\n}\n\nRemove-Job -Job $parentJob -Force\n\n$results | Export-Csv -Path $OutputPath -NoTypeInformation\n\n$succeeded = $ComputerName.Count - $failures.Count\nWrite-Host \"Inventory written to $OutputPath ($($results.Count) rows from $succeeded of $($ComputerName.Count) computers)\"\n\nif ($failures.Count -gt 0) {\n    Write-Warning \"Unreachable or failed computers: $($failures -join ', ')\"\n}\n",[15,436,437,443,450,455,460,468,474,480,486,492,498,509,515,525,531,537,547,553,563,569,577,583,591,597,603,609,615,621,633,642,657,664,676,681,698,703,719,725,730,745,774,783,789,794,843,849,854,878,895,904,909,939,944,950,961,973,1000,1023,1045,1051,1056,1071,1089,1104,1112,1130,1147,1158,1172,1185,1198,1211,1224,1237,1243,1249,1254,1259,1264,1295,1310,1315,1335,1351,1356,1362,1376,1387,1392,1407,1418,1424,1445,1451,1456,1461,1487,1531,1542,1567,1572,1577,1593,1598,1618,1623,1639,1681,1686,1701,1727],{"__ignoreMap":189},[110,438,439],{"class":194,"line":195},[110,440,442],{"class":441},"sAwPA","\u003C#\n",[110,444,445,447],{"class":194,"line":306},[110,446,152],{"class":201},[110,448,449],{"class":205},"SYNOPSIS\n",[110,451,452],{"class":194,"line":388},[110,453,454],{"class":441},"    Remotely enumerates installed software from the registry across a list of\n",[110,456,457],{"class":194,"line":401},[110,458,459],{"class":441},"    Windows computers and consolidates the results into one CSV.\n",[110,461,463,465],{"class":194,"line":462},5,[110,464,152],{"class":201},[110,466,467],{"class":205},"DESCRIPTION\n",[110,469,471],{"class":194,"line":470},6,[110,472,473],{"class":441},"    Reads the 64-bit and 32-bit (WOW6432Node) Uninstall keys under HKLM, plus the\n",[110,475,477],{"class":194,"line":476},7,[110,478,479],{"class":441},"    Uninstall key of every user hive currently loaded under HKEY_USERS, on each target\n",[110,481,483],{"class":194,"line":482},8,[110,484,485],{"class":441},"    over PowerShell remoting. One Invoke-Command call fans out to all computers; each\n",[110,487,489],{"class":194,"line":488},9,[110,490,491],{"class":441},"    computer runs as a child job, so failures are reported per computer. Never queries\n",[110,493,495],{"class":194,"line":494},10,[110,496,497],{"class":441},"    Win32_Product.\n",[110,499,501,503,506],{"class":194,"line":500},11,[110,502,152],{"class":201},[110,504,505],{"class":205},"PARAMETER",[110,507,508],{"class":205}," ComputerName\n",[110,510,512],{"class":194,"line":511},12,[110,513,514],{"class":441},"    One or more computer names to inventory.\n",[110,516,518,520,522],{"class":194,"line":517},13,[110,519,152],{"class":201},[110,521,505],{"class":205},[110,523,524],{"class":205}," ComputerListPath\n",[110,526,528],{"class":194,"line":527},14,[110,529,530],{"class":441},"    Path to a text file with one computer name per line, used when -ComputerName\n",[110,532,534],{"class":194,"line":533},15,[110,535,536],{"class":441},"    is not supplied.\n",[110,538,540,542,544],{"class":194,"line":539},16,[110,541,152],{"class":201},[110,543,505],{"class":205},[110,545,546],{"class":205}," OutputPath\n",[110,548,550],{"class":194,"line":549},17,[110,551,552],{"class":441},"    Path to the consolidated CSV. Defaults to .\\software-inventory.csv.\n",[110,554,556,558,560],{"class":194,"line":555},18,[110,557,152],{"class":201},[110,559,505],{"class":205},[110,561,562],{"class":205}," ThrottleLimit\n",[110,564,566],{"class":194,"line":565},19,[110,567,568],{"class":441},"    Maximum number of concurrent remote connections. Defaults to 32.\n",[110,570,572,574],{"class":194,"line":571},20,[110,573,152],{"class":201},[110,575,576],{"class":205},"EXAMPLE\n",[110,578,580],{"class":194,"line":579},21,[110,581,582],{"class":441},"    .\\Get-SoftwareInventory.ps1 -ComputerListPath C:\\Lists\\workstations.txt\n",[110,584,586,588],{"class":194,"line":585},22,[110,587,152],{"class":201},[110,589,590],{"class":205},"NOTES\n",[110,592,594],{"class":194,"line":593},23,[110,595,596],{"class":441},"    Author  : Thomas Lasswell (https:\u002F\u002Fwww.techcolumnist.com)\n",[110,598,600],{"class":194,"line":599},24,[110,601,602],{"class":441},"    Version : 1.0 (2025-08-27)\n",[110,604,606],{"class":194,"line":605},25,[110,607,608],{"class":441},"    Requires: PowerShell remoting (WinRM) on every target; Administrators or\n",[110,610,612],{"class":194,"line":611},26,[110,613,614],{"class":441},"              Remote Management Users membership on each target\n",[110,616,618],{"class":194,"line":617},27,[110,619,620],{"class":441},"#>\n",[110,622,624,627,630],{"class":194,"line":623},28,[110,625,626],{"class":198},"[",[110,628,629],{"class":201},"CmdletBinding",[110,631,632],{"class":198},"()]\n",[110,634,636,639],{"class":194,"line":635},29,[110,637,638],{"class":205},"param",[110,640,641],{"class":198},"(\n",[110,643,645,648,651,654],{"class":194,"line":644},30,[110,646,647],{"class":198},"    [",[110,649,650],{"class":205},"string",[110,652,653],{"class":198},"[]]$ComputerName",[110,655,656],{"class":205},",\n",[110,658,660],{"class":194,"line":659},31,[110,661,663],{"emptyLinePlaceholder":662},true,"\n",[110,665,667,669,671,674],{"class":194,"line":666},32,[110,668,647],{"class":198},[110,670,650],{"class":205},[110,672,673],{"class":198},"]$ComputerListPath",[110,675,656],{"class":205},[110,677,679],{"class":194,"line":678},33,[110,680,663],{"emptyLinePlaceholder":662},[110,682,684,686,688,691,693,696],{"class":194,"line":683},34,[110,685,647],{"class":198},[110,687,650],{"class":205},[110,689,690],{"class":198},"]$OutputPath ",[110,692,280],{"class":205},[110,694,695],{"class":291}," \".\\software-inventory.csv\"",[110,697,656],{"class":205},[110,699,701],{"class":194,"line":700},35,[110,702,663],{"emptyLinePlaceholder":662},[110,704,706,708,711,714,716],{"class":194,"line":705},36,[110,707,647],{"class":198},[110,709,710],{"class":205},"int",[110,712,713],{"class":198},"]$ThrottleLimit ",[110,715,280],{"class":205},[110,717,718],{"class":201}," 32\n",[110,720,722],{"class":194,"line":721},37,[110,723,724],{"class":198},")\n",[110,726,728],{"class":194,"line":727},38,[110,729,663],{"emptyLinePlaceholder":662},[110,731,733,736,739,742],{"class":194,"line":732},39,[110,734,735],{"class":205},"if",[110,737,738],{"class":198}," (",[110,740,741],{"class":205},"-not",[110,743,744],{"class":198}," $ComputerName) {\n",[110,746,748,751,753,755,758,761,764,766,769,771],{"class":194,"line":747},40,[110,749,750],{"class":205},"    if",[110,752,738],{"class":198},[110,754,741],{"class":205},[110,756,757],{"class":198}," $ComputerListPath ",[110,759,760],{"class":205},"-or",[110,762,763],{"class":205}," -not",[110,765,738],{"class":198},[110,767,768],{"class":201},"Test-Path",[110,770,206],{"class":205},[110,772,773],{"class":198},"Path $ComputerListPath)) {\n",[110,775,777,780],{"class":194,"line":776},41,[110,778,779],{"class":205},"        throw",[110,781,782],{"class":291}," \"Supply -ComputerName or a valid -ComputerListPath.\"\n",[110,784,786],{"class":194,"line":785},42,[110,787,788],{"class":198},"    }\n",[110,790,792],{"class":194,"line":791},43,[110,793,663],{"emptyLinePlaceholder":662},[110,795,797,800,802,805,807,810,813,816,818,820,823,826,829,831,833,836,838,840],{"class":194,"line":796},44,[110,798,799],{"class":198},"    $ComputerName ",[110,801,280],{"class":205},[110,803,804],{"class":201}," Get-Content",[110,806,206],{"class":205},[110,808,809],{"class":198},"Path $ComputerListPath ",[110,811,812],{"class":205},"|",[110,814,815],{"class":201}," Where-Object",[110,817,368],{"class":198},[110,819,371],{"class":201},[110,821,822],{"class":198},".Trim() ",[110,824,825],{"class":205},"-ne",[110,827,828],{"class":291}," \"\"",[110,830,383],{"class":198},[110,832,812],{"class":205},[110,834,835],{"class":201}," ForEach-Object",[110,837,368],{"class":198},[110,839,371],{"class":201},[110,841,842],{"class":198},".Trim() }\n",[110,844,846],{"class":194,"line":845},45,[110,847,848],{"class":198},"}\n",[110,850,852],{"class":194,"line":851},46,[110,853,663],{"emptyLinePlaceholder":662},[110,855,857,860,862,865,868,870,873,875],{"class":194,"line":856},47,[110,858,859],{"class":198},"$ComputerName ",[110,861,280],{"class":205},[110,863,864],{"class":205}," @",[110,866,867],{"class":198},"($ComputerName ",[110,869,812],{"class":205},[110,871,872],{"class":201}," Sort-Object",[110,874,206],{"class":205},[110,876,877],{"class":198},"Unique)\n",[110,879,881,883,886,889,892],{"class":194,"line":880},48,[110,882,735],{"class":205},[110,884,885],{"class":198}," ($ComputerName.Count ",[110,887,888],{"class":205},"-eq",[110,890,891],{"class":201}," 0",[110,893,894],{"class":198},") {\n",[110,896,898,901],{"class":194,"line":897},49,[110,899,900],{"class":205},"    throw",[110,902,903],{"class":291}," \"No computer names to query. Check -ComputerName or the contents of -ComputerListPath.\"\n",[110,905,907],{"class":194,"line":906},50,[110,908,848],{"class":198},[110,910,912,915,918,921,924,927,930,933,936],{"class":194,"line":911},51,[110,913,914],{"class":201},"Write-Host",[110,916,917],{"class":291}," \"Querying ",[110,919,920],{"class":205},"$",[110,922,923],{"class":291},"(",[110,925,926],{"class":198},"$ComputerName.Count",[110,928,929],{"class":291},")",[110,931,932],{"class":291}," computer(s) with a throttle limit of ",[110,934,935],{"class":198},"$ThrottleLimit",[110,937,938],{"class":291}," ...\"\n",[110,940,942],{"class":194,"line":941},52,[110,943,663],{"emptyLinePlaceholder":662},[110,945,947],{"class":194,"line":946},53,[110,948,949],{"class":441},"# The script block that runs on each remote computer.\n",[110,951,953,956,958],{"class":194,"line":952},54,[110,954,955],{"class":198},"$inventoryScript ",[110,957,280],{"class":205},[110,959,960],{"class":198}," {\n",[110,962,964,967,969,971],{"class":194,"line":963},55,[110,965,966],{"class":198},"    $sources ",[110,968,280],{"class":205},[110,970,864],{"class":205},[110,972,641],{"class":198},[110,974,976,979,982,984,987,990,992,995,998],{"class":194,"line":975},56,[110,977,978],{"class":205},"        @",[110,980,981],{"class":198},"{ Scope ",[110,983,280],{"class":205},[110,985,986],{"class":291}," \"Machine64\"",[110,988,989],{"class":198},"; Path ",[110,991,280],{"class":205},[110,993,994],{"class":291}," \"HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\"",[110,996,997],{"class":198}," }",[110,999,656],{"class":205},[110,1001,1003,1005,1007,1009,1012,1014,1016,1019,1021],{"class":194,"line":1002},57,[110,1004,978],{"class":205},[110,1006,981],{"class":198},[110,1008,280],{"class":205},[110,1010,1011],{"class":291}," \"Machine32\"",[110,1013,989],{"class":198},[110,1015,280],{"class":205},[110,1017,1018],{"class":291}," \"HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\"",[110,1020,997],{"class":198},[110,1022,656],{"class":205},[110,1024,1026,1028,1030,1032,1035,1037,1039,1042],{"class":194,"line":1025},58,[110,1027,978],{"class":205},[110,1029,981],{"class":198},[110,1031,280],{"class":205},[110,1033,1034],{"class":291}," \"User\"",[110,1036,989],{"class":198},[110,1038,280],{"class":205},[110,1040,1041],{"class":291}," \"Registry::HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\"",[110,1043,1044],{"class":198}," }\n",[110,1046,1048],{"class":194,"line":1047},59,[110,1049,1050],{"class":198},"    )\n",[110,1052,1054],{"class":194,"line":1053},60,[110,1055,663],{"emptyLinePlaceholder":662},[110,1057,1059,1062,1065,1068],{"class":194,"line":1058},61,[110,1060,1061],{"class":205},"    foreach",[110,1063,1064],{"class":198}," ($source ",[110,1066,1067],{"class":205},"in",[110,1069,1070],{"class":198}," $sources) {\n",[110,1072,1074,1077,1079,1082,1084,1087],{"class":194,"line":1073},62,[110,1075,1076],{"class":201},"        Get-ItemProperty",[110,1078,206],{"class":205},[110,1080,1081],{"class":198},"Path $source.Path ",[110,1083,212],{"class":205},[110,1085,1086],{"class":198},"ErrorAction SilentlyContinue ",[110,1088,360],{"class":205},[110,1090,1092,1095,1097,1099,1102],{"class":194,"line":1091},63,[110,1093,1094],{"class":201},"            Where-Object",[110,1096,368],{"class":198},[110,1098,371],{"class":201},[110,1100,1101],{"class":198},".DisplayName } ",[110,1103,360],{"class":205},[110,1105,1107,1110],{"class":194,"line":1106},64,[110,1108,1109],{"class":201},"            ForEach-Object",[110,1111,960],{"class":198},[110,1113,1115,1118,1121,1124,1127],{"class":194,"line":1114},65,[110,1116,1117],{"class":198},"                [",[110,1119,1120],{"class":205},"pscustomobject",[110,1122,1123],{"class":198},"]",[110,1125,1126],{"class":205},"@",[110,1128,1129],{"class":198},"{\n",[110,1131,1133,1136,1138,1141,1144],{"class":194,"line":1132},66,[110,1134,1135],{"class":198},"                    ComputerName    ",[110,1137,280],{"class":205},[110,1139,1140],{"class":198}," $",[110,1142,1143],{"class":201},"env:",[110,1145,1146],{"class":198},"COMPUTERNAME\n",[110,1148,1150,1153,1155],{"class":194,"line":1149},67,[110,1151,1152],{"class":198},"                    Scope           ",[110,1154,280],{"class":205},[110,1156,1157],{"class":198}," $source.Scope\n",[110,1159,1161,1164,1166,1169],{"class":194,"line":1160},68,[110,1162,1163],{"class":198},"                    DisplayName     ",[110,1165,280],{"class":205},[110,1167,1168],{"class":201}," $_",[110,1170,1171],{"class":198},".DisplayName\n",[110,1173,1175,1178,1180,1182],{"class":194,"line":1174},69,[110,1176,1177],{"class":198},"                    DisplayVersion  ",[110,1179,280],{"class":205},[110,1181,1168],{"class":201},[110,1183,1184],{"class":198},".DisplayVersion\n",[110,1186,1188,1191,1193,1195],{"class":194,"line":1187},70,[110,1189,1190],{"class":198},"                    Publisher       ",[110,1192,280],{"class":205},[110,1194,1168],{"class":201},[110,1196,1197],{"class":198},".Publisher\n",[110,1199,1201,1204,1206,1208],{"class":194,"line":1200},71,[110,1202,1203],{"class":198},"                    InstallDate     ",[110,1205,280],{"class":205},[110,1207,1168],{"class":201},[110,1209,1210],{"class":198},".InstallDate\n",[110,1212,1214,1217,1219,1221],{"class":194,"line":1213},72,[110,1215,1216],{"class":198},"                    SystemComponent ",[110,1218,280],{"class":205},[110,1220,1168],{"class":201},[110,1222,1223],{"class":198},".SystemComponent\n",[110,1225,1227,1230,1232,1234],{"class":194,"line":1226},73,[110,1228,1229],{"class":198},"                    KeyName         ",[110,1231,280],{"class":205},[110,1233,1168],{"class":201},[110,1235,1236],{"class":198},".PSChildName\n",[110,1238,1240],{"class":194,"line":1239},74,[110,1241,1242],{"class":198},"                }\n",[110,1244,1246],{"class":194,"line":1245},75,[110,1247,1248],{"class":198},"            }\n",[110,1250,1252],{"class":194,"line":1251},76,[110,1253,788],{"class":198},[110,1255,1257],{"class":194,"line":1256},77,[110,1258,848],{"class":198},[110,1260,1262],{"class":194,"line":1261},78,[110,1263,663],{"emptyLinePlaceholder":662},[110,1265,1267,1270,1272,1275,1277,1280,1282,1285,1287,1290,1292],{"class":194,"line":1266},79,[110,1268,1269],{"class":198},"$parentJob ",[110,1271,280],{"class":205},[110,1273,1274],{"class":201}," Invoke-Command",[110,1276,206],{"class":205},[110,1278,1279],{"class":198},"ComputerName $ComputerName ",[110,1281,212],{"class":205},[110,1283,1284],{"class":198},"ScriptBlock $inventoryScript ",[110,1286,212],{"class":205},[110,1288,1289],{"class":198},"AsJob ",[110,1291,212],{"class":205},[110,1293,1294],{"class":198},"ThrottleLimit $ThrottleLimit\n",[110,1296,1298,1300,1302,1305,1307],{"class":194,"line":1297},80,[110,1299,1269],{"class":198},[110,1301,812],{"class":205},[110,1303,1304],{"class":201}," Wait-Job",[110,1306,295],{"class":205},[110,1308,1309],{"class":201}," Out-Null\n",[110,1311,1313],{"class":194,"line":1312},81,[110,1314,663],{"emptyLinePlaceholder":662},[110,1316,1318,1321,1323,1326,1329,1332],{"class":194,"line":1317},82,[110,1319,1320],{"class":198},"$results ",[110,1322,280],{"class":205},[110,1324,1325],{"class":201}," New-Object",[110,1327,1328],{"class":198}," System.Collections.Generic.List[",[110,1330,1331],{"class":205},"object",[110,1333,1334],{"class":198},"]\n",[110,1336,1338,1341,1343,1345,1347,1349],{"class":194,"line":1337},83,[110,1339,1340],{"class":198},"$failures ",[110,1342,280],{"class":205},[110,1344,1325],{"class":201},[110,1346,1328],{"class":198},[110,1348,650],{"class":205},[110,1350,1334],{"class":198},[110,1352,1354],{"class":194,"line":1353},84,[110,1355,663],{"emptyLinePlaceholder":662},[110,1357,1359],{"class":194,"line":1358},85,[110,1360,1361],{"class":441},"# One child job per computer: read each separately so one failure doesn't hide the rest.\n",[110,1363,1365,1368,1371,1373],{"class":194,"line":1364},86,[110,1366,1367],{"class":205},"foreach",[110,1369,1370],{"class":198}," ($child ",[110,1372,1067],{"class":205},[110,1374,1375],{"class":198}," $parentJob.ChildJobs) {\n",[110,1377,1379,1382,1384],{"class":194,"line":1378},87,[110,1380,1381],{"class":198},"    $target ",[110,1383,280],{"class":205},[110,1385,1386],{"class":198}," $child.Location\n",[110,1388,1390],{"class":194,"line":1389},88,[110,1391,663],{"emptyLinePlaceholder":662},[110,1393,1395,1397,1400,1402,1405],{"class":194,"line":1394},89,[110,1396,750],{"class":205},[110,1398,1399],{"class":198}," ($child.State ",[110,1401,888],{"class":205},[110,1403,1404],{"class":291}," \"Failed\"",[110,1406,894],{"class":198},[110,1408,1410,1413,1415],{"class":194,"line":1409},90,[110,1411,1412],{"class":198},"        $reason ",[110,1414,280],{"class":205},[110,1416,1417],{"class":198}," $child.JobStateInfo.Reason.Message\n",[110,1419,1421],{"class":194,"line":1420},91,[110,1422,1423],{"class":198},"        $failures.Add($target)\n",[110,1425,1427,1430,1433,1436,1439,1442],{"class":194,"line":1426},92,[110,1428,1429],{"class":201},"        Write-Warning",[110,1431,1432],{"class":291}," \"Failed ",[110,1434,1435],{"class":198},"$target",[110,1437,1438],{"class":291},"`: ",[110,1440,1441],{"class":198},"$reason",[110,1443,1444],{"class":291},"\"\n",[110,1446,1448],{"class":194,"line":1447},93,[110,1449,1450],{"class":205},"        continue\n",[110,1452,1454],{"class":194,"line":1453},94,[110,1455,788],{"class":198},[110,1457,1459],{"class":194,"line":1458},95,[110,1460,663],{"emptyLinePlaceholder":662},[110,1462,1464,1467,1469,1471,1473,1476,1478,1481,1483,1485],{"class":194,"line":1463},96,[110,1465,1466],{"class":198},"    $rows ",[110,1468,280],{"class":205},[110,1470,864],{"class":205},[110,1472,923],{"class":198},[110,1474,1475],{"class":201},"Receive-Job",[110,1477,206],{"class":205},[110,1479,1480],{"class":198},"Job $child ",[110,1482,212],{"class":205},[110,1484,1086],{"class":198},[110,1486,360],{"class":205},[110,1488,1490,1493,1495,1498,1500,1503,1505,1507,1509,1511,1513,1516,1518,1521,1523,1526,1528],{"class":194,"line":1489},97,[110,1491,1492],{"class":201},"        Select-Object",[110,1494,206],{"class":205},[110,1496,1497],{"class":198},"Property ComputerName",[110,1499,218],{"class":205},[110,1501,1502],{"class":198}," Scope",[110,1504,218],{"class":205},[110,1506,412],{"class":198},[110,1508,218],{"class":205},[110,1510,417],{"class":198},[110,1512,218],{"class":205},[110,1514,1515],{"class":198}," Publisher",[110,1517,218],{"class":205},[110,1519,1520],{"class":198}," InstallDate",[110,1522,218],{"class":205},[110,1524,1525],{"class":198}," SystemComponent",[110,1527,218],{"class":205},[110,1529,1530],{"class":198}," KeyName)\n",[110,1532,1534,1537,1539],{"class":194,"line":1533},98,[110,1535,1536],{"class":198},"    $results.AddRange([",[110,1538,1331],{"class":205},[110,1540,1541],{"class":198},"[]]$rows)\n",[110,1543,1545,1548,1551,1553,1555,1557,1559,1562,1564],{"class":194,"line":1544},99,[110,1546,1547],{"class":201},"    Write-Host",[110,1549,1550],{"class":291}," \"Completed ",[110,1552,1435],{"class":198},[110,1554,738],{"class":291},[110,1556,920],{"class":205},[110,1558,923],{"class":291},[110,1560,1561],{"class":198},"$rows.Count",[110,1563,929],{"class":291},[110,1565,1566],{"class":291}," entries)\"\n",[110,1568,1570],{"class":194,"line":1569},100,[110,1571,848],{"class":198},[110,1573,1575],{"class":194,"line":1574},101,[110,1576,663],{"emptyLinePlaceholder":662},[110,1578,1580,1583,1585,1588,1590],{"class":194,"line":1579},102,[110,1581,1582],{"class":201},"Remove-Job",[110,1584,206],{"class":205},[110,1586,1587],{"class":198},"Job $parentJob ",[110,1589,212],{"class":205},[110,1591,1592],{"class":198},"Force\n",[110,1594,1596],{"class":194,"line":1595},103,[110,1597,663],{"emptyLinePlaceholder":662},[110,1599,1601,1603,1605,1608,1610,1613,1615],{"class":194,"line":1600},104,[110,1602,1320],{"class":198},[110,1604,812],{"class":205},[110,1606,1607],{"class":201}," Export-Csv",[110,1609,206],{"class":205},[110,1611,1612],{"class":198},"Path $OutputPath ",[110,1614,212],{"class":205},[110,1616,1617],{"class":198},"NoTypeInformation\n",[110,1619,1621],{"class":194,"line":1620},105,[110,1622,663],{"emptyLinePlaceholder":662},[110,1624,1626,1629,1631,1634,1636],{"class":194,"line":1625},106,[110,1627,1628],{"class":198},"$succeeded ",[110,1630,280],{"class":205},[110,1632,1633],{"class":198}," $ComputerName.Count ",[110,1635,212],{"class":205},[110,1637,1638],{"class":198}," $failures.Count\n",[110,1640,1642,1644,1647,1650,1652,1654,1656,1659,1661,1664,1667,1670,1672,1674,1676,1678],{"class":194,"line":1641},107,[110,1643,914],{"class":201},[110,1645,1646],{"class":291}," \"Inventory written to ",[110,1648,1649],{"class":198},"$OutputPath",[110,1651,738],{"class":291},[110,1653,920],{"class":205},[110,1655,923],{"class":291},[110,1657,1658],{"class":198},"$results.Count",[110,1660,929],{"class":291},[110,1662,1663],{"class":291}," rows from ",[110,1665,1666],{"class":198},"$succeeded",[110,1668,1669],{"class":291}," of ",[110,1671,920],{"class":205},[110,1673,923],{"class":291},[110,1675,926],{"class":198},[110,1677,929],{"class":291},[110,1679,1680],{"class":291}," computers)\"\n",[110,1682,1684],{"class":194,"line":1683},108,[110,1685,663],{"emptyLinePlaceholder":662},[110,1687,1689,1691,1694,1697,1699],{"class":194,"line":1688},109,[110,1690,735],{"class":205},[110,1692,1693],{"class":198}," ($failures.Count ",[110,1695,1696],{"class":205},"-gt",[110,1698,891],{"class":201},[110,1700,894],{"class":198},[110,1702,1704,1707,1710,1712,1714,1717,1720,1723,1725],{"class":194,"line":1703},110,[110,1705,1706],{"class":201},"    Write-Warning",[110,1708,1709],{"class":291}," \"Unreachable or failed computers: ",[110,1711,920],{"class":205},[110,1713,923],{"class":291},[110,1715,1716],{"class":198},"$failures",[110,1718,1719],{"class":205}," -join",[110,1721,1722],{"class":291}," ', '",[110,1724,929],{"class":291},[110,1726,1444],{"class":291},[110,1728,1730],{"class":194,"line":1729},111,[110,1731,848],{"class":198},[32,1733,1735],{"id":1734},"notes","Notes",[37,1737,1738,1756,1767,1774,1780,1790,1803],{},[40,1739,1740,1741,1743,1744,1747,1748,1751,1752,1755],{},"Why not ",[15,1742,25],{},": per KB 974524 the query isn't optimized, enumerates every product through ",[15,1745,1746],{},"msiprov.dll",", and triggers a consistency check and repair of installed packages. Microsoft's suggested lighter alternatives are ",[15,1749,1750],{},"Win32reg_AddRemovePrograms"," (only present when the Configuration Manager client is installed) or the ",[15,1753,1754],{},"StdRegProv"," registry provider. Reading the registry over remoting, as here, is the same idea.",[40,1757,1758,1759,1762,1763,1766],{},"The ",[15,1760,1761],{},"User"," scope only sees hives that are loaded, which in practice means users currently signed in (plus service profiles). Per-user installers that write to ",[15,1764,1765],{},"HKCU"," for someone who isn't signed in won't show up. If that matters, run the collection as a sign-in or scheduled task rather than a sweep.",[40,1768,1769,1770,1773],{},"The registry approach misses software that doesn't write an Uninstall key: portable apps and MSIX\u002FStore packages. For packaged apps, run ",[15,1771,1772],{},"Get-AppxPackage -AllUsers"," in a second pass.",[40,1775,1776,1779],{},[15,1777,1778],{},"InstallDate"," is less useful than it looks. Microsoft's Windows Installer documentation defines it as \"the last time this product received service\", replaced each time a patch is applied or removed or the product is repaired. Many non-MSI installers don't set it at all. Treat it as a hint.",[40,1781,1782,1785,1786,1789],{},[15,1783,1784],{},"SystemComponent"," is exported rather than filtered. An installer sets it (via the MSI ",[15,1787,1788],{},"ARPSYSTEMCOMPONENT"," property) to hide the entry from Add or Remove Programs. Filter on it in the report if you want output that matches what users see; keep it if you're hunting for agents and runtimes.",[40,1791,1792,1793,1795,1796,1798,1799,1802],{},"The throttle applies to the single ",[15,1794,174],{}," call: at most ",[15,1797,159],{}," connections are open at once, and the rest queue. The earlier pattern of calling ",[15,1800,1801],{},"Invoke-Command -AsJob"," once per computer in a loop doesn't throttle anything, because each call only has one computer.",[40,1804,1805,1806,1811,1812,152],{},"This pairs with the ",[1807,1808,1810],"a",{"href":1809},"\u002F2025\u002F10\u002F08\u002Fpowershell-windows-discover-local-admins-across-every-workstation\u002F","local admin audit script",", and both feed the approach in ",[1807,1813,1815],{"href":1814},"\u002F2026\u002F09\u002F02\u002Fwindows-management-building-a-discovery-inventory-nobody-has-to-maintain-by-hand\u002F","A Discovery Inventory Nobody Maintains by Hand",[32,1817,1819],{"id":1818},"source","Source",[37,1821,1822,1830,1837,1844,1850,1857],{},[40,1823,1824],{},[1807,1825,1829],{"href":1826,"rel":1827},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Ftroubleshoot\u002Fwindows-server\u002Fadmin-development\u002Fwindows-installer-reconfigured-all-applications",[1828],"nofollow","Windows Installer reconfigured all applications (KB 974524)",[40,1831,1832],{},[1807,1833,1836],{"href":1834,"rel":1835},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fwindows\u002Fwin32\u002Fmsi\u002Funinstall-registry-key",[1828],"Windows Installer properties for the Uninstall registry key",[40,1838,1839],{},[1807,1840,1843],{"href":1841,"rel":1842},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fwindows\u002Fwin32\u002Fmsi\u002Farpsystemcomponent",[1828],"ARPSYSTEMCOMPONENT property",[40,1845,1846],{},[1807,1847,174],{"href":1848,"rel":1849},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Fmicrosoft.powershell.core\u002Finvoke-command",[1828],[40,1851,1852],{},[1807,1853,1856],{"href":1854,"rel":1855},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Fmicrosoft.powershell.core\u002Fabout\u002Fabout_remote_requirements",[1828],"about_Remote_Requirements",[40,1858,1859],{},[1807,1860,1863],{"href":1861,"rel":1862},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Factivedirectory\u002Fget-adcomputer",[1828],"Get-ADComputer",[1865,1866,1867],"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}",{"title":189,"searchDepth":306,"depth":306,"links":1869},[1870,1871,1872,1873,1874,1875],{"id":34,"depth":306,"text":35},{"id":71,"depth":306,"text":72},{"id":178,"depth":306,"text":179},{"id":430,"depth":306,"text":431},{"id":1734,"depth":306,"text":1735},{"id":1818,"depth":306,"text":1819},"techcolumnist",[1878,1879],"ps","scripts","2025-08-27T14:00:00Z","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.","md",false,null,{},"\u002Fblog\u002F2025\u002F08\u002F27\u002Fpowershell-windows-inventory-installed-software-across-a-domain",{"title":6,"description":1881},[1876],"blog\u002F2025\u002F08\u002F27\u002Fpowershell-windows-inventory-installed-software-across-a-domain",[188,1891,1892,1893],"windows","discovery","active-directory","\u002F2025\u002F08\u002F27\u002Fpowershell-windows-inventory-installed-software-across-a-domain\u002F","n_t-l31gMd2y06fk7txj1NbKMqtFLltfzdIu5Zn_NA0",{"title":1897,"description":1898,"date":1899,"url":1900,"categories":1901,"tags":1902,"image":1884,"readingTime":462,"canonical":1876,"sites":1905,"series":1884,"seriesOrder":1884},"PowerShell: Exchange Online – Report Mailboxes Approaching Their Quota","Flag Exchange Online mailboxes above a percentage of their ProhibitSendQuota, plus Recoverable Items pressure, using the EXO V3 Get-EXO cmdlets.","2025-09-03T14:00:00Z","\u002F2025\u002F09\u002F03\u002Fpowershell-exchange-online-report-mailboxes-approaching-their-quota\u002F",[1878,1879],[188,1903,1904],"exchange-online","reporting",[1876],{"title":1907,"description":1908,"date":1909,"url":1910,"categories":1911,"tags":1912,"image":1884,"readingTime":401,"canonical":1876,"sites":1914,"series":1884,"seriesOrder":1884},"PowerShell: ConnectWise – Sync Configurations from Discovery Scans","Reconcile a network discovery CSV against ConnectWise PSA configurations over the REST API: match by serial, MAC or name, patch what changed, create the rest.","2025-08-20T14:00:00Z","\u002F2025\u002F08\u002F20\u002Fpowershell-connectwise-sync-configuration-items-from-discovery-scans\u002F",[1878,1879],[188,1913,1892],"connectwise",[1876],[1916,1923,1931],{"title":1917,"description":1918,"date":1919,"url":1809,"categories":1920,"tags":1921,"image":1884,"readingTime":462,"canonical":1876,"sites":1922,"series":1884,"seriesOrder":1884},"PowerShell: Windows – Discover Local Admins Across Every Workstation","A script that reads the local Administrators group on every workstation by SID, survives orphaned-SID errors, and flags members outside an approved allowlist.","2025-10-08T14:00:00Z",[1878,1879],[188,1891,1892,1893],[1876],{"title":1924,"description":1925,"date":1926,"url":1927,"categories":1928,"tags":1929,"image":1884,"readingTime":401,"canonical":1876,"sites":1930,"series":1884,"seriesOrder":1884},"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",[1878,1879],[188,1893,1891],[1876],{"title":1932,"description":1933,"date":1934,"url":1935,"categories":1936,"tags":1937,"image":1884,"readingTime":462,"canonical":1876,"sites":1938,"series":1884,"seriesOrder":1884},"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",[1878,1879],[188,1893,1904],[1876],{"doc":1884,"posts":1940},[],1790052513165]