diff --git a/.github/workflows/platform.mirror-mar-file.yml b/.github/workflows/platform.mirror-mar-file.yml new file mode 100644 index 000000000..bcb85d541 --- /dev/null +++ b/.github/workflows/platform.mirror-mar-file.yml @@ -0,0 +1,143 @@ +# Workflow for mirroring the MAR file to check Bicep modules against. +name: ".Platform: Mirror MAR File" + +on: + # Runs everyday at 4 am + schedule: + - cron: "0 4 * * *" # Daily Update at 4 am + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: {} + +env: + pipelinePrincipalGitUserName: "AVMPipelinePrincipal" + pipelinePrincipalGitUserEmail: "AVM@noreply.github.com" + branch_name: "update-mar-file" + pr_title: "Update mirrored MAR file (automated)" + pr_body: "This is an automated ``pull_request`` containing updates to the mirrored MAR file stored at ``docs/static/module-indexes/BicepMARModules.json``.\nPlease review the ``files changed`` tab to review changes." + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + id-token: write + contents: write + pull-requests: write + +# Default to bash +defaults: + run: + shell: bash + +jobs: + update_mar_file: + name: Update MAR file + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + environment: platform + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + # create a token + - uses: actions/create-github-app-token@v3 + name: Create App Token for MAR Repository + id: mcr-app-token + with: + owner: ${{ vars.MAR_REPO_OWNER}} + repositories: ${{ vars.MAR_REPO_REPOSITORY }} + app-id: ${{ vars.MAR_REPO_ACCESS_APPID }} + private-key: ${{ secrets.MAR_REPO_ACCESS_APP_PRIVATEKEY }} + + - uses: actions/create-github-app-token@v3 + name: Create App Token for AVM Repository (used for PR creation) + id: avm-app-token + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + # ensure the module is in the MAR file before publishing + - name: Confirm module in MAR + shell: pwsh + run: | + . './utilities/tools/platform/Get-ModuleNamesFromMAR.ps1' + # get the list of module names in the MAR file as string array + $marModuleList = Get-ModuleNamesFromMAR -GitHubToken ${{ steps.mcr-app-token.outputs.token }} -Owner ${{ vars.MAR_REPO_OWNER}} -Repo ${{ vars.MAR_REPO_REPOSITORY }} + + # set the content as JSON of the local MAR file to the list of module names retrieved from the MAR file in the repository + $localMARFilePath = Join-Path $env:GITHUB_WORKSPACE 'docs\static\module-indexes\BicepMARModules.json' + Set-LocalMARFileContent -LocalMARFilePath $localMARFilePath -FileContent $marModuleList + + - name: Configure local git + run: | + git config --global user.name '${{ env.pipelinePrincipalGitUserName }}' + git config --global user.email '${{ env.pipelinePrincipalGitUserEmail }}' + + - name: Format branch name + shell: pwsh + run: | + $rawBranch = '${{ env.branch_name }}' + $formattedBranch = "{0}_{1}" -f $rawBranch, (Get-Date).ToString('yyyy-MM-dd-HH-mm-ss') + Write-Verbose "Adjusting branch name [$rawBranch] to [$formattedBranch]" -Verbose + ('{0}={1}' -f 'branch_name', $formattedBranch) | Out-File -FilePath $env:GITHUB_ENV -Encoding 'utf8' # Overwrite env variable + + - name: Create and checkout branch + run: | + BRANCH_URL="repos/${{ github.repository }}/branches" + JQ_FILTER=".[] | select(.name == \"${{ env.branch_name }}\").name" + CHECK_BRANCH_ORIGIN=$(gh api $BRANCH_URL | jq -r "$JQ_FILTER") + if [ -z "$CHECK_BRANCH_ORIGIN" ] + then + echo "Checkout local branch (create new, no origin)..." + git checkout -b ${{ env.branch_name }} + else + echo "Checkout local branch (create new, track from origin)..." + git checkout -b ${{ env.branch_name }} --track origin/${{ env.branch_name }} + + git merge origin/main + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check for changes + id: git_status + shell: pwsh + run: | + $diff = git diff --name-only -- 'docs/static/module-indexes/BicepMARModules.json' + if ($diff.Count -gt 0) { + Write-Verbose 'Detected updates to mirrored MAR file.' -Verbose + 'changes=true' >> $env:GITHUB_OUTPUT + } + + - name: Add files, commit and push + if: steps.git_status.outputs.changes == 'true' + shell: pwsh + run: | + Write-Verbose "Pushing changes to origin..." -Verbose + git add (Join-Path $env:GITHUB_WORKSPACE 'docs' 'static' 'module-indexes' 'BicepMARModules.json') + git commit -m '${{ env.pr_title }}' + git push origin ${{ env.branch_name }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create pull request + if: steps.git_status.outputs.changes == 'true' + run: | + HEAD_LABEL="${{ github.repository_owner }}:${{ env.branch_name }}" + BASE_LABEL="${{ github.repository_owner }}:$(echo '${{ github.ref }}' | sed 's:refs/heads/::')" + PULL_REQUEST_URL="repos/${{ github.repository }}/pulls" + JQ_FILTER=".[] | select(.head.label == \"$HEAD_LABEL\") | select(.base.label == \"$BASE_LABEL\") | .url" + CHECK_PULL_REQUEST_URL=$(gh api $PULL_REQUEST_URL | jq -r "$JQ_FILTER") + if [ -z "$CHECK_PULL_REQUEST_URL" ] + then + CHECK_PULL_REQUEST_URL=$(gh pr create \ + --title "${{ env.pr_title }}" \ + --body "${{ env.pr_body }}" \ + --base "${{ github.ref }}" \ + --head "${{ env.branch_name }}") + echo "Created new PR: $CHECK_PULL_REQUEST_URL" + else + echo "Existing PR found: $CHECK_PULL_REQUEST_URL" + fi + env: + GITHUB_TOKEN: ${{ steps.avm-app-token.outputs.token }} diff --git a/docs/static/module-indexes/BicepMARModules.json b/docs/static/module-indexes/BicepMARModules.json new file mode 100644 index 000000000..8ef13953b --- /dev/null +++ b/docs/static/module-indexes/BicepMARModules.json @@ -0,0 +1,337 @@ +[ + "avm/ptn/aca-lza/hosting-environment", + "avm/ptn/ai-ml/ai-foundry", + "avm/ptn/ai-ml/landing-zone", + "avm/ptn/ai-platform/baseline", + "avm/ptn/alz/ama", + "avm/ptn/alz/empty", + "avm/ptn/app-service-lza/hosting-environment", + "avm/ptn/app/container-job-toolkit", + "avm/ptn/app/cosmos-db-account-container-app", + "avm/ptn/app/iaas-vm-cosmosdb-tier4", + "avm/ptn/app/mongodb-cluster-container-app", + "avm/ptn/app/paas-ase-cosmosdb-tier4", + "avm/ptn/authorization/pim-role-assignment", + "avm/ptn/authorization/policy-assignment", + "avm/ptn/authorization/policy-exemption", + "avm/ptn/authorization/resource-role-assignment", + "avm/ptn/authorization/role-assignment", + "avm/ptn/authorization/role-definition", + "avm/ptn/avd-lza/insights", + "avm/ptn/avd-lza/management-plane", + "avm/ptn/avd-lza/networking", + "avm/ptn/avd-lza/session-hosts", + "avm/ptn/azd/acr-container-app", + "avm/ptn/azd/aks", + "avm/ptn/azd/aks-automatic-cluster", + "avm/ptn/azd/apim-api", + "avm/ptn/azd/container-app-upsert", + "avm/ptn/azd/container-apps-stack", + "avm/ptn/azd/insights-dashboard", + "avm/ptn/azd/ml-ai-environment", + "avm/ptn/azd/ml-hub-dependencies", + "avm/ptn/azd/ml-project", + "avm/ptn/azd/monitoring", + "avm/ptn/data/private-analytical-workspace", + "avm/ptn/deployment-script/create-kv-ssh-key-pair", + "avm/ptn/deployment-script/import-image-to-acr", + "avm/ptn/deployment-script/private", + "avm/ptn/dev-center/dev-box", + "avm/ptn/dev-ops/cicd-agents-and-runners", + "avm/ptn/finops-toolkit/finops-hub", + "avm/ptn/lz/sub-vending", + "avm/ptn/lza-shared/data-services", + "avm/ptn/maintenance/azure-update-manager", + "avm/ptn/mgmt-groups/subscription-placement", + "avm/ptn/monitoring/amba", + "avm/ptn/monitoring/amba-alz", + "avm/ptn/network/hub-networking", + "avm/ptn/network/private-link-private-dns-zones", + "avm/ptn/network/virtual-wan", + "avm/ptn/network/vwan-connected-vnets", + "avm/ptn/openai/cognitive-search", + "avm/ptn/openai/e2e-baseline", + "avm/ptn/policy-insights/remediation", + "avm/ptn/sa/build-your-own-copilot", + "avm/ptn/sa/chat-with-your-data", + "avm/ptn/sa/content-generation", + "avm/ptn/sa/content-processing", + "avm/ptn/sa/conversation-knowledge-mining", + "avm/ptn/sa/customer-chatbot", + "avm/ptn/sa/document-knowledge-mining", + "avm/ptn/sa/modernize-your-code", + "avm/ptn/sa/multi-agent-custom-automation-engine", + "avm/ptn/security/security-center", + "avm/ptn/security/sentinel", + "avm/ptn/subscription/service-health-alerts", + "avm/ptn/virtual-machine-images/azure-image-builder", + "avm/res/alerts-management/action-rule", + "avm/res/analysis-services/server", + "avm/res/api-center/service", + "avm/res/api-management/service", + "avm/res/api-management/service/api", + "avm/res/api-management/service/api-version-set", + "avm/res/api-management/service/api/diagnostics", + "avm/res/api-management/service/api/policy", + "avm/res/api-management/service/authorization-server", + "avm/res/api-management/service/backend", + "avm/res/api-management/service/cache", + "avm/res/api-management/service/diagnostics", + "avm/res/api-management/service/identity-provider", + "avm/res/api-management/service/logger", + "avm/res/api-management/service/named-value", + "avm/res/api-management/service/policy", + "avm/res/api-management/service/portalsetting", + "avm/res/api-management/service/private-endpoint-connection", + "avm/res/api-management/service/product", + "avm/res/api-management/service/product/api", + "avm/res/api-management/service/product/group", + "avm/res/api-management/service/subscription", + "avm/res/api-management/service/workspace", + "avm/res/app-configuration/configuration-store", + "avm/res/app/agent", + "avm/res/app/container-app", + "avm/res/app/job", + "avm/res/app/managed-environment", + "avm/res/app/session-pool", + "avm/res/authorization/policy-assignment", + "avm/res/authorization/policy-assignment/mg-scope", + "avm/res/authorization/policy-assignment/rg-scope", + "avm/res/authorization/policy-assignment/sub-scope", + "avm/res/authorization/role-assignment", + "avm/res/authorization/role-assignment/mg-scope", + "avm/res/authorization/role-assignment/rg-scope", + "avm/res/authorization/role-assignment/sub-scope", + "avm/res/automation/automation-account", + "avm/res/avs/private-cloud", + "avm/res/azure-stack-hci/cluster", + "avm/res/azure-stack-hci/cluster/arc-setting/extension", + "avm/res/azure-stack-hci/logical-network", + "avm/res/azure-stack-hci/marketplace-gallery-image", + "avm/res/azure-stack-hci/network-interface", + "avm/res/azure-stack-hci/virtual-hard-disk", + "avm/res/azure-stack-hci/virtual-machine-instance", + "avm/res/batch/batch-account", + "avm/res/bot-service/bot-service", + "avm/res/cache/redis", + "avm/res/cache/redis-enterprise", + "avm/res/cdn/profile", + "avm/res/cdn/profile/afd-endpoint/route", + "avm/res/cdn/profile/custom-domain", + "avm/res/cdn/profile/origin-group", + "avm/res/cdn/profile/rule-set", + "avm/res/cdn/profile/security-policy", + "avm/res/chaos/experiment", + "avm/res/code-signing/code-signing-account", + "avm/res/cognitive-services/account", + "avm/res/communication/communication-service", + "avm/res/communication/email-service", + "avm/res/compute/availability-set", + "avm/res/compute/disk", + "avm/res/compute/disk-encryption-set", + "avm/res/compute/gallery", + "avm/res/compute/image", + "avm/res/compute/proximity-placement-group", + "avm/res/compute/ssh-public-key", + "avm/res/compute/virtual-machine", + "avm/res/compute/virtual-machine-scale-set", + "avm/res/consumption/budget", + "avm/res/consumption/budget/mg-scope", + "avm/res/consumption/budget/rg-scope", + "avm/res/consumption/budget/sub-scope", + "avm/res/container-instance/container-group", + "avm/res/container-registry/registry", + "avm/res/container-registry/registry/cache-rule", + "avm/res/container-registry/registry/credential-set", + "avm/res/container-registry/registry/replication", + "avm/res/container-registry/registry/scope-map", + "avm/res/container-registry/registry/task", + "avm/res/container-registry/registry/token", + "avm/res/container-registry/registry/webhook", + "avm/res/container-service/managed-cluster", + "avm/res/dashboard/grafana", + "avm/res/data-factory/factory", + "avm/res/data-protection/backup-vault", + "avm/res/data-protection/resource-guard", + "avm/res/databricks/access-connector", + "avm/res/databricks/workspace", + "avm/res/db-for-my-sql/flexible-server", + "avm/res/db-for-postgre-sql/flexible-server", + "avm/res/desktop-virtualization/application-group", + "avm/res/desktop-virtualization/host-pool", + "avm/res/desktop-virtualization/scaling-plan", + "avm/res/desktop-virtualization/workspace", + "avm/res/dev-center/devcenter", + "avm/res/dev-center/network-connection", + "avm/res/dev-center/project", + "avm/res/dev-ops-infrastructure/pool", + "avm/res/dev-test-lab/lab", + "avm/res/devices/iot-hub", + "avm/res/digital-twins/digital-twins-instance", + "avm/res/document-db/database-account", + "avm/res/document-db/database-account/sql-database", + "avm/res/document-db/database-account/sql-role-assignment", + "avm/res/document-db/database-account/sql-role-definition", + "avm/res/document-db/database-account/table", + "avm/res/document-db/mongo-cluster", + "avm/res/durable-task/scheduler", + "avm/res/edge-order/order-item", + "avm/res/edge/configuration", + "avm/res/edge/site", + "avm/res/edge/site/rg-scope", + "avm/res/edge/site/sub-scope", + "avm/res/elastic-san/elastic-san", + "avm/res/event-grid/domain", + "avm/res/event-grid/namespace", + "avm/res/event-grid/system-topic", + "avm/res/event-grid/topic", + "avm/res/event-hub/namespace", + "avm/res/event-hub/namespace/eventhub", + "avm/res/fabric/capacity", + "avm/res/health-bot/health-bot", + "avm/res/healthcare-apis/workspace", + "avm/res/hybrid-compute/gateway", + "avm/res/hybrid-compute/license", + "avm/res/hybrid-compute/machine", + "avm/res/hybrid-compute/private-link-scope", + "avm/res/hybrid-compute/setting", + "avm/res/hybrid-container-service/provisioned-cluster-instance", + "avm/res/insights/action-group", + "avm/res/insights/activity-log-alert", + "avm/res/insights/autoscale-setting", + "avm/res/insights/component", + "avm/res/insights/data-collection-endpoint", + "avm/res/insights/data-collection-rule", + "avm/res/insights/diagnostic-setting", + "avm/res/insights/metric-alert", + "avm/res/insights/private-link-scope", + "avm/res/insights/scheduled-query-rule", + "avm/res/insights/webtest", + "avm/res/iot-operations/instance", + "avm/res/key-vault/managed-hsm", + "avm/res/key-vault/vault", + "avm/res/key-vault/vault/access-policy", + "avm/res/key-vault/vault/key", + "avm/res/key-vault/vault/secret", + "avm/res/kubernetes-configuration/extension", + "avm/res/kubernetes-configuration/flux-configuration", + "avm/res/kubernetes-runtime/bpg-peer", + "avm/res/kubernetes-runtime/load-balancer", + "avm/res/kubernetes-runtime/service", + "avm/res/kubernetes/connected-cluster", + "avm/res/kusto/cluster", + "avm/res/load-test-service/load-test", + "avm/res/logic/integration-account", + "avm/res/logic/workflow", + "avm/res/machine-learning-services/registry", + "avm/res/machine-learning-services/workspace", + "avm/res/maintenance/configuration-assignment", + "avm/res/maintenance/maintenance-configuration", + "avm/res/managed-identity/user-assigned-identity", + "avm/res/managed-services/registration-definition", + "avm/res/management/management-group", + "avm/res/management/service-group", + "avm/res/maps/account", + "avm/res/net-app/net-app-account", + "avm/res/network/application-gateway", + "avm/res/network/application-gateway-web-application-firewall-policy", + "avm/res/network/application-security-group", + "avm/res/network/azure-firewall", + "avm/res/network/bastion-host", + "avm/res/network/connection", + "avm/res/network/ddos-protection-plan", + "avm/res/network/dns-forwarding-ruleset", + "avm/res/network/dns-resolver", + "avm/res/network/dns-zone", + "avm/res/network/express-route-circuit", + "avm/res/network/express-route-gateway", + "avm/res/network/express-route-port", + "avm/res/network/firewall-policy", + "avm/res/network/front-door", + "avm/res/network/front-door-web-application-firewall-policy", + "avm/res/network/ip-group", + "avm/res/network/load-balancer", + "avm/res/network/local-network-gateway", + "avm/res/network/nat-gateway", + "avm/res/network/network-interface", + "avm/res/network/network-manager", + "avm/res/network/network-security-group", + "avm/res/network/network-security-perimeter", + "avm/res/network/network-watcher", + "avm/res/network/p2s-vpn-gateway", + "avm/res/network/private-dns-zone", + "avm/res/network/private-dns-zone/a", + "avm/res/network/private-dns-zone/aaaa", + "avm/res/network/private-dns-zone/cname", + "avm/res/network/private-dns-zone/mx", + "avm/res/network/private-dns-zone/ptr", + "avm/res/network/private-dns-zone/soa", + "avm/res/network/private-dns-zone/srv", + "avm/res/network/private-dns-zone/txt", + "avm/res/network/private-dns-zone/virtual-network-link", + "avm/res/network/private-endpoint", + "avm/res/network/private-link-service", + "avm/res/network/public-ip-address", + "avm/res/network/public-ip-prefix", + "avm/res/network/route-table", + "avm/res/network/service-endpoint-policy", + "avm/res/network/trafficmanagerprofile", + "avm/res/network/virtual-hub", + "avm/res/network/virtual-hub/route-map", + "avm/res/network/virtual-network", + "avm/res/network/virtual-network-gateway", + "avm/res/network/virtual-network/subnet", + "avm/res/network/virtual-wan", + "avm/res/network/vpn-gateway", + "avm/res/network/vpn-server-configuration", + "avm/res/network/vpn-site", + "avm/res/operational-insights/cluster", + "avm/res/operational-insights/workspace", + "avm/res/operations-management/solution", + "avm/res/portal/dashboard", + "avm/res/power-bi-dedicated/capacity", + "avm/res/purview/account", + "avm/res/recovery-services/vault", + "avm/res/relay/namespace", + "avm/res/resource-graph/query", + "avm/res/resources/deployment-script", + "avm/res/resources/resource-group", + "avm/res/scom/managed-instance", + "avm/res/search/search-service", + "avm/res/security-insights/data-connector", + "avm/res/security-insights/onboarding-state", + "avm/res/security-insights/setting", + "avm/res/service-bus/namespace", + "avm/res/service-bus/namespace/queue", + "avm/res/service-bus/namespace/topic", + "avm/res/service-fabric/cluster", + "avm/res/service-networking/traffic-controller", + "avm/res/signal-r-service/signal-r", + "avm/res/signal-r-service/web-pub-sub", + "avm/res/sql-virtual-machine/sql-virtual-machine", + "avm/res/sql/instance-pool", + "avm/res/sql/managed-instance", + "avm/res/sql/server", + "avm/res/sql/server/database", + "avm/res/storage/storage-account", + "avm/res/storage/storage-account/blob-service/container", + "avm/res/storage/storage-account/blob-service/container/immutability-policy", + "avm/res/storage/storage-account/file-service/share", + "avm/res/storage/storage-account/local-user", + "avm/res/storage/storage-account/management-policy", + "avm/res/storage/storage-account/queue-service/queue", + "avm/res/storage/storage-account/table-service/table", + "avm/res/stream-analytics/streaming-job", + "avm/res/synapse/private-link-hub", + "avm/res/synapse/workspace", + "avm/res/virtual-machine-images/image-template", + "avm/res/web/connection", + "avm/res/web/hosting-environment", + "avm/res/web/serverfarm", + "avm/res/web/site", + "avm/res/web/site/config", + "avm/res/web/site/slot", + "avm/res/web/static-site", + "avm/utl/general/get-environment", + "avm/utl/types/avm-common-types" +] diff --git a/utilities/tools/platform/Get-ModuleNamesFromMAR.ps1 b/utilities/tools/platform/Get-ModuleNamesFromMAR.ps1 new file mode 100644 index 000000000..a3745d279 --- /dev/null +++ b/utilities/tools/platform/Get-ModuleNamesFromMAR.ps1 @@ -0,0 +1,86 @@ +<# +.SYNOPSIS +Check if a module in a given path does exist in the MAR file. Returns $true or $false. + +.DESCRIPTION +Check if a module in a given path does exist in the MAR file. Only then, it can be published to the MCR. + +.PARAMETER GitHubToken +Mandatory. A GitHub token with read access to the MAR repository (microsoft/mcr). + +.PARAMETER Owner +Mandatory. The Organisation, where the repository is located. Default is "Microsoft". + +.PARAMETER Repo +Mandatory. The repository name. Default is "mcr". + +.EXAMPLE +Get-ModuleNamesFromMAR -GitHubToken $env:MAR_REPO_ACCESS_PAT -Owner 'Microsoft' -Repo 'mcr' -Verbose + +Returns the list of module names in the MAR file as an array of strings. + +#> +function Get-ModuleNamesFromMAR { + + [CmdletBinding()] + [OutputType([string[]])] + param ( + [Parameter(Mandatory, HelpMessage = 'Provide a GitHub token (PAT for testing or GitHub App token for production) with read access to the MAR repository (microsoft/mcr).')] + [string] $GitHubToken, + + [Parameter(Mandatory, HelpMessage = 'Provide the Organisation, where the repository is located. Default is "Microsoft".')] + [string] $Owner, + + [Parameter(Mandatory, HelpMessage = 'Provide the repository name. Default is "mcr".')] + [string] $Repo + ) + + ################################## + ## Confirm module tag known ## + ################################## + $marFileUrl = "https://raw.githubusercontent.com/$Owner/$Repo/refs/heads/main/teams/bicep/bicep.yml" + $headers = @{ + Authorization = "Bearer $GitHubToken" + Accept = 'application/vnd.github.v3.raw' + 'User-Agent' = 'AVM-Publish-Pipeline' + } + + $marFileContent = $null + + try { + $marFileContent = (Invoke-WebRequest -Uri $marFileUrl -Headers $headers -ErrorAction Stop).Content + } + catch { + throw "Failed to fetch MAR file from [$marFileUrl]. Error: $($_.Exception.Message)" + } + + $marFileModuleNames = [System.Collections.Generic.List[string]]::new() + try { + foreach ($match in [regex]::Matches($marFileContent, '(?m)^\s*-\s*name:\s*(?[^\r\n]+)')) { + $moduleName = $match.Groups['name'].Value.Trim() -replace '^public/bicep/', '' + $null = $marFileModuleNames.Add($moduleName) + } + } + catch { + throw "Failed to parse module names from MAR file. Error: $($_.Exception.Message)" + } + + return $marFileModuleNames.ToArray() +} + +function Set-LocalMARFileContent { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory, HelpMessage = 'Provide the path to the local MAR file copy.')] + [string] $LocalMARFilePath, + + [Parameter(Mandatory, HelpMessage = 'Provide the new content for the local MAR file.')] + [string[]] $FileContent + ) + + $jsonContent = $FileContent | ConvertTo-Json + if ($PSCmdlet.ShouldProcess($LocalMARFilePath, 'Update local MAR file content')) { + $null = New-Item -Path $LocalMARFilePath -Value ($jsonContent | Out-String) -Force + Write-Verbose "File [$LocalMARFilePath] updated" -Verbose + } +}