Search code examples
excelvbams-wordonedriveelevated-privileges

How to call an unelevated process from an elevated process


I did read the related community posts*

In elevated Excel (Excel must be run elevated), VBA opens MS Word. MS Word VBA restarts previously disabled OneDrive. The problem is elevated Excel leads to Word being elevated which leads to calling OneDrive elevated which causes OneDrive to throw an error. Thus, I want Excel to open Word as unelevated. Code below.

  • 64-bit Win 10 Pro 21H1 19043.1526
  • 32-bit Office 365 installed desktop apps
  • OneDrive Personal (non-business)
  • UAC disabled
*P.S.

I read all the community posts, and 37 more results, that come up when I search variations of my problem but I can't find any that apply, maybe because my case is VBA or I'm not schooled enough to understand how to translate other answers into what I need. I try but I am 100% self-taught, with some copying of code I don't fully understand, like Hans Vogelaar's from social.msdn, below.

Here's the Excel VBA

Sub Open_Word_DocM()
'Credit: Hans Vogelaar https://social.msdn.microsoft.com/Forums/en-US/29265e5f-8df9-4cab-8984-1afb9b110d2f/in-excel-use-vba-to-check-if-a-word-document-is-open?forum=isvvba

Dim Wd As Object
Dim InstrDoc As Object
Dim f As Boolean

Const strpath = "C:\Users\ssttr\OneDrive\Documents\Testing\ReStartOneDrive.docm"

On Error Resume Next

9990100:
Set InstrDoc = GetObject(strpath)

If InstrDoc Is Nothing Then
    Set Wd = GetObject(, "Word.Application")
    If Wd Is Nothing Then
        Set Wd = CreateObject("Word.Application")
        If Wd Is Nothing Then
            Call ErrorLog
                If mErr = 4 Then
                    GoTo 9990100
                End If
        End If
        f = True
    End If

9990200:
    Set InstrDoc = Wd.Documents.Open(strpath)

    If InstrDoc Is Nothing Then
        Call ErrorLog
        If mErr = 4 Then
            GoTo 9990200
        End If
        If f Then
            Wd.Quit
        End If
        Exit Sub
    End If
    
    Wd.Visible = True

Else
    With InstrDoc.Parent
        .Visible = True
        .Activate
    End With
End If
End Sub

Here's the Word .docm VBA

Sub Restart_OneDrive()
    Dim shell
    Set shell = CreateObject("wscript.shell")
    shell.Run """C:\Users\ssttr\OneDrive\Documents\Investing\Automation\Static Inputs\OneDrive Restart.bat"""
        'batch file contents: start %LOCALAPPDATA%\Microsoft\OneDrive\OneDrive.exe /background
End Sub

Here's the OneDrive error

OneDrive can't be run using full administrator rights
Please restart OneDrive without administrator rights. OneDrive error

FWIW 1

SysInternals Process Explorer shows Word is parented by svchost.exe: ProcExp Properties

FWIW 2

I always have UAC disabled.

FWIW 3

I invoke Excel as Admin for all users via: Properties > Compatibility tab > Change settings for all users button > enable Run this program as administrator: Excel Admin Setting

Forum Concern?

A much more detailed version of this question was posted Dec-2021 at How to Restart OneDrive via VBA When Running Excel Elevated. I think it was TLDR bc I received no responses. A couple months ago, an earlier, different approach to this problem was at Start OneDrive Under Full Admin Rights. That post, also TLDR, did received one response, a response I attempted but was unable to implement successfully. If there's a forum rule (I can't find one) against posting a similar topic more than once, then please delete the overly verbose one(s) and kindly leave this one. Thanks.


Solution

  • In brief: called OneDrive from Explorer (which has a limitation which is useful in this case; it only invokes exe's as non-admin) then got rid of unwanted File Explorer window.

    It's a bit of a kluge job but it works.

    Changed MS Word VBA (and associated batch file, as noted in VBA comment) as follows (I didn't edit it down again into the simplified version I originally posted):

    'The #-prefixed Declarations are used to enable the Windows API Sleep function (since Word does not allow Excel's Application.Wait method)
    'VBA 7 replaces the VBA code base in Office 2007 and earlier versions. VBA 7 is available in both the 32-bit and 64-bit versions of Office. It provides two conditional compilation constants:
    'VBA7 - Helps ensure the backward compatibility of your code by testing whether your application is using VBA 7 or the previous version of VBA.
    'Win64 Tests whether code is running as 32-bit or 64-bit.
    'per https://www.myonlinetraininghub.com/pausing-or-delaying-vba-using-wait-sleep-or-a-loop
    #If VBA7 And Win64 Then
        ' For 64bit version of Excel
        Public Declare PtrSafe Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As LongPtr)
    #Else
        ' For 32bit version of Excel
        Public Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
    #End If
    
    Sub Restart_OneDrive()
    'Restarts OneDrive via batch file command.
    'Then closes the unwanted Explorer.exe window after a 5000 [ms] sleep.
    'NOTE: this method is necessary to solve the problem of invoking OneDrive
        '(which will not run with elevated privileges) from elevated Word
        '(elevated bc called from elevated Excel (elevated bc this is the only way
        'Excel PID functions can control VLIA).
    'https://www.myonlinetraininghub.com/pausing-or-delaying-vba-using-wait-sleep-or-a-loop
    'https://learn.microsoft.com/en-us/previous-versions/office/developer/office-2010/ee691831(v=office.14)?redirectedfrom=MSDN
    
    Dim shellt
    Set shellt = CreateObject("wscript.shell")
    
    shellt.Run """C:\Users\ssttr\OneDrive\Documents\Automation\Static Inputs\OneDrive Restart.bat"""
        'batch file contents: explorer %LOCALAPPDATA%\Microsoft\OneDrive\OneDrive.exe
    Dim waitOnReturn As Boolean: waitOnReturn = True 'Waits for shell to finish before returning to VBA
       
    Sleep 5000 'in milliseconds (ref Declarations)
    
    'Now kill the unwanted File Explorer window
        'Note that in order to not kill all Explorer.exe windows, TaskKill's syntax requires:
            '(1) each explorer window open in a separate process
                'View > Folder Options > View Tab > enable Display the full path in the titlebar
            '(2) the full path in title bar has been enabled in Folder view
                'View > Folder Options > View Tab > enable Launch folder windows in a separate process
            '^per https://superuser.com/questions/1263315/how-to-close-a-particular-opened-folder-using-cmd-or-batch-file
    
    Call shell("taskkill /fi ""IMAGENAME eq explorer.exe"" /fi ""windowtitle eq OneDrive - Personal""")
    waitOnReturn = True 'Waits for shell to finish before returning to VBA
    
    End Sub