UPN finden wenn nur der NetBIOS-Name angegeben ist

Die Frage ist eigentlich ganz einfach: Gegeben ein NetBIOS-Benutzername (d.h. im Format netBIOSdomain\samAccountName, also etwa “contoso\andresen”), wie kann der UPN gefunden werden. Viele Antworten sind dann in der Form “einfache String-Ersetzung” “contoso\andresen” –> “andresen@contoso.de”. Aber so einfach ist die Welt meistens nicht. (Als einfaches Beispiel könnte schon einmal sein, dass der UPN vielleicht eher “nils.andresen@contoso-weltweit.de” ist.)

Am “einfachsten” ist das vermutlich über TranslateNameA() aus der Secur32.dll gelöst. Oder?

Ich habe eine kleine Lösung geschrieben, die im Grunde mit reinen LDAP-Anfragen gegen das AD auskommt. Diese ist sowohl als PowerShell Cmdlet vorhanden:

<#
.SYNOPSIS
Find UPN for user from old netbios (i.e. domain\samAccountName) name
.PARAMETER Username
username in the netbios (i.e. domain\samAccountName) format
.EXAMPLE
Find-Upn -Username contoso\andresen
finds the user in AD and returns the UPN
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$Username
)
$ErrorActionPreference="Stop"
$parts = $Username.Split(@("\"), "None")
if($parts.Length -ne 2){
throw "Unable to parse '$($username)' into the domain\samAccountName-Syntax"
}
$netBiosDomain = $parts[0]
$samAccountName = $parts[1]
Write-Verbose "searching for netbios-domain:$($netBiosDomain)"
$rootDse = ([adsi]"LDAP://RootDSE")
if($null -eq $rootDse.dnsHostName) {
throw "no connection to AD."
}
$server = $rootDse.dnsHostName[0]
$rootDc = $rootDse.rootDomainNamingContext[0]
Write-Verbose "Root-DC is '$($rootDC)' at $($server)"
$connection = ([adsi]"LDAP://$($server)/CN=Partitions,CN=Configuration,$($rootDc)")
$searcher = ([adsisearcher]$connection)
$searcher.SearchScope = "Subtree"
$searcher.Filter = "netbiosname=$($netBiosDomain)"
$searcher.PropertiesToLoad.Add("ncname") | Out-Null
$domainDc = $searcher.FindOne().Properties.ncname[0]
Write-Verbose "Domain-DC is '$($domainDc)'"
$connection = ([adsi]"LDAP://$($server)/$($domainDc)")
$searcher = ([adsisearcher]$connection)
$searcher.PropertiesToLoad.Add("userprincipalname") | Out-Null
$searcher.SearchScope = "Subtree"
$searcher.Filter = "(&(objectClass=user)(samAccountName=$($samAccountName)))"
$user = $searcher.FindOne()
if($null -eq $user) {
throw "Could not find $($samAccountName) in AD-Subtree of '$($domainDc)'"
}
Write-Output $user.properties.userprincipalname[0]
view raw Find-Upn.ps1 hosted with ❤ by GitHub

Zusätzlich gibt es das auch in c#:

using System;
using System.DirectoryServices;
namespace FindUpn
{
internal class Program
{
private static void Main(string[] args)
{
var userName = "contoso\\andresen"; // should be dynamic, actually
string server;
string rootDc;
string domainDc = null;
// split userName in netbios-domain and samAccountName
var parts = userName.Split('\\');
var samAccountName = parts[1];
var netBiosDomain = parts[0];
// 1. first query AD for base-settings
// search RootDSE for some global properties
var connection = "LDAP://RootDSE";
Console.WriteLine("connection: " + connection);
using (var rootDse = new DirectoryEntry(connection)) // RootDSE is always available...
{
server = rootDse.Properties["dnsHostName"].Value as string;
rootDc = rootDse.Properties["rootDomainNamingContext"].Value as string;
Console.WriteLine(" - found server: " + server);
Console.WriteLine(" - found rootDc: " + rootDc);
}
// 2. query config for netbios-domain
// search rootDC-config for the corresponding DC of the netbios-domain
Console.WriteLine();
connection = string.Format("LDAP://{0}/CN=Partitions,CN=Configuration,{1}", server, rootDc);
Console.WriteLine("connection: " + connection);
using (var entry = new DirectoryEntry(connection))
using (var searcher = new DirectorySearcher(entry))
{
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("nCName");
searcher.Filter = string.Format("netBiosName={0}", netBiosDomain);
var cfgEntry = searcher.FindOne();
if (cfgEntry == null)
{
Console.WriteLine("Domain not found!"); // TODO: Handle...
}
else
{
domainDc = cfgEntry.Properties["nCName"][0] as string;
Console.WriteLine(" - found domainDc: " + domainDc);
}
}
// 2. now create the "real" query...
// search in domainDC for "user"-objects and samaccountname
Console.WriteLine();
connection = string.Format("LDAP://{0}/{1}", server, domainDc);
Console.WriteLine("connection: " + connection);
using (var entry = new DirectoryEntry(connection))
using (var searcher = new DirectorySearcher(entry))
{
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("userPrincipalName");
searcher.Filter = string.Format("(&(objectClass=user)(samAccountName={0}))", samAccountName);
var user = searcher.FindOne();
if (user == null)
{
Console.WriteLine("Nothing found"); // TODO: Handle...
}
else
{
var upn = user.Properties["userPrincipalName"][0] as string;
Console.WriteLine(" - UPN: " + upn);
}
}
#if DEBUG
Console.WriteLine("Done");
Console.ReadKey();
#endif
}
}
}
view raw FindUpn.cs hosted with ❤ by GitHub

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.