是否可以在 VBA 中考虑由数据连接刷新激活的 SharePoint 凭据提示?

Can a SharePoint credential prompt activated by a data connection refresh be accounted for in VBA?

提问人:KOstvoll 提问时间:5/5/2018 最后编辑:TylerHKOstvoll 更新时间:4/8/2020 访问量:1194

问:

我有一个 Excel 工作簿,该工作簿与公司服务器上的 SharePoint 列表具有活动数据连接。SP 列表只是该时间点的 SP 文档库中所有文件的列表。我有一个 VBA 子例程,负责刷新此数据连接以查看当时库中的内容,然后将一些信息从列表(文档名称、文档作者、提交时间戳等)移动到不同的工作簿。

SharePoint 网站使用 Active Directory 凭据进行身份验证,并且 SharePoint 还映射为运行代码的电脑上的网络驱动器。但即便如此,刷新此数据连接有时也会导致凭据提示,该提示看起来就像我文章末尾的图像一样。如果我再次手动输入相同的 AD 凭据,则连接请求将进行身份验证,并且列表将在 Excel 中更新。

我的问题是:我如何在我的代码中解释这一点?理想情况下,我希望这触发电子邮件警报或其他东西,但问题是执行连接刷新的代码行 () 在处理凭据提示之前不会运行到完成,所以我无法在随后的代码行中设置任何处理程序。我不能进行此刷新,这可能会导致代码挂在此行上,直到有人碰巧注意到有问题(它在无人值守的 PC 上运行)。有人知道任何可以帮助解决我的问题的事情吗?ThisWorkbook.RefreshAll

enter image description here

Excel VBA SharePoint Office365

评论

0赞 HackSlash 4/2/2020
VBA 是单线程的。听起来您需要一个多线程应用程序来执行这项工作。如果编写了使用 Excel 应用程序 COM 对象执行数据刷新的 .NET 应用程序,则可以有一个超时线程,如果刷新命令未在指定的时间限制内返回,则该线程将执行操作。你可以从那里做任何你想做的事。
0赞 HackSlash 4/2/2020
如果您想在后台无人值守地运行它,我会更进一步,使该应用程序作为 Windows 服务运行。这样,它可以像任何其他后台服务一样自动启动和维护。VBA 不是为无人值守而设计的,由于您遇到的原因,您不应该运行这样的长循环。
0赞 Shivang Gupta 4/3/2020
我只是想知道:你可以写一个errorHandler,然后在那里,使用sendkeys在登录弹出窗口中输入用户名和密码。
1赞 TylerH 4/3/2020
@ShivangGupta 您可以,但这样一来,您将向有权访问存储 VBA 文件的计算机的任何人提供对网络/O365 登录的未加密访问权限。因此,不幸的是,这并不是一个真正可接受的解决方法。
2赞 TylerH 4/3/2020
@ShivangGupta 一点点,但你还必须在代码中考虑到这一点,受密码保护的 Excel 文件可能会被破解。即使作为一种解决方法,测试/演示环境之外的任何人都不应以纯文本形式存储网络/Office 365 帐户凭据。

答:

0赞 Benjamin 4/3/2020 #1

由于驱动器是本地映射的,因此您应该能够直接转到文件并根据需要操作它,导入它,而不是具有活动的数据连接。与更严格的数据连接相比,它将为您提供更大的灵活性。

这个网站有一个很好的例子,展示了如何做你正在寻找的事情,但考虑到这种情况,我想象的方式会更有效。

评论

4赞 TylerH 4/3/2020
链接的文章似乎与刷新数据连接或处理凭据提示(或避免凭据)完全无关。此外,就其价值而言,我要指出的是,您给出的解决方案根本不适用于赏金原因。即使在这种情况下,SharePoint 中的文件也存储为 blob,所以我真的不知道 OP 在谈论什么 WRT 将 SharePoint 服务器(站点?)映射到映射驱动器。
0赞 Munsterlander 4/8/2020 #2

这实际上取决于您如何进行连接,在某些情况下这是不可能的,但您可以附加 和 到 URL 以传递您的凭据,例如此处定义(对于其他语言,但您得到了要点):UsernamePassword

https://www.connectionstrings.com/sharepoint/

现在的现实情况是,您可能没有进行REST连接,并且可能必须进行以下操作:https://www.experts-exchange.com/questions/28628642/Excel-VBA-code-using-authentication-to-SharePoint.html

他们建议:

Public Sub CopyToSharePoint()
On Error GoTo err_Copy

Dim xmlhttp
Dim sharepointUrl
Dim sharepointFileName
Dim tsIn
Dim sBody
Dim LlFileLength As Long
Dim Lvarbin() As Byte
Dim LobjXML As Object
Dim LstrFileName As String
Dim LvarBinData As Variant
Dim PstrFullfileName As String
Dim PstrTargetURL As String
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim fldr As Folder
Dim f As File
Dim pw As String
Dim UserName As String
Dim RetVal
Dim I As Integer
Dim totFiles As Integer
Dim Start As Date, Finish As Date

