├── docs ├── README.md └── wiki │ ├── Releases.md │ ├── Tests.md │ ├── .gitignore │ ├── GitHub-Packages.md │ ├── PowerShell.md │ ├── Visual-Studio-Code.md │ ├── Media │ ├── FAQ │ │ ├── pr.png │ │ ├── delete_deployments.png │ │ └── existing_pr_error.png │ ├── Folders.png │ ├── Hierachy.png │ ├── Pipelines │ │ ├── RG.PNG │ │ ├── SPN.PNG │ │ ├── Var.png │ │ ├── Pull.PNG │ │ ├── State.PNG │ │ ├── Import.png │ │ ├── Library.png │ │ ├── azopslib.png │ │ ├── Pipelines.PNG │ │ ├── Merge-Types.png │ │ ├── Permission1.PNG │ │ ├── Subscription.PNG │ │ ├── SwitchBranch.png │ │ ├── Azure-repo-git.PNG │ │ ├── Branch-Policies.png │ │ ├── Branch-policy-1.PNG │ │ ├── CreatePipeline.png │ │ ├── Delete-Actions.png │ │ ├── Repository-Perm.PNG │ │ ├── Subscription-2.PNG │ │ ├── Variable-Group.png │ │ ├── Build-validation.PNG │ │ ├── Existing-Pipeline.PNG │ │ ├── Import-Repository.png │ │ ├── Pipeline-Creation.png │ │ ├── Pipeline-Variables.png │ │ ├── Project-Creation.png │ │ ├── Pull-Push-Pipeline.PNG │ │ ├── Repository-Perm-2.PNG │ │ ├── Pull-Request-Verify.png │ │ ├── Remove-Github-Folder.PNG │ │ ├── Azure-DevOps-repository.PNG │ │ ├── Environment-Approvals.png │ │ ├── Repository-Permissions.png │ │ ├── Azure-DevOps-repository-2.png │ │ ├── Pipeline-Permissions-View.PNG │ │ ├── ado_environment_variable.png │ │ ├── Azure-DevOps-repository-URL.PNG │ │ └── Auto-Generated-Template-FolderPath.PNG │ ├── Subscriptions.png │ ├── Feeds │ │ └── New-Feed.png │ ├── Actions │ │ ├── GIT-Merge.PNG │ │ ├── GIT-Secret.PNG │ │ ├── Import-GIT.PNG │ │ ├── Root-GIT.PNG │ │ ├── workflow.PNG │ │ ├── GIT-Project.PNG │ │ ├── Merge-Types.png │ │ ├── GIT-Project-2.PNG │ │ ├── GIT-Repository.PNG │ │ ├── Open-code-Invs.PNG │ │ ├── Usetemplate-GIT.PNG │ │ ├── Reopen-In-Container.PNG │ │ ├── Repository-Secrets.png │ │ ├── Template-Repository.png │ │ ├── GIT-ActionPermissions.PNG │ │ ├── Repository-Configuration.png │ │ └── github_environment_secret.png │ ├── Contribution │ │ ├── Debug.PNG │ │ ├── Root.PNG │ │ ├── Open-code-Invs.PNG │ │ └── Reopen-In-Container.PNG │ ├── Implementation-Scope.png │ ├── AdjustingThrottleLimit.png │ ├── oidc │ │ ├── arm_client_secret.png │ │ └── remove-ado-arm_cs.png │ ├── Monitoring │ │ ├── transactionsearch.png │ │ ├── exception_condition.png │ │ └── logsearch_condition.png │ ├── ExtendedChildResources │ │ ├── settingfile.PNG │ │ └── ExtendedChildResourcesDiscovery.PNG │ └── ResourceDeletion │ │ ├── ResourceDeletion_RBAC_File.PNG │ │ ├── ResourceDeletion_workflow.PNG │ │ ├── ResourceDeletion_RBAC_portal.PNG │ │ ├── ResourceDeletion_intial_Pull.PNG │ │ ├── ResourceDeletion_RBAC_portal1.PNG │ │ ├── ResourceDeletion_azpolicy_File.PNG │ │ ├── ResourceDeletion_pipelineupdate.PNG │ │ ├── ResourceDeletion_azpolicy_portal.PNG │ │ ├── ResourceDeletion_azpolicy_portal1.PNG │ │ ├── ResourceDeletion_Pull_Request_merge.PNG │ │ ├── ResourceDeletion_Pull_Request_review.PNG │ │ ├── ResourceDeletion_Pull_Request_status.PNG │ │ ├── ResourceDeletion_azops_push_pipeline.PNG │ │ ├── ResourceDeletion_Pull_Request_creation.PNG │ │ ├── ResourceDeletion_azops_validate_pipeline.PNG │ │ └── ResourceDeletion_AutoGeneratedTemplateFolderPath.PNG │ ├── Roadmap.md │ ├── Feeds.md │ ├── Services.md │ ├── _Footer.md │ ├── Home.md │ ├── Sovereign-Clouds.md │ ├── Updates.md │ ├── Troubleshooting.md │ ├── _Sidebar.md │ └── Custom-Jq-Templates.md ├── src ├── README.md ├── data │ ├── README.md │ ├── template │ │ ├── Microsoft.Network │ │ │ ├── virtualwans.jq │ │ │ └── virtualnetworks.jq │ │ ├── Microsoft.Authorization │ │ │ ├── roleAssignments.jq │ │ │ ├── roleDefinitions.jq │ │ │ ├── policyExemptions.jq │ │ │ ├── roleEligibilityScheduleRequests.jq │ │ │ ├── policySetDefinitions.jq │ │ │ ├── policyAssignments.jq │ │ │ ├── locks.template.jq │ │ │ ├── policyDefinitions.jq │ │ │ └── roleEligibilityScheduleRequests.template.jq │ │ ├── Microsoft.Keyvault │ │ │ └── vaults.jq │ │ ├── template.parameters.jq │ │ ├── Microsoft.Storage │ │ │ └── storageaccounts.jq │ │ ├── templateChildResource.jq │ │ ├── generic.jq │ │ ├── Microsoft.Management │ │ │ ├── managementGroups │ │ │ │ └── subscriptions.template.jq │ │ │ └── managementGroups.template.jq │ │ ├── Microsoft.Resources │ │ │ └── resourcegroups.template.jq │ │ ├── Microsoft.Subscription │ │ │ └── subscriptions.template.jq │ │ └── template.jq │ └── auxiliary │ │ ├── providerfeatures.json │ │ └── resourceproviders.json ├── internal │ ├── classes │ │ ├── README.md │ │ └── AzOpsRoleEligibilityScheduleRequest.ps1 │ ├── scriptblocks │ │ ├── README.md │ │ └── ScriptBlocks.ps1 │ ├── tepp │ │ ├── Example.tepp.ps1 │ │ ├── Assignment.ps1 │ │ └── README.md │ ├── scripts │ │ ├── Initialize.ps1 │ │ ├── Strings.ps1 │ │ ├── Variables.ps1 │ │ ├── PreImport.ps1 │ │ ├── Validations.ps1 │ │ ├── PostImport.ps1 │ │ └── License.ps1 │ ├── functions │ │ ├── README.md │ │ ├── Get-AzOpsPim.ps1 │ │ ├── Set-AzOpsContext.ps1 │ │ ├── Get-AzOpsRole.ps1 │ │ ├── Assert-AzOpsBicepDependency.ps1 │ │ ├── Get-AzOpsNestedSubscription.ps1 │ │ ├── Invoke-AzOpsRestMethod.ps1 │ │ ├── Invoke-AzOpsNativeCommand.ps1 │ │ ├── Assert-AzOpsJqDependency.ps1 │ │ ├── Get-AzOpsCurrentPrincipal.ps1 │ │ ├── Set-AzOpsRemoveOrder.ps1 │ │ ├── Assert-AzOpsInitialization.ps1 │ │ ├── Get-AzOpsPolicyDefinition.ps1 │ │ ├── Assert-AzOpsWindowsLongPath.ps1 │ │ ├── Get-AzOpsPolicySetDefinition.ps1 │ │ ├── Register-AzOpsResourceProvider.ps1 │ │ ├── Register-AzOpsProviderFeature.ps1 │ │ ├── Get-AzOpsResourceLock.ps1 │ │ ├── Get-AzOpsManagementGroup.ps1 │ │ └── Remove-AzOpsInvalidCharacter.ps1 │ └── configurations │ │ └── README.md ├── tests │ ├── templates │ │ ├── rtsuffix0102.01.bicepparam │ │ ├── rtmultibase.xabc.bicepparam │ │ ├── staparalleldeploy.xabcd.bicepparam │ │ ├── staparalleldeploy.xabcde.bicepparam │ │ ├── staparalleldeploy.xabcdf.bicepparam │ │ ├── staserialdeploy2.xabcdfg.bicepparam │ │ ├── deployallrtbase.xabc.bicepparam │ │ ├── bicepparamtest.bicepparam │ │ ├── deployallrt.westeurope.xabc.bicepparam │ │ ├── deploystacksatmg.x1.bicepparam │ │ ├── deploystacksatmg.x1.deploymentStacks.json │ │ ├── deploystacksatsub.bicepparam │ │ ├── deploystacksatrg.deploymentStacks.json │ │ ├── deploystacksatsubrename.deploymentStacks.json │ │ ├── deploystacksatsub.deploymentStacks.json │ │ ├── rtsuffix0102.02.parameters.json │ │ ├── decoy.westeurope.x123.parameters.json │ │ ├── rtmultibase.x123.parameters.json │ │ ├── deployallrtbase.x123.parameters.json │ │ ├── deployallrt.westeurope.x123.parameters.json │ │ ├── policywithuam.bicepparam │ │ ├── customlockdelete.bicep │ │ ├── rgdualdeploy.bicep │ │ ├── bicepparamtest.bicep │ │ ├── rgsubonlydeploy.bicep │ │ ├── deployallrtbase.bicep │ │ ├── rtmultibase.bicep │ │ ├── rtsuffix0102.bicep │ │ ├── decoy.westeurope.bicep │ │ ├── deployallrt.westeurope.bicep │ │ ├── rtcustomdelete.parameters.json │ │ ├── deploystacksatrg.bicep │ │ ├── biceptest.bicep │ │ ├── deployallrt2.westeurope.bicep │ │ ├── deploystacksatmg.bicep │ │ ├── deploystacksatsub.bicep │ │ ├── rgdualdeploy.parameters.json │ │ ├── biceptest.parameters.json │ │ ├── rgsubonlydeploy.parameters.json │ │ ├── stasubonlydeploy.bicep │ │ ├── biceperror.bicep │ │ ├── staparalleldeploy.bicep │ │ ├── staserialdeploy2.bicep │ │ ├── rbactest.parameters.json │ │ ├── policywithuam.bicep │ │ ├── rbactest.bicep │ │ ├── rtcustomdelete.bicep │ │ ├── pushmgmttest1displayname (pushmgmttest1id) │ │ │ └── microsoft.management_managementgroups-pushmgmttest1id.json │ │ └── pushmgmttest2displayname (pushmgmttest2id) │ │ │ └── microsoft.management_managementgroups-pushmgmttest2id.json │ ├── functions │ │ ├── README.md │ │ └── Set-AzOpsRemoveOrder.Tests.ps1 │ ├── functional │ │ ├── Microsoft.Resources │ │ │ └── resourceGroups │ │ │ │ └── deploy │ │ │ │ ├── deploy.bicep │ │ │ │ └── deploy.ps1 │ │ ├── Microsoft.ManagedIdentity │ │ │ └── userAssignedIdentities │ │ │ │ └── deploy │ │ │ │ ├── deploy.parameters.json │ │ │ │ ├── deploy.ps1 │ │ │ │ └── deploy.json │ │ ├── Microsoft.Network │ │ │ ├── privateDnsZones │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.parameters.json │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.json │ │ │ ├── publicIPAddresses │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.parameters.json │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.json │ │ │ ├── networkSecurityGroups │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.parameters.json │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.json │ │ │ ├── azureFirewalls │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.parameters.json │ │ │ ├── bastionHosts │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.parameters.json │ │ │ ├── routeTables │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ ├── deploy.parameters.json │ │ │ │ │ └── deploy.json │ │ │ ├── virtualNetworks │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.parameters.json │ │ │ ├── connections │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.parameters.json │ │ │ ├── networkInterfaces │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.parameters.json │ │ │ ├── localNetworkGateways │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.parameters.json │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.json │ │ │ └── privateEndpoints │ │ │ │ └── deploy │ │ │ │ ├── deploy.ps1 │ │ │ │ └── deploy.parameters.json │ │ ├── Microsoft.Management │ │ │ └── managementGroups │ │ │ │ └── deploy │ │ │ │ ├── deploy.bicep │ │ │ │ └── deploy.ps1 │ │ ├── Microsoft.Web │ │ │ ├── sites │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.bicep │ │ │ └── serverfarms │ │ │ │ └── deploy │ │ │ │ ├── deploy.ps1 │ │ │ │ └── deploy.bicep │ │ ├── Microsoft.KeyVault │ │ │ └── vaults │ │ │ │ └── deploy │ │ │ │ ├── deploy.ps1 │ │ │ │ └── deploy.bicep │ │ ├── Microsoft.Storage │ │ │ └── storageAccounts │ │ │ │ └── deploy │ │ │ │ ├── deploy.ps1 │ │ │ │ └── deploy.bicep │ │ ├── Microsoft.Authorization │ │ │ ├── policyAssignments │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.bicep │ │ │ ├── roleAssignments │ │ │ │ └── deploy │ │ │ │ │ ├── deploy.ps1 │ │ │ │ │ └── deploy.bicep │ │ │ └── roleEligibilityScheduleRequests │ │ │ │ └── deploy │ │ │ │ ├── deploy.parameters.json │ │ │ │ ├── deploy.ps1 │ │ │ │ └── deploy.json │ │ ├── Microsoft.Logic │ │ │ └── workflows │ │ │ │ └── deploy │ │ │ │ ├── deploy.ps1 │ │ │ │ └── deploy.parameters.json │ │ ├── Microsoft.Compute │ │ │ └── virtualMachines │ │ │ │ └── deploy │ │ │ │ ├── deploy.ps1 │ │ │ │ └── deploy.parameters.json │ │ └── Microsoft.Insights │ │ │ └── activityLogAlerts │ │ │ └── deploy │ │ │ ├── deploy.ps1 │ │ │ └── deploy.parameters.json │ ├── general │ │ ├── Strings.Exceptions.ps1 │ │ ├── Help.Exceptions.ps1 │ │ ├── FileIntegrity.Exceptions.ps1 │ │ ├── PSScriptAnalyzer.Tests.ps1 │ │ └── Strings.Tests.ps1 │ └── README.md ├── localized │ └── en-us │ │ └── about_AzOps.help.txt ├── functions │ └── README.md ├── bin │ └── README.md └── xml │ ├── AzOps.Types.ps1xml │ ├── AzOps.Format.ps1xml │ └── README.md ├── .gitconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── FEATURE_REQUEST.md │ └── BUG_REPORT.md ├── workflows │ ├── activateFabricBot.yml │ ├── super-linter.yml │ ├── dependencies.yml │ ├── wiki-sync.yml │ └── release.yml ├── PULL_REQUEST_TEMPLATE.md └── linters │ └── .markdown-lint.yml ├── .vscode └── launch.json ├── CODE_OF_CONDUCT.md ├── .gitignore ├── scripts ├── Debug.ps1 ├── Version.ps1 ├── UpdateRequiredModules.ps1 └── Dependencies.ps1 ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── LICENSE ├── SUPPORT.md └── SECURITY.md /docs/README.md: -------------------------------------------------------------------------------- 1 | # docs/ 2 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # src/ 2 | -------------------------------------------------------------------------------- /src/data/README.md: -------------------------------------------------------------------------------- 1 | # data/ -------------------------------------------------------------------------------- /docs/wiki/Releases.md: -------------------------------------------------------------------------------- 1 | _Coming soon_ -------------------------------------------------------------------------------- /docs/wiki/Tests.md: -------------------------------------------------------------------------------- 1 | _Coming soon_ 2 | -------------------------------------------------------------------------------- /docs/wiki/.gitignore: -------------------------------------------------------------------------------- 1 | # System 2 | .DS_Store -------------------------------------------------------------------------------- /docs/wiki/GitHub-Packages.md: -------------------------------------------------------------------------------- 1 | _Coming soon_ -------------------------------------------------------------------------------- /docs/wiki/PowerShell.md: -------------------------------------------------------------------------------- 1 | _Coming soon_ 2 | -------------------------------------------------------------------------------- /src/internal/classes/README.md: -------------------------------------------------------------------------------- 1 | # classes/ 2 | -------------------------------------------------------------------------------- /docs/wiki/Visual-Studio-Code.md: -------------------------------------------------------------------------------- 1 | _Coming soon_ 2 | -------------------------------------------------------------------------------- /src/internal/scriptblocks/README.md: -------------------------------------------------------------------------------- 1 | # scriptblocks/ 2 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [core] 2 | longpaths = true 3 | filemode = false 4 | -------------------------------------------------------------------------------- /src/data/template/Microsoft.Network/virtualwans.jq: -------------------------------------------------------------------------------- 1 | del(.properties.provisioningState) 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.json text eol=lf 4 | *.jq text eol=lf 5 | *.sh text eol=lf -------------------------------------------------------------------------------- /docs/wiki/Media/FAQ/pr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/FAQ/pr.png -------------------------------------------------------------------------------- /docs/wiki/Media/Folders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Folders.png -------------------------------------------------------------------------------- /docs/wiki/Media/Hierachy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Hierachy.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/RG.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/RG.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/SPN.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/SPN.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Var.png -------------------------------------------------------------------------------- /docs/wiki/Media/Subscriptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Subscriptions.png -------------------------------------------------------------------------------- /src/tests/templates/rtsuffix0102.01.bicepparam: -------------------------------------------------------------------------------- 1 | using 'rtsuffix0102.bicep' 2 | 3 | param name = 'rtsuffix01' 4 | -------------------------------------------------------------------------------- /docs/wiki/Media/Feeds/New-Feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Feeds/New-Feed.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Pull.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Pull.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/State.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/State.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/GIT-Merge.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/GIT-Merge.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/GIT-Secret.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/GIT-Secret.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Import-GIT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Import-GIT.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Root-GIT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Root-GIT.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/workflow.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/workflow.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Contribution/Debug.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Contribution/Debug.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Contribution/Root.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Contribution/Root.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Import.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Library.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/azopslib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/azopslib.png -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/GIT-Project.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/GIT-Project.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Merge-Types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Merge-Types.png -------------------------------------------------------------------------------- /docs/wiki/Media/Implementation-Scope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Implementation-Scope.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Pipelines.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Pipelines.PNG -------------------------------------------------------------------------------- /src/tests/templates/rtmultibase.xabc.bicepparam: -------------------------------------------------------------------------------- 1 | using './rtmultibase.bicep' 2 | 3 | param name = toLower('rtmultibasexabc') 4 | -------------------------------------------------------------------------------- /src/tests/templates/staparalleldeploy.xabcd.bicepparam: -------------------------------------------------------------------------------- 1 | using './staparalleldeploy.bicep' 2 | 3 | param staName = 'p1azops' 4 | -------------------------------------------------------------------------------- /src/tests/templates/staparalleldeploy.xabcde.bicepparam: -------------------------------------------------------------------------------- 1 | using './staparalleldeploy.bicep' 2 | 3 | param staName = 'p2azops' 4 | -------------------------------------------------------------------------------- /src/tests/templates/staparalleldeploy.xabcdf.bicepparam: -------------------------------------------------------------------------------- 1 | using './staparalleldeploy.bicep' 2 | 3 | param staName = 'p3azops' 4 | -------------------------------------------------------------------------------- /src/tests/templates/staserialdeploy2.xabcdfg.bicepparam: -------------------------------------------------------------------------------- 1 | using './staserialdeploy2.bicep' 2 | 3 | param staName = 's1azops' 4 | -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/GIT-Project-2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/GIT-Project-2.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/GIT-Repository.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/GIT-Repository.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Open-code-Invs.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Open-code-Invs.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Usetemplate-GIT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Usetemplate-GIT.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/AdjustingThrottleLimit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/AdjustingThrottleLimit.png -------------------------------------------------------------------------------- /docs/wiki/Media/FAQ/delete_deployments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/FAQ/delete_deployments.png -------------------------------------------------------------------------------- /docs/wiki/Media/FAQ/existing_pr_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/FAQ/existing_pr_error.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Merge-Types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Merge-Types.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Permission1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Permission1.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Subscription.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Subscription.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/SwitchBranch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/SwitchBranch.png -------------------------------------------------------------------------------- /docs/wiki/Media/oidc/arm_client_secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/oidc/arm_client_secret.png -------------------------------------------------------------------------------- /docs/wiki/Media/oidc/remove-ado-arm_cs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/oidc/remove-ado-arm_cs.png -------------------------------------------------------------------------------- /src/internal/tepp/Example.tepp.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | # Example: 3 | Register-PSFTeppScriptblock -Name "AzOps.Test" -ScriptBlock { 'Test' } 4 | #> -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Azure-repo-git.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Azure-repo-git.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Branch-Policies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Branch-Policies.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Branch-policy-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Branch-policy-1.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/CreatePipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/CreatePipeline.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Delete-Actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Delete-Actions.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Repository-Perm.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Repository-Perm.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Subscription-2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Subscription-2.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Variable-Group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Variable-Group.png -------------------------------------------------------------------------------- /docs/wiki/Roadmap.md: -------------------------------------------------------------------------------- 1 | ## Roadmap 2 | 3 | Up to date project tracking can be found [here](https://github.com/Azure/AzOps/projects/2) 4 | -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Reopen-In-Container.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Reopen-In-Container.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Repository-Secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Repository-Secrets.png -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Template-Repository.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Template-Repository.png -------------------------------------------------------------------------------- /docs/wiki/Media/Contribution/Open-code-Invs.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Contribution/Open-code-Invs.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Monitoring/transactionsearch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Monitoring/transactionsearch.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Build-validation.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Build-validation.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Existing-Pipeline.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Existing-Pipeline.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Import-Repository.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Import-Repository.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Pipeline-Creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Pipeline-Creation.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Pipeline-Variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Pipeline-Variables.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Project-Creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Project-Creation.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Pull-Push-Pipeline.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Pull-Push-Pipeline.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Repository-Perm-2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Repository-Perm-2.PNG -------------------------------------------------------------------------------- /src/internal/tepp/Assignment.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | # Example: 3 | Register-PSFTeppArgumentCompleter -Command Get-Test -Parameter Type -Name AzOps.x 4 | #> -------------------------------------------------------------------------------- /src/tests/templates/deployallrtbase.xabc.bicepparam: -------------------------------------------------------------------------------- 1 | using './deployallrtbase.bicep' 2 | 3 | param name = toLower('deployallrtbasexabc') 4 | -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/GIT-ActionPermissions.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/GIT-ActionPermissions.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Monitoring/exception_condition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Monitoring/exception_condition.png -------------------------------------------------------------------------------- /docs/wiki/Media/Monitoring/logsearch_condition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Monitoring/logsearch_condition.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Pull-Request-Verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Pull-Request-Verify.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Remove-Github-Folder.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Remove-Github-Folder.PNG -------------------------------------------------------------------------------- /src/tests/templates/bicepparamtest.bicepparam: -------------------------------------------------------------------------------- 1 | using './bicepparamtest.bicep' 2 | 3 | param name = 'rt666' 4 | param location = 'northeurope' 5 | -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/Repository-Configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/Repository-Configuration.png -------------------------------------------------------------------------------- /docs/wiki/Media/Actions/github_environment_secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Actions/github_environment_secret.png -------------------------------------------------------------------------------- /docs/wiki/Media/Contribution/Reopen-In-Container.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Contribution/Reopen-In-Container.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Azure-DevOps-repository.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Azure-DevOps-repository.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Environment-Approvals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Environment-Approvals.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Repository-Permissions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Repository-Permissions.png -------------------------------------------------------------------------------- /src/tests/templates/deployallrt.westeurope.xabc.bicepparam: -------------------------------------------------------------------------------- 1 | using './deployallrt.westeurope.bicep' 2 | 3 | param name = toLower('deployallrtwexabc') 4 | -------------------------------------------------------------------------------- /docs/wiki/Media/ExtendedChildResources/settingfile.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ExtendedChildResources/settingfile.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Azure-DevOps-repository-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Azure-DevOps-repository-2.png -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Pipeline-Permissions-View.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Pipeline-Permissions-View.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/ado_environment_variable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/ado_environment_variable.png -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/roleAssignments.jq: -------------------------------------------------------------------------------- 1 | del(.properties.createdOn, .properties.updatedOn, .properties.createdBy, .properties.updatedBy) -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/roleDefinitions.jq: -------------------------------------------------------------------------------- 1 | del(.properties.createdOn, .properties.updatedOn, .properties.createdBy, .properties.updatedBy) -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Azure-DevOps-repository-URL.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Azure-DevOps-repository-URL.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_RBAC_File.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_RBAC_File.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_workflow.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_workflow.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/Pipelines/Auto-Generated-Template-FolderPath.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/Pipelines/Auto-Generated-Template-FolderPath.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_RBAC_portal.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_RBAC_portal.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_intial_Pull.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_intial_Pull.PNG -------------------------------------------------------------------------------- /src/data/auxiliary/providerfeatures.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "FeatureName": "", 4 | "ProviderName": "", 5 | "RegistrationState": "" 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /src/data/auxiliary/resourceproviders.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ProviderNamespace": "Microsoft.Security", 4 | "RegistrationState": "Registered" 5 | } 6 | 7 | ] -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_RBAC_portal1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_RBAC_portal1.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_azpolicy_File.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_azpolicy_File.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_pipelineupdate.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_pipelineupdate.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_azpolicy_portal.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_azpolicy_portal.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_azpolicy_portal1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_azpolicy_portal1.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_Pull_Request_merge.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_Pull_Request_merge.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_Pull_Request_review.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_Pull_Request_review.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_Pull_Request_status.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_Pull_Request_status.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_azops_push_pipeline.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_azops_push_pipeline.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ExtendedChildResources/ExtendedChildResourcesDiscovery.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ExtendedChildResources/ExtendedChildResourcesDiscovery.PNG -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_Pull_Request_creation.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_Pull_Request_creation.PNG -------------------------------------------------------------------------------- /docs/wiki/Feeds.md: -------------------------------------------------------------------------------- 1 | ### In this section 2 | 3 | - [Azure Artifacts](https://github.com/azure/azops/wiki/azure-artifacts) 4 | - [GitHub Packages](https://github.com/azure/azops/wiki/github-packages) 5 | -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_azops_validate_pipeline.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_azops_validate_pipeline.PNG -------------------------------------------------------------------------------- /docs/wiki/Services.md: -------------------------------------------------------------------------------- 1 | ### In this section 2 | 3 | - [GitHub Actions](https://github.com/azure/azops/wiki/github-actions) 4 | - [Azure Pipelines](https://github.com/azure/azops/wiki/azure-pipelines) 5 | -------------------------------------------------------------------------------- /src/data/template/Microsoft.Keyvault/vaults.jq: -------------------------------------------------------------------------------- 1 | del(.id, .resourceId, .identity, .kind, .resourceName, .extensionResourceName, .parentResource, .plan, .properties.provisioningState, .properties.vaultUri) -------------------------------------------------------------------------------- /src/data/template/Microsoft.Network/virtualnetworks.jq: -------------------------------------------------------------------------------- 1 | del(.. | .resourceGuid?, .resourceId?, .identity?, .kind?, .resourceName?, .extensionResourceName?, .parentResource?, .plan?, .etag? , .provisioningState?) -------------------------------------------------------------------------------- /docs/wiki/Media/ResourceDeletion/ResourceDeletion_AutoGeneratedTemplateFolderPath.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/AzOps/HEAD/docs/wiki/Media/ResourceDeletion/ResourceDeletion_AutoGeneratedTemplateFolderPath.PNG -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # See for instructions on this file https://help.github.com/articles/about-codeowners/ 2 | 3 | * @azure/azops-admins @azure/azops-extended-core-maintainers 4 | 5 | .github/CODEOWNERS @azure/azops-admins -------------------------------------------------------------------------------- /src/internal/scripts/Initialize.ps1: -------------------------------------------------------------------------------- 1 | Set-PSFFeature -Name PSFramework.Stop-PSFFunction.ShowWarning -Value $true -ModuleName AzOps 2 | 3 | if ([runspace]::DefaultRunspace.Id -eq 1) { 4 | Initialize-AzOpsEnvironment 5 | } -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatmg.x1.bicepparam: -------------------------------------------------------------------------------- 1 | using './deploystacksatmg.bicep' 2 | 3 | param policyDefinitionIdstring = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' 4 | -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatmg.x1.deploymentStacks.json: -------------------------------------------------------------------------------- 1 | { 2 | "actionOnUnmanage": "deleteAll", 3 | "bypassStackOutOfSyncError": true, 4 | "denySettingsMode": "none", 5 | "excludedAzOpsFiles": [] 6 | } -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatsub.bicepparam: -------------------------------------------------------------------------------- 1 | using './deploystacksatsub.bicep' 2 | 3 | param policyDefinitionIdstring = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' 4 | -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatrg.deploymentStacks.json: -------------------------------------------------------------------------------- 1 | { 2 | "actionOnUnmanage": "deleteResources", 3 | "bypassStackOutOfSyncError": true, 4 | "denySettingsMode": "denyDelete", 5 | "excludedAzOpsFiles": [] 6 | } -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatsubrename.deploymentStacks.json: -------------------------------------------------------------------------------- 1 | { 2 | "actionOnUnmanage": "deleteAll", 3 | "bypassStackOutOfSyncError": true, 4 | "denySettingsMode": "denyDelete", 5 | "excludedAzOpsFiles": [] 6 | } -------------------------------------------------------------------------------- /src/localized/en-us/about_AzOps.help.txt: -------------------------------------------------------------------------------- 1 | TOPIC 2 | about_AzOps 3 | 4 | SHORT DESCRIPTION 5 | Explains how to use the AzOps powershell module 6 | 7 | LONG DESCRIPTION 8 | 9 | 10 | KEYWORDS 11 | AzOps -------------------------------------------------------------------------------- /src/functions/README.md: -------------------------------------------------------------------------------- 1 | # functions/ 2 | 3 | This is the folder where the functions go. 4 | 5 | Depending on the complexity of the module, it is recommended to subdivide them into subfolders. 6 | 7 | The module will pick up all .ps1 files recursively -------------------------------------------------------------------------------- /src/tests/functions/README.md: -------------------------------------------------------------------------------- 1 | # functions/ 2 | 3 | This is where the function tests go. 4 | 5 | Make sure to put them in folders reflecting the actual module structure. 6 | 7 | It is not necessary to differentiate between internal and public functions here. 8 | -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/policyExemptions.jq: -------------------------------------------------------------------------------- 1 | del(.ResourceId, .resourceGroup, .subscriptionId, .properties.metadata.createdOn, .properties.metadata.updatedOn, .properties.metadata.createdBy, .properties.metadata.updatedBy, .properties.metadata.assignedBy) -------------------------------------------------------------------------------- /src/internal/functions/README.md: -------------------------------------------------------------------------------- 1 | # functions/ 2 | 3 | This is the folder where the internal functions go. 4 | 5 | Depending on the complexity of the module, it is recommended to subdivide them into subfolders. 6 | 7 | The module will pick up all .ps1 files recursively -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatsub.deploymentStacks.json: -------------------------------------------------------------------------------- 1 | { 2 | "actionOnUnmanage": "detachAll", 3 | "bypassStackOutOfSyncError": true, 4 | "denySettingsMode": "denyDelete", 5 | "excludedAzOpsFiles": [ 6 | "deploystacksatsub.bicep" 7 | ] 8 | } -------------------------------------------------------------------------------- /src/tests/templates/rtsuffix0102.02.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "rtsuffix02" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/tests/templates/decoy.westeurope.x123.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "decoywex123" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/tests/templates/rtmultibase.x123.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "rtmultibasex123" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/tests/templates/deployallrtbase.x123.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "deployallrtbasex123" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/tests/templates/deployallrt.westeurope.x123.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "deployallrtwex123" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/tests/templates/policywithuam.bicepparam: -------------------------------------------------------------------------------- 1 | using './policywithuam.bicep' 2 | 3 | param policyAssignmentName = 'TestPolicyAssignmentWithUAM' 4 | param policyDefinitionID = '/providers/Microsoft.Authorization/policyDefinitions/014664e7-e348-41a3-aeb9-566e4ff6a9df' 5 | param uamName = 'TestAzOpsUAM' 6 | -------------------------------------------------------------------------------- /src/tests/templates/customlockdelete.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | 3 | resource subLock 'Microsoft.Authorization/locks@2020-05-01' = { 4 | name: 'subscriptionLock' 5 | properties: { 6 | level: 'CanNotDelete' 7 | notes: 'This subscription is locked for Delete operations.' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/tests/templates/rgdualdeploy.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | 3 | param resourceGroupName string 4 | param location string 5 | 6 | resource myRg 'Microsoft.Resources/resourceGroups@2024-11-01' = { 7 | name: resourceGroupName 8 | location: location 9 | tags: {} 10 | properties: {} 11 | } 12 | -------------------------------------------------------------------------------- /src/tests/templates/bicepparamtest.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string 3 | 4 | resource symbolicname 'Microsoft.Network/routeTables@2024-05-01' = { 5 | name: name 6 | location: location 7 | properties: { 8 | disableBgpRoutePropagation: true 9 | routes: [ 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/templates/rgsubonlydeploy.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | 3 | param resourceGroupName string 4 | param location string 5 | 6 | resource myRg 'Microsoft.Resources/resourceGroups@2024-11-01' = { 7 | name: resourceGroupName 8 | location: location 9 | tags: {} 10 | properties: {} 11 | } 12 | -------------------------------------------------------------------------------- /src/data/template/template.parameters.jq: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "input": { 6 | "value": . 7 | } 8 | } 9 | } 10 | | del(.. | select(. == null)) -------------------------------------------------------------------------------- /docs/wiki/_Footer.md: -------------------------------------------------------------------------------- 1 | **This wiki is being actively developed** 2 | If you discover any documentation bugs or would like to request new content, please raise them as an [issue](https://github.com/azure/azops/issues). 3 | 4 | Contributions to this wiki are done through the main repo under [docs/wiki](https://github.com/Azure/AzOps/tree/main/docs/wiki) -------------------------------------------------------------------------------- /src/tests/templates/deployallrtbase.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | 4 | resource symbolicname 'Microsoft.Network/routeTables@2024-05-01' = { 5 | name: name 6 | location: location 7 | properties: { 8 | disableBgpRoutePropagation: false 9 | routes: [ 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/templates/rtmultibase.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | 4 | resource symbolicname 'Microsoft.Network/routeTables@2024-05-01' = { 5 | name: name 6 | location: location 7 | properties: { 8 | disableBgpRoutePropagation: false 9 | routes: [ 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/templates/rtsuffix0102.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | 4 | resource symbolicname 'Microsoft.Network/routeTables@2024-05-01' = { 5 | name: name 6 | location: location 7 | properties: { 8 | disableBgpRoutePropagation: false 9 | routes: [ 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Resources/resourceGroups/deploy/deploy.bicep: -------------------------------------------------------------------------------- 1 | param rgName string = 'resourceGroups-azopsrg' 2 | param location ('westeurope' | 'northeurope') = 'northeurope' 3 | targetScope = 'subscription' 4 | 5 | resource symbolicname 'Microsoft.Resources/resourceGroups@2024-11-01' = { 6 | name: rgName 7 | location: location 8 | } 9 | -------------------------------------------------------------------------------- /src/tests/templates/decoy.westeurope.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | 4 | resource symbolicname 'Microsoft.Network/routeTables@2024-05-01' = { 5 | name: name 6 | location: location 7 | properties: { 8 | disableBgpRoutePropagation: false 9 | routes: [ 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "PowerShell: Debug", 6 | "type": "PowerShell", 7 | "request": "launch", 8 | "script": "${workspaceFolder}/scripts/Debug.ps1", 9 | "cwd": "${workspaceFolder}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.ManagedIdentity/userAssignedIdentities/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "userMsiName": { 6 | "value": "sxx-az-msi-x-001" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/tests/templates/deployallrt.westeurope.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | 4 | resource symbolicname 'Microsoft.Network/routeTables@2024-05-01' = { 5 | name: name 6 | location: location 7 | properties: { 8 | disableBgpRoutePropagation: false 9 | routes: [ 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/templates/rtcustomdelete.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "CustomRouteTable" 7 | }, 8 | "staName": { 9 | "value": "deleteazops" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/privateDnsZones/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "privateDnsZoneName": { 6 | "value": "test.local" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatrg.bicep: -------------------------------------------------------------------------------- 1 | param name string = 'rtstackatrg' 2 | param location string = resourceGroup().location 3 | 4 | resource symbolicname 'Microsoft.Network/routeTables@2024-05-01' = { 5 | name: name 6 | location: location 7 | properties: { 8 | disableBgpRoutePropagation: false 9 | routes: [ 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/data/template/Microsoft.Storage/storageaccounts.jq: -------------------------------------------------------------------------------- 1 | del(.id, 2 | .properties.creationTime, 3 | .properties.primaryEndpoints, 4 | .properties.encryption.services.file.lastEnabledTime, 5 | .properties.encryption.services.blob.lastEnabledTime, 6 | .properties.provisioningState, 7 | .properties.primaryLocation, 8 | .properties.statusOfPrimary 9 | ) -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/roleEligibilityScheduleRequests.jq: -------------------------------------------------------------------------------- 1 | del((.Id), (.Properties.Condition | nulls), (.Properties.ConditionVersion | nulls), (.Properties.ScheduleInfo.Expiration.EndDateTime | nulls), (.Properties.ScheduleInfo.Expiration.Duration | nulls), (.Properties.ScheduleInfo.Expiration.ExpirationType | nulls), (.Properties.ScheduleInfo.StartDateTime | nulls)) -------------------------------------------------------------------------------- /src/tests/templates/biceptest.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | @description('Name of the resource group') 3 | param resourceGroupName string 4 | param location ('westeurope' | 'swedencentral') 5 | 6 | resource myRg 'Microsoft.Resources/resourceGroups@2024-11-01' = { 7 | name: resourceGroupName 8 | location: location 9 | tags: {} 10 | properties: {} 11 | } 12 | -------------------------------------------------------------------------------- /src/tests/templates/deployallrt2.westeurope.bicep: -------------------------------------------------------------------------------- 1 | param name string = 'deployallrt2wex123' 2 | param location string = resourceGroup().location 3 | 4 | resource symbolicname 'Microsoft.Network/routeTables@2024-05-01' = { 5 | name: name 6 | location: location 7 | properties: { 8 | disableBgpRoutePropagation: false 9 | routes: [ 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/bin/README.md: -------------------------------------------------------------------------------- 1 | # bin/ 2 | 3 | The bin folder exists to store binary data. And scripts related to the type system. 4 | 5 | This may include your own C#-based library, third party libraries you want to include (watch the license!), or a script declaring type accelerators (effectively aliases for .NET types) 6 | 7 | For more information on Type Accelerators, see the help on Set-PSFTypeAlias -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatmg.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'managementGroup' 2 | 3 | param policyDefinitionIdstring string 4 | 5 | resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { 6 | name: 'stacks-audit-vm-disks' 7 | properties: { 8 | displayName: 'Audit VMs with managed disks' 9 | policyDefinitionId: policyDefinitionIdstring 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/tests/templates/deploystacksatsub.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | 3 | param policyDefinitionIdstring string 4 | 5 | resource policyAssignment 'Microsoft.Authorization/policyAssignments@2022-06-01' = { 6 | name: 'stacks-audit-vm-disks' 7 | properties: { 8 | displayName: 'Audit VMs with managed disks' 9 | policyDefinitionId: policyDefinitionIdstring 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/tests/templates/rgdualdeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "resourceGroupName": { 6 | "value": "Test-azopsrg" 7 | }, 8 | "location": { 9 | "value": "northeurope" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/data/template/templateChildResource.jq: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": .resources, 12 | "outputs": {} 13 | } -------------------------------------------------------------------------------- /src/tests/templates/biceptest.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "resourceGroupName": { 6 | "value": "bicepTest-azopsrg" 7 | }, 8 | "location": { 9 | "value": "swedencentral" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Management/managementGroups/deploy/deploy.bicep: -------------------------------------------------------------------------------- 1 | param managementGroupName string = 'AzOpsMGMTName' 2 | param managementGroupId string = 'AzOpsMGMTID' 3 | 4 | targetScope = 'tenant' 5 | 6 | resource managementGroup 'Microsoft.Management/managementGroups@2023-04-01' = { 7 | name: managementGroupId 8 | properties: { 9 | displayName: managementGroupName 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/tests/templates/rgsubonlydeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "resourceGroupName": { 6 | "value": "TestSubOnly-azopsrg" 7 | }, 8 | "location": { 9 | "value": "northeurope" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/publicIPAddresses/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "value": "northeurope" 7 | }, 8 | "publicIpAddressName": { 9 | "value": "AzOps-PIP1" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/networkSecurityGroups/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "value": "northeurope" 7 | }, 8 | "networkSecurityGroupName": { 9 | "value": "nsg300" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/policySetDefinitions.jq: -------------------------------------------------------------------------------- 1 | del(.ResourceId, .id, .tenantId, .subscriptionId, .properties.policyType, .properties.policyDefinitions[].definitionVersion, .properties.metadata.createdOn, .properties.metadata.updatedOn, .properties.metadata.createdBy, .properties.metadata.updatedBy) 2 | | walk(if type == "object" then with_entries( 3 | select(.value != "" or (.key == "defaultValue" and .value == ""))) 4 | else . end) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Feature request \U0001F680" 3 | about: Suggest an idea for this project 4 | title: 'Feature Request' 5 | labels: 'needs triage :warning:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | 13 | **Describe the solution you'd like** 14 | 15 | -------------------------------------------------------------------------------- /src/internal/scriptblocks/ScriptBlocks.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Stored scriptblocks are available in [PsfValidateScript()] attributes. 3 | This makes it easier to centrally provide the same scriptblock multiple times, 4 | without having to maintain it in separate locations. 5 | 6 | It also prevents lengthy validation scriptblocks from making your parameter block 7 | hard to read. 8 | 9 | Set-PSFScriptblock -Name 'AzOps.ScriptBlockName' -Scriptblock { 10 | 11 | } 12 | #> -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Web/sites/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.bicep" 3 | $script:scope = "ResourceGroup" 4 | 5 | try { 6 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate 7 | } 8 | catch { 9 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 10 | throw 11 | } -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/policyAssignments.jq: -------------------------------------------------------------------------------- 1 | if .identity.userAssignedIdentities != null then del(.identity.userAssignedIdentities[].principalId, .identity.userAssignedIdentities[].clientId, .identity.tenantId, .identity.principalId) else . end | 2 | del(.ResourceId, .resourceGroup, .subscriptionId, .properties.metadata.createdOn, .properties.metadata.updatedOn, .properties.metadata.createdBy, .properties.metadata.updatedBy, .properties.metadata.assignedBy) -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.KeyVault/vaults/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.bicep" 3 | $script:scope = "ResourceGroup" 4 | 5 | try { 6 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate 7 | } 8 | catch { 9 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 10 | throw 11 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Web/serverfarms/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.bicep" 3 | $script:scope = "ResourceGroup" 4 | 5 | try { 6 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate 7 | } 8 | catch { 9 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 10 | throw 11 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Web/serverfarms/deploy/deploy.bicep: -------------------------------------------------------------------------------- 1 | param appServicePlanName string = uniqueString(resourceGroup().id) 2 | param sku string = 'S1' 3 | param location string = resourceGroup().location 4 | 5 | resource appServicePlan 'Microsoft.Web/serverfarms@2024-04-01' = { 6 | name: appServicePlanName 7 | location: location 8 | properties: { 9 | reserved: true 10 | } 11 | sku: { 12 | name: sku 13 | } 14 | kind: 'linux' 15 | } 16 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Resources/resourceGroups/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.bicep" 3 | $script:scope = "Subscription" 4 | 5 | try { 6 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate 7 | } 8 | catch { 9 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 10 | throw 11 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Storage/storageAccounts/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.bicep" 3 | $script:scope = "ResourceGroup" 4 | 5 | try { 6 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate 7 | } 8 | catch { 9 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 10 | throw 11 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Authorization/policyAssignments/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.bicep" 3 | $script:scope = "ResourceGroup" 4 | 5 | try { 6 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate 7 | } 8 | catch { 9 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 10 | throw 11 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Authorization/roleAssignments/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.bicep" 3 | $script:scope = "Subscription" 4 | 5 | try { 6 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate 7 | } 8 | catch { 9 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 10 | throw 11 | } -------------------------------------------------------------------------------- /src/data/template/generic.jq: -------------------------------------------------------------------------------- 1 | def matches: 2 | type == "string" 3 | and test("(?x: 4 | ^ 5 | (?: \\d{4}-\\d{2}-\\d{2}T 6 | | \\w{3},[ ][\\d ]\\d[ ]\\w{3}[ ]\\d{4} 7 | ) 8 | )"); 9 | 10 | del(.Id, .id, .Properties.provisioningState, .properties.provisioningState, .Properties.state, .properties.state, .Properties.resourceGuid, .properties.resourceGuid) | 11 | walk(if type=="object" 12 | then with_entries(if .value|matches then empty else . end) 13 | else . end) -------------------------------------------------------------------------------- /src/internal/scripts/Strings.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | This file loads the strings documents from the respective language folders. 3 | This allows localizing messages and errors. 4 | Load psd1 language files for each language you wish to support. 5 | Partial translations are acceptable - when missing a current language message, 6 | it will fallback to English or another available language. 7 | #> 8 | Import-PSFLocalizedString -Path "$($script:ModuleRoot)\localized\en-us\*.psd1" -Module 'AzOps' -Language 'en-US' -------------------------------------------------------------------------------- /src/internal/scripts/Variables.ps1: -------------------------------------------------------------------------------- 1 | # Module Cache for Subscriptions accessible for the current account 2 | $script:AzOpsSubscriptions = @() 3 | # Module Cache for Management Groups that are in scope for this module 4 | $script:AzOpsAzManagementGroup = @() 5 | # Module Cache for Management Group Roots that are in scope for this module, when accepting partial processing 6 | $script:AzOpsPartialRoot = @() 7 | # Module cache to load resource provider version 8 | $script:AzOpsResourceProvider = $null -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Bug report \U0001F41B" 3 | about: Report errors or unexpected behaviour 4 | title: 'Bug Report' 5 | labels: 'needs triage :warning:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | 13 | **Describe the bug** 14 | 15 | 16 | **Steps to reproduce** 17 | 18 | 1. 19 | 2. 20 | 21 | **Screenshots** 22 | 23 | -------------------------------------------------------------------------------- /docs/wiki/Home.md: -------------------------------------------------------------------------------- 1 | # Welcome to the AzOps Wiki 2 | 3 | These pages are used as the core documentation for the project. 4 | 5 | Please refer to the sidebar (on the right) for details on the Getting Started, Additional Documentation and Contributing Guides. 6 | 7 | If you'd like to contribute to the Wiki, please fork the AzOps repository and edit the Wiki pages within the `docs/wiki` directory. 8 | 9 | For an up-to-date view on active work items, please visit the Project [board](https://github.com/Azure/AzOps/projects/2) 10 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.KeyVault/vaults/deploy/deploy.bicep: -------------------------------------------------------------------------------- 1 | param vaultName string = 'kvazopstest${uniqueString(resourceGroup().id)}' 2 | param location string = resourceGroup().location 3 | 4 | resource key_vault 'Microsoft.KeyVault/vaults@2024-11-01' = { 5 | name: vaultName 6 | location: location 7 | properties: { 8 | sku: { 9 | family: 'A' 10 | name: 'standard' 11 | } 12 | tenantId: subscription().tenantId 13 | enableRbacAuthorization: true 14 | enableSoftDelete : false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/tests/templates/stasubonlydeploy.bicep: -------------------------------------------------------------------------------- 1 | param staName string = 'staazops${uniqueString(resourceGroup().id)}' 2 | param location string = resourceGroup().location 3 | 4 | resource storage_resource 'Microsoft.Storage/storageAccounts@2024-01-01' = { 5 | name: staName 6 | location: location 7 | kind: 'StorageV2' 8 | sku: { 9 | name: 'Standard_LRS' 10 | } 11 | properties: { 12 | minimumTlsVersion: 'TLS1_2' 13 | networkAcls: { 14 | bypass: 'None' 15 | defaultAction: 'Deny' 16 | } 17 | supportsHttpsTrafficOnly: true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/internal/configurations/README.md: -------------------------------------------------------------------------------- 1 | # configurations/ 2 | 3 | Through the `PSFramework` you have a simple method that allows you to ... 4 | 5 | - Publish settings 6 | - With onboard documentation 7 | - Input validation 8 | - Scripts that run on change of settings 9 | - That can be discovered and updated by the user 10 | - That can be administrated by policy & DSC 11 | 12 | The configuration system is a bit too complex to describe in a help file, you can however visit us at http://psframework.org for detailed guidance. 13 | 14 | An example can be seen in the attached ps1 file -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Authorization/policyAssignments/deploy/deploy.bicep: -------------------------------------------------------------------------------- 1 | param policyAssignmentName string = 'audit-vm-manageddisks-fn' 2 | param policyDefinitionID string = '/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d' 3 | 4 | targetScope = 'resourceGroup' 5 | 6 | resource assignment 'Microsoft.Authorization/policyAssignments@2025-01-01' = { 7 | name: policyAssignmentName 8 | properties: { 9 | policyDefinitionId: policyDefinitionID 10 | } 11 | } 12 | 13 | output assignmentId string = assignment.id 14 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Authorization/roleEligibilityScheduleRequests/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "value": "northeurope" 7 | }, 8 | "principalId": { 9 | "value": "d110cb6a-48b3-474b-8196-255e1589ee2b" 10 | }, 11 | "roleDefinitionId": { 12 | "value": "acdd72a7-3385-48ef-bd42-f606fba81ae7" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Logic/workflows/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Compute/virtualMachines/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/azureFirewalls/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/bastionHosts/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/routeTables/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/virtualNetworks/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Insights/activityLogAlerts/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/connections/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/networkInterfaces/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/publicIPAddresses/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/routeTables/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "value": "northeurope" 7 | }, 8 | "routeTableName": { 9 | "value": "azops-rt1" 10 | }, 11 | "routeName": { 12 | "value": "azops-rt1-r" 13 | }, 14 | "routeAddressPrefix": { 15 | "value": "192.168.0.0/24" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/localNetworkGateways/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "localNetworkGatewayName": { 6 | "value": "sxx-az-lng-x-001" 7 | }, 8 | "localAddressPrefixes": { 9 | "value": [ 10 | "192.168.1.0/24" 11 | ] 12 | }, 13 | "localGatewayPublicIpAddress": { 14 | "value": "8.8.8.8" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/networkSecurityGroups/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/privateDnsZones/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/privateEndpoints/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/general/Strings.Exceptions.ps1: -------------------------------------------------------------------------------- 1 | $exceptions = @{ } 2 | 3 | <# 4 | A list of entries that MAY be in the language files, without causing the tests to fail. 5 | This is commonly used in modules that generate localized messages straight from C#. 6 | Specify the full key as it is written in the language files, do not prepend the modulename, 7 | as you would have to in C# code. 8 | 9 | Example: 10 | $exceptions['LegalSurplus'] = @( 11 | 'Exception.Streams.FailedCreate' 12 | 'Exception.Streams.FailedDispose' 13 | ) 14 | #> 15 | $exceptions['LegalSurplus'] = @( 16 | 17 | ) 18 | 19 | $exceptions -------------------------------------------------------------------------------- /src/tests/templates/biceperror.bicep: -------------------------------------------------------------------------------- 1 | param staName string = 'eroazops${uniqueString(resourceGroup().id)}' 2 | param location string = resourceGroup().location 3 | 4 | resource storage_resource 'Microsoft.Storage/storageAccounts@2024-01-01' = { 5 | name: staName 6 | location: location 7 | kind: 'StorageV2' 8 | sku: { 9 | name: 'Standard_LRS' 10 | } 11 | properties000: { 12 | minimumTlsVersion: 'TLS1_2' 13 | networkAcls: { 14 | bypass: 'None' 15 | defaultOction: 'MaybeGivesError' 16 | } 17 | supportsHttpsTrafficOnly: true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.ManagedIdentity/userAssignedIdentities/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/localNetworkGateways/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Storage/storageAccounts/deploy/deploy.bicep: -------------------------------------------------------------------------------- 1 | param staName string = 'staazops${uniqueString(resourceGroup().id)}' 2 | param location string = resourceGroup().location 3 | 4 | resource storage_resource 'Microsoft.Storage/storageAccounts@2024-01-01' = { 5 | name: staName 6 | location: location 7 | kind: 'StorageV2' 8 | sku: { 9 | name: 'Standard_LRS' 10 | } 11 | properties: { 12 | minimumTlsVersion: 'TLS1_2' 13 | networkAcls: { 14 | bypass: 'None' 15 | defaultAction: 'Deny' 16 | } 17 | supportsHttpsTrafficOnly: true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/locks.template.jq: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": [ 12 | { 13 | "type": .ResourceType, 14 | "name": .Name, 15 | "apiVersion": "0000-00-00", 16 | "properties": .Properties 17 | } 18 | ], 19 | "outputs": {} 20 | } 21 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Authorization/roleEligibilityScheduleRequests/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.json" 3 | $script:deployTemplateParameter = "deploy.parameters.json" 4 | $script:scope = "ResourceGroup" 5 | 6 | try { 7 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate -DeployTemplateParameterFileName $script:deployTemplateParameter 8 | } 9 | catch { 10 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 11 | throw 12 | } -------------------------------------------------------------------------------- /src/tests/templates/staparalleldeploy.bicep: -------------------------------------------------------------------------------- 1 | param staName string 2 | param location string = resourceGroup().location 3 | 4 | var storageName = '${toLower(staName)}${uniqueString(resourceGroup().id)}' 5 | 6 | resource storage_resource 'Microsoft.Storage/storageAccounts@2024-01-01' = { 7 | name: storageName 8 | location: location 9 | kind: 'StorageV2' 10 | sku: { 11 | name: 'Standard_GZRS' 12 | } 13 | properties: { 14 | minimumTlsVersion: 'TLS1_2' 15 | networkAcls: { 16 | bypass: 'None' 17 | defaultAction: 'Deny' 18 | } 19 | supportsHttpsTrafficOnly: true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/tests/templates/staserialdeploy2.bicep: -------------------------------------------------------------------------------- 1 | param staName string 2 | param location string = resourceGroup().location 3 | 4 | var storageName = '${toLower(staName)}${uniqueString(resourceGroup().id)}' 5 | 6 | resource storage_resource 'Microsoft.Storage/storageAccounts@2024-01-01' = { 7 | name: storageName 8 | location: location 9 | kind: 'StorageV2' 10 | sku: { 11 | name: 'Standard_GZRS' 12 | } 13 | properties: { 14 | minimumTlsVersion: 'TLS1_2' 15 | networkAcls: { 16 | bypass: 'None' 17 | defaultAction: 'Deny' 18 | } 19 | supportsHttpsTrafficOnly: true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/data/template/Microsoft.Management/managementGroups/subscriptions.template.jq: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": [ 12 | { 13 | "type": "", 14 | "name": "", 15 | "apiVersion": "0000-00-00", 16 | "scope": "/" 17 | } 18 | ], 19 | "outputs": {} 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/activateFabricBot.yml: -------------------------------------------------------------------------------- 1 | name: Fabric Bot 2 | description: Description 3 | 4 | resource: repository 5 | where: 6 | - | 7 | repository.name.equals("Azure-Proactive-Resiliency-Library", StringComparison.InvariantCultureIgnoreCase) 8 | || repository.name.equals("azure-functions-durable-python", StringComparison.InvariantCultureIgnoreCase) 9 | || repository.name.equals("Azure-Governance-Visualizer", StringComparison.InvariantCultureIgnoreCase) 10 | || repository.name.equals("typespec-azure", StringComparison.InvariantCultureIgnoreCase) 11 | configuration: 12 | activateFabricBot: 13 | activate: true 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # System 2 | .DS_Store 3 | 4 | # VS Code 5 | .vscode/* 6 | *.code-workspace 7 | !.vscode/launch.json 8 | !.vscode/settings.json 9 | !.devcontainer/* 10 | 11 | # Visual Studio 12 | library/AzOps/.vs/* 13 | library/AzOps/AzOps/bin/* 14 | library/AzOps/AzOps/obj/* 15 | .vs/* 16 | 17 | # PowerShell Studio 18 | AzOps/AzOps.psproj 19 | AzOps/AzOps.psproj.bak 20 | AzOps/AzOps.psprojs 21 | AzOps/AzOps.psproj 22 | 23 | # Results 24 | TestResults/* 25 | results/* 26 | 27 | # Publishing 28 | publish/* 29 | 30 | # Generated 31 | azops/* 32 | root/* 33 | partialmgdiscoveryroot/* 34 | 35 | # Debug 36 | **.private** 37 | debug/* 38 | -------------------------------------------------------------------------------- /src/internal/scripts/PreImport.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Add all things you want to run before importing the main function code. 3 | 4 | WARNING: ONLY provide paths to files! 5 | 6 | After building the module, this file will be completely ignored, adding anything but paths to files ... 7 | - Will not work after publishing 8 | - Could break the build process 9 | #> 10 | 11 | $moduleRoot = Split-Path (Split-Path $PSScriptRoot) 12 | 13 | # Load the strings used in messages 14 | "$moduleRoot\internal\scripts\Strings.ps1" 15 | 16 | # Load the class definitions (must exist before declaring functions) 17 | (Get-ChildItem "$moduleRoot\internal\classes\*.ps1" -ErrorAction Ignore).FullName -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/networkSecurityGroups/deploy/deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string" 7 | }, 8 | "networkSecurityGroupName": { 9 | "type": "string" 10 | } 11 | }, 12 | "variables": {}, 13 | "resources": [ 14 | { 15 | "type": "Microsoft.Network/networkSecurityGroups", 16 | "apiVersion": "2024-05-01", 17 | "name": "[parameters('networkSecurityGroupName')]", 18 | "location": "[parameters('location')]" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Logic/workflows/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountSku": { 6 | "value": "Standard_LRS" 7 | }, 8 | "storageAccountKind": { 9 | "value": "StorageV2" 10 | }, 11 | "storageAccountContainerName": { 12 | "value": "my-container" 13 | }, 14 | "logicAppPollingIntervalInMinutes": { 15 | "value": 30 16 | }, 17 | "azureMgmtUri": { 18 | "value": "https://management.azure.com:443/" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/data/template/Microsoft.Resources/resourcegroups.template.jq: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": [ 12 | { 13 | "type": "microsoft.resources/resourcegroups", 14 | "name": .name, 15 | "apiVersion": "0000-00-00", 16 | "location": .location, 17 | "tags": .tags, 18 | "properties": {} 19 | } 20 | ], 21 | "outputs": {} 22 | } | 23 | .resources[].tags |= if . != null then to_entries | sort_by(.key) | from_entries else . end -------------------------------------------------------------------------------- /src/tests/templates/rbactest.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "policyAssignmentName": { 6 | "value": "AzOpsDep2 - audit-vm-manageddisks" 7 | }, 8 | "policyDefinitionID": { 9 | "value": "/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d" 10 | }, 11 | "location": { 12 | "value": "northeurope" 13 | }, 14 | "roleDefinitionId": { 15 | "value": "/providers/microsoft.authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/data/template/Microsoft.Subscription/subscriptions.template.jq: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": [ 12 | { 13 | "type": .Type, 14 | "name": .Name, 15 | "apiVersion": "0000-00-00", 16 | "tags": .Tags 17 | } 18 | ], 19 | "outputs": {} 20 | } | 21 | .resources[].tags |= if . != null then to_entries | sort_by(.key) | from_entries else . end 22 | | del(.. | select(. == null)) 23 | | del(.. | select(. == "")) -------------------------------------------------------------------------------- /src/tests/templates/policywithuam.bicep: -------------------------------------------------------------------------------- 1 | param policyAssignmentName string 2 | param policyDefinitionID string 3 | param location string = resourceGroup().location 4 | param uamName string 5 | 6 | targetScope = 'resourceGroup' 7 | 8 | resource uam 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = { 9 | name: uamName 10 | location: location 11 | } 12 | 13 | resource assignment 'Microsoft.Authorization/policyAssignments@2025-01-01' = { 14 | name: policyAssignmentName 15 | location: location 16 | identity: { 17 | type: 'UserAssigned' 18 | userAssignedIdentities: { 19 | '${uam.id}': {} 20 | } 21 | } 22 | properties: { 23 | policyDefinitionId: policyDefinitionID 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/tests/general/Help.Exceptions.ps1: -------------------------------------------------------------------------------- 1 | # List of functions that should be ignored 2 | $global:FunctionHelpTestExceptions = @( 3 | 4 | ) 5 | 6 | <# 7 | List of arrayed enumerations. These need to be treated differently. Add full name. 8 | Example: 9 | 10 | "Sqlcollaborative.Dbatools.Connection.ManagementConnectionType[]" 11 | #> 12 | $global:HelpTestEnumeratedArrays = @( 13 | 14 | ) 15 | 16 | <# 17 | Some types on parameters just fail their validation no matter what. 18 | For those it becomes possible to skip them, by adding them to this hashtable. 19 | Add by following this convention: = @() 20 | Example: 21 | 22 | "Get-DbaCmObject" = @("DoNotUse") 23 | #> 24 | $global:HelpTestSkipParameterType = @{ 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/connections/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "connectionName": { 6 | "value": "sxx-connection" 7 | }, 8 | "virtualNetworkName": { 9 | "value": "sxx-az-vnet-weu-x-004" 10 | }, 11 | "localNetworkGatewayName": { 12 | "value": "sxx-az-lng-weu-x-001" 13 | }, 14 | "virtualNetworkGatewayName": { 15 | "value": "sxx-az-vnet-vpn-gw-weu-p-001" 16 | }, 17 | "publicIPAddressesName": { 18 | "value": "sxx-az-vnet-vpn-gw-weu-p-001-pip-03" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/tests/templates/rbactest.bicep: -------------------------------------------------------------------------------- 1 | param policyAssignmentName string 2 | param policyDefinitionID string 3 | param location string 4 | param roleDefinitionId string 5 | targetScope = 'subscription' 6 | 7 | resource assignment 'Microsoft.Authorization/policyAssignments@2025-01-01' = { 8 | name: policyAssignmentName 9 | location: location 10 | identity: { 11 | type: 'SystemAssigned' 12 | } 13 | properties: { 14 | policyDefinitionId: policyDefinitionID 15 | } 16 | } 17 | 18 | resource roleassignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 19 | name: guid(assignment.id) 20 | properties: { 21 | principalId: assignment.identity.principalId 22 | principalType: 'ServicePrincipal' 23 | roleDefinitionId: roleDefinitionId 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/tests/templates/rtcustomdelete.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param staName string 3 | param location string = resourceGroup().location 4 | 5 | var storageName = '${toLower(staName)}${uniqueString(resourceGroup().id)}' 6 | 7 | resource rt 'Microsoft.Network/routeTables@2024-05-01' = { 8 | name: name 9 | location: location 10 | properties: { 11 | disableBgpRoutePropagation: false 12 | routes: [ 13 | ] 14 | } 15 | } 16 | 17 | resource storage_resource 'Microsoft.Storage/storageAccounts@2024-01-01' = { 18 | name: storageName 19 | location: location 20 | kind: 'StorageV2' 21 | sku: { 22 | name: 'Standard_GZRS' 23 | } 24 | properties: { 25 | minimumTlsVersion: 'TLS1_2' 26 | networkAcls: { 27 | bypass: 'None' 28 | defaultAction: 'Deny' 29 | } 30 | supportsHttpsTrafficOnly: true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/policyDefinitions.jq: -------------------------------------------------------------------------------- 1 | del(.ResourceId, .id, .tenantId, .subscriptionId, .properties.policyType, .properties.metadata.createdOn, .properties.metadata.updatedOn, .properties.metadata.createdBy, .properties.metadata.updatedBy) 2 | | walk(if type == "object" then with_entries( 3 | if .key == "equals" or .key == "notEquals" or .key == "like" or .key == "notLike" or .key == "match" or .key == "matchInsensitively" or .key == "notMatch" or .key == "notMatchInsensitively" or .key == "contains" or .key == "notContains" or .key == "in" or .key == "notIn" or .key == "containsKey" or .key == "notContainsKey" or .key == "less" or .key == "lessOrEquals" or .key == "greater" or .key == "greaterOrEquals" or .key == "exists" 4 | then . 5 | else select(.value != "" or (.key == "defaultValue" and .value == "")) 6 | end 7 | ) 8 | else . end) -------------------------------------------------------------------------------- /src/internal/scripts/Validations.ps1: -------------------------------------------------------------------------------- 1 | Register-PSFConfigValidation -Name "stringorempty" -ScriptBlock { 2 | 3 | param ( 4 | $Value 5 | ) 6 | 7 | $Result = New-Object PSObject -Property @{ 8 | Success = $True 9 | Value = $null 10 | Message = "" 11 | } 12 | 13 | try { 14 | [string]$data = $Value 15 | } 16 | catch { 17 | $Result.Message = "Not a string: $Value" 18 | $Result.Success = $False 19 | return $Result 20 | } 21 | 22 | if ([string]::IsNullOrEmpty($data)) { 23 | $data = "" 24 | } 25 | 26 | if ($data -eq $Value.GetType().FullName) { 27 | $Result.Message = "Is an object with no proper string representation: $Value" 28 | $Result.Success = $False 29 | return $Result 30 | } 31 | 32 | $Result.Value = $data 33 | 34 | return $Result 35 | 36 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/networkInterfaces/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "value": "northeurope" 7 | }, 8 | "virtualNetworkName": { 9 | "value": "vnet200" 10 | }, 11 | "addressSpaces": { 12 | "value": [ 13 | "10.2.0.0/16" 14 | ] 15 | }, 16 | "subnet0_name": { 17 | "value": "default" 18 | }, 19 | "subnet0_addressRange": { 20 | "value": "10.2.0.0/24" 21 | }, 22 | "ddosProtectionPlanEnabled": { 23 | "value": false 24 | }, 25 | "nic0_name": { 26 | "value": "vnet200nic" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/virtualNetworks/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "value": "northeurope" 7 | }, 8 | "virtualNetworkName": { 9 | "value": "vnet100" 10 | }, 11 | "addressSpaces": { 12 | "value": [ 13 | "10.1.0.0/16" 14 | ] 15 | }, 16 | "subnet0_name": { 17 | "value": "default" 18 | }, 19 | "subnet0_addressRange": { 20 | "value": "10.1.0.0/24" 21 | }, 22 | "ddosProtectionPlanEnabled": { 23 | "value": false 24 | }, 25 | "nic0_name": { 26 | "value": "vnet100nic" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/publicIPAddresses/deploy/deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string" 7 | }, 8 | "publicIpAddressName": { 9 | "type": "string" 10 | } 11 | }, 12 | "resources": [ 13 | { 14 | "apiVersion": "2024-05-01", 15 | "type": "Microsoft.Network/publicIpAddresses", 16 | "name": "[parameters('publicIpAddressName')]", 17 | "location": "[parameters('location')]", 18 | "sku": { 19 | "name": "Standard" 20 | }, 21 | "properties": { 22 | "publicIPAllocationMethod": "Static" 23 | }, 24 | "tags": {} 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/privateEndpoints/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "privateEndpointName": { 6 | "value": "azops-keyvault-endpoint" 7 | }, 8 | "groupId": { 9 | "value": ["vault"] 10 | }, 11 | "virtualNetworkName": { 12 | "value": "vnet102" 13 | }, 14 | "addressSpaces": { 15 | "value": [ 16 | "10.3.0.0/16" 17 | ] 18 | }, 19 | "subnet0_name": { 20 | "value": "privateEndpointSubnet" 21 | }, 22 | "subnet0_addressRange": { 23 | "value": "10.3.0.0/24" 24 | }, 25 | "ddosProtectionPlanEnabled": { 26 | "value": false 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Authorization/roleAssignments/deploy/deploy.bicep: -------------------------------------------------------------------------------- 1 | param roleDefinitionResourceId string = 'acdd72a7-3385-48ef-bd42-f606fba81ae7' 2 | param principalId string = '4dacdaa1-2044-490c-a603-36f80b6aaa0c' 3 | 4 | targetScope = 'subscription' 5 | 6 | @description('This is the built-in Reader role. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#reader') 7 | resource readerRoleDefinition 'Microsoft.Authorization/roleDefinitions@2022-05-01-preview' existing = { 8 | name: roleDefinitionResourceId 9 | } 10 | 11 | resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 12 | name: guid(subscription().id, principalId, roleDefinitionResourceId) 13 | properties: { 14 | roleDefinitionId: readerRoleDefinition.id 15 | principalId: principalId 16 | principalType: 'User' 17 | } 18 | } 19 | 20 | output roleAssignmentName string = roleAssignment.name 21 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/bastionHosts/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "azureBastionName": { 6 | "value": "sxx-az-bas-x-001" 7 | }, 8 | "azureBastionPipName": { 9 | "value": "sxx-az-baspip-x-001-pip" 10 | }, 11 | "virtualNetworkName": { 12 | "value": "vnet156" 13 | }, 14 | "addressSpaces": { 15 | "value": [ 16 | "10.2.0.0/16" 17 | ] 18 | }, 19 | "subnet0_name": { 20 | "value": "AzureBastionSubnet" 21 | }, 22 | "subnet0_addressRange": { 23 | "value": "10.2.0.0/24" 24 | }, 25 | "ddosProtectionPlanEnabled": { 26 | "value": false 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Web/sites/deploy/deploy.bicep: -------------------------------------------------------------------------------- 1 | param webAppName string = uniqueString(resourceGroup().id) 2 | param sku string = 'S1' 3 | param linuxFxVersion string = 'node|14-lts' 4 | param location string = resourceGroup().location 5 | 6 | var appServicePlanName = toLower('AppServicePlan-${webAppName}') 7 | var webSiteName = toLower('azapp-${webAppName}') 8 | 9 | resource appServicePlan 'Microsoft.Web/serverfarms@2024-04-01' = { 10 | name: appServicePlanName 11 | location: location 12 | properties: { 13 | reserved: true 14 | } 15 | sku: { 16 | name: sku 17 | } 18 | kind: 'linux' 19 | } 20 | resource appService 'Microsoft.Web/sites@2024-04-01' = { 21 | name: webSiteName 22 | location: location 23 | properties: { 24 | serverFarmId: appServicePlan.id 25 | siteConfig: { 26 | linuxFxVersion: linuxFxVersion 27 | } 28 | } 29 | } 30 | 31 | output webSiteName string = appService.name 32 | -------------------------------------------------------------------------------- /scripts/Debug.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Notes 3 | # 4 | 5 | # 6 | # Config 7 | # 8 | 9 | Set-PSFConfig -FullName PSFramework.Message.Info.Maximum -Value 9 10 | # Set-PSFConfig -FullName AzOps.Core.State -Value "/workspaces/AzOps/root" 11 | # Set-PSFConfig -FullName AzOps.Import.DoDotSource -Value $true 12 | # Set-PSFConfig -FullName AzOps.Import.IndividualFiles -Value $true 13 | 14 | # 15 | # Import 16 | # 17 | 18 | Import-Module ./src/AzOps.psd1 -Force 19 | 20 | # 21 | # Initialize 22 | # 23 | 24 | Initialize-AzOpsEnvironment 25 | 26 | # 27 | # Internal 28 | # 29 | 30 | # & ( Get-Module -Name AzOps ) { $host.EnterNestedPrompt() } 31 | # $module = Get-Module -Name AzOps 32 | 33 | # 34 | # Pull 35 | # 36 | 37 | # Invoke-AzOpsPull 38 | 39 | # 40 | # Push 41 | # 42 | 43 | # $tenantId = "" 44 | # $managementId = "" 45 | # $subscriptionId = "" 46 | 47 | # $change = "A root/tenant root group ($tenantId)/azuredeploy.json" 48 | # Invoke-AzOpsPush -ChangeSet $change -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/powershell:debian-12 2 | 3 | # [Option] Upgrade OS packages to their latest versions 4 | ARG UPGRADE_PACKAGES="true" 5 | 6 | # Install needed packages and setup non-root user. Use a separate RUN statement to add your own dependencies. 7 | ARG USERNAME=vscode 8 | ARG USER_UID=1000 9 | ARG USER_GID=$USER_UID 10 | COPY library-scripts/*.sh /tmp/library-scripts/ 11 | RUN apt-get update \ 12 | && /bin/bash /tmp/library-scripts/common-debian.sh "false" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "false" "false" \ 13 | && chsh "${USERNAME}" -s "$(which pwsh)" \ 14 | && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts 15 | 16 | # [Optional] Uncomment this section to install additional packages. 17 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 18 | # && apt-get -y install --no-install-recommends 19 | -------------------------------------------------------------------------------- /src/data/template/template.jq: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": [ 12 | { 13 | "type": .type, 14 | "name": .name, 15 | "sku": .sku, 16 | "kind": .kind, 17 | "apiVersion": "0000-00-00", 18 | "location": .location, 19 | "identity": .identity, 20 | "tags": .tags, 21 | "properties": .properties, 22 | "zones": .zones 23 | } 24 | ], 25 | "outputs": {} 26 | } | 27 | .resources[].tags |= if . != null then to_entries | sort_by(.key) | from_entries else . end 28 | | del(.. | select(. == null)) 29 | | del(.. | select(. == "")) 30 | | del (.resources[].properties.extended) -------------------------------------------------------------------------------- /src/data/template/Microsoft.Authorization/roleEligibilityScheduleRequests.template.jq: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": [ 12 | { 13 | "type": .ResourceType, 14 | "name": .Name, 15 | "apiVersion": "2020-10-01", 16 | "properties": .Properties 17 | } 18 | ], 19 | "outputs": {} 20 | } 21 | | del((.resources[].properties.Condition | nulls), (.resources[].properties.ConditionVersion | nulls), (.resources[].properties.ScheduleInfo.Expiration.EndDateTime | nulls), (.resources[].properties.ScheduleInfo.Expiration.Duration | nulls), (.resources[].properties.ScheduleInfo.Expiration.ExpirationType | nulls), (.resources[].properties.ScheduleInfo.StartDateTime | nulls)) -------------------------------------------------------------------------------- /.github/workflows/super-linter.yml: -------------------------------------------------------------------------------- 1 | # This workflow executes several linters on changed files based on languages used in your code base whenever 2 | # you push a code or open a pull request. 3 | # 4 | # You can adjust the behavior by modifying this file. 5 | # For more information, see: 6 | # https://github.com/github/super-linter 7 | name: "Lint Code Base" 8 | 9 | on: 10 | pull_request: 11 | branches: [main] 12 | 13 | jobs: 14 | run-lint: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: "Checkout code" 18 | uses: actions/checkout@v4 19 | with: 20 | # Full git history is needed to get a proper list of changed files within `super-linter` 21 | fetch-depth: 0 22 | 23 | - name: "Lint Code Base" 24 | uses: github/super-linter@v4 25 | env: 26 | VALIDATE_ALL_CODEBASE: false 27 | DEFAULT_BRANCH: main 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | FILTER_REGEX_INCLUDE: .*.md -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/azureFirewalls/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "value": "swedencentral" 7 | }, 8 | "azureFirewallName": { 9 | "value": "AzOpsFw1" 10 | }, 11 | "azureFirewallTier": { 12 | "value": "Premium" 13 | }, 14 | "vnetName": { 15 | "value": "vnetAzFw100" 16 | }, 17 | "vnetAddressSpace": { 18 | "value": "10.0.0.0/16" 19 | }, 20 | "subnetAddressSpace": { 21 | "value": "10.0.0.0/24" 22 | }, 23 | "publicIpAddressName": { 24 | "value": "AzOpsFw-pip1" 25 | }, 26 | "zones": { 27 | "value": [ 28 | "1", 29 | "2", 30 | "3" 31 | ] 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/internal/tepp/README.md: -------------------------------------------------------------------------------- 1 | # tepp/ 2 | 3 | ## Description 4 | 5 | Modern Tab Expansion was opened to users with the module `Tab Expansion Plus Plus` (TEPP). 6 | 7 | It allows you to define, what options a user is offered when tabbing through input options. This can save a lot of time for the user and is considered a key element in user experience. 8 | 9 | The `PSFramework` offers a simplified way of offering just this, as the two example files show. 10 | 11 | ## Concept 12 | 13 | Custom tab completion is defined in two steps: 14 | 15 | - Define a scriptblock that is run when the user hits `TAB` and provides the strings that are his options. 16 | - Assign that scriptblock to the parameter of a command. You can assign the same scriptblock multiple times. 17 | 18 | ## Structure 19 | 20 | Import order matters. In order to make things work with the default scaffold, follow those rules: 21 | 22 | - All scriptfiles _defining_ completion scriptblocks like this: `*.tepp.ps1` 23 | - Put all your completion assignments in `assignment.ps1` 24 | -------------------------------------------------------------------------------- /src/tests/README.md: -------------------------------------------------------------------------------- 1 | # tests/ 2 | 3 | This is the folder, where all the tests go. 4 | 5 | Those are subdivided in two categories: 6 | 7 | - General 8 | - Function 9 | 10 | ## General Tests 11 | 12 | General tests are function generic and test for general policies. 13 | 14 | These test scan answer questions such as: 15 | 16 | - Is my module following my style guides? 17 | - Does any of my scripts have a syntax error? 18 | - Do my scripts use commands I do not want them to use? 19 | - Do my commands follow best practices? 20 | - Do my commands have proper help? 21 | 22 | Basically, these allow a general module health check. 23 | 24 | These tests are already provided as part of the template. 25 | 26 | ## Function Tests 27 | 28 | A healthy module should provide unit and integration tests for the commands & components it ships. 29 | Only then can be guaranteed, that they will actually perform as promised. 30 | 31 | However, as each such test must be specific to the function it tests, there cannot be much in the way of templates. 32 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/routeTables/deploy/deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string" 7 | }, 8 | "routeTableName": { 9 | "type": "string" 10 | }, 11 | "routeName": { 12 | "type": "string" 13 | }, 14 | "routeAddressPrefix": { 15 | "type": "string" 16 | } 17 | }, 18 | "variables": {}, 19 | "resources": [{ 20 | "type": "Microsoft.Network/routeTables", 21 | "apiVersion": "2024-05-01", 22 | "name": "[parameters('routeTableName')]", 23 | "location": "[parameters('location')]", 24 | "properties": { 25 | "routes": [ 26 | { 27 | "name": "[parameters('routeName')]", 28 | "properties": { 29 | "addressPrefix": "[parameters('routeAddressPrefix')]", 30 | "nextHopType": "None", 31 | "hasBgpOverride": false 32 | } 33 | } 34 | ], 35 | "disableBgpRoutePropagation": false 36 | } 37 | }] 38 | } -------------------------------------------------------------------------------- /src/internal/functions/Get-AzOpsPim.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzOpsPim { 2 | <# 3 | .SYNOPSIS 4 | Get Privileged Identity Management objects from provided scope 5 | .PARAMETER ScopeObject 6 | ScopeObject 7 | .PARAMETER StatePath 8 | StatePath 9 | #> 10 | 11 | [CmdletBinding()] 12 | param ( 13 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 14 | [object] 15 | $ScopeObject, 16 | [Parameter(Mandatory = $true)] 17 | $StatePath 18 | ) 19 | 20 | process { 21 | # Process RoleEligibilitySchedule 22 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Get-AzOpsResourceDefinition.Processing.Detail' -LogStringValues 'RoleEligibilitySchedule', $scopeObject.Scope 23 | $roleEligibilityScheduleRequest = Get-AzOpsRoleEligibilityScheduleRequest -ScopeObject $ScopeObject 24 | if ($roleEligibilityScheduleRequest) { 25 | $roleEligibilityScheduleRequest | ConvertTo-AzOpsState -StatePath $StatePath 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /scripts/Version.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | This script updates the module manifest version. 3 | #> 4 | 5 | param ( 6 | [Parameter()] 7 | [ValidateSet("Major", "Minor", "Patch")] 8 | $Type 9 | ) 10 | 11 | if ($Type) { 12 | Write-PSFMessage -Level Important -Message "Updating module version" 13 | 14 | [Version]$currentVersion = (Import-PowerShellDataFile -Path "./src/AzOps.psd1").ModuleVersion 15 | [Version]$releaseVersion = switch($Type) { 16 | "Major" { 17 | [Version]::new($currentVersion.Major + 1, 0, 0) 18 | } 19 | "Minor" { 20 | $Minor = if($currentVersion.Minor -le 0) { 1 } else { $currentVersion.Minor + 1 } 21 | [Version]::new($currentVersion.Major, $Minor, 0) 22 | } 23 | "Patch" { 24 | $Build = if($currentVersion.Build -le 0) { 1 } else { $currentVersion.Build + 1 } 25 | [Version]::new($currentVersion.Major, $currentVersion.Minor, $Build) 26 | } 27 | } 28 | 29 | Update-ModuleManifest -Path "./src/AzOps.psd1" -ModuleVersion $releaseVersion 30 | } 31 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.ManagedIdentity/userAssignedIdentities/deploy/deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "userMsiName": { 6 | "type": "string", 7 | "defaultValue": "[guid(resourceGroup().id)]", 8 | "metadata": { 9 | "description": "Optional. Name of the User Assigned Identity." 10 | } 11 | }, 12 | "location": { 13 | "type": "string", 14 | "defaultValue": "[resourceGroup().location]", 15 | "metadata": { 16 | "description": "Optional. Location for all resources." 17 | } 18 | } 19 | }, 20 | "resources": [ 21 | { 22 | "type": "Microsoft.ManagedIdentity/userAssignedIdentities", 23 | "name": "[parameters('userMsiName')]", 24 | "apiVersion": "2024-11-30", 25 | "location": "[parameters('location')]" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /src/tests/general/FileIntegrity.Exceptions.ps1: -------------------------------------------------------------------------------- 1 | # List of forbidden commands 2 | $global:BannedCommands = @( 3 | 'Write-Host' 4 | 'Write-Verbose' 5 | 'Write-Warning' 6 | 'Write-Error' 7 | 'Write-Output' 8 | 'Write-Information' 9 | 'Write-Debug' 10 | 11 | # Use CIM instead where possible 12 | 'Get-WmiObject' 13 | 'Invoke-WmiMethod' 14 | 'Register-WmiEvent' 15 | 'Remove-WmiObject' 16 | 'Set-WmiInstance' 17 | 18 | # Use Get-WinEvent instead 19 | 'Get-EventLog' 20 | ) 21 | 22 | <# 23 | Contains list of exceptions for banned cmdlets. 24 | Insert the file names of files that may contain them. 25 | 26 | Example: 27 | "Write-Host" = @('Write-PSFHostColor.ps1','Write-PSFMessage.ps1') 28 | #> 29 | $global:MayContainCommand = @{ 30 | "Write-Host" = @() 31 | "Write-Verbose" = @() 32 | "Write-Warning" = @() 33 | "Write-Error" = @('Invoke-AzOpsPull.ps1') 34 | "Write-Output" = @('Get-AzOpsResourceDefinition.ps1') 35 | "Write-Information" = @() 36 | "Write-Debug" = @() 37 | } -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | # Overview/Summary 3 | 4 | Replace this with a brief description of what this Pull Request fixes, changes, etc. 5 | 6 | ## This PR fixes/adds/changes/removes 7 | 8 | 1. *Replace me* 9 | 2. *Replace me* 10 | 3. *Replace me* 11 | 12 | ### Breaking Changes 13 | 14 | 1. *Replace me* 15 | 2. *Replace me* 16 | 17 | ## Testing Evidence 18 | 19 | Please provide any testing evidence to show that your Pull Request works/fixes as described and planned (include screenshots, if appropriate). 20 | 21 | ## As part of this Pull Request I have 22 | 23 | - [ ] Checked for duplicate [Pull Requests](https://github.com/Azure/azops/pulls) 24 | - [ ] Associated it with relevant [issues](https://github.com/Azure/azops/issues), for tracking and closure. 25 | - [ ] Ensured my code/branch is up-to-date with the latest changes in the `main` [branch](https://github.com/Azure/azops/tree/main) 26 | - [ ] Performed testing and provided evidence. 27 | - [ ] Updated relevant and associated documentation. 28 | -------------------------------------------------------------------------------- /scripts/UpdateRequiredModules.ps1: -------------------------------------------------------------------------------- 1 | $data = Import-PowerShellDataFile -Path "./src/AzOps.psd1" 2 | $modules = @() 3 | $existingmodule = @() 4 | $newmodule = @() 5 | $updated = $false 6 | $data.RequiredModules | ForEach-Object { 7 | $moduleVersion = New-Object System.Version($_.RequiredVersion) 8 | $galleryVersion = New-Object System.Version((Find-Module -Name $_.ModuleName).Version) 9 | if ($moduleVersion -lt $galleryVersion) { 10 | $newmodule = @{ 11 | "ModuleName" = $_.ModuleName 12 | "RequiredVersion" = $galleryVersion 13 | } 14 | $updated = $true 15 | $modules += $newmodule 16 | } else { 17 | $existingmodule = @{ 18 | "ModuleName" = $_.ModuleName 19 | "RequiredVersion" = $moduleVersion 20 | } 21 | $modules += $existingmodule 22 | } 23 | } 24 | if ($updated -eq $true) { 25 | Update-ModuleManifest -Path "./src/AzOps.psd1" -RequiredModules $modules 26 | $filePath = Join-Path -Path "/tmp" -ChildPath "updates.json" 27 | ConvertTo-Json $modules | Out-File -FilePath $filePath 28 | } 29 | -------------------------------------------------------------------------------- /src/xml/AzOps.Types.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Deserialized.Foo.Bar 6 | 7 | 8 | PSStandardMembers 9 | 10 | 11 | 12 | TargetTypeForDeserialization 13 | 14 | 15 | Foo.Bar 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Foo.Bar 24 | 25 | 26 | SerializationData 27 | 28 | PSFramework.Serialization.SerializationTypeConverter 29 | GetSerializationData 30 | 31 | 32 | 33 | 34 | PSFramework.Serialization.SerializationTypeConverter 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/wiki/Sovereign-Clouds.md: -------------------------------------------------------------------------------- 1 | ## Sovereign clouds 2 | In addition to Public Azure Cloud that most of us are familiar with, there’s also separate sovereign Azure clouds for US Government and China. 3 | 4 | To use AzOps with one of the sovereign clouds, the following additional configuration is required. 5 | 6 | 1) Create the `ARM_ENVIRONMENT` variable/secret with the sovereign cloud [environment name](https://learn.microsoft.com/en-us/powershell/module/az.accounts/get-azenvironment?view=azps-7.1.0#example-1--getting-all-azure-environments) as value, for example `AzureUSGovernment` or `AzureChinaCloud`. 7 | **GitHub Actions** 8 | ![Add GH Action Secret](./Media/Actions/github_environment_secret.png) 9 | **Azure DevOps** 10 | ![Add Azure DevOps variable in variable group](./Media/Pipelines/ado_environment_variable.png) 11 | 2) Update `"Core.DefaultDeploymentRegion"` in [settings.json](https://github.com/Azure/AzOps-Accelerator/blob/main/settings.json) to a supported region in the sovereign cloud, for example `usgovvirginia` for Azure US Government and `chinaeast2`for Azure China. 12 | 3) Run a pull to validate settings and populate the repository. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/internal/scripts/PostImport.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Add all things you want to run after importing the main function code 3 | 4 | WARNING: ONLY provide paths to files! 5 | 6 | After building the module, this file will be completely ignored, adding anything but paths to files ... 7 | - Will not work after publishing 8 | - Could break the build process 9 | #> 10 | 11 | $moduleRoot = Split-Path (Split-Path $PSScriptRoot) 12 | 13 | # Load Validations 14 | "$moduleRoot\internal\scripts\Validations.ps1" 15 | 16 | # Load Configurations 17 | (Get-ChildItem "$moduleRoot\internal\configurations\*.ps1" -ErrorAction Ignore).FullName 18 | 19 | # Load Scriptblocks 20 | (Get-ChildItem "$moduleRoot\internal\scriptblocks\*.ps1" -ErrorAction Ignore).FullName 21 | 22 | # Load Tab Expansion 23 | (Get-ChildItem "$moduleRoot\internal\tepp\*.tepp.ps1" -ErrorAction Ignore).FullName 24 | 25 | # Load Tab Expansion Assignment 26 | "$moduleRoot\internal\tepp\Assignment.ps1" 27 | 28 | # Load the module-wide variables 29 | "$moduleRoot\internal\scripts\Variables.ps1" 30 | 31 | # Run startup script 32 | "$moduleRoot\internal\scripts\Initialize.ps1" 33 | 34 | # Load License 35 | "$moduleRoot\internal\scripts\License.ps1" 36 | -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Management/managementGroups/deploy/deploy.ps1: -------------------------------------------------------------------------------- 1 | $script:runtimePath = $PSScriptRoot 2 | $script:deployTemplate = "deploy.bicep" 3 | $script:scope = "Tenant" 4 | 5 | try { 6 | New-AzOpsTestsDeploymentHelper -RuntimePath $script:runtimePath -Scope $script:scope -DeployTemplateFileName $script:deployTemplate 7 | 8 | $script:timeOutMinutes = 30 9 | $script:mgmtRun = "Run" 10 | 11 | While ($script:mgmtRun -eq "Run") { 12 | Write-PSFMessage -Level Verbose -Message "Waiting for Management Group structure consistency" -FunctionName "BeforeAll" 13 | 14 | $script:mgmt = Get-AzManagementGroup 15 | $script:testManagementGroup = ($script:mgmt | Where-Object Name -eq "AzOpsMGMTID") 16 | 17 | if ($null -ne $script:testManagementGroup) { 18 | $script:mgmtRun = "Done" 19 | } 20 | else { 21 | Start-Sleep -Seconds 60 22 | $script:timeOutMinutes-- 23 | } 24 | if ($script:timeOutMinutes -le 0) { 25 | break 26 | } 27 | } 28 | } 29 | catch { 30 | Write-PSFMessage -Level Critical -Message "Deployment failed" -Exception $_.Exception 31 | throw 32 | } -------------------------------------------------------------------------------- /.github/linters/.markdown-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ########################### 3 | ########################### 4 | ## Markdown Linter rules ## 5 | ########################### 6 | ########################### 7 | 8 | # Linter rules doc: 9 | # - https://github.com/DavidAnson/markdownlint 10 | # 11 | # Note: 12 | # To comment out a single error: 13 | # 14 | # any violations you want 15 | # 16 | # 17 | 18 | ############### 19 | # Rules by id # 20 | ############### 21 | MD004: false # Unordered list style 22 | MD007: 23 | indent: 2 # Unordered list indentation 24 | MD013: 25 | line_length: 1000 # Line length 80 is far to short 26 | MD026: 27 | punctuation: ".,;:!。,;:" # List of not allowed 28 | MD029: false # Ordered list item prefix 29 | MD033: # Allow inline HTML 30 | allowed_elements: 31 | - br 32 | MD034: true # Allow bare urls 33 | MD036: false # Emphasis used instead of a heading 34 | 35 | ################# 36 | # Rules by tags # 37 | ################# 38 | blank_lines: false # Error on blank lines -------------------------------------------------------------------------------- /src/xml/AzOps.Format.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Foo.Bar 7 | 8 | Foo.Bar 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Foo 21 | 22 | 23 | Bar 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/internal/functions/Set-AzOpsContext.ps1: -------------------------------------------------------------------------------- 1 | function Set-AzOpsContext { 2 | 3 | <# 4 | .SYNOPSIS 5 | Changes the currently active azure context to the subscription of the specified scope object. 6 | .DESCRIPTION 7 | Changes the currently active azure context to the subscription of the specified scope object. 8 | .PARAMETER ScopeObject 9 | The scope object [AzOpsScope] into which context to change. 10 | .EXAMPLE 11 | > Set-AzOpsContext -ScopeObject $scopeObject 12 | Changes the current context to the subscription of $scopeObject. 13 | #> 14 | 15 | [CmdletBinding()] 16 | param ( 17 | [Parameter(Mandatory = $true)] 18 | $ScopeObject 19 | ) 20 | 21 | begin { 22 | $context = Get-AzContext 23 | } 24 | 25 | process { 26 | if (-not $ScopeObject.Subscription) { return } 27 | if ($context.Subscription.Id -ne $ScopeObject.Subscription) { 28 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Set-AzOpsContext.Change' -LogStringValues $context.Subscription.Name, $ScopeObject.SubscriptionDisplayName, $ScopeObject.Subscription 29 | $null = Set-AzContext -SubscriptionId $scopeObject.Subscription -WhatIf:$false 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PowerShell", 3 | "dockerFile": "Dockerfile", 4 | "features": { 5 | "ghcr.io/devcontainers/features/common-utils:2": { 6 | "installTools": true, 7 | "installZsh": true, 8 | "installOhMyZsh": true, 9 | "upgradePackages": true 10 | } 11 | }, 12 | "customizations": { 13 | "vscode": { 14 | // Add the IDs of extensions you want installed when the container is created. 15 | "extensions": [ 16 | "ms-vscode.powershell" 17 | ], 18 | // Set *default* container specific settings.json values on container create. 19 | "settings": { 20 | "terminal.integrated.shell.linux": "/bin/zsh" 21 | } 22 | } 23 | }, 24 | // Uncomment the next line to run commands after the container is created. This gets run in bash which is why we call `pwsh`. 25 | "postCreateCommand": "pwsh -c './scripts/Dependencies.ps1'", 26 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 27 | "remoteUser": "vscode", 28 | // Add runtime environment variables 29 | "remoteEnv": { 30 | "ARM_TENANT_ID": "", 31 | "ARM_SUBSCRIPTION_ID": "" 32 | } 33 | } -------------------------------------------------------------------------------- /src/internal/scripts/License.ps1: -------------------------------------------------------------------------------- 1 | New-PSFLicense -Product 'AzOps' -Manufacturer 'Friedrich Weinmann' -ProductVersion $script:ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date "2020-11-07") -Text @" 2 | Copyright (c) 2020 Friedrich Weinmann 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | "@ -------------------------------------------------------------------------------- /src/internal/functions/Get-AzOpsRole.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzOpsRole { 2 | <# 3 | .SYNOPSIS 4 | Get role objects from provided scope 5 | .PARAMETER ScopeObject 6 | ScopeObject 7 | .PARAMETER StatePath 8 | StatePath 9 | #> 10 | 11 | [CmdletBinding()] 12 | param ( 13 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 14 | [object] 15 | $ScopeObject, 16 | [Parameter(Mandatory = $true)] 17 | $StatePath 18 | ) 19 | 20 | process { 21 | # Process role definitions 22 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Get-AzOpsResourceDefinition.Processing.Detail' -LogStringValues 'Role Definitions', $ScopeObject.Scope 23 | $roleDefinitions = Get-AzOpsRoleDefinition -ScopeObject $ScopeObject 24 | if ($roleDefinitions) { 25 | $roleDefinitions | ConvertTo-AzOpsState -StatePath $StatePath 26 | } 27 | 28 | # Process role assignments 29 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Get-AzOpsResourceDefinition.Processing.Detail' -LogStringValues 'Role Assignments', $ScopeObject.Scope 30 | $roleAssignments = Get-AzOpsRoleAssignment -ScopeObject $ScopeObject 31 | if ($roleAssignments) { 32 | $roleAssignments | ConvertTo-AzOpsState -StatePath $StatePath 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Insights/activityLogAlerts/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "alertName": { 6 | "value": "sxx-az-ala-weu-x-001" 7 | }, 8 | "conditions": { 9 | "value": [{ 10 | "field": "category", 11 | "equals": "Administrative" 12 | }, 13 | { 14 | "field": "resourceType", 15 | "equals": "microsoft.compute/virtualmachines" 16 | }, 17 | { 18 | "field": "operationName", 19 | "equals": "Microsoft.Compute/virtualMachines/performMaintenance/action" 20 | } 21 | ] 22 | }, 23 | "actionGroupName": { 24 | "value": "sxx-az-ag-weu-x-001" 25 | }, 26 | "groupShortName":{ 27 | "value": "azagweux001" 28 | }, 29 | "emailReceivers":{ 30 | "value":[ 31 | { 32 | "name": "TestUser_-EmailAction-", 33 | "emailAddress": "test.user@1jztm.onmicrosoft.com", 34 | "useCommonAlertSchema": true 35 | } 36 | ] 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /scripts/Dependencies.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [string] 3 | $Repository = 'PSGallery' 4 | ) 5 | 6 | # Development Modules 7 | Set-PSRepository -Name $Repository -InstallationPolicy Trusted 8 | $modules = @("Pester", "PSModuleDevelopment", "PSScriptAnalyzer") 9 | Write-Output "Installing development modules" 10 | foreach ($module in $modules) { 11 | Write-Output "Installing: $module" 12 | Install-Module $module -Repository $Repository -Force 13 | } 14 | # Runtime Modules 15 | $data = Import-PowerShellDataFile -Path "$PSScriptRoot/../src/AzOps.psd1" 16 | Write-Output "Installing runtime modules" 17 | foreach ($dependency in $data.RequiredModules) { 18 | $module = Get-Module -Name $dependency.ModuleName -ListAvailable 19 | if ($module) { 20 | foreach ($item in $module) { 21 | Write-Output "Cleanup of: $($item.Name)" 22 | Uninstall-Module -Name $item.Name -Force 23 | } 24 | } 25 | Write-Output "Installing: $($dependency.ModuleName) $($dependency.RequiredVersion)" 26 | Install-Module -Name $dependency.ModuleName -RequiredVersion $dependency.RequiredVersion -Repository $Repository 27 | } 28 | # Download and add bicep to PATH 29 | curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64 30 | chmod +x ./bicep 31 | sudo mv ./bicep /usr/local/bin/bicep 32 | bicep --help 33 | 34 | # List Modules 35 | Get-InstalledModule | Select-Object Name, Version, Repository, InstalledDate | Sort-Object Name | Format-Table 36 | -------------------------------------------------------------------------------- /src/internal/functions/Assert-AzOpsBicepDependency.ps1: -------------------------------------------------------------------------------- 1 | function Assert-AzOpsBicepDependency { 2 | 3 | <# 4 | .SYNOPSIS 5 | Asserts that - if bicep is installed and in current path 6 | .DESCRIPTION 7 | Asserts that - if bicep is installed and in current path 8 | .PARAMETER Cmdlet 9 | The $PSCmdlet variable of the calling command. 10 | .EXAMPLE 11 | > Assert-AzOpsBicepDependency -Cmdlet $PSCmdlet 12 | #> 13 | 14 | [CmdletBinding()] 15 | param ( 16 | [Parameter(Mandatory = $false)] 17 | $Cmdlet 18 | ) 19 | 20 | process { 21 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Assert-AzOpsBicepDependency.Validating' 22 | 23 | $result = (Invoke-AzOpsNativeCommand -ScriptBlock { bicep --version } -IgnoreExitcode) 24 | $installed = $result -as [bool] 25 | 26 | if ($installed) { 27 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Assert-AzOpsBicepDependency.Success' 28 | } 29 | else { 30 | $exception = [System.InvalidOperationException]::new('Unable to locate bicep installation') 31 | $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, "ConfigurationError", 'InvalidOperation', $null) 32 | Write-AzOpsMessage -LogLevel Warning -LogString 'Assert-AzOpsBicepDependency.NotFound' 33 | $Cmdlet.ThrowTerminatingError($errorRecord) 34 | } 35 | 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/tests/general/PSScriptAnalyzer.Tests.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | Param ( 3 | [switch] 4 | $SkipTest, 5 | 6 | [string[]] 7 | $CommandPath = @("$global:testroot\..\functions", "$global:testroot\..\internal\functions", "$global:testroot\..\..\scripts") 8 | ) 9 | 10 | if ($SkipTest) { return } 11 | 12 | $global:__pester_data.ScriptAnalyzer = New-Object System.Collections.ArrayList 13 | 14 | Describe 'Invoking PSScriptAnalyzer against commandbase' { 15 | $commandFiles = foreach ($path in $CommandPath) { Get-ChildItem -Path $path -Recurse | Where-Object Name -like "*.ps1" } 16 | $scriptAnalyzerRules = Get-ScriptAnalyzerRule 17 | 18 | foreach ($file in $commandFiles) 19 | { 20 | Context "Analyzing $($file.BaseName)" { 21 | $analysis = Invoke-ScriptAnalyzer -Path $file.FullName -ExcludeRule PSShouldProcess 22 | 23 | forEach ($rule in $scriptAnalyzerRules) 24 | { 25 | It "Should pass $rule" -TestCases @{ analysis = $analysis; rule = $rule } { 26 | If ($analysis.RuleName -contains $rule) 27 | { 28 | $analysis | Where-Object RuleName -EQ $rule -outvariable failures | ForEach-Object { $null = $global:__pester_data.ScriptAnalyzer.Add($_) } 29 | 30 | 1 | Should -Be 0 31 | } 32 | else 33 | { 34 | 0 | Should -Be 0 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/xml/README.md: -------------------------------------------------------------------------------- 1 | # xml/ 2 | 3 | This is the folder where project XML files go, notably: 4 | 5 | - Format XML 6 | - Type Extension XML 7 | 8 | External help files should _not_ be placed in this folder! 9 | 10 | ## Notes on Files and Naming 11 | 12 | There should be only one format file and one type extension file per project, as importing them has a notable impact on import times. 13 | 14 | - The Format XML should be named `AzOps.Format.ps1xml` 15 | - The Type Extension XML should be named `AzOps.Types.ps1xml` 16 | 17 | ## Tools 18 | 19 | ### New-PSMDFormatTableDefinition 20 | 21 | This function will take an input object and generate format xml for an auto-sized table. 22 | 23 | It provides a simple way to get started with formats. 24 | 25 | ### Get-PSFTypeSerializationData 26 | 27 | ``` 28 | C# Warning! 29 | This section is only interest if you're using C# together with PowerShell. 30 | ``` 31 | 32 | This function generates type extension XML that allows PowerShell to convert types written in C# to be written to file and restored from it without being 'Deserialized'. Also works for jobs or remoting, if both sides have the `PSFramework` module and type extension loaded. 33 | 34 | In order for a class to be eligible for this, it needs to conform to the following rules: 35 | 36 | - Have the `[Serializable]` attribute 37 | - Be public 38 | - Have an empty constructor 39 | - Allow all public properties/fields to be set (even if setting it doesn't do anything) without throwing an exception. 40 | 41 | non-public properties and fields will be lost in this process! -------------------------------------------------------------------------------- /src/tests/templates/pushmgmttest1displayname (pushmgmttest1id)/microsoft.management_managementgroups-pushmgmttest1id.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": [ 12 | { 13 | "type": "Microsoft.Management/managementGroups", 14 | "name": "pushmgmttest1id", 15 | "apiVersion": "2023-04-01", 16 | "scope": "/", 17 | "properties": { 18 | "displayName": "pushmgmttest1displayname", 19 | "details": { 20 | "parent": { 21 | "id": "/providers/Microsoft.Management/managementGroups/52fd72ab-b56e-5a52-83a1-1f87365f7998" 22 | } 23 | } 24 | } 25 | }, 26 | { 27 | "type": "Microsoft.Resources/deployments", 28 | "apiVersion": "2024-11-01", 29 | "name": "AzOps-microsoft.management_managementgroups-nested", 30 | "location": "[deployment().location]", 31 | "properties": { 32 | "mode": "Incremental", 33 | "template": { 34 | "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", 35 | "contentVersion": "1.0.0.0", 36 | "resources": [], 37 | "outputs": {} 38 | } 39 | }, 40 | "dependsOn": [ 41 | "Microsoft.Management/managementGroups/pushmgmttest1id" 42 | ] 43 | } 44 | ], 45 | "outputs": {} 46 | } 47 | -------------------------------------------------------------------------------- /src/tests/templates/pushmgmttest2displayname (pushmgmttest2id)/microsoft.management_managementgroups-pushmgmttest2id.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_generator": { 6 | "name": "AzOps" 7 | } 8 | }, 9 | "parameters": {}, 10 | "variables": {}, 11 | "resources": [ 12 | { 13 | "type": "Microsoft.Management/managementGroups", 14 | "name": "pushmgmttest2id", 15 | "apiVersion": "2023-04-01", 16 | "scope": "/", 17 | "properties": { 18 | "displayName": "pushmgmttest2displayname", 19 | "details": { 20 | "parent": { 21 | "id": "/providers/Microsoft.Management/managementGroups/52fd72ab-b56e-5a52-83a1-1f87365f7998" 22 | } 23 | } 24 | } 25 | }, 26 | { 27 | "type": "Microsoft.Resources/deployments", 28 | "apiVersion": "2024-11-01", 29 | "name": "AzOps-microsoft.management_managementgroups-nested", 30 | "location": "[deployment().location]", 31 | "properties": { 32 | "mode": "Incremental", 33 | "template": { 34 | "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", 35 | "contentVersion": "1.0.0.0", 36 | "resources": [], 37 | "outputs": {} 38 | } 39 | }, 40 | "dependsOn": [ 41 | "Microsoft.Management/managementGroups/pushmgmttest2id" 42 | ] 43 | } 44 | ], 45 | "outputs": {} 46 | } 47 | -------------------------------------------------------------------------------- /src/tests/general/Strings.Tests.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .DESCRIPTION 3 | This test verifies, that all strings that have been used, 4 | are listed in the language files and thus have a message being displayed. 5 | 6 | It also checks, whether the language files have orphaned entries that need cleaning up. 7 | #> 8 | 9 | Describe "Testing localization strings" { 10 | $moduleRoot = (Get-Module AzOps).ModuleBase 11 | $scripts = "$moduleRoot\..\scripts" 12 | $strings = Get-PSFLocalizedString -Module AzOps 13 | $stringsResults = Export-PSMDString -ModuleRoot $moduleRoot 14 | $exceptions = & "$global:testroot\general\Strings.Exceptions.ps1" 15 | $allFiles = Get-ChildItem -Path $moduleRoot -Recurse | Where-Object Name -like "*.ps1" 16 | $allFiles += Get-ChildItem -Path $scripts -Recurse | Where-Object Name -like "*.ps1" 17 | 18 | foreach ($stringEntry in $stringsResults) { 19 | if ($stringEntry.String -eq "key") { continue } # Skipping the template default entry 20 | It "Should be used & have text: $($stringEntry.String)" -TestCases @{ stringEntry = $stringEntry } { 21 | if ($exceptions.LegalSurplus -notcontains $stringEntry.String) { 22 | $stringEntry.Surplus | Should -BeFalse 23 | } 24 | $stringEntry.Text | Should -Not -BeNullOrEmpty 25 | } 26 | } 27 | 28 | foreach ($string in $($strings.Keys)) { 29 | It "Should be used: $string" -TestCases @{ allFiles = $allFiles; string = $string } { 30 | Select-String -Path $allFiles -Pattern $string | Should -Not -BeNullOrEmpty 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /docs/wiki/Updates.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This Accelerator has been constructed whereby user generated repositories are created from a template design. This means at the point in time when the downstream repository is created, it is up to date however as time progresses there is the possibility that the downstream repository 4 | doesn't maintain the latest workflow files. Due to on-going development of this project (AzOps) there are times where it's recommended that the downstream workflows / pipelines are updated. We aren't planning to alter the Actions / Pipelines files too frequently however manually copying the contents isn't the perfect solution. 5 | 6 | To provide the ability to update Actions / Pipelines on demand we created a solution 'Patch', this will allow users to periodically check the upstream repository (azure/azops) for any changes to the SCM folders and if so copy them changes downstream by creating a new temporary branch and opening a Pull Request for the user to review the changes. 7 | 8 | ## Prerequisites 9 | 10 | Due to permission limitations on the built-in GitHub Token which Git authenticates with it's not possible to push any changes to the `.github/` directory. This means that the Patch workflow requires a manually created [Personal Access Token](https://github.com/settings/tokens) to be provides as a Repository Secrets with the `workflow` permissions set. 11 | 12 | 13 | 14 | ## GitHub Actions 15 | 16 | [Source](https://github.com/azure/azops-accelerator/blob/main/.github/workflows/update.yml) 17 | 18 | ## Azure Pipelines 19 | 20 | [Source](https://github.com/azure/azops-accelerator/blob/main/.pipelines/update.yml) 21 | -------------------------------------------------------------------------------- /.github/workflows/dependencies.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Dependencies" 3 | 4 | on: 5 | schedule: 6 | - cron: '30 1 1,15 * *' 7 | workflow_dispatch: 8 | 9 | env: 10 | # 11 | # Branch Name 12 | # As part of the Dependencies workflow we create a temporary branch 13 | # this value can be changed if this name is already reserved for other systems 14 | # within the repository. 15 | # 16 | # Default: automated-dependencies 17 | # 18 | 19 | branch: "automated-dependencies" 20 | 21 | jobs: 22 | dependencies: 23 | name: "Automated Dependencies" 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: "Checkout" 27 | uses: actions/checkout@v4 28 | 29 | - name: "Configure" 30 | run: | 31 | git config user.name github-actions 32 | git config user.email '41898282+github-actions[bot]@users.noreply.github.com' 33 | 34 | - name: "Switch" 35 | run: | 36 | git checkout -b ${{ env.branch }} 37 | 38 | - name: "Dependencies" 39 | run: | 40 | ./scripts/Dependencies.ps1 41 | shell: pwsh 42 | 43 | - name: "Updates" 44 | run: ./scripts/UpdateRequiredModules.ps1 45 | shell: pwsh 46 | 47 | - name: "Execute" 48 | run: | 49 | FILE=/tmp/updates.json 50 | if [ -f "$FILE" ]; then 51 | git add src/AzOps.psd1 52 | git commit -m 'Update AzOps.psd1' 53 | git push origin ${{ env.branch }} 54 | gh pr create --base 'main' --head ${{ env.branch }} --title 'Bump Dependencies' --body '' --label 'dependencies' 55 | fi 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /src/internal/functions/Get-AzOpsNestedSubscription.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzOpsNestedSubscription { 2 | <# 3 | .SYNOPSIS 4 | Create a list of subscriptionId's nested at ManagementGroup Scope 5 | .PARAMETER Scope 6 | ManagementGroup Name 7 | .PARAMETER SkipSubscription 8 | Filter which Subscription IDs should be excluded from pull. 9 | .EXAMPLE 10 | > Get-AzOpsNestedSubscription -Scope 5663f39e-feb1-4303-a1f9-cf20b702de61 11 | Discover subscriptions at Management Group scope and below 12 | #> 13 | 14 | [CmdletBinding()] 15 | param ( 16 | [Parameter(Mandatory = $false)] 17 | [string] 18 | $Scope, 19 | 20 | [string[]] 21 | $SkipSubscription = (Get-PSFConfigValue -FullName 'AzOps.Core.SkipSubscription') 22 | ) 23 | 24 | process { 25 | $children = ($script:AzOpsAzManagementGroup | Where-Object {$_.Name -eq $Scope}).Children 26 | if ($children) { 27 | $subscriptionIds = @() 28 | foreach ($child in $children) { 29 | if (($child.Type -eq '/subscriptions') -and ($script:AzOpsSubscriptions.id -contains $child.Id) -and ($child.Name -notin $SkipSubscription)) { 30 | $subscriptionIds += [PSCustomObject] @{ 31 | Name = $child.DisplayName 32 | Id = $child.Name 33 | Type = $child.Type 34 | } 35 | } 36 | else { 37 | $subscriptionIds += Get-AzOpsNestedSubscription -Scope $child.Name 38 | } 39 | } 40 | if ($subscriptionIds) { 41 | return $subscriptionIds 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/localNetworkGateways/deploy/deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "localNetworkGatewayName": { 6 | "type": "string", 7 | "minLength": 1, 8 | "metadata": { 9 | "description": "Required. Name of the Local Network Gateway" 10 | } 11 | }, 12 | "location": { 13 | "type": "string", 14 | "defaultValue": "[resourceGroup().location]", 15 | "metadata": { 16 | "description": "Optional. Location for all resources." 17 | } 18 | }, 19 | "localAddressPrefixes": { 20 | "type": "array", 21 | "metadata": { 22 | "description": "Required. List of the local (on-premises) IP address ranges" 23 | } 24 | }, 25 | "localGatewayPublicIpAddress": { 26 | "type": "string", 27 | "metadata": { 28 | "description": "Required. Public IP of the local gateway" 29 | } 30 | } 31 | }, 32 | "resources": [ 33 | { 34 | "type": "Microsoft.Network/localNetworkGateways", 35 | "apiVersion": "2024-05-01", 36 | "name": "[parameters('localNetworkGatewayName')]", 37 | "location": "[parameters('location')]", 38 | "properties": { 39 | "localNetworkAddressSpace": { 40 | "addressPrefixes": "[parameters('localAddressPrefixes')]" 41 | }, 42 | "gatewayIpAddress": "[parameters('localGatewayPublicIpAddress')]" 43 | } 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/wiki-sync.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "docs/wiki/**" 9 | workflow_dispatch: 10 | 11 | env: 12 | wiki_source_repo: "Azure/AzOps" 13 | wiki_source_repo_dir: "Azure/AzOps/docs/wiki" 14 | wiki_target_repo: "Azure/AzOps.wiki" 15 | github_user_name: "github-actions" 16 | github_email: "github-actions@github.com" 17 | github_commit_message: "GitHub Action syncing wiki from docs/wiki" 18 | 19 | permissions: 20 | contents: write 21 | 22 | jobs: 23 | sync-wiki: 24 | name: Sync Wiki 25 | if: github.repository == 'Azure/AzOps' 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout Source Repo 29 | uses: actions/checkout@v4 30 | with: 31 | repository: ${{ env.wiki_source_repo }} 32 | path: ${{ env.wiki_source_repo }} 33 | 34 | - name: Checkout Wiki Repo 35 | uses: actions/checkout@v4 36 | with: 37 | repository: ${{ env.wiki_target_repo }} 38 | path: ${{ env.wiki_target_repo }} 39 | 40 | - name: Configure Local Git 41 | run: | 42 | git config --global user.name $github_user_name 43 | git config --global user.email $github_email 44 | working-directory: ${{ env.GITHUB_WORKSPACE }} 45 | 46 | - name: Sync docs/wiki Into Wiki Repo 47 | run: | 48 | rsync -avzr --delete --exclude='.git/' "$wiki_source_repo_dir/" "$wiki_target_repo" 49 | working-directory: ${{ env.GITHUB_WORKSPACE }} 50 | 51 | - name: Stage & Push Files Into Wiki Repo 52 | run: | 53 | git add . 54 | git commit -m "$github_commit_message [$GITHUB_ACTOR/${GITHUB_SHA::8}]" 55 | git push --set-upstream https://$GITHUB_TOKEN@github.com/$wiki_target_repo.git master 56 | working-directory: ${{ env.wiki_target_repo }} -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## Microsoft Support Policy 4 | 5 | If issues are encountered when using template and code in this repo, users will be able to engage Microsoft support via their usual channels. Please provide corelation IDs where possible when contacting support to be able to investigate issue effectively and in timely fashion. For instruction on how to get deployments and correlation ID, please follow this link [here](https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/deployment-history?tabs=azure-portal#get-deployments-and-correlation-id). 6 | 7 | Following list of issues are within the scope of Microsoft support: 8 | 9 | - Tenant, Management Group, Subscription and Resource Group deployment 10 | - Az PowerShell commandlets e.g. Get-AzManagementGroup 11 | - ARM Deployment Issues e.g. template validation, CheckAccess API etc. 12 | - Git Actions/Azure DevOps pipeline itself however please note that PowerShell module will be supported via community support only. 13 | 14 | Any issues that deemed outside of the above list by Microsoft support and/or requires bugfix in the Template or Code in the repo, Microsoft support will redirect user to file the issue on GitHub. 15 | 16 | Project maintainers and community aim to get issues resolved in timely fashion as per community support policy of this repo. 17 | 18 | ## Community Support Policy 19 | 20 | Project maintainers will aim to respond within 3 business days to get a meaningful response for any new issues. 21 | 22 | ## How to file issues and get help 23 | 24 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new Issue. 25 | 26 | For help and questions about using this project, please submit a GitHub issue with corresponding [Issue Labels found here](https://github.com/Azure/AzOps/labels). -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Network/privateDnsZones/deploy/deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "privateDnsZoneName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Required. Private DNS zone name." 9 | } 10 | }, 11 | "location": { 12 | "type": "string", 13 | "defaultValue": "global", 14 | "metadata": { 15 | "description": "Optional. The location of the PrivateDNSZone. Should be global." 16 | } 17 | } 18 | }, 19 | "variables": { }, 20 | "resources": [ 21 | { 22 | "type": "Microsoft.Network/privateDnsZones", 23 | "apiVersion": "2024-06-01", 24 | "name": "[parameters('privateDnsZoneName')]", 25 | "location": "[parameters('location')]" 26 | } 27 | ], 28 | "outputs": { 29 | "privateDnsZoneResourceGroup": { 30 | "type": "string", 31 | "value": "[resourceGroup().name]", 32 | "metadata": { 33 | "description": "The name of the Resource Group the resources was deployed to." 34 | } 35 | }, 36 | "privateDnsZoneName": { 37 | "type": "string", 38 | "value": "[parameters('privateDnsZoneName')]", 39 | "metadata": { 40 | "description": "The Name of the private DNS zone." 41 | } 42 | }, 43 | "privateDnsZoneResourceId": { 44 | "type": "string", 45 | "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('privateDnsZoneName'))]", 46 | "metadata": { 47 | "description": "The Resource Id of the private DNS zone." 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/tests/functions/Set-AzOpsRemoveOrder.Tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "Function Test - Set-AzOpsRemoveOrder" { 2 | 3 | BeforeAll { 4 | 5 | } 6 | 7 | Context "Test: Set-AzOpsRemoveOrder Sorts as Expected" { 8 | It 'Sort based on priority' { 9 | InModuleScope AzOps { 10 | $storageAccount = 'storageAccount' 11 | $resourceGroups = 'resourceGroups' 12 | $locks = 'locks' 13 | $managementGroups = 'managementGroups' 14 | $routeTables = 'routeTables' 15 | $testList = @( 16 | [PSCustomObject]@{ 17 | Name = 'Item1' 18 | Type = $storageAccount 19 | }, 20 | [PSCustomObject]@{ 21 | Name = 'Item2' 22 | Type = $resourceGroups 23 | }, 24 | [PSCustomObject]@{ 25 | Name = 'Item3' 26 | Type = $locks 27 | }, 28 | [PSCustomObject]@{ 29 | Name = 'Item4' 30 | Type = $managementGroups 31 | }, 32 | [PSCustomObject]@{ 33 | Name = 'Item5' 34 | Type = $routeTables 35 | } 36 | ) 37 | $returnList = Set-AzOpsRemoveOrder -DeletionList $testList -Index { $_.Type } 38 | $returnList[0].Type | Should -Be $locks 39 | $returnList[1].Type | Should -Be $resourceGroups 40 | $returnList[2].Type | Should -Be $managementGroups 41 | $returnList[3].Type | Should -BeIn $storageAccount,$routeTables 42 | $returnList[4].Type | Should -BeIn $storageAccount,$routeTables 43 | } 44 | } 45 | } 46 | 47 | AfterAll { 48 | 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Compute/virtualMachines/deploy/deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "value": "westeurope" 7 | }, 8 | "networkInterfaceName": { 9 | "value": "vm01470" 10 | }, 11 | "networkSecurityGroupName": { 12 | "value": "vm01-nsg" 13 | }, 14 | "networkSecurityGroupRules": { 15 | "value": [] 16 | }, 17 | "subnetName": { 18 | "value": "default" 19 | }, 20 | "virtualNetworkName": { 21 | "value": "vnet104" 22 | }, 23 | "addressPrefixes": { 24 | "value": [ 25 | "10.2.0.0/16" 26 | ] 27 | }, 28 | "subnets": { 29 | "value": [ 30 | { 31 | "name": "default", 32 | "properties": { 33 | "addressPrefix": "10.2.0.0/24" 34 | } 35 | } 36 | ] 37 | }, 38 | "virtualMachineName": { 39 | "value": "vm01" 40 | }, 41 | "virtualMachineComputerName": { 42 | "value": "vm01" 43 | }, 44 | "osDiskType": { 45 | "value": "StandardSSD_LRS" 46 | }, 47 | "osDiskDeleteOption": { 48 | "value": "Detach" 49 | }, 50 | "virtualMachineSize": { 51 | "value": "Standard_DS1_v2" 52 | }, 53 | "nicDeleteOption": { 54 | "value": "Detach" 55 | }, 56 | "adminUsername": { 57 | "value": "adminuser" 58 | }, 59 | "patchMode": { 60 | "value": "AutomaticByOS" 61 | }, 62 | "enableHotpatching": { 63 | "value": false 64 | }, 65 | "zone": { 66 | "value": ["2"] 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/tests/functional/Microsoft.Authorization/roleEligibilityScheduleRequests/deploy/deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "location": { 6 | "type": "string" 7 | }, 8 | "scheduleRequestName": { 9 | "type": "string", 10 | "defaultValue": "[newGuid()]", 11 | "metadata": { 12 | "description": "A new GUID used to identify the role assignment" 13 | } 14 | }, 15 | "principalId": { 16 | "type": "string" 17 | }, 18 | "roleDefinitionId": { 19 | "type": "string" 20 | }, 21 | "startDateTime": { 22 | "type": "string", 23 | "defaultValue": "[utcNow()]", 24 | "metadata": { 25 | "description": "Start DateTime of the role eligibility schedule" 26 | } 27 | } 28 | }, 29 | "variables": { 30 | "add1Year": "[dateTimeAdd(parameters('startDateTime'), 'P1Y')]" 31 | }, 32 | "resources": [ 33 | { 34 | "name": "[parameters('scheduleRequestName')]", 35 | "type": "Microsoft.Authorization/roleEligibilityScheduleRequests", 36 | "apiVersion": "2020-10-01", 37 | "location": "[parameters('location')]", 38 | "dependsOn": [], 39 | "tags": {}, 40 | "properties": { 41 | "RoleDefinitionId": "[concat('/providers/Microsoft.Authorization/roleDefinitions/',parameters('roleDefinitionId'))]", 42 | "PrincipalId": "[parameters('principalId')]", 43 | "ScheduleInfo": { 44 | "Expiration": { 45 | "EndDateTime": "[variables('add1Year')]", 46 | "ExpirationType": "AfterDuration" 47 | }, 48 | "StartDateTime": "[parameters('startDateTime')]" 49 | }, 50 | "RequestType": "AdminAssign" 51 | } 52 | } 53 | ] 54 | } -------------------------------------------------------------------------------- /src/internal/functions/Invoke-AzOpsRestMethod.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-AzOpsRestMethod { 2 | <# 3 | .SYNOPSIS 4 | Process Path with given Method and manage paging of results and returns value's 5 | .PARAMETER Path 6 | Path 7 | .PARAMETER Method 8 | Method 9 | .EXAMPLE 10 | > Invoke-AzOpsRestMethod -Path "/subscriptions/{subscription}/resourcegroups/{resourcegroup}/providers/microsoft.operationalinsights/workspaces/{workspace}?api-version={API}" -Method GET 11 | #> 12 | 13 | [CmdletBinding()] 14 | param ( 15 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 16 | [object] 17 | $Path, 18 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 19 | $Method 20 | ) 21 | 22 | process { 23 | # Process Path with given Method 24 | Write-AzOpsMessage -LogLevel Debug -LogString 'Invoke-AzOpsRestMethod.Processing' -LogStringValues $Path 25 | $allresults = do { 26 | try { 27 | $results = ((Invoke-AzRestMethod -Path $Path -Method $Method -ErrorAction Stop).Content | ConvertFrom-Json -Depth 100) 28 | $results.value 29 | $path = $results.nextLink -replace 'https://management\.azure\.com' 30 | if ($results.StatusCode -eq '429' -or $results.StatusCode -like '5*') { 31 | $results.Headers.GetEnumerator() | ForEach-Object { 32 | if ($_.key -eq 'Retry-After') { 33 | Write-AzOpsMessage -LogLevel Warning -LogString 'Invoke-AzOpsRestMethod.Processing.RateLimit' -LogStringValues $Path, $_.value 34 | Start-Sleep -Seconds $_.value 35 | } 36 | } 37 | } 38 | } 39 | catch { 40 | Write-AzOpsMessage -LogLevel Error -LogString 'Invoke-AzOpsRestMethod.Processing.Error' -LogStringValues $_, $Path 41 | } 42 | } 43 | while ($path) 44 | if ($allresults) { 45 | return $allresults 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/internal/functions/Invoke-AzOpsNativeCommand.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-AzOpsNativeCommand { 2 | 3 | <# 4 | .SYNOPSIS 5 | Executes a native command. 6 | .DESCRIPTION 7 | Executes a native command. 8 | .PARAMETER ScriptBlock 9 | The scriptblock containing the native command to execute. 10 | Note: Specifying a scriptblock WITHOUT any native command may cause erroneous LASTEXITCODE detection. 11 | .PARAMETER IgnoreExitcode 12 | Whether to ignore exitcodes. 13 | .PARAMETER Quiet 14 | Quiet mode disables printing error output of a native command. 15 | .EXAMPLE 16 | > Invoke-AzOpsNativeCommand -Scriptblock { git config --system -l } 17 | Executes "git config --system -l" 18 | #> 19 | 20 | [CmdletBinding()] 21 | param ( 22 | [Parameter(Mandatory = $true)] 23 | [scriptblock] 24 | $ScriptBlock, 25 | 26 | [switch] 27 | $IgnoreExitcode, 28 | 29 | [switch] 30 | $Quiet 31 | ) 32 | 33 | try { 34 | if ($Quiet) { 35 | $output = & $ScriptBlock 2>&1 36 | } 37 | else { $output = & $ScriptBlock } 38 | 39 | if (-not $Quiet -and $output) { 40 | $output | Out-String -NoNewLine | ForEach-Object { 41 | Write-AzOpsMessage -LogLevel Debug -LogString 'Invoke-AzOpsNativeCommand' -LogStringValues $ScriptBlock, $_ 42 | } 43 | $output 44 | } 45 | } 46 | catch { 47 | if (-not $IgnoreExitcode) { 48 | $caller = Get-PSCallStack -ErrorAction SilentlyContinue 49 | if ($caller) { 50 | Stop-PSFFunction -String 'Invoke-AzOpsNativeCommand.Failed.WithCallstack' -StringValues $ScriptBlock, $caller[1].ScriptName, $caller[1].ScriptLineNumber, $LASTEXITCODE -Cmdlet $PSCmdlet -EnableException $true 51 | } 52 | Stop-PSFFunction -String 'Invoke-AzOpsNativeCommand.Failed.NoCallstack' -StringValues $ScriptBlock, $LASTEXITCODE -Cmdlet $PSCmdlet -EnableException $true 53 | } 54 | $output 55 | } 56 | } -------------------------------------------------------------------------------- /src/internal/functions/Assert-AzOpsJqDependency.ps1: -------------------------------------------------------------------------------- 1 | function Assert-AzOpsJqDependency { 2 | 3 | <# 4 | .SYNOPSIS 5 | Asserts that - if jq is installed and in current path 6 | .DESCRIPTION 7 | Asserts that - if jq is installed and in current path 8 | .PARAMETER Cmdlet 9 | The $PSCmdlet variable of the calling command. 10 | .EXAMPLE 11 | > Assert-AzOpsJqDependency -Cmdlet $PSCmdlet 12 | #> 13 | 14 | [CmdletBinding()] 15 | param ( 16 | [Parameter(Mandatory = $false)] 17 | $Cmdlet 18 | ) 19 | 20 | process { 21 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Assert-AzOpsJqDependency.Validating' 22 | $minVersion = New-Object System.Version("1.6") 23 | $result = (Invoke-AzOpsNativeCommand -ScriptBlock { jq --version } -IgnoreExitcode) 24 | $installed = $result -as [bool] 25 | 26 | if ($installed) { 27 | $version = New-Object System.Version(($result).Split("-")[1]) 28 | if ($version -ge $minVersion) { 29 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Assert-AzOpsJqDependency.Success' 30 | return 31 | } 32 | else { 33 | $exception = [System.InvalidOperationException]::new('Unsupported version of jq installed. Please update to a minimum jq version of 1.6') 34 | $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, "ConfigurationError", 'InvalidOperation', $null) 35 | Write-AzOpsMessage -LogLevel Warning -LogString 'Assert-AzOpsJqDependency.Failed' 36 | $Cmdlet.ThrowTerminatingError($errorRecord) 37 | } 38 | } 39 | 40 | $exception = [System.InvalidOperationException]::new('Unable to locate jq installation') 41 | $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, "ConfigurationError", 'InvalidOperation', $null) 42 | Write-AzOpsMessage -LogLevel Warning -LogString 'Assert-AzOpsJqDependency.Failed' 43 | $Cmdlet.ThrowTerminatingError($errorRecord) 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/internal/functions/Get-AzOpsCurrentPrincipal.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzOpsCurrentPrincipal { 2 | <# 3 | .SYNOPSIS 4 | Gets the objectid/clientid from the current Azure context 5 | .DESCRIPTION 6 | Gets the objectid/clientid from the current Azure context 7 | .PARAMETER AzContext 8 | The AzContext used when pulling the information. 9 | .EXAMPLE 10 | > Get-AzOpsCurrentPrincipal -AzContext $AzContext 11 | #> 12 | 13 | [CmdletBinding()] 14 | param ( 15 | [Parameter(Mandatory = $false)] 16 | $AzContext = (Get-AzContext) 17 | ) 18 | 19 | process { 20 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Get-AzOpsCurrentPrincipal.AccountType' -LogStringValues $AzContext.Account.Type 21 | 22 | switch ($AzContext.Account.Type) { 23 | 'User' { 24 | $restMethodResult = Invoke-AzRestMethod -Uri https://graph.microsoft.com/v1.0/me -ErrorAction Stop 25 | if ($restMethodResult) { 26 | $principalObject = $restMethodResult.Content | ConvertFrom-Json -ErrorAction Stop 27 | } 28 | } 29 | 'ManagedService' { 30 | # Get managed identity application id via IMDS (https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token) 31 | $restMethodResult = Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F" -Headers @{ Metadata = $true } -ErrorAction Stop 32 | if ($restMethodResult.client_id) { 33 | $principalObject = Get-AzADServicePrincipal -ApplicationId $restMethodResult.client_id -ErrorAction Stop 34 | } 35 | } 36 | default { 37 | $principalObject = Get-AzADServicePrincipal -ApplicationId $AzContext.Account.Id -ErrorAction Stop 38 | } 39 | } 40 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Get-AzOpsCurrentPrincipal.PrincipalId' -LogStringValues $principalObject.Id 41 | return $principalObject 42 | } 43 | } -------------------------------------------------------------------------------- /src/internal/functions/Set-AzOpsRemoveOrder.ps1: -------------------------------------------------------------------------------- 1 | function Set-AzOpsRemoveOrder { 2 | 3 | <# 4 | .SYNOPSIS 5 | Sorts a custom object list based on a specified priority order using a user-defined index. 6 | .DESCRIPTION 7 | Used to sort deletion priority, aka locks are removed prior to resource deletion attempts. 8 | .PARAMETER DeletionList 9 | Custom object list to be sorted based on the defined priority. 10 | .PARAMETER Index 11 | Script block that determines the index used for sorting the deletion list. 12 | .PARAMETER Priority 13 | Optional array of strings representing the priority order. Defaults to a predefined order if not provided. 14 | .EXAMPLE 15 | > $sortedList = Set-AzOpsRemoveOrder -DeletionList $myCustomObjectList -Index { $_.SomeProperty } 16 | #> 17 | 18 | [CmdletBinding()] 19 | param ( 20 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 21 | $DeletionList, 22 | [Parameter(Mandatory = $true)] 23 | [scriptblock] 24 | $Index, 25 | [string[]] 26 | $Priority = @( 27 | "locks", 28 | "deploymentStacks", 29 | "policyExemptions", 30 | "policyAssignments", 31 | "policySetDefinitions", 32 | "policyDefinitions", 33 | "resourceGroups", 34 | "managementGroups" 35 | ) 36 | ) 37 | 38 | process { 39 | #Sort 'DeletionList' based on 'Priority' 40 | $deletionListSorted = $DeletionList | Sort-Object -Property { 41 | $resolvedIndex = & $Index 42 | # Check if the item has a non-null DeploymentStackSettings 43 | if ($null -ne $_.DeploymentStackSettings) { 44 | $resolvedIndex = "deploymentStacks" 45 | } 46 | $priorityIndex = $Priority.IndexOf($resolvedIndex) 47 | if ($priorityIndex -eq -1) { 48 | # Set a default priority for items not found in Priority 49 | return [int]::MaxValue 50 | } 51 | else { 52 | return $priorityIndex 53 | } 54 | } 55 | # Return processed list 56 | return $deletionListSorted 57 | } 58 | } -------------------------------------------------------------------------------- /src/internal/functions/Assert-AzOpsInitialization.ps1: -------------------------------------------------------------------------------- 1 | function Assert-AzOpsInitialization { 2 | 3 | <# 4 | .SYNOPSIS 5 | Asserts AzOps has been correctly prepare for execution. 6 | .DESCRIPTION 7 | Asserts AzOps has been correctly prepare for execution. 8 | This boils down to Initialize-AzOpsEnvironment having been executed successfully. 9 | .PARAMETER Cmdlet 10 | The $PSCmdlet variable of the calling command. 11 | .PARAMETER StatePath 12 | Path to where the AzOps processing state / repository is located at. 13 | .EXAMPLE 14 | > Assert-AzOpsInitialization -Cmdlet $PSCmdlet -Statepath $StatePath 15 | Asserts AzOps has been correctly prepare for execution. 16 | #> 17 | 18 | [CmdletBinding()] 19 | param ( 20 | [Parameter(Mandatory = $true)] 21 | $Cmdlet, 22 | 23 | [Parameter(Mandatory = $true)] 24 | [string] 25 | $StatePath 26 | ) 27 | 28 | begin { 29 | $strings = Get-PSFLocalizedString -Module AzOps 30 | $invalidPathPattern = [System.IO.Path]::GetInvalidPathChars() -replace '\|', '\|' -join "|" 31 | } 32 | 33 | process { 34 | $stateGood = $StatePath -and $StatePath -notmatch $invalidPathPattern 35 | if (-not $stateGood) { 36 | Write-AzOpsMessage -LogLevel Warning -LogString 'Assert-AzOpsInitialization.StateError' 37 | $exception = [System.InvalidOperationException]::new($strings.'Assert-AzOpsInitialization.StateError') 38 | $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, "BadData", 'InvalidData', $null) 39 | } 40 | $cacheBuilt = $script:AzOpsSubscriptions -or $script:AzOpsAzManagementGroup 41 | if (-not $cacheBuilt) { 42 | Write-AzOpsMessage -LogLevel Warning -LogString 'Assert-AzOpsInitialization.NoCache' 43 | $exception = [System.InvalidOperationException]::new($strings.'Assert-AzOpsInitialization.NoCache') 44 | $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, "NoCache", 'InvalidData', $null) 45 | } 46 | 47 | if (-not $stateGood -or -not $cacheBuilt) { 48 | $Cmdlet.ThrowTerminatingError($errorRecord) 49 | } 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /docs/wiki/Troubleshooting.md: -------------------------------------------------------------------------------- 1 | # In this guide 2 | 3 | - [General](#general) 4 | - [GitHub Actions](#github-actions) 5 | - [Azure Pipelines](#azure-pipelines) 6 | - [Windows](#windows) 7 | 8 | ## General 9 | 10 | To enable debug logging for the AzOps module, please add the following configuration item to the `settings.json` within the repository. 11 | 12 | ```json 13 | { 14 | "PSFramework": { 15 | "Message.Info.Maximum": 9 16 | } 17 | } 18 | ``` 19 | 20 | ## GitHub Actions 21 | 22 | To enable debug logging within GitHub Actions workflows, please visit the [Product Documentation](https://docs.github.com/en/actions/managing-workflow-runs/enabling-debug-logging) 23 | 24 | --- 25 | 26 | ## Azure Pipelines 27 | 28 | To enable debug logging within Azure Pipelines, please visit the [Product Documentation](https://learn.microsoft.com/en-us/azure/devops/pipelines/troubleshooting/review-logs?view=azure-devops). 29 | 30 | TF401027: You need the Git 'ForcePush' permission to perform this action 31 | As part of Step 4, you need to either allow the Build Service, or the Contributor group Force Push on the main branch. 32 | 33 | The Directory Role Directory Readers is not returned by Get-AzureADDirectoryRole 34 | The Get-AzureADDirectoryRole only returns roles which have at least one assignment, to use the script to make the role assignment you need to have already been to the Azure Portal and assigned the role previously. 35 | 36 | Conversion from JSON failed with error: Input string is not a valid number - AzOps Pull Run Container 37 | Ensure that you're using the $escapedServicePrincipalJson variable string from the script at the beginning of this article. If you use an unescaped JSON string then this error will occur. 38 | 39 | --- 40 | 41 | ## Windows 42 | 43 | Enabling long paths on Windows 44 | The Git clone below and AzOps GitHub Action implementation requires that you enable long paths in Windows. To enable this, execute the following command from a terminal with elevated privileges: 45 | 46 | ```powershell 47 | REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f 48 | ``` 49 | 50 | You will also need to execute the following command-line from an elevated terminal: 51 | 52 | ```powershell 53 | git config --system core.longpaths true 54 | ``` 55 | 56 | Restart your computer to ensure changes take effect. -------------------------------------------------------------------------------- /src/internal/functions/Get-AzOpsPolicyDefinition.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzOpsPolicyDefinition { 2 | 3 | <# 4 | .SYNOPSIS 5 | Discover all custom policy definitions at the provided scope (Management Groups or subscriptions) 6 | .DESCRIPTION 7 | Discover all custom policy definitions at the provided scope (Management Groups or subscriptions) 8 | .PARAMETER ScopeObject 9 | The scope object representing the azure entity to retrieve policy definitions for. 10 | .PARAMETER Subscription 11 | Complete Subscription list 12 | .EXAMPLE 13 | > Get-AzOpsPolicyDefinition -ScopeObject (New-AzOpsScope -Scope /providers/Microsoft.Management/managementGroups/contoso -StatePath $StatePath) 14 | Discover all custom policy definitions deployed at Management Group scope 15 | #> 16 | 17 | [OutputType([Microsoft.Azure.PowerShell.Cmdlets.Policy.Models.IPolicyDefinition])] 18 | [CmdletBinding()] 19 | param ( 20 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 21 | [object] 22 | $ScopeObject, 23 | [Parameter(Mandatory = $false)] 24 | [object] 25 | $Subscription 26 | ) 27 | 28 | process { 29 | if ($ScopeObject.Type -notin 'subscriptions', 'managementGroups') { 30 | return 31 | } 32 | if ($ScopeObject.Type -eq 'managementGroups') { 33 | Write-AzOpsMessage -LogLevel Debug -LogString 'Get-AzOpsPolicyDefinition.ManagementGroup' -LogStringValues $ScopeObject.ManagementGroupDisplayName, $ScopeObject.ManagementGroup -Target $ScopeObject 34 | $query = "policyresources | where type == 'microsoft.authorization/policydefinitions' and properties.policyType == 'Custom' and subscriptionId == '' | order by ['id'] asc" 35 | Search-AzOpsAzGraph -ManagementGroupName $ScopeObject.Name -Query $query -ErrorAction Stop 36 | } 37 | if ($Subscription) { 38 | Write-AzOpsMessage -LogLevel Debug -LogString 'Get-AzOpsPolicyDefinition.Subscription' -LogStringValues $Subscription.count -Target $ScopeObject 39 | $query = "policyresources | where type == 'microsoft.authorization/policydefinitions' and properties.policyType == 'Custom' | order by ['id'] asc" 40 | Search-AzOpsAzGraph -Subscription $Subscription -Query $query -ErrorAction Stop 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/internal/functions/Assert-AzOpsWindowsLongPath.ps1: -------------------------------------------------------------------------------- 1 | function Assert-AzOpsWindowsLongPath { 2 | 3 | <# 4 | .SYNOPSIS 5 | Asserts that - if on windows - long paths have been enabled. 6 | .DESCRIPTION 7 | Asserts that - if on windows - long paths have been enabled. 8 | .PARAMETER Cmdlet 9 | The $PSCmdlet variable of the calling command. 10 | .EXAMPLE 11 | > Assert-AzOpsWindowsLongPath -Cmdlet $PSCmdlet 12 | Asserts that - if on windows - long paths have been enabled. 13 | #> 14 | 15 | [CmdletBinding()] 16 | param ( 17 | [Parameter(Mandatory = $true)] 18 | $Cmdlet 19 | ) 20 | 21 | process { 22 | if (-not $IsWindows) { 23 | return 24 | } 25 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Assert-AzOpsWindowsLongPath.Validating' 26 | $hasRegKey = 1 -eq (Get-ItemPropertyValue -Path HKLM:SYSTEM\CurrentControlSet\Control\FileSystem -Name LongPathsEnabled) 27 | $hasGitConfig = (Invoke-AzOpsNativeCommand -ScriptBlock { git config --system -l } -IgnoreExitcode | Select-String 'core.longpaths=true') -as [bool] 28 | if (-not $hasGitConfig) { 29 | # Check global git config if setting not found in system settings 30 | $hasGitConfig = (Invoke-AzOpsNativeCommand -ScriptBlock { git config --global -l } -IgnoreExitcode | Select-String 'core.longpaths=true') -as [bool] 31 | } 32 | 33 | if ($hasGitConfig -and $hasRegKey) { 34 | return 35 | } 36 | if (-not $hasRegKey) { 37 | Write-AzOpsMessage -LogLevel Warning -LogString 'Assert-AzOpsWindowsLongPath.No.Registry' 38 | } 39 | if (-not $hasGitConfig) { 40 | Write-AzOpsMessage -LogLevel Warning -LogString 'Assert-AzOpsWindowsLongPath.No.GitCfg' 41 | } 42 | 43 | $exception = [System.InvalidOperationException]::new('Windows not configured for long paths. Please follow instructions for "Enabling long paths on Windows" on https://github.com/azure/azops/wiki/troubleshooting#windows.') 44 | $errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, "ConfigurationError", 'InvalidOperation', $null) 45 | Write-AzOpsMessage -LogLevel Warning -LogString 'Assert-AzOpsWindowsLongPath.Failed' 46 | $Cmdlet.ThrowTerminatingError($errorRecord) 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/internal/functions/Get-AzOpsPolicySetDefinition.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzOpsPolicySetDefinition { 2 | 3 | <# 4 | .SYNOPSIS 5 | Discover all custom policyset definitions at the provided scope (Management Groups or subscriptions) 6 | .DESCRIPTION 7 | Discover all custom policyset definitions at the provided scope (Management Groups or subscriptions) 8 | .PARAMETER ScopeObject 9 | The scope object representing the azure entity to retrieve policyset definitions for. 10 | .PARAMETER Subscription 11 | Complete Subscription list 12 | .EXAMPLE 13 | > Get-AzOpsPolicySetDefinition -ScopeObject (New-AzOpsScope -Scope /providers/Microsoft.Management/managementGroups/contoso -StatePath $StatePath) 14 | Discover all custom policyset definitions deployed at Management Group scope 15 | #> 16 | 17 | [OutputType([Microsoft.Azure.PowerShell.Cmdlets.Policy.Models.IPolicySetDefinition])] 18 | [CmdletBinding()] 19 | param ( 20 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 21 | [object] 22 | $ScopeObject, 23 | [Parameter(Mandatory = $false)] 24 | [object] 25 | $Subscription 26 | ) 27 | 28 | process { 29 | if ($ScopeObject.Type -notin 'subscriptions', 'managementGroups') { 30 | return 31 | } 32 | if ($ScopeObject.Type -eq 'managementGroups') { 33 | Write-AzOpsMessage -LogLevel Debug -LogString 'Get-AzOpsPolicySetDefinition.ManagementGroup' -LogStringValues $ScopeObject.ManagementGroupDisplayName, $ScopeObject.ManagementGroup -Target $ScopeObject 34 | $query = "policyresources | where type == 'microsoft.authorization/policysetdefinitions' and properties.policyType == 'Custom' and subscriptionId == '' | order by ['id'] asc" 35 | Search-AzOpsAzGraph -ManagementGroupName $ScopeObject.Name -Query $query -ErrorAction Stop 36 | } 37 | if ($Subscription) { 38 | Write-AzOpsMessage -LogLevel Debug -LogString 'Get-AzOpsPolicySetDefinition.Subscription' -LogStringValues $Subscription.count -Target $ScopeObject 39 | $query = "policyresources | where type == 'microsoft.authorization/policysetdefinitions' and properties.policyType == 'Custom' | order by ['id'] asc" 40 | Search-AzOpsAzGraph -Subscription $Subscription -Query $query -ErrorAction Stop 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/data/template/Microsoft.Management/managementGroups.template.jq: -------------------------------------------------------------------------------- 1 | . | . as $input | 2 | 3 | [ 4 | if $input.Children != null 5 | then 6 | foreach $input.Children[] as $item ([[],[]]; 7 | if $item.Type == "/providers/Microsoft.Management/managementGroups" 8 | then 9 | { 10 | "type": "Microsoft.Management/managementGroups", 11 | "apiVersion": "2023-04-01", 12 | "name": $item.Name, 13 | "scope": "/", 14 | "properties": { 15 | "displayName": $item.DisplayName, 16 | "details": { 17 | "parent": { 18 | "id": ($input.Type + "/" + $input.Name) 19 | } 20 | } 21 | } 22 | } 23 | elif $item.Type == "/subscriptions" 24 | then 25 | { 26 | "type": "Microsoft.Management/managementGroups/subscriptions", 27 | "apiVersion": "2023-04-01", 28 | "name": ($input.Name + "/" + $item.Name), 29 | "scope": "/" 30 | } 31 | else 32 | empty 33 | end 34 | ) 35 | else 36 | empty 37 | end 38 | ] as $resources | 39 | 40 | { 41 | "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", 42 | "contentVersion": "1.0.0.0", 43 | "metadata": { 44 | "_generator": { 45 | "name": "AzOps" 46 | } 47 | }, 48 | "parameters": {}, 49 | "variables": {}, 50 | "resources": [ 51 | { 52 | "type": "Microsoft.Management/managementGroups", 53 | "name": .Name, 54 | "apiVersion": "0000-00-00", 55 | "scope": "/", 56 | "properties": { 57 | "displayName": .DisplayName, 58 | "details": { 59 | "parent": { 60 | "id": .ParentId 61 | } 62 | } 63 | } 64 | }, 65 | { 66 | "type": "Microsoft.Resources/deployments", 67 | "apiVersion": "2024-11-01", 68 | "name": "AzOps-microsoft.management_managementgroups-nested", 69 | "location": "[deployment().location]", 70 | "properties": { 71 | "mode": "Incremental", 72 | "template": { 73 | "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#", 74 | "contentVersion": "1.0.0.0", 75 | "resources": $resources, 76 | "outputs": {} 77 | } 78 | }, 79 | "dependsOn": [ 80 | (.Type + "/" + .Name) 81 | ] 82 | } 83 | ], 84 | "outputs": {} 85 | } 86 | -------------------------------------------------------------------------------- /docs/wiki/_Sidebar.md: -------------------------------------------------------------------------------- 1 | # Navigation 2 | 3 | ## Getting started 4 | 5 | * [Introduction](https://github.com/azure/azops/wiki/introduction) 6 | * [Prerequisites](https://github.com/azure/azops/wiki/prerequisites) 7 | * [Sovereign Clouds](https://github.com/azure/azops/wiki/sovereign-clouds) 8 | * [Services](https://github.com/azure/azops/wiki/services) 9 | * [GitHub Actions](https://github.com/azure/azops/wiki/github-actions) 10 | * [Azure Pipelines](https://github.com/azure/azops/wiki/azure-pipelines) 11 | * [Workload Identity Federation](https://github.com/azure/azops/wiki/oidc) 12 | 13 | ## Documentation 14 | 15 | * [Settings](https://github.com/azure/azops/wiki/settings) 16 | * [Custom Jq Templates](https://github.com/azure/azops/wiki/custom-jq-templates) 17 | * [Monitoring](https://github.com/azure/azops/wiki/monitoring) 18 | * [Performance Considerations](https://github.com/azure/azops/wiki/performance-considerations) 19 | * [Updates](https://github.com/azure/azops/wiki/updates) 20 | * [Steps](https://github.com/azure/azops/wiki/steps) 21 | * [Deployments](https://github.com/Azure/Enterprise-Scale/wiki/Deploying-ALZ#operating-the-azure-platform-using-azops-infrastructure-as-code-with-github-actions) 22 | * [Subscriptions](https://github.com/Azure/Enterprise-Scale/wiki/Create-Landingzones#create-landing-zones-subscription-using-azops) 23 | * [DeploymentStacks Feature](https://github.com/azure/azops/wiki/DeploymentStacks) 24 | * [Resources Deletion Feature](https://github.com/azure/azops/wiki/ResourceDeletion) 25 | * [Feeds](https://github.com/azure/azops/wiki/feeds) 26 | * [Azure Artifacts](https://github.com/azure/azops/wiki/azure-artifacts) 27 | * [GitHub Packages](https://github.com/azure/azops/wiki/github-packages) 28 | * [Self-hosted agents/runners](https://github.com/azure/azops/wiki/self-hosted) 29 | * [Roadmap](https://github.com/azure/azops/wiki/roadmap) 30 | * [Troubleshooting](https://github.com/azure/azops/wiki/troubleshooting) 31 | * [FAQ](https://github.com/azure/azops/wiki/frequently-asked-questions) 32 | 33 | ## Contributing 34 | 35 | * [Contribution Guide](https://github.com/azure/azops/wiki/azops-contribution) 36 | * [Releases](https://github.com/azure/azops/wiki/releases) 37 | * [Tests](https://github.com/azure/azops/wiki/tests) 38 | * [Prerelease](https://github.com/azure/azops/wiki/pre-release) 39 | * [Debugging](https://github.com/azure/azops/wiki/debugging) 40 | * [Visual Studio Code](https://github.com/azure/azops/wiki/visual-studio-code) 41 | * [PowerShell](https://github.com/azure/azops/wiki/powershell) 42 | -------------------------------------------------------------------------------- /src/internal/functions/Register-AzOpsResourceProvider.ps1: -------------------------------------------------------------------------------- 1 | function Register-AzOpsResourceProvider { 2 | 3 | <# 4 | .SYNOPSIS 5 | Registers an azure resource provider. 6 | .DESCRIPTION 7 | Registers an azure resource provider. 8 | Assumes an ARM definition of a resource provider as input. 9 | .PARAMETER FileName 10 | The path to the file containing an ARM template defining a resource provider. 11 | .PARAMETER ScopeObject 12 | The current AzOps scope. 13 | .EXAMPLE 14 | PS C:\> Register-ResourceProvider -FileName $fileName -ScopeObject $scopeObject 15 | Registers an azure resource provider. 16 | #> 17 | 18 | [CmdletBinding()] 19 | param ( 20 | [string] 21 | $FileName, 22 | 23 | [AzOpsScope] 24 | $ScopeObject 25 | ) 26 | 27 | process { 28 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Register-AzOpsResourceProvider.Processing' -LogStringValues $ScopeObject, $FileName -Target $ScopeObject 29 | $currentContext = Get-AzContext 30 | if ($ScopeObject.Subscription -and $currentContext.Subscription.Id -ne $ScopeObject.Subscription) { 31 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Register-AzOpsResourceProvider.Context.Switching' -LogStringValues $currentContext.Subscription.Name, $CurrentAzContext.Subscription.Id, $ScopeObject.Subscription, $ScopeObject.Name -Target $ScopeObject 32 | try { 33 | $null = Set-AzContext -SubscriptionId $ScopeObject.Subscription -ErrorAction Stop 34 | } 35 | catch { 36 | Stop-PSFFunction -String 'Register-AzOpsResourceProvider.Context.Failed' -StringValues $ScopeObject.SubscriptionDisplayName -ErrorRecord $_ -EnableException $true -Cmdlet $PSCmdlet -Target $ScopeObject 37 | throw "Couldn't switch context $_" 38 | } 39 | } 40 | 41 | $resourceproviders = Get-Content $FileName | ConvertFrom-Json 42 | foreach ($resourceprovider in $resourceproviders | Where-Object RegistrationState -eq 'Registered') { 43 | if (-not $resourceprovider.ProviderNamespace) { continue } 44 | 45 | Write-AzOpsMessage -LogLevel Important -LogString 'Register-AzOpsResourceProvider.Provider.Register' -LogStringValues $resourceprovider.ProviderNamespace 46 | Register-AzResourceProvider -Confirm:$false -Pre -ProviderNamespace $resourceprovider.ProviderNamespace 47 | } 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/internal/classes/AzOpsRoleEligibilityScheduleRequest.ps1: -------------------------------------------------------------------------------- 1 | class AzOpsRoleEligibilityScheduleRequest { 2 | [string]$ResourceType 3 | [string]$Name 4 | [string]$Id 5 | [hashtable]$Properties 6 | 7 | AzOpsRoleEligibilityScheduleRequest($roleEligibilitySchedule, $roleEligibilityScheduleRequest) { 8 | $this.Properties = [ordered]@{ 9 | Condition = $roleEligibilitySchedule.Condition 10 | ConditionVersion = $roleEligibilitySchedule.ConditionVersion 11 | PrincipalId = $roleEligibilitySchedule.PrincipalId 12 | RoleDefinitionId = $roleEligibilitySchedule.RoleDefinitionId 13 | RequestType = $roleEligibilityScheduleRequest.RequestType.ToString() 14 | ScheduleInfo = [ordered]@{ 15 | Expiration = [ordered]@{ 16 | EndDateTime = $roleEligibilitySchedule.EndDateTime 17 | Duration = $roleEligibilitySchedule.ExpirationDuration 18 | ExpirationType = if ($roleEligibilitySchedule.ExpirationType) {$roleEligibilitySchedule.ExpirationType.ToString()} 19 | } 20 | StartDateTime = $roleEligibilitySchedule.StartDateTime 21 | } 22 | } 23 | $this.Id = $roleEligibilitySchedule.RequestId 24 | $this.Name = $roleEligibilitySchedule.Name 25 | $this.ResourceType = $roleEligibilityScheduleRequest.Type 26 | } 27 | 28 | AzOpsRoleEligibilityScheduleRequest($roleEligibilitySchedule) { 29 | $this.Properties = [ordered]@{ 30 | Condition = $roleEligibilitySchedule.Condition 31 | ConditionVersion = $roleEligibilitySchedule.ConditionVersion 32 | PrincipalId = $roleEligibilitySchedule.PrincipalId 33 | RoleDefinitionId = $roleEligibilitySchedule.RoleDefinitionId 34 | RequestType = "AdminAssign" 35 | ScheduleInfo = [ordered]@{ 36 | Expiration = [ordered]@{ 37 | EndDateTime = $roleEligibilitySchedule.EndDateTime 38 | Duration = $roleEligibilitySchedule.ExpirationDuration 39 | ExpirationType = if ($roleEligibilitySchedule.ExpirationType) {$roleEligibilitySchedule.ExpirationType.ToString()} 40 | } 41 | StartDateTime = $roleEligibilitySchedule.StartDateTime 42 | } 43 | } 44 | $this.Id = $roleEligibilitySchedule.RequestId 45 | $this.Name = $roleEligibilitySchedule.Name 46 | $this.ResourceType = "Microsoft.Authorization/roleEligibilityScheduleRequests" 47 | } 48 | } -------------------------------------------------------------------------------- /src/internal/functions/Register-AzOpsProviderFeature.ps1: -------------------------------------------------------------------------------- 1 | function Register-AzOpsProviderFeature { 2 | 3 | <# 4 | .SYNOPSIS 5 | Registers a provider feature from ARM. 6 | .DESCRIPTION 7 | Registers a provider feature from ARM. 8 | .PARAMETER FileName 9 | Path to the ARM template file representing a provider feature. 10 | .PARAMETER ScopeObject 11 | The current AzOps scope. 12 | .EXAMPLE 13 | PS C:\> Register-ProviderFeature -FileName $file -ScopeObject $scopeObject 14 | Registers a provider feature from ARM. 15 | #> 16 | 17 | [CmdletBinding()] 18 | param ( 19 | [string] 20 | $FileName, 21 | 22 | [AzOpsScope] 23 | $ScopeObject 24 | ) 25 | 26 | process { 27 | #TODO: Clarify original function design intent 28 | 29 | # Get Subscription ID from scope (since Subscription ID is not available for Resource Groups and Resources) 30 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Register-AzOpsProviderFeature.Processing' -LogStringValues $ScopeObject, $FileName -Target $scopeObject 31 | $currentContext = Get-AzContext 32 | if ($ScopeObject.Subscription -and $currentContext.Subscription.Id -ne $ScopeObject.Subscription) { 33 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Register-AzOpsProviderFeature.Context.Switching' -LogStringValues $currentContext.Subscription.Name, $CurrentAzContext.Subscription.Id, $ScopeObject.Subscription, $ScopeObject.Name -Target $scopeObject 34 | try { 35 | $null = Set-AzContext -SubscriptionId $ScopeObject.Subscription -ErrorAction Stop 36 | } 37 | catch { 38 | Stop-PSFFunction -String 'Register-AzOpsProviderFeature.Context.Failed' -StringValues $ScopeObject.SubscriptionDisplayName -ErrorRecord $_ -EnableException $true -Cmdlet $PSCmdlet -Target $ScopeObject 39 | throw "Couldn't switch context $_" 40 | } 41 | } 42 | 43 | $providerFeatures = Get-Content $FileName | ConvertFrom-Json 44 | foreach ($providerFeature in $providerFeatures) { 45 | if ($ProviderFeature.FeatureName -and $ProviderFeature.ProviderName) { 46 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Register-AzOpsProviderFeature.Provider.Feature' -LogStringValues $ProviderFeature.FeatureName, $ProviderFeature.ProviderName -Target $scopeObject 47 | Register-AzProviderFeature -Confirm:$false -ProviderNamespace $ProviderFeature.ProviderName -FeatureName $ProviderFeature.FeatureName 48 | } 49 | } 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /src/internal/functions/Get-AzOpsResourceLock.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzOpsResourceLock { 2 | 3 | <# 4 | .SYNOPSIS 5 | Discover resource locks at the provided scope (Subscription or resource group) 6 | .DESCRIPTION 7 | Discover resource locks at the provided scope (Subscription or resource group) 8 | .PARAMETER ScopeObject 9 | The scope object representing the azure entity to retrieve resource locks from. 10 | .PARAMETER StatePath 11 | StatePath 12 | .EXAMPLE 13 | > Get-AzOpsResourceLock -ScopeObject xxx 14 | Discover all resource locks deployed at resource group scope 15 | #> 16 | 17 | [CmdletBinding()] 18 | param ( 19 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 20 | [object] 21 | $ScopeObject, 22 | [Parameter(Mandatory = $true)] 23 | $StatePath 24 | ) 25 | 26 | process { 27 | if ($ScopeObject.Type -notin 'resourceGroups', 'subscriptions') { 28 | return 29 | } 30 | switch ($ScopeObject.Type) { 31 | subscriptions { 32 | # ScopeObject is a subscription 33 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Get-AzOpsResourceLock.Subscription' -LogStringValues $ScopeObject.SubscriptionDisplayName, $ScopeObject.Subscription -Target $ScopeObject 34 | } 35 | resourcegroups { 36 | # ScopeObject is a resourcegroup 37 | Write-AzOpsMessage -LogLevel Verbose -LogString 'Get-AzOpsResourceLock.ResourceGroup' -LogStringValues $ScopeObject.ResourceGroup -Target $ScopeObject 38 | } 39 | } 40 | try { 41 | $parameters = @{ 42 | Scope = $ScopeObject.Scope 43 | } 44 | # Gather resource locks at scopeObject with retry and backoff support from Invoke-AzOpsScriptBlock 45 | $resourceLocks = Invoke-AzOpsScriptBlock -ArgumentList $parameters -ScriptBlock { 46 | Get-AzResourceLock @parameters -AtScope -ErrorAction Stop | Where-Object {$($_.ResourceID.Substring(0, $_.ResourceId.LastIndexOf('/'))) -Like ("$($parameters.Scope)/providers/Microsoft.Authorization/locks")} 47 | } -RetryCount 3 -RetryWait 5 -RetryType Exponential -ErrorAction Stop 48 | } 49 | catch { 50 | Write-AzOpsMessage -LogLevel Warning -LogString 'Get-AzOpsResourceLock.Failed' -LogStringValues $_ 51 | } 52 | if ($resourceLocks) { 53 | # Process each resource lock 54 | foreach ($lock in $resourceLocks) { 55 | $lock | ConvertTo-AzOpsState -StatePath $StatePath 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /docs/wiki/Custom-Jq-Templates.md: -------------------------------------------------------------------------------- 1 | # Custom Jq Templates 2 | 3 | - [Introduction](#introduction) 4 | - [Logic](#logic) 5 | - [Template Folder and filename](#template-folder-and-filename) 6 | 7 | --- 8 | 9 | ## Introduction 10 | 11 | As a part of **AzOps Pull**, information retrieved from Azure is converted into files. This is performed at processing with [jq](https://stedolan.github.io/jq/) which applies filters based on templates and re-structures information. 12 | 13 | For scenarios where you need to customize the information filtered or its structure, AzOps supports the use of *bring your own templates* by configuring two settings: `Core.SkipCustomJqTemplate` and `Core.CustomJqTemplatePath`. 14 | 15 | The setting `Core.SkipCustomJqTemplate` represents the flag to enable (`false`) or disable (`true`) the capability and `Core.CustomJqTemplatePath` is the path to the folder location of your custom templates (default's to `.customtemplates`). 16 | 17 | ## Logic 18 | 19 | What happens, when the following is set: `"Core.SkipCustomJqTemplate": true` and `"Core.CustomJqTemplatePath": ".customtemplates"`? 20 | 21 | For retrieved resources, AzOps will look for a matching template file in the custom location. If no match is found AzOps falls back to [built-in templates](https://github.com/Azure/AzOps/tree/main/src/data/template). 22 | 23 | ### Template Folder and filename 24 | 25 | AzOps performs transformation of pulled information in three high level steps. 26 | 27 | 1. Removal templates (*templates specifying information to be filtered away*) 28 | * Look for folder matching `providerNamespace` and a file matching `resourceType`.jq 29 | * If no match found default to `generic.jq` at given template folder root 30 | 31 | 2. Generating Template Parameter (*treat policy definitions with json escaping*) 32 | * Look for folder matching `providerNamespace` and a file matching `resourceTypeName`.parameters.jq 33 | * If no match found default to `template.parameters.jq` at given template folder root 34 | 35 | 3. Generating Template 36 | * Look for folder matching `providerNamespace` and a file matching `resourceTypeName`.template.jq 37 | * If no match found default to `template.jq` at given template folder root 38 | 39 | Example of custom templates for `policyExemptions`, resulting in `policyExemptions` resources being transformed with custom templates (according to step 1 and 3 above) and all other resources being transformed with built-in: 40 | ```bash 41 | .customtemplates 42 | └── Microsoft.Authorization 43 | ├── policyExemptions.template.jq 44 | └── policyExemptions.jq 45 | ``` 46 | Example of built-in base templates: 47 | ```bash 48 | .built-in 49 | ├── Microsoft.Network 50 | │ └── virtualnetworks.jq 51 | ├── generic.jq 52 | ├── template.jq 53 | ├── template.parameters.jq 54 | └── templateChildResource.jq 55 | ``` -------------------------------------------------------------------------------- /src/internal/functions/Get-AzOpsManagementGroup.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzOpsManagementGroup { 2 | 3 | <# 4 | .SYNOPSIS 5 | The cmdlet will recursively enumerates a management group and returns all children 6 | .DESCRIPTION 7 | The cmdlet will recursively enumerates a management group and returns all children mgs. 8 | If the -PartialDiscovery parameter has been used, it will add all MG's where discovery should initiate to the AzOpsPartialRoot variable. 9 | .PARAMETER ManagementGroup 10 | Name of the management group to enumerate 11 | .PARAMETER PartialDiscovery 12 | Whether to recursively grab all Management Groups and add them to the partial root cache 13 | .EXAMPLE 14 | Get-AzOpsManagementGroup -ManagementGroup Tailspin 15 | Id : /providers/Microsoft.Management/managementGroups/Tailspin 16 | Type : /providers/Microsoft.Management/managementGroups 17 | Name : Tailspin 18 | TenantId : d4c7591d-9b0c-49a4-9670-5f0349b227f1 19 | DisplayName : Tailspin 20 | UpdatedTime : 0001-01-01 00:00:00 21 | UpdatedBy : 22 | ParentId : /providers/Microsoft.Management/managementGroups/d4c7591d-9b0c-49a4-9670-5f0349b227f1 23 | ParentName : d4c7591d-9b0c-49a4-9670-5f0349b227f1 24 | ParentDisplayName : Tenant Root Group 25 | .INPUTS 26 | ManagementGroupName 27 | .OUTPUTS 28 | Management Group Object 29 | #> 30 | 31 | [CmdletBinding()] 32 | param ( 33 | [Parameter(Mandatory = $true)] 34 | $ManagementGroup, 35 | 36 | [switch] 37 | $PartialDiscovery 38 | ) 39 | 40 | process { 41 | try { 42 | $groupObject = Get-AzManagementGroup -GroupId $ManagementGroup -Expand -WarningAction SilentlyContinue 43 | } 44 | catch { 45 | Write-AzOpsMessage -LogLevel Error -LogString 'Get-AzOpsManagementGroup.Failed' -LogStringValues $ManagementGroup 46 | throw 47 | } 48 | if ($PartialDiscovery) { 49 | if ($groupObject.ParentId -and -not (Get-AzManagementGroup -GroupId $groupObject.ParentName -ErrorAction Ignore -WarningAction SilentlyContinue)) { 50 | $script:AzOpsPartialRoot += $groupObject 51 | } 52 | if ($groupObject.Children) { 53 | $groupObject.Children | Where-Object Type -eq "Microsoft.Management/managementGroups" | Foreach-Object -Process { 54 | Get-AzOpsManagementGroup -ManagementGroup $_.Name -PartialDiscovery:$PartialDiscovery 55 | } 56 | } 57 | } 58 | return $groupObject 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/internal/functions/Remove-AzOpsInvalidCharacter.ps1: -------------------------------------------------------------------------------- 1 | function Remove-AzOpsInvalidCharacter { 2 | 3 | <# 4 | .SYNOPSIS 5 | Takes string input and removes invalid characters. 6 | .DESCRIPTION 7 | Takes string input and removes invalid characters. 8 | .PARAMETER String 9 | String to remove invalid characters from. 10 | .PARAMETER Override 11 | Accepts input to skip selected invalid characters. 12 | .EXAMPLE 13 | > Remove-AzOpsInvalidCharacter -String "microsoft.operationalinsights_workspaces_savedsearches-fgh341_logmanagement(fgh343)_logmanagement|countofiislogentriesbyhostrequestedbyclient.json" 14 | Function returns with the '|' invalid character removed: 15 | microsoft.operationalinsights_workspaces_savedsearches-fgh341_logmanagement(fgh343)_logmanagementcountofiislogentriesbyhostrequestedbyclient.json 16 | #> 17 | 18 | [CmdletBinding()] 19 | [OutputType([System.String])] 20 | param ( 21 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 22 | [string] 23 | $String, 24 | [array] 25 | $InvalidChars = @('"','<','>','|','►','◄','↕','‼','¶','§','▬','↨','↑','↓','→','∟','↔','*','?','\','/',':'), 26 | [array] 27 | $Override 28 | ) 29 | 30 | process { 31 | # If Override has been provided remove them from InvalidChars 32 | if ($Override) { 33 | $InvalidChars = Compare-Object -ReferenceObject $InvalidChars -DifferenceObject $Override -PassThru 34 | } 35 | # Check if string contains invalid characters 36 | $pattern = $InvalidChars | Out-String -NoNewline 37 | if ($String -match "[$pattern]") { 38 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzOpsInvalidCharacter.Invalid' -LogStringValues $String 39 | # Arrange string into character array 40 | $fileNameChar = $String.ToCharArray() 41 | # Iterate over each character in string 42 | foreach ($character in $fileNameChar) { 43 | # If character exists in invalid array then replace character 44 | if ($character -in $InvalidChars) { 45 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzOpsInvalidCharacter.Removal' -LogStringValues $character, $String 46 | # Remove invalid character 47 | $String = $String.Replace($character.ToString(),'') 48 | } 49 | } 50 | } 51 | # Always remove square brackets 52 | $String = $String -replace "(\[|\])","" 53 | Write-AzOpsMessage -LogLevel InternalComment -LogString 'Remove-AzOpsInvalidCharacter.Completed' -LogStringValues $String 54 | # Return processed string 55 | return $String 56 | } 57 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Release" 3 | 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | type: 8 | description: "Type (Major / Minor / Patch)" 9 | required: true 10 | default: "Patch" 11 | 12 | permissions: 13 | contents: write 14 | 15 | jobs: 16 | release: 17 | name: "Release" 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: "Checkout" 21 | uses: actions/checkout@v4 22 | 23 | - name: "Configure" 24 | run: | 25 | git config user.name github-actions 26 | git config user.email '41898282+github-actions[bot]@users.noreply.github.com' 27 | 28 | - name: "Switch" 29 | run: | 30 | git checkout -b release 31 | 32 | - name: "Dependencies" 33 | run: | 34 | ./scripts/Dependencies.ps1 35 | shell: pwsh 36 | 37 | - name: "Version" 38 | id: version 39 | run: | 40 | ./scripts/Version.ps1 -Type ${{ github.event.inputs.type }} 41 | $Version = (Import-PowerShellDataFile -Path "./src/AzOps.psd1").ModuleVersion 42 | echo "version=$Version" >> $env:GITHUB_OUTPUT 43 | shell: pwsh 44 | 45 | - name: "Release" 46 | run: | 47 | ./scripts/Release.ps1 -ApiKey ${{ secrets.PWSH_GALLERY }} 48 | shell: pwsh 49 | 50 | - name: "Add" 51 | run: | 52 | git add src/AzOps.psd1 53 | 54 | - name: "Commit" 55 | run: | 56 | git commit -m 'Update AzOps.psd1' 57 | 58 | - name: "Push" 59 | run: | 60 | git push origin release 61 | 62 | #- name: "Merge" 63 | # run: | 64 | # gh pr create --base 'main' --head 'release' --title 'Release v${{ steps.version.outputs.version }}' --body '' --label 'release' 65 | # COUNTER=0 66 | # while : ; do 67 | # DECISION=$(gh pr status --json reviewDecision --jq '.currentBranch.reviewDecision') 68 | # if [ "$DECISION" == "APPROVED" ]; then 69 | # gh pr merge 'release' --squash --delete-branch 70 | # break 71 | # else 72 | # if [ $COUNTER -lt 300 ]; then 73 | # echo "Pending pull request approval - $COUNTER seconds" 74 | # sleep 30s 75 | # COUNTER=$(( $COUNTER + 30 )) 76 | # else 77 | # echo "Expired pull request approval" 78 | # exit 1 79 | # fi 80 | # fi 81 | # done 82 | # env: 83 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 84 | 85 | - name: "Release" 86 | run: | 87 | gh release create ${{ steps.version.outputs.version }} --title 'v${{ steps.version.outputs.version }}' --target 'main' --notes 'Coming soon...' 88 | env: 89 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 90 | --------------------------------------------------------------------------------