如何在VBA中通过活动目录用户名查找任意用户的全名或电子邮件地址?

huangapple go评论76阅读模式
英文:

How to look up an arbitrary user's Full Name OR Email address from their Active Directory username in VBA?

问题

以下是翻译好的部分:

我有一个活动目录(AD)用户名列表,从服务器日志中检索到,代表那些在使用不应该使用的软件的同事。

我需要从AD中查找他们的电子邮件地址或全名,如果电子邮件地址不可行或不可靠,以便联系这些用户。

我有一个工具,它从服务器日志中收集用户名列表,它是在Excel中使用VBA编写的。理想情况下,我需要一个能在VBA中工作的解决方案。

是否有办法传递一个任意的AD用户名,而不是当前用户,并从AD中返回FullName或电子邮件地址?

从原则上讲,这应该是可能的,因为使用win32net.NetUserGetInfo在Python中执行这个任务非常简单 - 因此底层API必须存在。

我也可以在CMD中实现我所需的功能,使用以下命令行:

net user %userid% /DOMAIN | find /I "Full name"

是否可以从VBA中调用上述命令行(而不会有很高的风险,因为这在以前在从VBA生成的隐藏CMD窗口中发生过,可能会被公司的杀毒软件阻止)?

英文:

I have a list of Active Directory (AD) usernames, retrieved from a server log, representing colleagues who are using software they shouldn't be.

I need to look up, from the AD, their email address or full name, if email address is not possible/reliable, to contact those users.

A tool I have, that gathers the list of usernames from the server logs, is in Excel, thus VBA. I ideally need a solution that works from VBA.

Is there any way to pass an arbitrary AD username, not the current user, and return either the FullName or email address from the AD?

This should be possible in principle, because it is trivial to do in Python using win32net.NetUserGetInfo - so the underlying API must be there.

I can achieve what I need in CMD as well, with the line:

net user %userid% /DOMAIN | find /I "Full name"

Is it possible to call the above line from within VBA (without high risk of corporate antivirus blocking it, because this has happened before when spawning hidden CMD shells from VBA)?

答案1

得分: 0

我用了一种相当不够优雅的方法解决了这个问题,所以我愿意接受更好的答案,但我是通过直接使用CMD.exe(从VBA使用Shell)调用“net user”,然后使用另一个SO答案来解析来自该Shell命令的输出的(https://stackoverflow.com/questions/2784367/capture-output-value-from-a-shell-command-in-vba)。

我的代码的重要部分位于主VBA表格中(为您提供“Me”的上下文):

' 请注意,d_offenders是一个AD用户名的字典(存储的值是他们打开的软件列表,所以与此解决方案无关)
Dim key As Variant
For Each key In d_offenders.Keys
    Me.Cells(start_row + i, output_col).Value2 = key
    Me.Cells(start_row + i, output_col + 1).Value2 = get_name(CStr(key))
    Me.Cells(start_row + i, output_col + 2).Value2 = d_offenders(key)
    i = i + 1
Next key

然后我使用以下两个函数来定义如何检索全名:

Private Function get_name(uname As String) As String
    Dim res As String
    res = ShellRun("cmd.exe /C net user " & uname & " /DOMAIN | find /I ""Full name""")
    If res > vbNullString Then get_name = Right(res, Len(res) - 29) Else get_name = "Not found."
End Function

Public Function ShellRun(sCmd As String) As String

    ' 运行一个shell命令,并将输出作为字符串返回

    Dim oShell As Object
    On Error GoTo errHandler
    Set oShell = CreateObject("WScript.Shell")

    ' 运行命令
    Dim oExec As Object
    Dim oOutput As Object
    Set oExec = oShell.Exec(sCmd)
    Set oOutput = oExec.StdOut

    ' 处理写入和从StdOut对象读取的结果
    Dim s As String
    Dim sLine As String
    While Not oOutput.AtEndOfStream
        sLine = oOutput.ReadLine
        If sLine <> vbNullString Then s = s & sLine & vbCrLf
    Wend

    ShellRun = s
    Exit Function
errHandler:
    ShellRun = vbNullString
End Function

正如我所说的,稍微有些笨拙,会有(临时的)CMD窗口弹出,但它能够工作,并且最终我得到了一个列表:

  • 用户名
  • 他们在AD中的全名
  • 他们打开的软件包。
英文:

I have solved this in a fairly inelegant way, so am open to better answers, but I have done it by a combination of calling "net user" directly using CMD.exe (from VBA using Shell) and then another SO answer for parsing the output from that Shell command from STDOUT (https://stackoverflow.com/questions/2784367/capture-output-value-from-a-shell-command-in-vba).

The important bits of my code are, in my main VBA sheet (gives you context for 'Me') code:

&#39; Note d_offenders is a dictionary of AD usernames (the value stored is a list of software they have open, so not relevant to this solution)
Dim key As Variant
For Each key In d_offenders.Keys
    Me.Cells(start_row + i, output_col).Value2 = key
    Me.Cells(start_row + i, output_col + 1).Value2 = get_name(CStr(key))
    Me.Cells(start_row + i, output_col + 2).Value2 = d_offenders(key)
    i = i + 1
Next key

Then I use the following two functions to define how the full name is retrieved:

Private Function get_name(uname As String) As String
    Dim res As String
    res = ShellRun(&quot;cmd.exe /C net user &quot; &amp; uname &amp; &quot; /DOMAIN | find /I &quot;&quot;Full name&quot;&quot;&quot;)
    If res &gt; vbNullString Then get_name = Right(res, Len(res) - 29) Else get_name = &quot;Not found.&quot;
End Function

Public Function ShellRun(sCmd As String) As String

    &#39;Run a shell command, returning the output as a string

    Dim oShell As Object
    On Error GoTo errHandler
    Set oShell = CreateObject(&quot;WScript.Shell&quot;)

    &#39;run command
    Dim oExec As Object
    Dim oOutput As Object
    Set oExec = oShell.Exec(sCmd)
    Set oOutput = oExec.StdOut

    &#39;handle the results as they are written to and read from the StdOut object
    Dim s As String
    Dim sLine As String
    While Not oOutput.AtEndOfStream
        sLine = oOutput.ReadLine
        If sLine &lt;&gt; vbNullString Then s = s &amp; sLine &amp; vbCrLf
    Wend

    ShellRun = s
    Exit Function
errHandler:
    ShellRun = vbNullString
End Function

As I said, slightly clunky with the (temporary) CMD windows popping up, but it works and I end up with a list of:

  • usernames
  • their full name from AD
  • the software packages they have open

huangapple
  • 本文由 发表于 2023年2月24日 16:35:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75554253.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定