{"id":19283754,"url":"https://github.com/eryoneta/roboversion","last_synced_at":"2025-02-23T22:40:52.268Z","repository":{"id":184865634,"uuid":"672080126","full_name":"Eryoneta/Roboversion","owner":"Eryoneta","description":"Based on Robocopy, Roboversion is capable of not only mirroring a folder system, but also versioning all of its files","archived":false,"fork":false,"pushed_at":"2023-11-17T23:35:14.000Z","size":87,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-05T17:33:05.274Z","etag":null,"topics":["completed","powershell","small","small-project"],"latest_commit_sha":null,"homepage":"","language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Eryoneta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-07-28T21:48:44.000Z","updated_at":"2024-01-12T22:58:34.000Z","dependencies_parsed_at":"2023-11-18T00:55:26.097Z","dependency_job_id":"3fa389f5-f40c-43e6-a9d6-b752bb246c2a","html_url":"https://github.com/Eryoneta/Roboversion","commit_stats":null,"previous_names":["eryoneta/roboversion"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eryoneta%2FRoboversion","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eryoneta%2FRoboversion/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eryoneta%2FRoboversion/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eryoneta%2FRoboversion/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Eryoneta","download_url":"https://codeload.github.com/Eryoneta/Roboversion/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240390697,"owners_count":19793781,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["completed","powershell","small","small-project"],"created_at":"2024-11-09T21:34:56.380Z","updated_at":"2025-02-23T22:40:52.233Z","avatar_url":"https://github.com/Eryoneta.png","language":"PowerShell","readme":"# RoboVersion\n\nBased on _Robocopy_, Roboversion is a script based on _PowerShell_ capable of not only mirroring a folder system, but also versioning all of its files. A simple, yet effective, backup solution.\n\n## Usage\n\nOpening a _PowerShell_ console, run \"`. \"PATH_TO_FOLDER/RoboVersion.ps1\";`\"(The \"`.`\" is important!), where \"`PATH_TO_FOLDER`\" leads to the \"`RoboVersion.ps1`\" file.\n\nWith that, the command `Roboversion` will properly call a function.\n\n## Parameters\n\n### `-OrigPath`, `-OP`:\n- Path to the origin-folder, which contains the files to be mirrored.\n\n### `-DestPath`, `-DP`:\n- Path to the target-folder, which will contain the copies and versions.\n\n### `-VersionLimit`, `-VL`, `-V`:\n- Total of versions allowed before replacing old ones.\n- Needs to be between `0` and `99999`. Default is `5`.\n- Optional.\n\n### `-RemotionCountdown`, `-RC`, `-R`:\n- Number of times the script needs to be run before the removed file is permanently deleted.\n- Needs to be between `0` and `99999`. Default is `10`.\n- Optional.\n\n### `-Destructive`, `-D`:\n- Forces the number of versions and removed to be within the parameters given.\n- Default is `false`.\n- Optional.\n\n### `-ListOnly`, `-LO`, `-L`:\n- Lists only, don't do any changes.\n- Default is `false`.\n- Optional.\n\n## Examples\n\n- `Roboversion -OrigPath \"D:/Test/MyFolder\" -DestPath \"D:/Test/BackupFolder\" -VersionLimit 3 -RemotionCountdown 5` mirrors all files from \"`MyFolder`\" to \"`BackupFolder`\", creating up to 3 versions, and having all removed files deleted after running the script 5 more times.\n- `Roboversion \"D:/Test/MyFolder\" \"D:/Test/BackupFolder\" -V 3 -R 5` does the same thing.\n- `Roboversion \"D:/Test/MyFolder\" \"D:/Test/BackupFolder\" -V 3 -R 5 -D` does the same thing, but all versions above `3` are decreased, maybe causing old versions starting from `1` to be deleted as needed. The same happens with remotions as well.\n- `Roboversion \"D:/Test/MyFolder\" \"D:/Test/BackupFolder\" -V 3 -R 5 -L` only lists the changes it would do, but no actions are made.\n\n## Behaviour\n\n- Mirroring a origin-folder into a target-folder, it can do different things in different situations:\n  - __New File__:\n    - A file does not exist on target-folder.\n    - A simple copy is made.\n  - __Modified files__:\n    - A file had been modified on origin-folder, and it's present on target-folder.\n    - A copy is made, marked as a new version, and the original file is replaced by the one present in the origin-folder.\n  - __Removed files__:\n    - A file is not present on the target-folder, but it is on target-folder.\n    - A copy is made, marked as removed, and the original is deleted.\n- __Versions__:\n  - If a file \"`filename.ext`\" has a new version, it's named \"`filename _version[v].ext`\", where `v` can range from `1` to `VersionLimit`.\n    - When all numbers are occupied, version `1` is deleted and all others are renamed, leaving version `VersionLimit` free to be occupied.\n      - Versions above `VersionLimit` are ignored.\n    - Removed versions are ignored.\n  - If `Destructive` is marked, then all versions that happen to be above `VersionLimit` are decreased to fit within the limit.\n  - If `VersionLimit` is `0`, then no versions are created. Modified files are simply copied over.\n    - Using with `Destructive` results in all versions being deleted.\n- __Remotions__:\n  - If a file \"`filename.ext`\" is marked as removed, it's named \"`filename _removeIn[r].ext`\", where `r` can range from `RemotionCountdown` to `0`.\n    - All of its versions are also marked: \"`filename _version[v] _removeIn[r].ext`\".\n    - Everytime the script is run, the number decreases. If its `0`, then it's permanently deleted.\n  - If a folder \"`foldername`\" is marked as removed, it's named \"`foldername _removeIfEmpty`\".\n    - When all of its content are deleted and the folder is empty, then it's permanently deleted.\n  - If `Destructive` is marked, then all remotions that happen to be above `RemotionCountdown` are decreased to fit within the limit.\n  - If `RemotionCountdown` is `0`, then no remotions are created. Deleted files are simply deleted.\n    - Using with `Destructive` results in all remotions being deleted.\n- __Note__:\n  - All files on origin-folder that contains \"`..._version[...]...`\", \"`..._removeIn[...]...`\" are ignored.\n    - All folders that contains \"`..._removeIfEmpty...`\" are also ignored.\n  - Files that begin with a \"`.`\" are understood as a extension without a name: \"`.filename`\" results into versions named \"` _version[v].filename`\".\n  - The space before the mark is optional: \"`filename _version[v].ext`\"(With space) is the same as \"`filename_version[v].ext`\"(No space).\n  - Versions and remotions can be manually renamed, respecting the `1-99999` and `0-99999` ranges.\n- __Caveats__:\n  - Newly created folders with no files are not listed, but are still copied over.\n  - Before processing files, it needs _Robocopy_ to list them all. That can be a little slow.\n    - During the listing process, a file will be temporarily created on the target-folder. That's the only way for _Robocopy_ to list files with special characters on it's name.\n\n## In Practice\n| \"D:\\myFolder\" | Command | \"M:\\myBackup\" |\n| --- | --- | --- |\n| _myFile.ext_ (\"A\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 4`\u003cbr/\u003e(To create a inicial copy, same as _Robocopy_) | _myFile.ext_ (\"A\") |\n| _myFile.ext_ (\"B\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 4`\u003cbr/\u003e(Here, it creates a version) | _myFile.ext_ (\"B\")\u003cbr/\u003e_myFile \\_version[1].ext_ (\"A\") |\n| _myFile.ext_ (\"C\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 4`\u003cbr/\u003e(Another version) | _myFile.ext_ (\"C\")\u003cbr/\u003e_myFile \\_version[2].ext_ (\"B\")\u003cbr/\u003e_myFile \\_version[1].ext_ (\"A\") |\n| _myFile.ext_ (\"D\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 4` | _myFile.ext_ (\"D\")\u003cbr/\u003e_myFile \\_version[3].ext_ (\"C\")\u003cbr/\u003e_myFile \\_version[2].ext_ (\"B\")\u003cbr/\u003e_myFile \\_version[1].ext_ (\"A\") |\n| _myFile.ext_ (\"E\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 4` | _myFile.ext_ (\"E\")\u003cbr/\u003e_myFile \\_version[4].ext_ (\"D\")\u003cbr/\u003e_myFile \\_version[3].ext_ (\"C\")\u003cbr/\u003e_myFile \\_version[2].ext_ (\"B\")\u003cbr/\u003e_myFile \\_version[1].ext_ (\"A\") |\n| _myFile.ext_ (\"F\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 4`\u003cbr/\u003e(Now, any new versions causes the oldest one to be replaced) | _myFile.ext_ (\"F\")\u003cbr/\u003e_myFile \\_version[4].ext_ (\"E\")\u003cbr/\u003e_myFile \\_version[3].ext_ (\"D\")\u003cbr/\u003e_myFile \\_version[2].ext_ (\"C\")\u003cbr/\u003e_myFile \\_version[1].ext_ (\"B\") |\n| _myFile.ext_ (\"G\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 4` | _myFile.ext_ (\"G\")\u003cbr/\u003e_myFile \\_version[4].ext_ (\"F\")\u003cbr/\u003e_myFile \\_version[3].ext_ (\"E\")\u003cbr/\u003e_myFile \\_version[2].ext_ (\"D\")\u003cbr/\u003e_myFile \\_version[1].ext_ (\"C\") |\n| _myFile.ext_ (\"H\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 2 -D`\u003cbr/\u003e(Too many versions! Only two is good) | _myFile.ext_ (\"H\")\u003cbr/\u003e_myFile \\_version[2].ext_ (\"G\")\u003cbr/\u003e_myFile \\_version[1].ext_ (\"F\") |\n| _myFile.ext_ (\"I\") | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 2`\u003cbr/\u003e(Using `2` instead of `4` now) | _myFile.ext_ (\"I\")\u003cbr/\u003e_myFile \\_version[2].ext_ (\"H\")\u003cbr/\u003e_myFile \\_version[1].ext_ (\"G\") |\n| | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 2 -R 30`\u003cbr/\u003e(To reflect the deleted file) | _myFile \\_removeIn[30].ext_ (\"I\")\u003cbr/\u003e_myFile \\_version[2] \\_removeIn[30].ext_ (\"H\")\u003cbr/\u003e_myFile \\_version[1] \\_removeIn[30].ext_ (\"G\") |\n| | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 2 -R 30`\u003cbr/\u003e(Running now, it only decreases the countdown) | _myFile \\_removeIn[29].ext_ (\"I\")\u003cbr/\u003e_myFile \\_version[2] \\_removeIn[29].ext_ (\"H\")\u003cbr/\u003e_myFile \\_version[1] \\_removeIn[29].ext_ (\"G\") |\n| | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 2 -R 30` | _myFile \\_removeIn[28].ext_ (\"I\")\u003cbr/\u003e_myFile \\_version[2] \\_removeIn[28].ext_ (\"H\")\u003cbr/\u003e_myFile \\_version[1] \\_removeIn[28].ext_ (\"G\") |\n| | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 2 -R 1 -D`\u003cbr/\u003e(It's taking too long!) | _myFile \\_removeIn[1].ext_ (\"I\")\u003cbr/\u003e_myFile \\_version[2] \\_removeIn[1].ext_ (\"H\")\u003cbr/\u003e_myFile \\_version[1] \\_removeIn[1].ext_ (\"G\") |\n| | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 2 -R 1` | _myFile \\_removeIn[0].ext_ (\"I\")\u003cbr/\u003e_myFile \\_version[2] \\_removeIn[0].ext_ (\"H\")\u003cbr/\u003e_myFile \\_version[1] \\_removeIn[0].ext_ (\"G\") |\n| | `Roboversion \"D:\\myFolder\" \"M:\\myBackup\" -V 2 -R 1`\u003cbr/\u003e(With `0`, all remotions are deleted) | |\n\n## Inner Workings\n\nEverything is based around _Robocopy_:\n- All versions and remotions present on the target-folder are listed with a _Robocopy_ command that only checks marked files.\n  - Versions and remotions are renamed or deleted as needed.\n  - (Unfortunadely, _Robocopy_ does not allow to filter folders. So, all folders have to be listed by it and filtered by _Roboversion_. This can be a little slow).\n- All files to be modified are listed with another _Robocopy_ command that only lists differences.\n  - New versions and remotions are created, renaming or deleting old ones as needed.\n- Then a final _Robocopy_ does the mirroring.\n\nIt all happens in five stages: `UpdateVersioned`, `UpdateRemoved`, `UpdateToVersion`, `UpdateToRemove`, and `Mirror`.\n## Dependecies\n\nDeveloped using _Robocopy.exe_ and _PowerShell v5.1_.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feryoneta%2Froboversion","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feryoneta%2Froboversion","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feryoneta%2Froboversion/lists"}