diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e4217d78..c80136a75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Drive items backup and restore link shares +- Restore commands now accept an optional top-level restore destination with the `--destination` flag. Setting the destination to '/' will restore items back into their original location. +- Restore commands can specify item collision behavior. Options are Skip (default), Replace, and Copy. ### Fixed - Return a ServiceNotEnabled error when a tenant has no active SharePoint license. diff --git a/src/cli/flags/restore_config.go b/src/cli/flags/restore_config.go index 8e5774f67..a2b8c3a86 100644 --- a/src/cli/flags/restore_config.go +++ b/src/cli/flags/restore_config.go @@ -21,10 +21,9 @@ func AddRestoreConfigFlags(cmd *cobra.Command) { fs := cmd.Flags() fs.StringVar( &CollisionsFV, CollisionsFN, string(control.Skip), - "How to handle item collisions: "+string(control.Skip)+", "+string(control.Copy)+", or "+string(control.Replace)) - cobra.CheckErr(fs.MarkHidden(CollisionsFN)) + //nolint:lll + "Sets the behavior for existing item collisions: "+string(control.Skip)+", "+string(control.Copy)+", or "+string(control.Replace)) fs.StringVar( &DestinationFV, DestinationFN, "", - "Overrides the destination where items get restored. '/' places items back in their original location.") - cobra.CheckErr(fs.MarkHidden(DestinationFN)) + "Overrides the destination where items get restored; '/' places items into their original location") } diff --git a/src/cli/restore/restore.go b/src/cli/restore/restore.go index 787de551e..a3e3dce85 100644 --- a/src/cli/restore/restore.go +++ b/src/cli/restore/restore.go @@ -34,15 +34,46 @@ func AddCommands(cmd *cobra.Command) { const restoreCommand = "restore" +// FIXME: this command doesn't build docs, and so these examples +// are not visible within the website. +// +//nolint:lll +const restoreCommandExamples = `# Restore email inbox messages to their original location +corso restore exchange \ + --backup 1234abcd-12ab-cd34-56de-1234abcd \ + --email-folder '/inbox' \ + --destination '/' + +# Restore a specific OneDrive folder to the top-level destination named "recovered_june_releases" +corso restore onedrive \ + --backup 1234abcd-12ab-cd34-56de-1234abcd \ + --folder '/work/corso_june_releases' \ + --destination /recovered_june_releases + +# Restore a calendar event, making a copy if the event already exists. +corso restore exchange \ + --backup 1234abcd-12ab-cd34-56de-1234abcd \ + --event-calendar 'Company Events' \ + --event abdef0101 \ + --collisions copy + +# Restore a SharePoint library in-place, replacing any conflicting files. +corso restore sharepoint \ + --backup 1234abcd-12ab-cd34-56de-1234abcd \ + --library documents \ + --destination '/' \ + --collisions replace` + // The restore category of commands. // `corso restore [] [...]` func restoreCmd() *cobra.Command { return &cobra.Command{ - Use: restoreCommand, - Short: "Restore your service data", - Long: `Restore the data stored in one of your M365 services.`, - RunE: handleRestoreCmd, - Args: cobra.NoArgs, + Use: restoreCommand, + Short: "Restore your service data", + Long: `Restore the data stored in one of your M365 services.`, + RunE: handleRestoreCmd, + Args: cobra.NoArgs, + Example: restoreCommandExamples, } } diff --git a/website/docs/quickstart.md b/website/docs/quickstart.md index 906202070..da2ecf9dc 100644 --- a/website/docs/quickstart.md +++ b/website/docs/quickstart.md @@ -281,9 +281,63 @@ A confirmation of the recovered email will be shown and the email will appear in 360bf6840396 phish@contoso.info Re: Request for Apple/Amazon gift cards 2022-10-18T02:27:47Z ``` +## Advanced Restores + +You can control where your data gets restored, and what happens if restored items would overwrite existing +ones. Let's restore a folder in OneDrive back to its original location. Since the folder already exists, we can +tell corso to with duplicate names as copies. + + + + + ```powershell + # Restore a folder to its original location + .\corso restore onedrive --backup ` + --folder "/presentations/company_culture" ` + --destination "/" ` + --collisions copy + ``` + + + + + ```bash + # Restore a folder to its original location + ./corso restore onedrive --backup \ + --folder "/presentations/company_culture" \ + --destination "/" \ + --collisions copy + ``` + + + + +{ + `# Restore a folder to its original location +docker run --env-file $HOME/.corso/corso.env \\ + --volume $HOME/.corso:/app/corso ghcr.io/alcionai/corso:${Version()} \\ + restore exchange --backup \\ + --email --folder '/presentations/company_culture' \\ + --destination '/' --collisions copy` +} + + + + +A confirmation of the recovered files will be shown and those files will appear back in their original folder. + +```text + ID ItemName ParentPath Size Owner Created Modified + f43bff59de56 slides 1.ppt /presentations/company_culture 23 kB 2023-07-05T18:37:57Z 2023-07-05T18:37:58Z + c0de2282e9c7 giftcards.xls /presentations/company_culture 0 B 2023-07-05T18:37:47Z 2023-07-05T18:37:47Z +``` + +See [here](../setup/restore-options) for more restoration options. + ## Read more The above tutorial only scratches the surface for Corso's capabilities. We encourage you to dig deeper by: * Learning about [Corso concepts and setup](../setup/concepts) * Explore Corso backup and restore options for Exchange and Onedrive in the [Command Line Reference](../cli/corso) +* Leverage Corso's [Advanced Restoration Options](../setup/restore-options) diff --git a/website/docs/setup/restore-options.md b/website/docs/setup/restore-options.md new file mode 100644 index 000000000..f1c3a8de0 --- /dev/null +++ b/website/docs/setup/restore-options.md @@ -0,0 +1,110 @@ +# Restore Options + +import CodeBlock from '@theme/CodeBlock'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import {Version} from '@site/src/corsoEnv'; + +The default restore command is an great way to restore data in a non-destructive +manner to a new folder. When you need more control over the results you can +use the advanced configuration options to change where and how your data +gets restored. + +## Destination + +The `--destination` flag lets you select the top-level folder where Corso will +write all of the restored data. + +### The default destination + +{ + `corso restore onedrive --backup abcd` +} + +If the flag isn't provided, Corso will create a new folder with a standard name: +`Corso_Restore_`. The default restore folder is always newly +created, and can't interfere with any existing items. If you're concerned about +data integrity then this is always the safest option. + +### An alternate destination + +{ + `corso restore onedrive --backup abcd --destination /my-latest-restore` +} + +When a destination is manually specified, all restored will appear in that top-level +folder. In the example above, Corso will restore everything into `my-latest-restore`. +If that folder doesn't already exist, Corso will automatically create it. If it does +exist, the restore will use the existing folder, allowing you to restore to the same +folder multiple times. + +### The original location + +{ + `corso restore onedrive --backup abcd --destination /` +} + +You can restore items back to their original location by setting the destination +to `/`. This skips the creation of a top-level folder, and all restored items will +appear back in their location at the time of backup. + +### Limitations + +* Destination won't create N-depth folder structures. `--destination a/b/c` +doesn't create three folders; it creates a single, top-level folder named `a/b/c`. + +* Exchange Calendars don't support folder hierarchy. If your backup contains the +calendars `MyCalendar` and `Birthdays`, and you restore to `--destination Restored`, +all of the restored calendar events will appear in the `Restored` calendar. However, +if you restore events in-place (`--destination /`) then all events will return to +their original calendars. + +* When restoring Exchange Calendar Events to a destination folder, Events that were +safe in different calendars may collide with each other in the destination calendar. + +## Item collision handling + +When restoring data into an existing folder, the items restored may conflict +with existing data. When this happens, Corso resolves the conflict using its +collision configuration. + +Collision detection differs between each service and type of data. The general +comparison always follows the same pattern: "within the current folder, if the +restore item looks identical to an existing item, it collides." + +The comparison uses item metadata (names, subjects, titles, etc), not item content. +If the current `reports.txt` has different contents than the backup `reports.txt`, +it still collides. + +Collisions can be handled with three different configurations: `Skip`, `Copy`, +and `Replace`. + +## Skip (default) + +{ + `corso restore onedrive --backup abcd --collisions skip --destination /` +} + +When a collision is identified, the item is skipped and +no restore is attempted. + +## Copy + +{ + `corso restore onedrive --backup abcd --collisions copy --destination /my-latest-restore` +} + +Item collisions create a copy of the item in the backup. The copy holds the backup +version of the item, leaving the current version unchanged. If necessary, changes +item properties (such as filenames) to avoid additional collisions. Eg: +the copy of`reports.txt` is named `reports 1.txt`. + +## Replace + +{ + `corso restore onedrive --backup abcd --collisions replace --destination /` +} + +Collisions will entirely replace the current version of the item with the backup +version. If multiple existing items collide with the backup item, only one of the +existing items is replaced. diff --git a/website/docs/support/known-issues.md b/website/docs/support/known-issues.md index 16e5fb1fd..754bddfb6 100644 --- a/website/docs/support/known-issues.md +++ b/website/docs/support/known-issues.md @@ -8,26 +8,22 @@ Below is a list of known Corso issues and limitations: * Backups of Exchange email may not include changes to the read status of an email if no other changes to the email have been made since the previous backup. -* Restores are non-destructive to a dedicated restore folder in the original Exchange mailbox or OneDrive account. - Advanced restore options such as in-place restore, or restore to a specific folder or to a different account aren't - yet supported. - * Restoration of Nested attachments within Exchange Mail or Calendars aren't yet supported. * Folders and Calendars containing zero items or subfolders aren't included in the backup. -* Provides no guarantees about whether data moved, added, or deleted in M365 - while a backup is being created will be included in the running backup. - Future backups run when the data isn't modified will include the data. +* Provides no guarantees the inclusion of data that's moved, added, or deleted + from M365 while a backup creation is running. + The next backup creation will correct any missing data. * SharePoint document library data can't be restored after the library has been deleted. * Sharing information of items in OneDrive/SharePoint using sharing links aren't backed up and restored. -* Permissions/Access given to a site group can't be restored +* Permissions/Access given to a site group can't be restored. * If a link share is created for an item with inheritance disabled (via the Graph API), the link shares restored in that item will - not be inheritable by children + not be inheritable by children. -* Link shares with password protection can't be restored +* Link shares with password protection can't be restored.