I want to clear Windows Operating System Clipboard history via VBA and PowerShell command.
I am a Windows 10 user.
Prerequisite:
There are two ways to clear the clipboard history using PowerShell:
Note:
Both methods by design do not clear pinned items from the history, i.e. items the current user has explicitly chosen to remember indefinitely.
If your intent is to merely clear the clipboard, i.e. remove its current content (as available for regular pasting), use
Set-Clipboard $null
, though note that in PowerShell 7+ this technically doesn't clear the clipboard, but replaces the current content with an empty string. If that is a concern, use
Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Clipboard]::Clear()
Note that clearing the clipboard does not remove the previous content from the clipboard history.
Option 1: Using the static ::ClearHistory()
method of the Windows.ApplicationModel.DataTransfer.Clipboard
class.
# Windows PowerShell only (not PowerShell 7+)
[Windows.ApplicationModel.DataTransfer.Clipboard, Windows, ContentType = WindowsRuntime]::ClearHistory()
This has the advantage of not requiring elevation (Run as Administrator).
However, because it is a UWP class, it works in Windows PowerShell only, because PowerShell (Core) 7+ at least as of the .NET 8 version underlying the current version, 7.4.x, does not have access to such classes.
Also, this works only from the foreground runspace (UI thread) and can therefore not be used from background jobs (including thread-based jobs), for instance.
Option 2: Using the Restart-Service
cmdlet to stop and restart the clipboard history Windows service:
#requires -RunAsAdministrator
Set-Clipboard $null; Restart-Service cbdhsvc_*
Unfortunately, this method only works from an elevated PowerShell session.
However, it also works in PowerShell 7+ and can also be used in (elevated) non-foreground calls, such as from jobs.
The Set-Clipboard $null
call ensures that the current clipboard data is removed too (something that the .NET API call above does automatically), though note that in PowerShell 7+ - unlike in Windows PowerShell - this doesn't clear the current clipboard, but replaces its content with an empty string, which is recorded as such in the history; however, due to restarting the service and thereby clearing the history after this call, that won't matter.
If you're running on an older system (prior to Window 10 or possibly a very early, long-obsolete build of Windows 10), the wildcard expression will not match an existing service name and the operation will be a quiet no-op.
To rule out this case, you can run the following:
if (-not (Get-Service cbdhsvc_*)) { throw "Clipboard history service not found." }
A wildcard pattern is needed, because the clipboard history service's full name changes on every login due to a (pseudo) random suffix composed of _
followed by 5 hex digits, e.g. cbdhsvc_5e5a8
.
Use the .Run()
method of the WScript.Shell
COM object...
... to invoke powershell.exe
, the Windows PowerShell CLI, with the ::ClearHistory()
call shown at the top.
The code below runs the PowerShell console window that is invariably created hidden, by using vbHide
window style in the .Run()
call.
For troubleshooting, switch to vbNormalFocus
, and place -NoExit
before -Command
in the powershell.exe
call.
Dim exitCode as Integer
' Run the PowerShell command hidden (vbHide), synchronously (True)
' and obtain its exit code.
exitCode = CreateObject("WScript.Shell").Run( _
"powershell.exe -NoProfile -Command [Windows.ApplicationModel.DataTransfer.Clipboard, Windows, ContentType = WindowsRuntime]::ClearHistory()", _
vbHide, _
True _
)
If exitCode = 0 Then ' Command succeeded.
' Report success.
MsgBox "Successfully cleared the clipboard history.", vbInformation
Else ' Command indicated failure.
MsgBox "An unexpected error occurred while trying to clear the clipboard history", vbExclamation
End If
If, for some reason, the powershell.exe
call can not be made from the UI thread of the VBA-hosting application, you'll need to use the Restart-Service
method, and doing so then invariably requires elevation.
You must then invoke powershell.exe
in a nested manner so that an inner powershell.exe
call can request elevation via Start-Process
-Verb RunAs
.
Important: Unless the application hosting VBA happens to be running with elevation itself, you'll get a UAC dialog to confirm or authorize the elevation request.
As in direct use of PowerShell, the implication is that a non-admin user cannot run the command unless an administrator is present to supply their credentials in order to authorize the request.
By security-minded design, you cannot automate responding to UAC dialogs, and the only way to avoid them from a non-elevated process is to disable (parts of) UAC altogether, which is strongly discouraged for security reasons, or - but only if you are member of the Administrators group in principle - to define a scheduled task that performs the desired operation. See this answer for details.
The code below runs the PowerShell console windows that are created hidden, by using vbHide
instead of vbNormalFocus
in the .Run()
call, and by using -WindowStyle Hidden
in the nested PowerShell Start-Process
call.
For troubleshooting, switch to vbNormalFocus
and use -NoExit
in both powershell.exe
calls.
Dim exitCode as Integer
' Run the PowerShell command with elevation, synchronously,
' and obtain the exit code.
exitCode = CreateObject("WScript.Shell").Run("powershell.exe Start-Process -Wait -Verb RunAs -WindowStyle Hidden powershell.exe 'Restart-Service cbdhsvc_*'", vbHide, True)
If exitCode = 0 Then ' Command succeeded.
' Display the output.
MsgBox "Successfully cleared the clipboard history.", vbInformation
Else ' Command indicated failure.
MsgBox "An unexpected error occurred while trying to clear the clipboard history", vbExclamation
End If