{"id":22246333,"url":"https://github.com/thgossler/azsavemoney","last_synced_at":"2025-07-28T03:30:46.930Z","repository":{"id":63108788,"uuid":"558074841","full_name":"thgossler/AzSaveMoney","owner":"thgossler","description":"Save money and energy and clean-up by identifying and marking unused Azure resources/groups as subject for deletion by tagging.","archived":false,"fork":false,"pushed_at":"2024-08-01T21:12:19.000Z","size":1016,"stargazers_count":28,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-04T12:52:34.830Z","etag":null,"topics":["automation","azure","cleanup","climateprotection","cloud","cost","deletion","efficiency","finops","governance","infrastructure","optimization","powershell","resourcemanagement","resourcetracking","scripting","tagging","unusedresources"],"latest_commit_sha":null,"homepage":"","language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thgossler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["thgossler"]}},"created_at":"2022-10-26T21:08:53.000Z","updated_at":"2025-01-07T00:17:04.000Z","dependencies_parsed_at":"2024-05-11T22:30:52.484Z","dependency_job_id":"9d029402-4a1f-4496-a96a-f6c166db2854","html_url":"https://github.com/thgossler/AzSaveMoney","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/thgossler/AzSaveMoney","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thgossler%2FAzSaveMoney","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thgossler%2FAzSaveMoney/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thgossler%2FAzSaveMoney/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thgossler%2FAzSaveMoney/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thgossler","download_url":"https://codeload.github.com/thgossler/AzSaveMoney/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thgossler%2FAzSaveMoney/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267458158,"owners_count":24090541,"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","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["automation","azure","cleanup","climateprotection","cloud","cost","deletion","efficiency","finops","governance","infrastructure","optimization","powershell","resourcemanagement","resourcetracking","scripting","tagging","unusedresources"],"created_at":"2024-12-03T05:27:12.851Z","updated_at":"2025-07-28T03:30:46.602Z","avatar_url":"https://github.com/thgossler.png","language":"PowerShell","funding_links":["https://github.com/sponsors/thgossler","https://www.paypal.com/donate/?hosted_button_id=JVG7PFJ8DMW7J"],"categories":[],"sub_categories":[],"readme":"\u003c!-- SHIELDS --\u003e\n\u003cdiv align=\"center\"\u003e\n\n[![Contributors][contributors-shield]][contributors-url]\n[![Forks][forks-shield]][forks-url]\n[![Stargazers][stars-shield]][stars-url]\n[![Issues][issues-shield]][issues-url]\n[![MIT License][license-shield]][license-url]\n\n\u003c/div\u003e\n\n\u003c!-- PROJECT LOGO --\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/thgossler/AzSaveMoney\"\u003e\n    \u003cimg src=\"images/logo.png\" alt=\"Logo\" width=\"80\" height=\"80\"\u003e\n  \u003c/a\u003e\n  \u003ch1 align=\"center\"\u003eAzSaveMoney\u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\n    Clean-up unused resources and save money and energy in your Azure environment.\n    \u003cbr /\u003e\n    \u003ca href=\"https://github.com/thgossler/AzSaveMoney/issues\"\u003eReport Bug\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/thgossler/AzSaveMoney/issues\"\u003eRequest Feature\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/thgossler/AzSaveMoney#contributing\"\u003eContribute\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/sponsors/thgossler\"\u003eSponsor project\u003c/a\u003e\n    ·\n    \u003ca href=\"https://www.paypal.com/donate/?hosted_button_id=JVG7PFJ8DMW7J\"\u003eSponsor via PayPal\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n## Overview\n\nThis project is intended to clean up large Azure environments and save money and energy in the process. It was inspired by the project [`itoleck/AzureSaveMoney`](https://github.com/itoleck/AzureSaveMoney) but is not derived from it.\n\nThe script [`MarkAndDeleteUnusedResources.ps1`](MarkAndDeleteUnusedResources.ps1) checks all Azure resources and resource groups across all subscriptions and eventually tags them as subject for deletion or deletes them automatically (after confirmation, configurable). Based on the value of the tag, suspicious resources can be confirmed or rejected as subject for deletion and will be considered accordingly in subsequent runs.\n\n\u003e **Note**: The script supports the -WhatIf parameter to first simulate what it would do. And it was also implemented to be defensive, i.e. by default only empty resource groups are deleted (and only after confirmation), nothing else.\n\nExample usage:\n\n```powershell\n# Display usage help\nGet-Help .\\MarkAndDeleteUnusedResources.ps1 -Detailed\n```\n\n```powershell\n# Simulate execution on all subscriptions in the default directory of the AzureCloud environment\n. .\\MarkAndDeleteUnusedResources.ps1 -WhatIf\n```\n\n```powershell\n# Execute on all subscriptions in the default directory of the AzureCloud environment.\n# The parameter UseDeviceAuthentication allows indirect user sign-in with device code, e.g.\n# in a devcontainer where the web browser cannot used.\n. .\\MarkAndDeleteUnusedResources.ps1 -UseDeviceAuthentication\n```\n\n```powershell\n# Execute on all subscriptions in the default directory of the AzureCloud environment.\n# The parameter ServicePrincipalCredential allows sign-in with a service principal.\n$appId = 'f246e0a1-5996-4a2f-971d-c6d4da41510e'\n$secret = (ConvertTo-SecureString -String '...' -AsPlainText)  # secret must not be in source code, just for illustration!\n$cred = (New-Object System.Management.Automation.PSCredential $appId, $secret)\n. .\\MarkAndDeleteUnusedResources.ps1 -ServicePrincipalCredential $cred\n```\n\n```powershell\n# Execute on one subscription in the specified directory of the AzureChinaCloud environment\n. .\\MarkAndDeleteUnusedResources.ps1 `\n      -DirectoryId 'e0fe770b-8e36-4af1-9b67-4cda0ebe97e0' `\n      -AzEnvironment 'AzureChinaCloud' `\n      -SubscriptionIdsToProcess @(\"e6229d85-f212-44a3-b9f2-c0bd3394c833\") `\n      -TryMakingUserContributorTemporarily `\n      -DisableTimeoutForDeleteConfirmationPrompt\n```\n\nExample output:\n![Example output](images/Screenshot.png)\n\nExample tags:\n![Example tags](images/Screenshot4.png)\n\nThe script was intentionally written in a single file to ensure ease of use across various environments. The log output is written to the host using colors to improve human readability.\n\nThe default values for some parameters can be specified in a config file named `Defaults.json`.\n\nThe script implements function hooks named for each supported resource type/kind. Function hooks determine for a specific resource which action shall be taken. The naming convention for hooks is `Test-ResourceActionHook-\u003cresourceType\u003e[-\u003cresourceKind\u003e]`. New hooks can easily be added by implementing a new function and will be discovered and called automatically. New hooks should be inserted after the marker `[ADD NEW HOOKS HERE]`.\n\nExample hook function:\n![Example hook function](images/Screenshot3.png)\n\nThere are multiple tags which are set when a resource is marked as  subject for deletion (tag names are configurable):\n`SubjectForDeletion`,\n`SubjectForDeletion-FindingDate`,\n`SubjectForDeletion-Reason` and\n`SubjectForDeletion-Hint` (optional).\n\nThe `SubjectForDeletion` tag has one of the following values after the script ran and the tag was created:\n\n- `suspected`: resource marked as subject for deletion\n- `suspectedSubResources`: at least one sub resource is subject for deletion\n\nAs long as the tag `SubjectForDeletion` has a value starting with `suspected...` the resource is reevaluated in every run and the tag value is updated (overwritten). You can update the tag value to one of the following values in order to influence the script behavior in subsequent runs (see below).\n\nHere is a sample Azure Resource Graph query that identifies all resources suspected to be unused:\n\n```kusto\nresources \n| where tags['SubjectForDeletion'] != '' and tags['SubjectForDeletion'] startswith 'suspected'\n| project name, type, subjectForDeletionReason=tags['SubjectForDeletion-Reason'], resourceGroup, subscriptionId, id\n| sort by name asc \n```\n\nThe following process is recommended for large organizations:\n\n1. **RUN** the script regularly\n2. **ALERT** `suspected` or `suspectedSubResources` resources to resource owners\n3. **MANUAL RESOLUTION** by owners by reviewing and changing the `SubjectForDeletion` tag value to one of the following predefined terms (case-sensitive!):\n   - `rejected`: Resource is needed and shall NOT be deleted (this status will not be overwritten in subsequent runs, except if configured to be reset e.g. every 6 months after `SubjectForDeletion-FindingDate`)\n   - `confirmed`: Resource shall be deleted (will be automatically deleted in the next run)\n4. **AUTO-DELETION/REEVALUATION**: Subsequent script runs will check all resources again with the following special handling for status:\n   - `confirmed`: resource will be deleted\n   - `suspected`: if `SubjectForDeletion-FindingDate` is older that 30 days (e.g. resource was not reviewed in time), the resource will be automatically deleted\n\nThe script [`RemoveTagsFromAllResourcesAndGroups.ps1`](RemoveTagsFromAllResourcesAndGroups.ps1) can be used to remove all tags again.\n\n## Contributing\n\nContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.\n\nIf you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag \"enhancement\".\nDon't forget to give the project a star :wink: Thanks!\n\n1. Fork the Project\n2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the Branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\n## Donate\n\nIf you are using the tool but are unable to contribute technically, please consider promoting it and donating an amount that reflects its value to you. You can do so either via PayPal\n\n[![Donate via PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=JVG7PFJ8DMW7J)\n\nor via [GitHub Sponsors](https://github.com/sponsors/thgossler).\n\n## License\n\nDistributed under the MIT License. See [`LICENSE`](https://github.com/thgossler/AzSaveMoney/blob/main/LICENSE) for more information.\n\n\u003c!-- MARKDOWN LINKS \u0026 IMAGES (https://www.markdownguide.org/basic-syntax/#reference-style-links) --\u003e\n[contributors-shield]: https://img.shields.io/github/contributors/thgossler/AzSaveMoney.svg\n[contributors-url]: https://github.com/thgossler/AzSaveMoney/graphs/contributors\n[forks-shield]: https://img.shields.io/github/forks/thgossler/AzSaveMoney.svg\n[forks-url]: https://github.com/thgossler/AzSaveMoney/network/members\n[stars-shield]: https://img.shields.io/github/stars/thgossler/AzSaveMoney.svg\n[stars-url]: https://github.com/thgossler/AzSaveMoney/stargazers\n[issues-shield]: https://img.shields.io/github/issues/thgossler/AzSaveMoney.svg\n[issues-url]: https://github.com/thgossler/AzSaveMoney/issues\n[license-shield]: https://img.shields.io/github/license/thgossler/AzSaveMoney.svg\n[license-url]: https://github.com/thgossler/AzSaveMoney/blob/main/LICENSE\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthgossler%2Fazsavemoney","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthgossler%2Fazsavemoney","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthgossler%2Fazsavemoney/lists"}