9

tl;dr: Is there a way to configure windows 8 file history via unattended command-line/some script?

long story: I'm configuring a lot of stand-alone (non-domain) PCs and I think some backup is better than no backup. On Windows 7, I even configure its standard backup, despite it's retarded – by default it significantly slows computer every Monday, unless by some obscure reason user didn't turn off their PC before weekend, and it fills backup medium and stops backing up.

And I resigned to try to automate its configuration, but at least there I can set it up once as admin, and it's effective for all, including new, users. And I'm scheduling (scheduling is automated) custom script to remove old backups when backup media is low on space, so it's does not require maintenance afterwards (set once and forget).

Since Windows 8, there is this thingy called File History, which is a lot less intrusive for users (it's performance impact is barely noticeable), and it can clean up for itself (automatic history management based on age or free space). It's real back up solution, for real now :) But it also requires manual configuration for each user. Which is not acceptable, as users will forget to configure it.

My plan is to configure it per-user using some runonce logon script. I'm already doing some things via runonce-logon scripts, so installing such a script is not a problem. But I don't know how to configure File History via a script.

I tried some research, but the only official (there are some unofficial findings, see below screenshots) related tool I found is FhManagew.exe, which removes old file versions. And I need to set it up via GUI first. On the link, there is complete API, and seemingly File History can be configured via that API. But I assume this is API for .NET apps, so it can't be used via command line. Or can it?

Tried registry search, but file history location is not found anywhere :(

For specifics, let's say I want to set up file history to \\localhost\FileHistory$ and to keep file version until free space needed (by default it keeps forever). Here's how it should look:

File History in classic Control Panel File History Advanced Settings File History Select Drive

For reference: backup to local share is workaround to make File History work on single HDD, otherwise it claims it's unsafe.


Here is what I found via comments: configuration is stored in xml files in %LocalAppData%\Microsoft\Windows\FileHistory\Configuration. It's referenced in registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\fhsvc\Parameters\Configs with value name = path to configuration folder (as above), and value data = REG_DWORD:1.

But simply adding these files and registry values and starting the service (there's script for it) does not start backups, neither configuration gets updated in Control Panel. However if File History is configured already, updates to xml files get reflected in control panel.

  • 1
    Take a look at this link. This might help you out. – Smeerpijp Feb 24 '16 at 10:36
  • thanks, following its traces found another. Trying to write setup script using these two. – LogicDaemon Feb 26 '16 at 15:06
  • I still have no success with it. And I have no idea what can be wrong. Will append initial question with my findings. – LogicDaemon Jan 12 '17 at 15:22
  • 1
    I found though that once FileHistory is setup, I can modify the Config1.xml file and the changes seem to take affect right away. – joeking Nov 16 '18 at 21:03
5

Unfortunately the API is not very straightforward to use - most of the relevant calls are to a COM object that doesn't implement IDispatch. It would therefore be exceedingly difficult and messy to call these functions from PowerShell. These are the calls we need to make:

To call all these functions, we can use my open-source application SprintDLL. I wrote this script for you, commented with faux-C++ equivalents of each section:

// CoCreateInstance(CLSID_FhConfigMgr, NULL, CLSCTX_INPROC_SERVER, IID_IFhConfigMgr, &fh)
newslot native fhPtr
call ole32.dll!CoCreateInstance /return uint (blockptr(guid {ED43BB3C-09E9-498a-9DF6-2177244C6DB4}), nullptr, int 1, blockptr(guid {6A5FEA5B-BF8F-4EE5-B8C3-44D8A0D7331C}), slotptr fhPtr)
newslot native fh
copyslot fh = fhPtr dereferenced
newslot block vtbl = nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
copyslot vtbl = fh dereferenced

// fh->CreateDefaultConfiguration(TRUE)
newslot native createDefaultConfiguration
copyslot createDefaultConfiguration = vtbl field 4
call funcat createDefaultConfiguration /call thiscall /return uint (slotdata fhPtr, int 1)

// fh->ProvisionAndSetNewTarget("\\localhost\FileHistory$\", "Local Disk")
newslot native provisionAndSetNewTarget
copyslot provisionAndSetNewTarget = vtbl field 14
call funcat provisionAndSetNewTarget /call thiscall /return uint (slotdata fhPtr, bstr "\\\\localhost\\FileHistory$\\", bstr "Local Disk")

// fh->SetLocalPolicy(FH_RETENTION_TYPE, FH_RETENTION_UNLIMITED)
newslot native setLocalPolicy
copyslot setLocalPolicy = vtbl field 9
call funcat setLocalPolicy /call thiscall /return uint (slotdata fhPtr, int 1, int 1)

// fh->SetBackupStatus(FH_STATUS_ENABLED)
newslot native setBackupStatus
copyslot setBackupStatus = vtbl field 11
call funcat setBackupStatus /call thiscall /return uint (slotdata fhPtr, int 2)

// fh->SaveConfiguration()
newslot native saveConfiguration
copyslot saveConfiguration = vtbl field 5
call funcat saveConfiguration /call thiscall /return uint (slotdata fhPtr)

// FhServiceOpenPipe(TRUE, &fhPipe)
newslot native fhPipe
call fhsvcctl.dll!FhServiceOpenPipe /return int (int 1, slotptr fhPipe)

// FhServiceReloadConfiguration(fhPipe)
call fhsvcctl.dll!FhServiceReloadConfiguration /return int (slotdata fhPipe)

// FhServiceClosePipe(fhPipe)
call fhsvcctl.dll!FhServiceClosePipe /return int (slotdata fhPipe)

I got the VTable field IDs from the positions of the functions in the C-style COM interface for the File History manager COM object. If the script succeeds, it will say that every function returned zero.

To use the script, save it to a file, e.g. filehistory.sprint. You can then run it from a batch file like this:

sprintdll run filehistory.sprint

If deploying across the network, you might want to include a command that copies the utility and the script onto the local machine first.

  • 2
    Ok, so not only has this saved me a significant amount of time in MSDN documentation hell for this particular issue, but I'm loving SprintDLL! The lack of documentation sucks a bit, but the code itself is straightforward enough it sort of pulls double duty. Good on you for putting it out there, and you might even see a PR or two from me soon :) – Reid Rankin Mar 26 '18 at 9:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.