Is my powershell bit to get the current user's email out of AD TRWTF?



  • ⚠ Get-ADUser and other AD commandlets unavailable because raisins. ⚠

    ([adsi]"LDAP://CN=$((([adsi]"WinNT://$env:USERDOMAIN/$env:USERNAME,user").FullName).Replace(',','\,')),OU=Users,DC=contoso,DC=com").mail
    

    Translates to:

    ([adsi]"LDAP://CN=Doe\, John,OU=Users,DC=contoso,DC=com").mail

    Is this really that bad? I just whipped it up in about 5 seconds and it just seems wrong, but I don't know if it is.


  • FoxDev

    @rc4 said:

    ⚠ Get-ADUser and other AD commandlets unavailable because raisins. ⚠

    ... i'll get me cluebat.... cause somone needs a thwacking



  • As long as you have .NET 3.0 something like below should work. Haven't tested cause that sounds like work.

    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $email = [System.DirectoryServices.AccountManagement.UserPrincipal]::Current.EmailAddress
    


  • @rc4 said:

    ⚠ Get-ADUser and other AD commandlets unavailable because raisins. ⚠

    ([adsi]"LDAP://CN=$((([adsi]"WinNT://$env:USERDOMAIN/$env:USERNAME,user").FullName).Replace(',','\,')),OU=Users,DC=contoso,DC=com").mail
    

    Translates to:

    ([adsi]"LDAP://CN=Doe\, John,OU=Users,DC=contoso,DC=com").mail

    Is this really that bad? I just whipped it up in about 5 seconds and it just seems wrong, but I don't know if it is.

    No, there's nothing wrong with it. Your second code block is the equivalent of:

    New-Object -TypeName System.DirectoryServices.DirectoryEntry -ArgumentList "LDAP://CN=Doe\, John,OU=Users,DC=contoso,DC=com" | Select-Object -ExpandProperty mail;
    

    Which looks a lot more like normal PowerShell.

    The first code is pretty ugly because you're looking up the user first with the WinNT provider and then looking them up again with the LDAP provider, and you're assuming that the FullName (which is to say, AD attribute Display-Name and the LDAP attribute displayName) and the LDAP cn (AD attributed Common-Name) are identical as long as you escape the commas. That's just not true. It may work, but it's logically incorrect and will easily fail.


    @MathNerdCNU said:

    As long as you have .NET 3.0 something like below should work. Haven't tested cause that sounds like work.

    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $email = [System.DirectoryServices.AccountManagement.UserPrincipal]::Current.EmailAddress
    ```</blockquote>
    
    This works fine for me on PowerShell v4.0 (which is .Net 4.0).  It also worked for me under PowerShell v2.0 (which is .Net 2.0).  Yes, we still have an ancient server running 2003.


  • @BaconBits said:

    It may work, but it's logically incorrect and will easily fail.

    It works for almost everyone in our system, with the exception of the one or two people who have duplicate names.



  • I guess I could get it to work (✂ 🔴 :tape:) , but why bother when ADSI and LDAP work just fine?



  • @rc4 said:

    @BaconBits said:
    It may work, but it's logically incorrect and will easily fail.

    It works for almost everyone in our system, with the exception of the one or two people who have duplicate names.

    So what you're saying is that it's wrong.

    Try this:

    $LdapServer = 'fqdn.of.ldap.server.org';
    $rootDSE = [adsi]'LDAP://RootDSE';
    $AD = [adsi]('LDAP://{0}/{1}' -f $LdapServer, $rootDSE.DefaultNamingContext.ToString());
    $ADSearcher = [adsisearcher]$AD;
    
    $ADSearcher.PageSize = 5;
    $ADSearcher.CacheResults = $false;
    $ADSearcher.PropertiesToLoad.AddRange('mail');
    $ADSearcher.Filter = '(&(samaccountname={0})(objectCategory=person)(objectClass=user))' -f $env:USERNAME;
    
    $email = $ADSearcher.FindAll() | ForEach-Object { $_.Properties.Item('mail'); };
    $ADSearcher.Dispose();
    
    if ($email -eq $null) { Write-Error "Man, we ain't found shit.";}
    else {
        $email | ForEach-Object { Send-MailMessage -To $_ -From $_ -Bcc 'root@server.org' -Subject "Why you logging in to my servers?" -Body "Boy, you done fucked up now."  -SmtpServer your.mail.server.org; }
    }
    

    Yes, it's a lot more code, but it's actually doing what you want instead of using the wrong attributes and pounding that square peg into the round hole. If you don't want to use MathNerdCNU's method that's a hell of a lot more elegant, this is going to be the most accurate way to do what you're trying to.

    The variable $LdapServer should have the FQDN of the domain controller you prefer people connect to to run queries against. You can leave that portion of the LDAP string out if you don't care.

    You definitely want to be sure to call $ADSearcher.Dispose(). That class is horrible about memory leaks. If you don't ever enumerate the results, it actually sticks around in memory. I've accidentally left PowerShell sessions open like that overnight, and come in to a system that was locked up because of it.


Log in to reply