UserName = InputBox(Username?") pw = InputBox("Password?")

sharepointUrl = "[http path to server]/[server folder to write to]"

Set LobjXML = CreateObject("Microsoft.XMLHTTP")

Set fldr = fso.GetFolder(CurrentProject.Path & "\[folder with files to
upload]\") totFiles = fldr.Files.Count

For Each f In fldr.Files

  sharepointFileName = sharepointUrl & f.Name

'****************************   Upload text files 
**************************************************

  If Not sharepointFileName Like "*.gif" And Not sharepointFileName
Like "*.xls" And Not sharepointFileName Like "*.mpp" Then

    Set tsIn = f.OpenAsTextStream
    sBody = tsIn.ReadAll
    tsIn.Close
  
    Set xmlhttp = CreateObject("MSXML2.XMLHTTP.4.0")
    xmlhttp.Open "PUT", sharepointFileName, False, UserName, Password
    xmlhttp.Send sBody
       Else

'****************************   Upload binary files 
**************************************************
  
    PstrFullfileName = CurrentProject.Path & "\[folder with files to upload]\" & f.Name
    LlFileLength = FileLen(PstrFullfileName) - 1

    ' Read the file into a byte array.
    ReDim Lvarbin(LlFileLength)
    Open PstrFullfileName For Binary As #1
    Get #1, , Lvarbin
    Close #1

    ' Convert to variant to PUT.
    LvarBinData = Lvarbin
    PstrTargetURL = sharepointUrl & f.Name


    ' Put the data to the server, false means synchronous.
    LobjXML.Open "PUT", PstrTargetURL, False, Username, Password

   ' Send the file in.
    LobjXML.Send LvarBinData

  End If
     I = I + 1   RetVal = SysCmd(acSysCmdSetStatus, "File " & I & " of " & totFiles & " copied...")    Next f

  RetVal = SysCmd(acSysCmdClearStatus)   Set LobjXML = Nothing   Set
fso = Nothing


err_Copy: If Err <> 0 Then   MsgBox Err & " " & Err.Description End If

End Sub 

实际上,我认为这个答案可能会让你走上正确的道路:https://sharepoint.stackexchange.com/questions/255264/sharepoint-api-and-vba-access-denied

无论如何,这是一个问题,祝你好运。我运气更好,使用 MS Access 将列表链接为表格,然后使用 Excel 调用 Access 并获取我需要的内容。


Private Sub cmdSyncSP_Click()
On Error GoTo ErrorCode
    Application.Cursor = xlWait
    Dim app As New Access.Application
    'Set app = CreateObject("Application.Access")
    app.OpenCurrentDatabase Application.ActiveWorkbook.Path & "\SP_Sync.accdb"
    app.Visible = False
    app.Run "doManualCheck"
    app.CloseCurrentDatabase
    Set app = Nothing
    MsgBox "Sync has finished.  Refresh and proceed to copy your data.", vbInformation + vbOKOnly, "Success"
ExitCode:
    On Error Resume Next
    Application.Cursor = xlDefault
    Exit Sub
ErrorCode:
    MsgBox "Error " & Err.Number & ": " & Err.Description, vbCritical, "Sync Error"
    Resume ExitCode
End Sub

评论

1赞 TylerH 4/8/2020
与评论中的建议一样,将 Office 365 许可密码设置为纯文本并不是真正的解决方案。同样,提示用户输入凭据不适用于本应自动化的流程(读取:无人值守)。
0赞 TylerH 4/8/2020
至于 REST,你说得对,我没有使用它(我使用的是从 SharePoint 列表下载的 .iqy 文件中的 ListObject)。但是,不应要求 REST,因为刷新在我的开发环境中的 Office 365(2016 版)中确实有效,只是在 prod 的 Office 2010 中不起作用。我承认我刚才意识到我忘了在我的赏金理由中提到 Office 版本......不幸的是,我认为这可能是至关重要的信息,因为我目前的假设是连接现在需要新式身份验证,而 Office 2010 根本不支持(而 2013 仅部分支持)。
0赞 Munsterlander 4/8/2020
右。这就是我使用 Access 的原因。它似乎更好地持有凭据。然后在 Excel 中,我调用了 Access 来执行我需要的操作。这可能是您唯一的选择。在迁移到 O365 时,我们在 SSO 和 SharePoint 方面遇到了类似的问题。
0赞 Ryan Wildry 4/9/2020
嗯,也许尝试保持凭据有效可能比发送凭据更好。我还没有测试过这个,但也许这种方法会有所帮助。kb.intermedia.net/article/1668。例如,映射为网络驱动器,并按照上述步骤保持身份验证。映射后,它应该像普通驱动器一样运行。您仍然需要处理即将到期的凭据,但我认为这几乎是不可避免的。
0赞 Munsterlander 4/9/2020
这可能是可行的,但这需要在每台客户端机器上完成 - 如果我没看错的话。我强烈建议您尝试访问路线。它只是在我们从未遇到过这个问题的地方有所不同。将列表设置为表的远程连接。我想有一次我们实际上是在创建访问文件,所以我们知道它被创建了。然后 Excel 可以直接从那里读取数据。