Find then save and close all open Excel documents

后端 未结 2 1226
不思量自难忘°
不思量自难忘° 2020-12-21 11:47

I need help creating a PowerShell script that will find all open Excel documents, then first if the document is read only close the document without saving and suppress prom

相关标签:
2条回答
  • 2020-12-21 12:36

    @bgalea had the right idea, but the answer is very incomplete. For one thing, re-attaching to COM objects only works in the context of the user who created the object, so you'd have to create either a scheduled task that runs as that particular user or a logoff script (automatically runs in a user's context at logoff).

    Since you apparently want to run this periodically, a logoff script probably isn't an option, so you may want to use a logon script to create a respective scheduled task for each user, e.g. like this:

    schtasks /query /tn "Excel Cleanup" >nul 2>&1
    if %errorlevel% neq 0 schtasks /create /tn "Excel Cleanup" /sc DAILY /tr "wscript.exe \"C:\path\to\your.vbs\"" /f
    

    The VBScript run by these tasks might look somewhat like this:

    On Error Resume Next
    'attach to running Excel instance
    Set xl = GetObject(, "Excel.Application")
    If Err Then
      If Err.Number = 429 Then
        'Excel not running (nothing to do)
        WScript.Quit 0
      Else
        'unexpected error: log and terminate
        CreateObject("WScript.Shell").LogEvent 1, Err.Description & _
          " (0x" & Hex(Err.Number) & ")"
        WScript.Quit 1
      End If
    End If
    On Error Goto 0
    
    xl.DisplayAlerts = False  'prevent Save method from asking for confirmation
                              'about overwriting existing files (when saving new
                              'workbooks)
                              'WARNING: this might cause data loss!
    
    For Each wb In xl.Workbooks
      wb.Save
      wb.Close False
    Next
    
    xl.Quit
    Set xl = Nothing
    

    If you want a PowerShell script instead of VBScript you need to use the GetActiveObject() method to attach to a running Excel instance.

    try {
      # attach to running Excel instance
      $xl = [Runtime.InteropServices.Marshal]::GetActiveObject('Excel.Application')
    } catch {
      if ($_.Exception.HResult -eq -2146233087) {
        # Excel not running (nothing to do)
        exit 0
      } else {
        # unexpected error: log and terminate
        Write-EventLog -LogName Application `
          -Source 'Application Error' `
          -EventId 500 `
          -EntryType Error `
          -Message $_.Exception.Message
        exit 1
      }
    }
    
    $xl.DisplayAlerts = $false  # prevent Save() method from asking for confirmation
                                # about overwriting existing files (when saving new
                                # workbooks)
                                # WARNING: this might cause data loss!
    
    foreach ($wb in $xl.Workbooks) {
      $wb.Save()
      $wb.Close($false)
    }
    
    $xl.Quit()
    [void][Runtime.InteropServices.Marshal]::ReleaseComObject($xl)
    [GC]::Collect()
    [GC]::WaitForPendingFinalizers()
    

    According to Microsoft's documentation the GetObject() method is supposed to work as well:

    [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
    $xl = [Microsoft.VisualBasic.Interaction]::GetObject($null, 'Excel.Application')
    

    but when I tried it I ended up with an additional (hidden) Excel instance instead of attaching to the already running one.

    Note: If for some reason a user has started multiple Excel instances you will need to run the code once for each instance.

    0 讨论(0)
  • 2020-12-21 12:50
    Set xlBook = GetObject("C:\Users\David Candy\Documents\Super.xls", "Excel.Application")
    For each wsheet in xlbook.worksheets
        msgbox wsheet.name
    next
    

    VBScript, JScript, PS, VBA can all do it. Above is VBScript (and thus also VBA). The technology is COM not a language.

    EDIT

    As said using the app object doesn't work in excel.

    A excel file opened.

    EXCEL.EXE                    13560 Console                    1     19,228 K Running         DESKTOP-UCDGI39\David Candy
                                 0:00:00 Microsoft Excel - Super.xls
    

    Running GetObject using Excel.Application

    EXCEL.EXE                    13560 Console                    1     19,236 K Running         DESKTOP-UCDGI39\David Candy
                                 0:00:00 Microsoft Excel - Super.xls
    EXCEL.EXE                    15124 Console                    1     12,772 K Running         DESKTOP-UCDGI39\David Candy
                                 0:00:00 N/A
    

    NOTE

    • Separate process
    • Not started with COM switches (/a or /automation and /embedding)
    • No access to the other excel

    This is in addition to other faulty behaviour by excel where it won't exit memory when references are released.

    0 讨论(0)
提交回复
热议问题