How to enable volume shadow copy using Powershell?

Solution 1:

You can create a Shadow copy on a specific drive using WMI object like it's explained in Microsoft Article.

Enable volume shadow copy on specific drive (D:, E:,...) is two things

  1. Creating a shadow copy as shown in the preceding article
  2. Creating a scheduled task to create shadow copy

Solution 2:

It took me a little while to get this to worked (after finding the simple error causing it to fail), and the function is incomplete. I want to add the ability to enable it on a remote computer, which will probably have to be done via a task that is ran once. If anybody modifies this and adds that, let me know!

function Enable-ShadowCopies {
param(
    [String]$ComputerName = $Env:ComputerName,

    [Parameter(Mandatory=$true)]
    [String]$Drive
)
$volumeWMI = Get-WmiObject -ComputerName $ComputerName -Class Win32_Volume -Filter "DriveLetter = '$Drive'";
$volumeID = ($volumeWMI.DeviceID.SubString(10)).SubString(0,($volumeWMI.DeviceID.SubString(10)).Length-1);

$scheduler = New-Object -ComObject Schedule.Service
$scheduler.Connect($ComputerName)
$tskDef = $scheduler.NewTask(0);
$tskRegInfo = $tskDef.RegistrationInfo;
$tskSettings = $tskDef.Settings;
$tskTriggers = $tskDef.Triggers;
$tskActions = $tskDef.Actions;
$tskPrincipals = $tskDef.Principal;

# Registration Info
$tskRegInfo.Author = "PowerShell Script";

# Settings
$tskSettings.DisallowStartIfOnBatteries = $false;
$tskSettings.StopIfGoingOnBatteries = $false
$tskSettings.AllowHardTerminate = $false;
$tskSettings.IdleSettings.IdleDuration = "PT600S";
$tskSettings.IdleSettings.WaitTimeout = "PT3600S";
$tskSettings.IdleSettings.StopOnIdleEnd = $false;
$tskSettings.IdleSettings.RestartOnIdle = $false;
$tskSettings.Enabled = $true;
$tskSettings.Hidden = $false;
$tskSettings.RunOnlyIfIdle = $false;
$tskSettings.WakeToRun = $false;
$tskSettings.ExecutionTimeLimit = "PT259200S";
$tskSettings.Priority = "5";
$tskSettings.StartWhenAvailable = $false;
$tskSettings.RunOnlyIfNetworkAvailable = $false;

# Triggers
$tskTrigger1 = $tskTriggers.Create(3);
$tskTrigger2 = $tskTriggers.Create(3);

## Trigger 1
$tskTrigger1.Id = "Trigger1"
$tskTrigger1.StartBoundary = (Get-Date -format "yyyy-MM-dd")+"T07:00:00";
$tskTrigger1.DaysOfWeek = 0x3E; # Monday - Friday - http://msdn.microsoft.com/en-us/library/windows/desktop/aa384024(v=vs.85).aspx
$tskTrigger1.Enabled = $true;

## Trigger 2
$tskTrigger2.Id = "Trigger2";
$tskTrigger2.StartBoundary = (Get-Date -format "yyyy-MM-dd")+"T12:00:00";
$tskTrigger2.DaysOfWeek = 0x3E; # Monday - Friday - http://msdn.microsoft.com/en-us/library/windows/desktop/aa384024(v=vs.85).aspx
$tskTrigger2.Enabled = $true;

# Principals (RunAs User)
$tskPrincipals.Id = "Author";
$tskPrincipals.UserID = "SYSTEM";
$tskPrincipals.RunLevel = 1;

 # Actions
$tskActions.Context = "Author"
$tskAction1 = $tskActions.Create(0);

# Action 1
$tskAction1.Path = "C:\Windows\system32\vssadmin.exe";
$tskAction1.Arguments = "Create Shadow /AutoRetry=15 /For="+$volumeWMI.DeviceID;
$tskAction1.WorkingDirectory = "%systemroot%\system32";

# Configure VSS, Add scheduled task
vssadmin Add ShadowStorage /For=$Drive /On=$Drive /MaxSize=10%;
$tskFolder = $scheduler.GetFolder("\")
$tskFolder.RegisterTaskDefinition("ShadowCopyVolume$volumeID", $tskDef, 6, "SYSTEM", $null,5);
}

Even though this works, and it mimics what happens when you do it via the GUI, it still shows as disabled for that drive. But if you enable it, nothing changes! (LOL) I'm guessing there's something that needs to also be modified in the registry.


Solution 3:

$diskname = "C:\"
$VolumeWmi = gwmi Win32_Volume -Namespace root/cimv2 | ?{ $_.Name -eq $diskname }
$DeviceID = $VolumeWmi.DeviceID.ToUpper().Replace("\\?\VOLUME", "").Replace("\","")
$TaskName = "ShadowCopyVolume" + $DeviceID
$TaskFor = "\\?\Volume" + $DeviceID + "\"
$Task = "C:\Windows\system32\vssadmin.exe"
$Argument = "Create Shadow /AutoRetry=15 /For=$TaskFor"
$WorkingDir = "%systemroot%\system32"

$ScheduledAction = New-ScheduledTaskAction –Execute $Task -WorkingDirectory $WorkingDir -Argument $Argument
$ScheduledTrigger = @()
$ScheduledTrigger += New-ScheduledTaskTrigger -Daily -At 10:00
$ScheduledTrigger += New-ScheduledTaskTrigger -Daily -At 15:00
$ScheduledSettings = New-ScheduledTaskSettingsSet -Compatibility V1 -DontStopOnIdleEnd -ExecutionTimeLimit (New-TimeSpan -Days 3) -Priority 5
$ScheduledTask = New-ScheduledTask -Action $ScheduledAction -Trigger $ScheduledTrigger -Settings $ScheduledSettings
Register-ScheduledTask $TaskName -InputObject $ScheduledTask -User "NT AUTHORITY\SYSTEM"

After a whole bunch of messing with it, got it to work slightly differently (it also seems to show up properly via the GUI).

Shoutouts to this page for a bit of help: https://social.technet.microsoft.com/forums/windowsserver/en-US/fb69840d-5f52-4711-8168-2faa23088233/shadow-copy-schedule-per-script

The downside to using schtasks (what that page uses) is that you can't have multiple triggers as far as I can see.

Also because of the way I troubleshot the solution (Used a bindiff of working/not working xml), I'm not entirely convinced that the flags I use are optimal.


Solution 4:

Simpler means using schtasks that shows in the UI, compatible in PowerShell 2. Designed for a standard build, may need to play about with $volumeinfo[x] when creating $taskrun to find the appropriate volume.

$volumeinfo = GWMI -namespace root\cimv2 -class win32_volume
$volumeid = $volumeinfo[1].deviceid
$taskname = "ShadowCopyVolume" + $volumeid.replace("\","").replace("?Volume","")
$taskrun = "C:\Windows\system32\vssadmin.exe Create Shadow /AutoRetry=15 /For=$volumeid"
schtasks /create /RU SYSTEM /SC DAILY /ST 07:00 /RI 60 /DU 12:00 /K /V1 /TN $TaskName /TR "$taskrun "

Can configure the following arguments appropriately:

  • /SC - frequency task is triggered
  • /ST - time task is triggered
  • /RI - repetition of task every x minutes after trigger
  • /DU - duration of task to be repeated

NOTE: The /TR switch REQUIRES the space at the end, if it is not there it replaces the final backslash with a double quote causing the VSS UI to not recognise the task.


Solution 5:

Shadow Copy is actually enabled by creating tasks that call vssadmin.exe.

PowerShell 3.0 has cmdlets that enable you to create tasks, but these depend upon syscalls that weren't implemented until Windows 8 / Windows Server 2012. You need the following three of these cmdlets to do this the PowerShell way:

register-scheduledTask
new-scheduledtaskaction
new-scheduledtasktrigger

In earlier versions of Windows, you will be restricted to using schtasks.exe.

However -- and this is where this answer differs from the others -- creating a Shadow Copy task in these ways is not the right way to do things, as any changes you make will not show up in the GUI. As such, an unobservant user may be unaware that Shadow Copy has been enabled, thus resulting in them enabling a second instance of it, or worse silently overwriting your task (if you followed Windows's naming conventions (VolumeShadowCopy{$GUID})).

What you need to do, is create one via the GUI (preferably on Win7/Win2008, as newer versions of Windows use taskxml 1.2 by default instead of the more compatible taskxml 1.1), export the task as XML via schtasks, programmatically edit that XML, save that XML as UTF16, and import it. Thankfully, once you get past the GUI at the beginning, this can all be done on the commandline.

I would like to post code, but what I wrote is proprietary, and I do not have permission from my employer. I hope that the XML tip will, at the very least, save you countless hours. I just deployed the XML solution across hundreds of managed servers, to great success.

Tags:

Powershell

Vss