Search This Blog

Mar 14, 2025

Running AD cmdlets within foreach parallel script block



 Powershell's parallel foreach script block runs in its own runspace so anything defined outside of the block is not visible in it. A few steps to make AD cmdlets work:


  1. Import activedirectory module within the block. It may throw warning "Error initializing default drive", which can be safely ignored but you will have to
  2. Specify DC to establish connection via -server parameter in get-ad* cmdlets
    get-aduser -server "DC1.foobar.com" -.....
  3. The runspace won't have your credential from main session either so you have to transfer credential explicitly into script block

    $cred = get-credential
    $users | foreach -parallel {
          get-aduser -identity $_.samAccountName -credential $using:cred
    }
  4. If there are too many concurrent connections to AD, some connections may fail. Tweak to find the ThrottleLimit that works for you. 
  5. Use inputObject to return result
    $_ | add-member -notepropertyname "pn" -notepropertyValue "pv"
  6. Putting it altogether
    $cred = get-credential
    $users | foreach -parallel {
          import-module ActiveDictory
          $u=get-aduser -identity $_.samAccountName -credential $using:cred
          $_ | add-member -NotePropertyName "DN" -NotePropertyValue $u.distinguishedName
    } -ThrottleLimit 5

[UPDATE]

So limiting the number of threads is not ideal, with the number as long as 2, there is still chance where connection be refused by DC, not to mention we lost most of benefit if the number is too low.

One workaround is to make sure only one runspace connects to a particular DC at a time. This can be achieved by using a file as a lock. First get list of all DCs in a domain, then when a connection is made to a DC, obtain an exclusive handle to a file that represents the DC (e.g. "dc01.lock"). Once finish access the DC, release the lock file.

# Acquire lock before connecting to a DC
$server = $null
while ($null -eq $server){                   
  foreach ($DC in $using:dcs) {
    try {
          $lockFile = [system.io.file]::open("c:\temp\$($DC).lock",
                         'OpenOrCreate','ReadWrite','None')
          $server = $DC
          break
    }catch{                }
}
if($null -eq $server) {Start-Sleep -Milliseconds 50}
}
try {
    get-aduser -server $server ....

    # Release lock
    $lockFile.close()
    remove-item "c:\temp\$($server).lock" -force -erroraction silentlyContinue
   
}catch {}



There are other ways to implement a lock, such as described in Dave's blog, but above file lock works very well and is less complicated.

Jan 14, 2025

Why it's so easy to confuse between OAuth and OpenID Connect

 OAuth is an authorization protocol that wasn't designed for authentication. All it gets ( and cares) is an access token from resource server that gives it access to certain resources. Technically it doesn't know (and it doesn't need to know) the owner behind those resources. 

The reason that OAuth often seems to be an authentication protocol - and tons of applications do use it for authenticatino purpose - is that in all use cases of OAuth, the resource it was granted access to almost always contain something that can be used/seen/considered as an piece of ID, such as an email address. However, strictly speaking, just because the client (requestor) has obtained an email (or other ID-related info), it shouldn't assume it as a true identity.  

 For true authentiction, applications should use OpenID Connect, which is just an extension of OAuth. The extension provides an ID token instead of an access token.

Apr 29, 2024

What is "alias" type in whoami output?

 You probably noticed that besides "well-known group" and "group" in the output of whoami /all command, there is also another type called "alias". There was much result in googling to tell what this exactly is.

After much searching, find this document: SAM Remote Protocol - not that kind of doc you'd think of for the question we have above. Anyhow, even info in this doc is obscure: 

alias object: See resource group

then:

resource group: A group object whose membership is added to the authorization context only if the server receiving the context is a member of the same domain as the resource group.

Translation:

An alias is a domain local group from same domain as the resource server where it receives the context