There is a utility to do this, as indicated in this post.
You could use Windows Task Scheduler to have it run periodically.
Alternatively, if you have a specific set of files you'd like to remove from Windows' standby cache, you can open them with NtCreateFile (part of WDM) and call FlushFileBuffers to clear them from standby cache.
Here's what I did to test it with a small command-line application. You'll need to include winternl.h and pull in ntdll.lib. This can obviously be made more robust - it's a quick test app in this state. (I tried using CreateFile instegad of NtCreateFile so that I wouldn't need the WDK, but haven't had luck with that route, yet.)
int _tmain(int argc, _TCHAR* argv[])
{
if (argc < 2)
{
_tprintf(TEXT("No filepath entered. Full path required.\r\n"));
return 0;
}
// Convert the "DOS" name to a Windows object model name so NtCreateFile can handle it below
// MAX_FILE_PATH_LEN is just #define'd elsewhere to 1024
TCHAR filePath[MAX_FILE_PATH_LEN] = { 0 };
TCHAR deviceName[8] = { 0 };
_tcsncpy_s(deviceName, 8, argv[1], 2);
QueryDosDevice(deviceName, filePath, MAX_FILE_PATH_LEN - 1);
_tcscat_s(filePath, MAX_FILE_PATH_LEN, &argv[1][2]);
_tprintf(TEXT("Converted: \"%s\"\r\n ==> \"%s\"\r\n"), argv[1], filePath);
UNICODE_STRING usFilePath = { 0 };
#ifndef _UNICODE
WCHAR filePath_W[MAX_FILE_PATH_LEN];
size_t convCount = 0;
mbstowcs_s(&convCount, filePath_W, MAX_FILE_PATH_LEN, filePath, MAX_FILE_PATH_LEN);
usFilePath.Buffer = filePath_W;
#else
usFilePath.Buffer = filePath;
#endif
// Lengths specifically noted as bytes, not characters
usFilePath.Length = wcslen(filePath) * sizeof(WCHAR);
// Leaving one character for null term
usFilePath.MaximumLength = (MAX_FILE_PATH_LEN - 1) * sizeof(WCHAR);
OBJECT_ATTRIBUTES objAttrs;
InitializeObjectAttributes(&objAttrs, &usFilePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL)
IO_STATUS_BLOCK ioStatus_OpenFile = {0};
HANDLE hFile = INVALID_HANDLE_VALUE;
NTSTATUS statusCreateFile = NtCreateFile(&hFile, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &objAttrs, &ioStatus_OpenFile, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, 0);
if (NT_SUCCESS(statusCreateFile))
{
_tprintf(TEXT("Opened file successfully.\r\n"));
IO_STATUS_BLOCK fileFlushStatus = { 0 };
BOOL bFlushResult = FlushFileBuffers(hFile);
_tprintf(TEXT("FlushFileBuffers returned %d; last error: %d\r\n"), bFlushResult, GetLastError());
// Close the file
statusCreateFile = NtClose(hFile);
if (NT_SUCCESS(statusCreateFile))
_tprintf(TEXT("File closed successfully.\r\n"));
else
_tprintf(TEXT("File close error: %08x\r\n"), statusCreateFile);
}
else
{
//WriteIoStatusResultLine is just a function to dump an IO_STATUS_BLOCK to output
//WriteIoStatusResultLine(&ioStatus_OpenFile);
_tprintf(TEXT("NtCreateFile error, Status=%08x\r\n"), statusCreateFile);
}
return 0;
}