what are the process flows and service components delivered in Azure subscription vending
Azure subscription vending is a process of programmatically provisioning and handing out Azure subscriptions to internal application teams in a standardized, governed way. It’s a key part of a well-architected Azure Landing Zone.
The core idea is to shift from a manual, ad-hoc process to an automated “vending machine” model. The platform team pre-packages and automates the delivery of subscriptions, enabling application teams to get a compliant, ready-to-use environment on demand.
⚙️ The Core Process Flow
The automation streamlines the request, setup, and delivery of a subscription. This flow is typically triggered by an application team’s request.
The process involves three key automated stages:
- Stage 1: Collect Data: Application teams submit requests through a standardized form (e.g., a Power App or ITSM tool). This collects key information like cost center, expected budget, networking needs, and required Azure regions.
- Stage 2: Initiate Automation: After approval, the system generates a parameter file (JSON/YAML) with the request details and commits it to a source control repository (like GitHub or Azure DevOps) as a Pull Request. This merge then triggers the deployment pipeline.
- Stage 3: Create the Subscription: An automated CI/CD pipeline executes the request using Infrastructure as Code (IaC) modules (like Bicep or Terraform) to deliver a configured subscription.
📦 Service Components Delivered
The “vending” process automatically delivers a fully configured environment, typically including:
- Azure Subscription: The core billing and security boundary. The automation creates it with a user-friendly display name and associated tags (e.g., CostCenter, Environment, Project).
- Governance & Management: The subscription is automatically placed into a pre-defined management group (e.g., “Corp”, “Online”, “Sandbox”) which enforces baseline policies like allowed regions and data encryption. The process also creates a preliminary budget to set cost expectations.
- Security & Access (RBAC): Azure role-based access control (RBAC) assignments are made, granting the application team appropriate permissions (e.g., Contributor) and securing access.
- Core Networking: The process can create an empty virtual network (VNet) and automatically set up VNet peering to a central hub. This provides secure connectivity to on-premises or shared services and includes DDoS protection plans.
- Azure Resource Providers: The system can pre-register common or project-specific resource providers (e.g., Microsoft.Compute, Microsoft.ContainerService), preventing deployment delays.
👤 Who Does What in the Process
Success relies on three key groups:
- The Cloud Center of Excellence (CCoE): Defines the standardized “menu” of subscriptions (e.g., a “Tier 1” vs. “Sandbox” product line) and the business logic for approval.
- The Application Team: Initiates the request and, after receiving the subscription, deploys and manages their workloads within it.
- The Platform Team: Builds, maintains, and runs the automation pipeline that vends the subscriptions.
✅ Why Use Subscription Vending
This approach ensures every new subscription is compliant from day one and can be delivered in minutes rather than weeks, freeing your platform team to focus on higher-value tasks.
This is a significant investment in platform engineering, but for organizations operating at scale, it’s an essential one. If you’d like to explore specific implementation details, such as the technical configurations for Bicep or Terraform modules, feel free to ask.
give me a sample subscription vending workflow for a user to request an Azure subscription for s designated Azure landing zone, including a form with appropriate fields to fill in, approval stage gate, etc.
We need to provide a sample subscription vending workflow, including a request form and approval stage gate, similar to the earlier W365 example but for Azure subscription vending. The user wants a form, approval, and workflow. Should be practical, with fields, approval steps, and possibly integration with automation. Provide as a structured answer.
Here is a sample subscription vending workflow for requesting an Azure subscription within a designated Azure Landing Zone (ALZ), including a request form, approval stage gate, and automation handoff.
Overview: Azure Subscription Vending Workflow
Goal: Enable an application team to request a new Azure subscription that is automatically configured according to the enterprise Landing Zone policies (management group, policy assignments, RBAC, networking, budget alerts).
Actors:
- Requester: Application lead or developer
- Approver: Cloud Center of Excellence (CCoE) or FinOps owner
- Automation Engine: Azure DevOps / GitHub Actions + IaC (Bicep/Terraform) + Azure Subscription Creation API
High-Level Steps:
- Requester fills out subscription request form
- Form triggers approval request to CCoE
- Upon approval, automation pipeline runs to create and configure subscription
- Subscription is handed over to the application team with all governance and connectivity in place
Part 1: Request Form for Azure Subscription Vending
Form Title: Azure Subscription Request – Landing Zone Enabled
Target: Enterprise Azure Landing Zone (e.g., Corp, Online, Sandbox)
Field | Type | Description / Options | Validation |
Requester Name | Text | Full name | Required |
Requester Email | Work email | Required | |
Application/Project Name | Text | Name of the workload | Required |
Cost Center | Text | Valid finance code | Required |
Business Justification | Textarea | Why a new subscription is needed (vs existing) | Required |
Landing Zone Type | Dropdown | • Corp (connected to on-prem) | Required |
Environment Purpose | Dropdown | • Development/Test | Required |
Primary Azure Region | Dropdown | East US, West Europe, etc. (based on allowed regions) | Required |
Secondary Region (DR) | Dropdown | Optional | Optional |
Expected Monthly Spend | Number (USD) | Estimated budget | Required |
Network Requirements | Checkboxes | • VNet peering to hub | Required |
Additional Azure Policies | Multiselect | • Deny public IPs | Optional |
Requested Resource Providers | Multiselect | • Microsoft.Compute | Optional |
Subscription Name Alias | Text | Short name (e.g., myapp-dev) – used in management group path | Required, unique |
Subscription Owner(s) | Text (emails) | Primary and backup owners (RBAC Owner role) | Required |
Additional Contributor(s) | Text (emails) | Users/groups who need Contributor access | Optional |
Start Date | Date | When subscription is needed | Required |
End Date (if temporary) | Date | For sandbox subscriptions | Conditional |
Form Footer:
By submitting, you agree that this subscription will be subject to automatic policy enforcement and monthly budget reviews. Unused subscriptions may be deprovisioned after 90 days of zero activity.
Part 2: Approval Stage Gate
Who Approves?
- CCoE Lead or Cloud Governance Board – reviews for compliance, cost, and alignment with landing zone strategy.
- For Sandbox subscriptions under a certain budget (e.g., < $200/month), auto-approval may be allowed.
Approval Workflow Steps:
- Review Request – Approver checks:
- Is the landing zone type appropriate for the workload (e.g., production workloads cannot use Sandbox)?
- Is the cost center valid and has sufficient remaining budget?
- Does the naming convention follow standards?
- Are the requested policies aligned with security requirements?
- Decision Options:
- ✅ Approve → Proceed to subscription creation
- ❌ Reject → Send reason back (e.g., “Use existing subscription”)
- 🔄 Modify → Approver changes a field (e.g., region) and approves
- Escalation:
- If no action in 2 business days → escalate to Cloud Governance Manager
Sample Approval Email
Subject: Azure Subscription Request – Action Required: [App/Project Name]
Requester: John Doe (john.doe@company.com)
Landing Zone Type: Corp
Environment: Production
Region: East US
Estimated monthly spend: $1,200
Justification: “New microservices platform – requires isolation”
[Approve] [Reject] [Modify Request]
View full request in Subscription Vending Portal
Part 3: Post-Approval – Automated Subscription Vending
Once approved, an automation pipeline (Azure DevOps or GitHub Actions) runs the following steps:
Step | Action | Tool / API |
1. Create subscription | Call EA or MCA API to create new subscription under the specified enrollment account | Azure Billing API / ARM |
2. Move to management group | Place subscription under the appropriate ALZ management group (e.g., Corp → Prod) | ARM / Policy API |
3. Assign RBAC | Grant Owner role to primary owner(s), Contributor role to additional users/groups | Microsoft Graph / ARM |
4. Apply Azure Policy | Assign built-in and custom policies (e.g., allowed regions, deny public IPs) | Policy assignments |
5. Create budget & alert | Set budget = expected monthly spend, email alert at 80% and 100% | Consumption API |
6. Configure networking | Create default VNet (optional), set up VNet peering to central hub if requested | ARM / Network API |
7. Register resource providers | Register selected RPs at subscription level | ARM |
8. Tag subscription | Apply required tags: CostCenter, Environment, LandingZoneType, ProjectName | ARM |
9. Notify team | Send final email with subscription ID and portal link | Outlook / Teams |
Estimated completion time: 5–15 minutes from approval.
Part 4: End-to-End User Journey
Step | Actor | System |
1. User opens subscription request portal (SharePoint / Power App) | Requester | SharePoint / App Service |
2. Fills and submits form | Requester | Form |
3. Power Automate / Logic App triggers approval email | Automation | Outlook |
4. CCoE approver reviews and clicks Approve | Approver | Outlook / Teams |
5. Automation pipeline runs (IaC) | DevOps / GitHub | Azure APIs |
6. Subscription created and configured | Automation | Azure |
7. Notification sent to requester with subscription details | Automation | |
8. Requester can now deploy workloads into the new subscription | Requester | Azure Portal / CLI |
Part 5: Sample Implementation Options
Component | Technology Suggestion |
Request frontend | SharePoint list + Power Apps (or Microsoft Forms) |
Workflow & approval | Power Automate (or Azure Logic Apps) |
Approval email | Outlook actionable messages |
Subscription creation | Azure DevOps pipeline triggered by Power Automate (HTTP call) |
IaC for subscription config | Bicep or Terraform modules |
Audit log | SharePoint log list or Azure Log Analytics |
Part 6: Audit & Historical Log (Same as previous pattern)
Create a Subscription Request Log SharePoint list to track:
- Request ID
- Requester
- Landing Zone Type
- Approval date
- Approver name
- Subscription ID (after creation)
- Status (Submitted, Approved, Provisioned, Rejected)
Each approval action writes a log entry (as shown in the earlier answer).
Sample Flow Diagram (Simplified)
text
User submits form → SharePoint list item created
↓
Power Automate trigger → send approval email to CCoE
↓
CCoE approves (Outlook button)
↓
Power Automate calls Azure DevOps REST API to queue pipeline
↓
Pipeline runs Bicep/Terraform:
– Create subscription
– Assign to management group
– Apply RBAC
– Assign policies
– Create VNet peering
– Register RPs
↓
Pipeline returns subscription ID → Power Automate updates SharePoint
↓
Email sent to requester: “Your subscription is ready – ID: xxx”
Next Steps for Implementation
- Create the request form in SharePoint / Power Apps with the fields above.
- Build the Power Automate flow that:
- Triggers on new item
- Sends approval email (with actionable buttons)
- On approval, calls Azure DevOps pipeline (or runs ARM directly)
- Develop the IaC module for subscription configuration (Bicep/Terraform).
- Set up the audit log SharePoint list.
- Test the full flow with a sandbox subscription offer.
Would you like me to provide the Power Automate flow JSON for this subscription vending workflow as well? Or the Bicep module for subscription configuration?
Yes. expand this into how this can be implemented as a sharepoint request front page with instructions to fill in a linked Sharepoint form, and power automate to automate the workflow with outlook/team email notifications
We need to produce a detailed implementation guide for an Azure subscription vending request system using SharePoint front page + SharePoint list form + Power Automate + Outlook/Teams notifications. The user wants expansion similar to the earlier W365 workflow but for subscription vending. Provide instructions, form fields, Power Automate flow logic, and integration with Azure subscription creation (likely via ARM or DevOps). Also include audit logging.
Here is a complete implementation guide for an Azure Subscription Vending request system using:
- SharePoint Online – front page with instructions + a linked SharePoint list form
- Power Automate – workflow engine for approvals and orchestration
- Outlook / Microsoft Teams – notifications with actionable buttons
- Azure DevOps – optional pipeline for subscription creation
- SharePoint Setup – Front Page & Request Form
1.1 Create a SharePoint Site
- Example: https://yourtenant.sharepoint.com/sites/AzureSubscriptionVending
1.2 Create a SharePoint List – “Subscription Requests”
This list serves as both the request form and the data store.
Column Name | Type | Options / Notes |
Title | Single line of text | Will store the Application/Project Name |
RequesterEmail | Single line of text | Email address |
CostCenter | Single line of text | Financial code |
Justification | Multiple lines of text | Business need |
LandingZoneType | Choice | Corp, Online, Sandbox |
EnvironmentPurpose | Choice | Development/Test, Production, Shared Services, Disaster Recovery |
PrimaryRegion | Choice | East US, West Europe, etc. (pre-filter allowed regions) |
SecondaryRegion | Choice | Optional, can be blank |
ExpectedMonthlySpend | Currency | USD estimate |
NetworkRequirements | Choice (or multi-choice) | VNet peering to hub, Direct on-prem connectivity, Isolated |
AdditionalPolicies | Multi-choice | Deny public IPs, Enforce tags, Encrypt disks |
ResourceProviders | Multi-choice | Microsoft.Compute, Microsoft.ContainerService, Microsoft.Sql, Microsoft.Storage |
SubscriptionAlias | Single line of text | e.g., myapp-prod – must be unique |
SubscriptionOwners | Single line of text | Comma-separated emails |
AdditionalContributors | Single line of text | Optional comma-separated emails |
StartDate | Date | Required |
EndDate | Date | Optional, for temporary subscriptions |
Status | Choice | Submitted, Approved, Provisioning, Provisioned, Rejected (default: Submitted) |
SubscriptionID | Single line of text | Populated after creation |
ApproverComment | Multiple lines of text | Populated by Power Automate |
Tip: Use “Require that this column contains information” for mandatory fields.
1.3 Customise the List Form (Optional with Power Apps)
- Open the list → Integrate → Power Apps → Customise forms
- Add conditional visibility: show EndDate only if user selects a temporary duration (you can add a “IsTemporary” Yes/No column to control this).
1.4 Create the SharePoint Front Page (Instructions)
Create a modern site page named “Request an Azure Subscription – Landing Zone”
Sample content:
Request a New Azure Subscription (Landing Zone Enabled)
Use this form to request a fully governed subscription in our enterprise Azure Landing Zone.
Before you begin
- You must have a valid cost center.
- Understand the difference between Corp, Online, and Sandbox landing zones ([link to internal doc]).
- Production subscriptions require additional lead approval.
How to request
- Click the button below to open the request form.
- Fill in all required fields (marked with *).
- After submission, your CCoE approver will receive an email.
- Once approved, the subscription will be automatically created within 15 minutes.
[Request Subscription] – link to the SharePoint list new form:
https://yourtenant.sharepoint.com/sites/AzureSubscriptionVending/Lists/SubscriptionRequests/NewForm.aspx
Check status
View all your requests [here – link to a filtered view of the list].
- Power Automate – Workflow for Subscription Vending
2.1 Trigger
- Flow name: Subscription Vending – Approval & Provisioning
- Trigger: When an item is created (SharePoint)
- Site address: your site
- List name: Subscription Requests
2.2 Determine Approver (Dynamic or Static)
- Option A (simple): Use a fixed CCoE email (e.g., cceo@company.com).
- Option B (dynamic): Create a SharePoint list “LandingZoneApprovers” with columns LandingZoneType and ApproverEmail. Then in the flow, use Get items to fetch the approver based on the selected LandingZoneType.
2.3 Send Approval Notification (Outlook + Teams)
- Use the Approvals connector: Start and wait for an approval
- Approval type: Approve/Reject – First to respond
- Title: Azure Subscription request: {Application Name}
- Assigned to: [dynamic approver email]
- Details: include all key fields (see below)
- Enable actionable messages (Approve/Reject buttons in email)
- Also send a Teams notification using the Post a message in a chat or channel action (Teams connector) to alert the approver.
Sample approval email body (HTML):
html
<b>Requester:</b> {RequesterEmail}<br>
<b>Project:</b> {Title}<br>
<b>Landing Zone Type:</b> {LandingZoneType}<br>
<b>Environment:</b> {EnvironmentPurpose}<br>
<b>Region:</b> {PrimaryRegion}<br>
<b>Est. monthly cost:</b> {ExpectedMonthlySpend}<br>
<b>Justification:</b> {Justification}<br>
<b>Subscription Alias:</b> {SubscriptionAlias}<br>
<br>
Click one of the buttons below to approve or reject.
2.4 Condition – Approval Outcome
Case: Approve
- Update SharePoint item – Status = Approved
- Create audit log entry (see section 4)
- Trigger subscription provisioning (two options):
Option A – Call Azure DevOps Pipeline (recommended)
Use the HTTP action to call Azure DevOps REST API to queue a pipeline.
- Method: POST
- URI: https://dev.azure.com/{org}/{project}/_apis/pipelines/{pipelineId}/runs?api-version=7.0
- Headers: Authorization Basic with PAT (store as secret)
- Body: JSON containing all request parameters (subscription alias, owners, region, etc.)
Option B – Direct ARM / Bicep via Azure Automation
Use Azure Automation runbook or Azure CLI task via a hybrid worker.
Simpler for demo: send an email to an IT shared mailbox with all details (semi-automated).
- Wait for provisioning completion (if using DevOps, you can poll the run status)
- Update SharePoint – Status = Provisioned, fill SubscriptionID
- Send final notification to requester (Outlook + Teams) with subscription details.
Case: Reject
- Update SharePoint – Status = Rejected, ApproverComment = approval comments
- Create audit log entry
- Send rejection email to requester with reason.
2.5 Timeout & Escalation (Optional)
- Add a Delay action before the approval, then a second approval action assigned to a higher-level manager if no response in 48 hours.
- Integration with Azure Subscription Creation
3.1 Prerequisites
- You must have an EA (Enterprise Agreement) or MCA (Microsoft Customer Agreement) with permission to create subscriptions using the Billing API.
- Service principal with Subscription Creator role at the enrollment account level.
- Pre-created management groups (e.g., Corp, Online, Sandbox).
- Pre-created Azure Policies assigned at management group level (or to be assigned per subscription).
3.2 Sample Azure DevOps Pipeline (YAML) to Create Subscription
The pipeline can be triggered by Power Automate via REST API. It performs:
yaml
steps:
– task: AzureCLI@2
inputs:
azureSubscription: ‘ServicePrincipal-Creation’
scriptType: ‘bash’
scriptLocation: ‘inlineScript’
inlineScript: |
# Create subscription (EA)
az account subscription create –enrollment-account-name “EA-123” \
–offer-type “MS-AZR-0017G” \
–display-name “$(SubscriptionAlias)” \
–subscription-name “$(SubscriptionAlias)”
# Get subscription ID
SUB_ID=$(az account subscription list –query “[?displayName==’$(SubscriptionAlias)’].subscriptionId” -o tsv)
# Move to management group
az account management-group subscription add –name “$(LandingZoneType)” –subscription $SUB_ID
# Assign RBAC (Owner to primary owners)
for owner in $(echo “$(SubscriptionOwners)” | tr “,” ” “); do
az role assignment create –assignee $owner –role Owner –subscription $SUB_ID
done
# Apply Azure Policy (example: deny public IPs)
az policy assignment create –name “DenyPublicIPs” \
–policy “/providers/Microsoft.Authorization/policyDefinitions/deny-public-ip” \
–subscription $SUB_ID
# Create budget alert
az consumption budget create –budget-name “MonthlyBudget” \
–subscription $SUB_ID \
–amount $(ExpectedMonthlySpend) \
–time-grain Monthly \
–start-date $(date +%Y-%m-01) \
–notifications “80Percent” –threshold-type Actual –operator GreaterThan –threshold 80 –contact-emails $(RequesterEmail)
# Register resource providers
for rp in $(echo “$(ResourceProviders)” | tr “,” ” “); do
az provider register –namespace $rp –subscription $SUB_ID
done
echo “##vso[task.setvariable variable=SUB_ID;isOutput=true]$SUB_ID”
3.3 Call the Pipeline from Power Automate
After approval, add an HTTP action in Power Automate:
- Method: POST
- URI: https://dev.azure.com/{organization}/{project}/_apis/pipelines/{pipelineId}/runs?api-version=7.0
- Headers:
- Content-Type: application/json
- Authorization: Basic [Base64 encoded PAT]
- Body:
json
{
“parameters”: {
“SubscriptionAlias”: “@{triggerBody()?[‘SubscriptionAlias’]}”,
“LandingZoneType”: “@{triggerBody()?[‘LandingZoneType’]}”,
“SubscriptionOwners”: “@{triggerBody()?[‘SubscriptionOwners’]}”,
“ExpectedMonthlySpend”: “@{triggerBody()?[‘ExpectedMonthlySpend’]}”,
“RequesterEmail”: “@{triggerBody()?[‘RequesterEmail’]}”,
“ResourceProviders”: “@{triggerBody()?[‘ResourceProviders’]}”
}
}
Then poll the pipeline status (use a Delay + another HTTP GET) until completion, then retrieve the subscription ID from the pipeline output.
- Audit Log – Historical Record
Create a second SharePoint list: Subscription Vending Log
Column | Type | Description |
Title | Single line | Auto: Request {ID} – {Action} |
RequestID | Number | Link to original request ID |
RequestTitle | Single line | Application/Project name |
Action | Choice | Submitted, Approved, ProvisioningStarted, Provisioned, Rejected |
Actor | Single line | Who performed action (email) |
Timestamp | Date/Time | Default now |
Comments | Multiple lines | Approver comments or system notes |
StatusBefore | Single line | Previous status |
StatusAfter | Single line | New status |
In Power Automate, add Create item actions at each stage:
- After trigger (Submitted)
- After approval (Approved)
- Before calling provisioning (ProvisioningStarted)
- After subscription creation (Provisioned)
- After rejection (Rejected)
- Complete End-to-End Flow Diagram
text
Requester opens SharePoint page → Clicks form link
↓
Fills and submits SharePoint list form
↓
Power Automate trigger (item created)
↓
Write audit log: “Submitted”
↓
Send approval email to CCoE (Outlook + Teams)
↓
Approver clicks Approve (actionable email/Teams)
↓
Power Automate condition: Approved?
↓ Yes
Write audit log: “Approved”
Update SharePoint status = “Approved”
↓
Call Azure DevOps pipeline (HTTP)
Write audit log: “ProvisioningStarted”
↓
Pipeline runs:
– Create subscription
– Assign to management group
– RBAC, policies, budget, RPs
↓
Pipeline returns subscription ID
↓
Update SharePoint: Status=”Provisioned”, SubscriptionID
Write audit log: “Provisioned”
↓
Send final email/Teams message to requester:
“Your subscription is ready. ID: xxx”
↓
(If reject) Write log “Rejected”, send rejection email.
- Example Teams Notification for Approval
Use the Post a message in a chat or channel action (Teams connector) with:
- Post as: Flow bot
- Message:
text
**New Azure Subscription Request**
– Project: {Title}
– Requester: {RequesterEmail}
– Landing Zone: {LandingZoneType}
– Est. cost: {ExpectedMonthlySpend}
[Approve](link to approval action) | [Reject](link)
But for actionable messages, the Approvals connector already supports Teams. Use the same approval action; it will appear in Teams as an adaptive card if Teams is the notification destination.
- Sample Power Automate Flow (Simplified JSON Structure)
json
{
“triggers”: {
“When_an_item_is_created”: { … }
},
“actions”: {
“Create_audit_log_submitted”: { … },
“Send_approval”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: { “connectionName”: “shared_approvals” },
“operationId”: “SendApproval”,
“parameters”: {
“approvalType”: “ApproveRejectFirstToRespond”,
“title”: “@{triggerBody()?[‘Title’]} – Subscription Request”,
“assignedTo”: “cceo@company.com”,
“details”: “…”,
“enableActionableMessages”: true
}
}
},
“Condition_approved”: {
“type”: “If”,
“expression”: { “equals”: [“@body(‘Send_approval’)?[‘result’]?[‘outcome’]”, “Approve”] },
“actions”: {
“Update_SP_approved”: { … },
“Create_audit_log_approved”: { … },
“Call_DevOps_pipeline”: {
“type”: “Http”,
“inputs”: {
“method”: “POST”,
“uri”: “https://dev.azure.com/…/runs?api-version=7.0”,
“headers”: { “Authorization”: “Basic …” },
“body”: { … }
}
},
“Poll_pipeline_status”: { … },
“Update_SP_provisioned”: { … },
“Send_final_email”: { … }
},
“else”: {
“actions”: {
“Update_SP_rejected”: { … },
“Send_rejection_email”: { … }
}
}
}
}
}
- Testing Checklist
- SharePoint list created with all columns.
- Power Automate flow imported and connections reconfigured (SharePoint, Approvals, Outlook, Teams, HTTP).
- Service principal or PAT configured for Azure DevOps API.
- Test with a small budget sandbox subscription.
- Verify audit log entries are created.
- Confirm Teams notifications are received (if configured).
Next Steps
- Build the SharePoint list using the schema above.
- Create the Power Automate flow – start with the approval part, then add the provisioning call.
- Set up the Azure DevOps pipeline (or start with a manual email handoff for testing).
- Add the audit log list and integrate logging actions.
- Test end-to-end with a real subscription creation (use a test EA account if possible).
Would you like me to provide the complete Power Automate export JSON for this subscription vending flow (including the HTTP call to Azure DevOps and audit log creation)? Just let me know.
power automate export package please
We need to provide a Power Automate export package for the Azure subscription vending workflow. The user asked “power automate export package please” in the context of the subscription vending workflow. I’ll provide the flow definition JSON that can be imported into Power Automate, similar to the previous W365 example but now for subscription vending. I’ll include the necessary placeholders and instructions.
Below is the Power Automate flow definition JSON for the Azure Subscription Vending workflow. You can import this into your Power Automate environment and reconfigure the connections.
How to Import
- Copy the JSON below into a file named SubscriptionVending_Flow.json
- In Power Automate → My flows → Import → Select file → upload the JSON
- After import, you will be prompted to set up connections for:
- SharePoint
- Approvals
- Outlook
- Microsoft Teams
- HTTP (for Azure DevOps)
- Update all placeholders (marked with YOUR_…) in the flow actions (SharePoint site address, approver email, Azure DevOps details, etc.)
- Turn on the flow
Flow Definition JSON
json
{
“$schema”: “https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“$connections”: {
“defaultValue”: {},
“type”: “Object”
}
},
“triggers”: {
“When_an_item_is_created”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “WhenItemCreated”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“recurrence”: {
“frequency”: “Second”,
“interval”: 60
},
“splitOn”: “@triggerBody()?[‘value’]”
}
},
“actions”: {
“Get_item_details”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “GetItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”,
“id”: “@triggerBody()?[‘ID’]”
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Create_audit_log_submitted”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Submitted”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Submitted”,
“Actor”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “@{triggerBody()?[‘Justification’]}”,
“StatusBefore”: “”,
“StatusAfter”: “Submitted”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Get_item_details”: [“Succeeded”]
}
},
“Initialize_approver_email”: {
“type”: “InitializeVariable”,
“inputs”: {
“variables”: [
{
“name”: “ApproverEmail”,
“type”: “string”,
“value”: “cceo@yourcompany.com”
}
]
},
“runAfter”: {
“Create_audit_log_submitted”: [“Succeeded”]
}
},
“Send_approval_email”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_approvals”,
“operationId”: “SendApproval”
},
“parameters”: {
“approvalType”: “ApproveRejectFirstToRespond”,
“title”: “Azure Subscription Request: @{triggerBody()?[‘Title’]}”,
“assignedTo”: “@variables(‘ApproverEmail’)”,
“details”: “<b>Requester:</b> @{triggerBody()?[‘RequesterEmail’]}<br><b>Project:</b> @{triggerBody()?[‘Title’]}<br><b>Landing Zone Type:</b> @{triggerBody()?[‘LandingZoneType’]}<br><b>Environment:</b> @{triggerBody()?[‘EnvironmentPurpose’]}<br><b>Region:</b> @{triggerBody()?[‘PrimaryRegion’]}<br><b>Est. monthly cost:</b> @{triggerBody()?[‘ExpectedMonthlySpend’]}<br><b>Justification:</b> @{triggerBody()?[‘Justification’]}<br><b>Subscription Alias:</b> @{triggerBody()?[‘SubscriptionAlias’]}<br><br>Click one of the buttons below to approve or reject.”,
“itemLink”: “YOUR_SHAREPOINT_SITE_URL/Lists/SubscriptionRequests/DispForm.aspx?ID=@{triggerBody()?[‘ID’]}”,
“notificationType”: “Email”,
“enableActionableMessages”: true
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_approvals’][‘connectionId’]”
}
},
“runAfter”: {
“Initialize_approver_email”: [“Succeeded”]
}
},
“Send_Teams_approval_notification”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_teams”,
“operationId”: “PostMessageToChannel”
},
“parameters”: {
“team”: “YOUR_TEAM_ID”,
“channel”: “YOUR_CHANNEL_ID”,
“message”: “**New Azure Subscription Request**\n- Project: @{triggerBody()?[‘Title’]}\n- Requester: @{triggerBody()?[‘RequesterEmail’]}\n- Landing Zone: @{triggerBody()?[‘LandingZoneType’]}\n- Est. cost: @{triggerBody()?[‘ExpectedMonthlySpend’]}\n\n[Approve or Reject in Outlook]”
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_teams’][‘connectionId’]”
}
},
“runAfter”: {
“Send_approval_email”: [“Succeeded”]
}
},
“Condition_approval_outcome”: {
“type”: “If”,
“expression”: {
“equals”: [
“@body(‘Send_approval_email’)?[‘result’]?[‘outcome’]”,
“Approve”
]
},
“actions”: {
“Update_SharePoint_status_approved”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “UpdateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”,
“id”: “@triggerBody()?[‘ID’]”,
“item”: {
“Status”: “Approved”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Create_audit_log_approved”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Approved”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Approved”,
“Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,
“StatusBefore”: “Submitted”,
“StatusAfter”: “Approved”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Update_SharePoint_status_approved”: [“Succeeded”]
}
},
“Call_DevOps_pipeline”: {
“type”: “Http”,
“inputs”: {
“method”: “POST”,
“uri”: “https://dev.azure.com/YOUR_ORG/YOUR_PROJECT/_apis/pipelines/YOUR_PIPELINE_ID/runs?api-version=7.0”,
“headers”: {
“Content-Type”: “application/json”,
“Authorization”: “Basic YOUR_BASE64_PAT”
},
“body”: {
“parameters”: {
“SubscriptionAlias”: “@{triggerBody()?[‘SubscriptionAlias’]}”,
“LandingZoneType”: “@{triggerBody()?[‘LandingZoneType’]}”,
“SubscriptionOwners”: “@{triggerBody()?[‘SubscriptionOwners’]}”,
“AdditionalContributors”: “@{triggerBody()?[‘AdditionalContributors’]}”,
“ExpectedMonthlySpend”: “@{triggerBody()?[‘ExpectedMonthlySpend’]}”,
“RequesterEmail”: “@{triggerBody()?[‘RequesterEmail’]}”,
“PrimaryRegion”: “@{triggerBody()?[‘PrimaryRegion’]}”,
“ResourceProviders”: “@{triggerBody()?[‘ResourceProviders’]}”
}
}
},
“runAfter”: {
“Create_audit_log_approved”: [“Succeeded”]
}
},
“Delay_for_provisioning”: {
“type”: “Delay”,
“inputs”: {
“interval”: {
“count”: 30,
“unit”: “Second”
}
},
“runAfter”: {
“Call_DevOps_pipeline”: [“Succeeded”]
}
},
“Get_pipeline_run_status”: {
“type”: “Http”,
“inputs”: {
“method”: “GET”,
“uri”: “@{outputs(‘Call_DevOps_pipeline’)?[‘headers’]?[‘Location’]}”,
“headers”: {
“Authorization”: “Basic YOUR_BASE64_PAT”
}
},
“runAfter”: {
“Delay_for_provisioning”: [“Succeeded”]
}
},
“Condition_pipeline_success”: {
“type”: “If”,
“expression”: {
“equals”: [
“@body(‘Get_pipeline_run_status’)?[‘state’]”,
“completed”
]
},
“actions”: {
“Update_SharePoint_provisioned”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “UpdateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”,
“id”: “@triggerBody()?[‘ID’]”,
“item”: {
“Status”: “Provisioned”,
“SubscriptionID”: “@body(‘Get_pipeline_run_status’)?[‘result’]?[‘subscriptionId’]”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Create_audit_log_provisioned”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Provisioned”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Provisioned”,
“Actor”: “System”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “Subscription ID: @{body(‘Get_pipeline_run_status’)?[‘result’]?[‘subscriptionId’]}”,
“StatusBefore”: “Approved”,
“StatusAfter”: “Provisioned”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Update_SharePoint_provisioned”: [“Succeeded”]
}
},
“Send_final_success_email”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_outlook”,
“operationId”: “SendEmail”
},
“parameters”: {
“emailMessage”: {
“To”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Subject”: “Your Azure subscription is ready”,
“Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour requested Azure subscription has been provisioned successfully.\n\n**Subscription ID:** @{body(‘Get_pipeline_run_status’)?[‘result’]?[‘subscriptionId’]}\n**Landing Zone Type:** @{triggerBody()?[‘LandingZoneType’]}\n\nYou can now access it in the Azure portal.\n\nRequest ID: @{triggerBody()?[‘ID’]}\n\nThank you.”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_outlook’][‘connectionId’]”
}
},
“runAfter”: {
“Create_audit_log_provisioned”: [“Succeeded”]
}
}
},
“else”: {
“actions”: {
“Send_provisioning_failure_alert”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_outlook”,
“operationId”: “SendEmail”
},
“parameters”: {
“emailMessage”: {
“To”: “cceo@yourcompany.com”,
“Subject”: “Subscription provisioning failed for @{triggerBody()?[‘Title’]}”,
“Body”: “The automated provisioning pipeline failed. Please check Azure DevOps run logs.\n\nRequest ID: @{triggerBody()?[‘ID’]}\nSubscription Alias: @{triggerBody()?[‘SubscriptionAlias’]}”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_outlook’][‘connectionId’]”
}
},
“runAfter”: {}
}
}
},
“runAfter”: {
“Get_pipeline_run_status”: [“Succeeded”]
}
}
},
“else”: {
“actions”: {
“Update_SharePoint_status_rejected”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “UpdateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”,
“id”: “@triggerBody()?[‘ID’]”,
“item”: {
“Status”: “Rejected”,
“ApproverComment”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Create_audit_log_rejected”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Rejected”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Rejected”,
“Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,
“StatusBefore”: “Submitted”,
“StatusAfter”: “Rejected”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Update_SharePoint_status_rejected”: [“Succeeded”]
}
},
“Send_rejection_email_to_requester”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_outlook”,
“operationId”: “SendEmail”
},
“parameters”: {
“emailMessage”: {
“To”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Subject”: “Your Azure subscription request was not approved”,
“Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour request for a new Azure subscription has been **rejected** by the approver.\n\n**Reason:** @{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}\n\nIf you believe this is an error, please contact the Cloud Center of Excellence.”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_outlook’][‘connectionId’]”
}
},
“runAfter”: {
“Create_audit_log_rejected”: [“Succeeded”]
}
}
}
},
“runAfter”: {
“Send_Teams_approval_notification”: [“Succeeded”]
}
}
},
“outputs”: {}
}
Important Placeholders to Replace
Placeholder | Where to find in the flow | Example value |
YOUR_SHAREPOINT_SITE_URL | Multiple actions (trigger, get item, update, create log) | https://contoso.sharepoint.com/sites/AzureSubscriptionVending |
cceo@yourcompany.com | Initialize_approver_email variable | Actual CCoE email address |
YOUR_TEAM_ID & YOUR_CHANNEL_ID | Send_Teams_approval_notification action | Obtained from Teams connector |
YOUR_ORG, YOUR_PROJECT, YOUR_PIPELINE_ID | Call_DevOps_pipeline HTTP action | contoso, SubscriptionVending, 42 |
YOUR_BASE64_PAT | HTTP actions (authorization header) | Convert :PAT to Base64 (e.g., OmFhYmNk…) |
Prerequisites Before Import
- SharePoint lists must exist:
- Subscription Requests (columns as defined in earlier answer)
- Subscription Vending Log (columns as defined)
- Azure DevOps pipeline (optional but recommended) – a pipeline that accepts the parameters and returns subscriptionId in its output.
- Approvals connector – will be automatically added when you set up connections.
- Teams connector – if you want Teams notifications.
Testing After Import
- Create a new item in the Subscription Requests list.
- The flow should trigger within 1 minute.
- Approver receives an email with Approve/Reject buttons.
- After clicking Approve, the flow calls Azure DevOps.
- Check the audit log list for entries: Submitted → Approved → Provisioned.
Let me know if you need a simplified version without Azure DevOps (e.g., email handoff to IT) or a version with escalation and auto‑expiry. I can provide those JSON snippets as well.
show me the version with email handoff to IT
We need to provide a simplified version of the Power Automate flow that uses email handoff to IT instead of Azure DevOps API. The user wants “email handoff to IT” meaning after approval, an email is sent to an IT team (shared mailbox) with all the details, and IT will manually provision the subscription. The flow still includes the SharePoint front page, form, approval stage gate, audit log, and notifications. We’ll produce the JSON for this simplified flow.
We’ll adapt the previous JSON: remove HTTP calls to Azure DevOps, replace with a “Send email to IT” action. Also remove pipeline polling logic. Keep audit log entries for “Submitted”, “Approved”, “Rejected”, and add “Handed off to IT” (or similar). We’ll keep Teams notification optional.
Let’s produce the answer with explanation and the JSON.
Here is the simplified Power Automate flow JSON that uses email handoff to IT instead of direct Azure DevOps integration. After approval, an email is sent to an IT shared mailbox containing all subscription request details. IT then manually provisions the subscription.
Flow Overview (Email Handoff to IT)
text
User submits SharePoint form
↓
Flow trigger: item created
↓
Audit log: “Submitted”
↓
Send approval email to CCoE (Outlook + Teams optional)
↓
Approver clicks Approve/Reject (actionable email)
↓
If Approved:
– Update SharePoint status → “Approved”
– Audit log: “Approved”
– Send email to IT shared mailbox with all request details
– Audit log: “Handed off to IT”
– Notify requester: “Request approved, IT will provision”
If Rejected:
– Update SharePoint status → “Rejected”
– Audit log: “Rejected”
– Email requester with rejection reason
No HTTP calls, no pipeline polling, no complex waits.
How to Import
- Copy the JSON below into a file named SubscriptionVending_EmailHandoff.json
- In Power Automate → My flows → Import → Select file → upload
- Reconfigure connections: SharePoint, Approvals, Outlook, Teams (optional)
- Replace all placeholders (YOUR_SHAREPOINT_SITE_URL, cceo@yourcompany.com, it-team@yourcompany.com, etc.)
- Turn on the flow
Flow Definition JSON (Email Handoff to IT)
json
{
“$schema”: “https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“$connections”: {
“defaultValue”: {},
“type”: “Object”
}
},
“triggers”: {
“When_an_item_is_created”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “WhenItemCreated”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“recurrence”: {
“frequency”: “Second”,
“interval”: 60
},
“splitOn”: “@triggerBody()?[‘value’]”
}
},
“actions”: {
“Get_item_details”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “GetItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”,
“id”: “@triggerBody()?[‘ID’]”
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Create_audit_log_submitted”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Submitted”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Submitted”,
“Actor”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “@{triggerBody()?[‘Justification’]}”,
“StatusBefore”: “”,
“StatusAfter”: “Submitted”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Get_item_details”: [“Succeeded”]
}
},
“Initialize_approver_email”: {
“type”: “InitializeVariable”,
“inputs”: {
“variables”: [
{
“name”: “ApproverEmail”,
“type”: “string”,
“value”: “cceo@yourcompany.com”
}
]
},
“runAfter”: {
“Create_audit_log_submitted”: [“Succeeded”]
}
},
“Send_approval_email”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_approvals”,
“operationId”: “SendApproval”
},
“parameters”: {
“approvalType”: “ApproveRejectFirstToRespond”,
“title”: “Azure Subscription Request: @{triggerBody()?[‘Title’]}”,
“assignedTo”: “@variables(‘ApproverEmail’)”,
“details”: “<b>Requester:</b> @{triggerBody()?[‘RequesterEmail’]}<br><b>Project:</b> @{triggerBody()?[‘Title’]}<br><b>Landing Zone Type:</b> @{triggerBody()?[‘LandingZoneType’]}<br><b>Environment:</b> @{triggerBody()?[‘EnvironmentPurpose’]}<br><b>Region:</b> @{triggerBody()?[‘PrimaryRegion’]}<br><b>Est. monthly cost:</b> @{triggerBody()?[‘ExpectedMonthlySpend’]}<br><b>Justification:</b> @{triggerBody()?[‘Justification’]}<br><b>Subscription Alias:</b> @{triggerBody()?[‘SubscriptionAlias’]}<br><br>Click one of the buttons below to approve or reject.”,
“itemLink”: “YOUR_SHAREPOINT_SITE_URL/Lists/SubscriptionRequests/DispForm.aspx?ID=@{triggerBody()?[‘ID’]}”,
“notificationType”: “Email”,
“enableActionableMessages”: true
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_approvals’][‘connectionId’]”
}
},
“runAfter”: {
“Initialize_approver_email”: [“Succeeded”]
}
},
“Send_Teams_approval_notification”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_teams”,
“operationId”: “PostMessageToChannel”
},
“parameters”: {
“team”: “YOUR_TEAM_ID”,
“channel”: “YOUR_CHANNEL_ID”,
“message”: “**New Azure Subscription Request**\n- Project: @{triggerBody()?[‘Title’]}\n- Requester: @{triggerBody()?[‘RequesterEmail’]}\n- Landing Zone: @{triggerBody()?[‘LandingZoneType’]}\n- Est. cost: @{triggerBody()?[‘ExpectedMonthlySpend’]}\n\n[Approve or Reject in Outlook]”
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_teams’][‘connectionId’]”
}
},
“runAfter”: {
“Send_approval_email”: [“Succeeded”]
}
},
“Condition_approval_outcome”: {
“type”: “If”,
“expression”: {
“equals”: [
“@body(‘Send_approval_email’)?[‘result’]?[‘outcome’]”,
“Approve”
]
},
“actions”: {
“Update_SharePoint_status_approved”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “UpdateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”,
“id”: “@triggerBody()?[‘ID’]”,
“item”: {
“Status”: “Approved”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Create_audit_log_approved”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Approved”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Approved”,
“Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,
“StatusBefore”: “Submitted”,
“StatusAfter”: “Approved”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Update_SharePoint_status_approved”: [“Succeeded”]
}
},
“Send_email_to_IT_shared_mailbox”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_outlook”,
“operationId”: “SendEmail”
},
“parameters”: {
“emailMessage”: {
“To”: “it-team@yourcompany.com”,
“Cc”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Subject”: “ACTION REQUIRED: Provision Azure subscription – @{triggerBody()?[‘Title’]}”,
“Body”: “A subscription request has been approved. Please provision manually.\n\n**Request Details:**\n- Request ID: @{triggerBody()?[‘ID’]}\n- Project: @{triggerBody()?[‘Title’]}\n- Requester: @{triggerBody()?[‘RequesterEmail’]}\n- Landing Zone Type: @{triggerBody()?[‘LandingZoneType’]}\n- Environment: @{triggerBody()?[‘EnvironmentPurpose’]}\n- Primary Region: @{triggerBody()?[‘PrimaryRegion’]}\n- Subscription Alias: @{triggerBody()?[‘SubscriptionAlias’]}\n- Subscription Owners: @{triggerBody()?[‘SubscriptionOwners’]}\n- Additional Contributors: @{triggerBody()?[‘AdditionalContributors’]}\n- Expected Monthly Spend: @{triggerBody()?[‘ExpectedMonthlySpend’]}\n- Resource Providers: @{triggerBody()?[‘ResourceProviders’]}\n- Network Requirements: @{triggerBody()?[‘NetworkRequirements’]}\n- Additional Policies: @{triggerBody()?[‘AdditionalPolicies’]}\n- Start Date: @{triggerBody()?[‘StartDate’]}\n- End Date: @{triggerBody()?[‘EndDate’]}\n\n**SharePoint Link:** @{body(‘Send_approval_email’)?[‘itemLink’]}\n\nAfter provisioning, please update the SharePoint item with the Subscription ID and change status to ‘Provisioned’.”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_outlook’][‘connectionId’]”
}
},
“runAfter”: {
“Create_audit_log_approved”: [“Succeeded”]
}
},
“Create_audit_log_handoff”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Handed off to IT”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Handed off to IT”,
“Actor”: “System”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “Email sent to IT shared mailbox for manual provisioning”,
“StatusBefore”: “Approved”,
“StatusAfter”: “Handed off”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Send_email_to_IT_shared_mailbox”: [“Succeeded”]
}
},
“Send_approval_notification_to_requester”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_outlook”,
“operationId”: “SendEmail”
},
“parameters”: {
“emailMessage”: {
“To”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Subject”: “Your Azure subscription request has been approved”,
“Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour request for a new Azure subscription has been **approved**.\n\nThe IT team has been notified and will provision the subscription manually. You will receive another email when it is ready.\n\n**Request ID:** @{triggerBody()?[‘ID’]}\n**Subscription Alias:** @{triggerBody()?[‘SubscriptionAlias’]}\n\nEstimated provisioning time: 1-2 business days.\n\nThank you.”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_outlook’][‘connectionId’]”
}
},
“runAfter”: {
“Create_audit_log_handoff”: [“Succeeded”]
}
}
},
“else”: {
“actions”: {
“Update_SharePoint_status_rejected”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “UpdateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”,
“id”: “@triggerBody()?[‘ID’]”,
“item”: {
“Status”: “Rejected”,
“ApproverComment”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Create_audit_log_rejected”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Rejected”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Rejected”,
“Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,
“StatusBefore”: “Submitted”,
“StatusAfter”: “Rejected”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Update_SharePoint_status_rejected”: [“Succeeded”]
}
},
“Send_rejection_email_to_requester”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_outlook”,
“operationId”: “SendEmail”
},
“parameters”: {
“emailMessage”: {
“To”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Subject”: “Your Azure subscription request was not approved”,
“Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour request for a new Azure subscription has been **rejected** by the approver.\n\n**Reason:** @{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}\n\nIf you believe this is an error, please contact the Cloud Center of Excellence.”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_outlook’][‘connectionId’]”
}
},
“runAfter”: {
“Create_audit_log_rejected”: [“Succeeded”]
}
}
}
},
“runAfter”: {
“Send_Teams_approval_notification”: [“Succeeded”]
}
}
},
“outputs”: {}
}
Key Differences from the Azure DevOps Version
Feature | DevOps Version | Email Handoff Version |
Provisioning trigger | HTTP call to Azure DevOps pipeline | Email to IT shared mailbox |
Status after approval | ProvisioningStarted → Provisioned | Approved → Handed off to IT |
Final user notification | “Your subscription is ready (with ID)” | “Approved, IT will provision manually” |
Audit log entries | ProvisioningStarted, Provisioned | Handed off to IT |
Complexity | High (requires PAT, pipeline, polling) | Low (just email) |
Placeholders to Replace
Placeholder | Example |
YOUR_SHAREPOINT_SITE_URL | https://contoso.sharepoint.com/sites/AzureSubscriptionVending |
cceo@yourcompany.com | cloud-governance@contoso.com |
it-team@yourcompany.com | azure-provisioning@contoso.com |
YOUR_TEAM_ID / YOUR_CHANNEL_ID (optional) | Teams channel ID (or remove the Teams action if not needed) |
What IT Needs to Do Manually
When IT receives the email, they will:
- Create a new subscription using EA portal / Azure Billing API
- Move it to the correct management group
- Assign RBAC roles (Owner, Contributor)
- Apply policies, budget alerts, and register resource providers
- Configure VNet peering if requested
- Update the SharePoint list item: add SubscriptionID, change Status to Provisioned
- Notify the requester (or the flow can be extended to detect the status change and send a final email)
Optional enhancement: Create a second Power Automate flow that triggers when a list item is modified (status changes to Provisioned) and then sends the “ready” email to the requester. That keeps the manual step but automates the final notification.
Testing Checklist
- SharePoint lists (Subscription Requests, Subscription Vending Log) exist
- Flow connections reconfigured (SharePoint, Approvals, Outlook, Teams optional)
- Approver email address is correct
- IT shared mailbox is correct
- Submit a test request → Approver gets email → Click Approve → IT receives email
- Audit log shows: Submitted → Approved → Handed off to IT
- Requester receives “approved” email
Let me know if you want me to provide the second flow that watches for Provisioned status and sends the final “ready” email automatically when IT updates the item.
yes
We need to provide the second flow that watches for when IT updates the SharePoint list item status to “Provisioned” and then sends the final “ready” email to the requester. This will be a separate Power Automate flow (trigger: when an item is modified). Include the JSON export for that flow as well.
Here is the second Power Automate flow that watches for when IT updates the SharePoint list item status to Provisioned and then automatically sends the final “ready” email to the requester.
Flow Overview – Final Notification after IT Provisioning
text
IT manually provisions subscription (outside of flow)
↓
IT updates SharePoint list item:
– Status = “Provisioned”
– SubscriptionID = <actual ID>
↓
Flow trigger: When an item is modified (only if Status changed to Provisioned)
↓
Get item details
↓
Check if Status is “Provisioned” AND previous status was not Provisioned (avoid loops)
↓
Send final “ready” email to requester with Subscription ID
↓
Update audit log: “Provisioned” entry (if not already logged)
This flow runs independently of the approval flow and completes the user journey.
How to Import
- Copy the JSON below into a file named SubscriptionProvisionedNotification_Flow.json
- In Power Automate → My flows → Import → Select file → upload
- Reconfigure connections: SharePoint, Outlook
- Replace placeholder YOUR_SHAREPOINT_SITE_URL
- Turn on the flow
Flow Definition JSON (Final Notification on Provisioned Status)
json
{
“$schema”: “https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“$connections”: {
“defaultValue”: {},
“type”: “Object”
}
},
“triggers”: {
“When_an_item_is_modified”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “WhenItemModified”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“recurrence”: {
“frequency”: “Second”,
“interval”: 60
},
“splitOn”: “@triggerBody()?[‘value’]”
}
},
“actions”: {
“Get_item_details”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “GetItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Requests”,
“id”: “@triggerBody()?[‘ID’]”
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Condition_status_is_provisioned”: {
“type”: “If”,
“expression”: {
“equals”: [
“@triggerBody()?[‘Status’]”,
“Provisioned”
]
},
“actions”: {
“Check_previous_status_not_provisioned”: {
“type”: “If”,
“expression”: {
“not”: {
“equals”: [
“@{triggerBody()?[‘Status’]}”,
“@{triggerBody()?[‘PreviousStatus’]}”
]
}
},
“actions”: {
“Send_final_ready_email”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_outlook”,
“operationId”: “SendEmail”
},
“parameters”: {
“emailMessage”: {
“To”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Subject”: “Your Azure subscription is ready for use”,
“Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour requested Azure subscription has been **provisioned successfully** by the IT team.\n\n**Subscription ID:** @{triggerBody()?[‘SubscriptionID’]}\n**Landing Zone Type:** @{triggerBody()?[‘LandingZoneType’]}\n**Environment:** @{triggerBody()?[‘EnvironmentPurpose’]}\n\nYou can now access it in the Azure portal: https://portal.azure.com\n\n**Next steps:**\n- Ensure you have the required RBAC roles (Owner/Contributor as requested).\n- Review the assigned Azure policies and budget alerts.\n- Start deploying your workloads.\n\nRequest ID: @{triggerBody()?[‘ID’]}\n\nThank you for using the Subscription Vending service.”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_outlook’][‘connectionId’]”
}
},
“runAfter”: {}
},
“Create_audit_log_provisioned”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: {
“connectionName”: “shared_sharepointonline”,
“operationId”: “CreateItem”
},
“parameters”: {
“siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Provisioned”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Provisioned”,
“Actor”: “IT Team (manual)”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “Subscription ID: @{triggerBody()?[‘SubscriptionID’]}”,
“StatusBefore”: “@{triggerBody()?[‘Status’]}”,
“StatusAfter”: “Provisioned”
}
},
“authentication”: {
“type”: “Raw”,
“scheme”: “Key”,
“parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”
}
},
“runAfter”: {
“Send_final_ready_email”: [“Succeeded”]
}
}
},
“runAfter”: {}
}
},
“runAfter”: {
“Get_item_details”: [“Succeeded”]
}
}
},
“outputs”: {}
}
Important Notes
Trigger Considerations
- The trigger When an item is modified will fire for any change to the list item.
- The condition Status == “Provisioned” ensures we only proceed when status changes to Provisioned.
- The nested condition PreviousStatus != Status prevents re-triggering if IT saves the same status again. (Note: The trigger body includes a PreviousStatus property automatically for SharePoint list modifications.)
Audit Log
- This flow creates a Provisioned entry in the audit log. If your approval flow already created a Handed off to IT entry, this adds the final Provisioned entry.
- If you want a single Provisioned entry, you can disable the audit log creation in this flow and rely on IT manually adding it when they update the status. The JSON above includes it for completeness.
IT Workflow Integration
- IT receives the handoff email from the approval flow.
- After manually provisioning, IT updates the SharePoint list item:
- Change Status dropdown to Provisioned
- Fill in SubscriptionID column
- (Optional) Add a comment in ApproverComment or a separate ITNotes column
- This flow then sends the final email automatically.
Optional Enhancement: Email IT if Provisioning Fails
If IT needs to mark a request as failed, add another condition in this flow (or a separate flow) that watches for Status == “ProvisioningFailed” and sends an alert to both requester and CCoE.
Testing Checklist for This Flow
- SharePoint list Subscription Requests exists with columns Status, SubscriptionID, RequesterEmail, Title, LandingZoneType, EnvironmentPurpose
- Flow imported and connections reconfigured (SharePoint, Outlook)
- Placeholder YOUR_SHAREPOINT_SITE_URL replaced
- Existing request is in Approved or Handed off to IT status
- Manually edit the list item: change Status to Provisioned, add a dummy SubscriptionID
- Verify the requester receives the final “ready” email
- Check audit log for new Provisioned entry
End-to-End Flow Summary (Both Flows Combined)
Step | Flow | Trigger | Action |
1 | Approval flow | Item created in SharePoint | Send approval email |
2 | Approval flow | Approver clicks Approve | Email IT shared mailbox, notify requester |
3 | (Manual) | IT provisions subscription | IT updates SharePoint: Status = Provisioned |
4 | Notification flow | Item modified (Status = Provisioned) | Send final “ready” email to requester |
Now you have a complete, low‑code solution for Azure Subscription Vending using SharePoint + Power Automate + email handoff to IT, with full audit logging and final user notification.
Let me know if you want the flows packaged as a single importable solution (using Power Platform Solution export) or if you need help with the SharePoint list templates (schema JSON for list creation via PnP PowerShell).
show me the power platform solution export and hlep with sharepoint list templates
The user is asking for two things: a Power Platform solution export and help with SharePoint list templates. This is a follow-up to a previous conversation where we provided Power Automate flow JSONs for subscription vending and W365 workflows. Now they want to package these as a Power Platform solution and get SharePoint list templates (likely as XML or JSON for PnP PowerShell).
I need to search for the most up-to-date documentation and methods for creating Power Platform solutions and SharePoint list templates.
I’ll search for “Power Platform solution export unmanaged 2026” and “SharePoint list template PnP PowerShell schema”.
Found 20 web pages
The search results for Power Platform solutions show relevant links, but they are mostly about CLI and DevOps, not a simple “export package” feature. For SharePoint list templates, the results show methods using PnP PowerShell and XML schemas.
To provide comprehensive help, I need to open several of these results to gather detailed information.
Read 4 pages
Microsoft Power Platform CLI solution command group – Power Platform
【SharePointリスト作成】 Excel 定義から SharePoint リストを一括作成する方法 #0225|Shinichi Kawara
SharePointのリストをPowerShellで他のサイトに移行する
How to Create a Custom List Template in SharePoint Online (2026)
The search results provide a good foundation. The Power Platform CLI documentation shows the pac solution export command. The PnP provisioning XML method is detailed in the Japanese article, which includes a PowerShell script to generate the XML from a CSV. The other article shows how to export a list template using Get-PnPSiteTemplate. The “mrsharepoint.com” article shows how to use Get-SPOSiteScriptFromList.
I need to provide a comprehensive answer covering Power Platform solution export and SharePoint list templates. I’ll structure the answer with two main parts: Part 1 for Power Platform solution export and Part 2 for SharePoint list templates. I’ll include step-by-step instructions, code examples, and best practices.
I’ll show you how to create a reusable Power Platform solution containing the Power Automate flows, along with the SharePoint list templates for the request form and audit log.
🗃️ Part 1: SharePoint List Templates
You can deploy the required lists quickly using PnP PowerShell. This method is ideal for source-controlling your list structures (schema and columns).
Here are the complete templates for your two lists.
- Main Request List: Subscription Requests
This template includes all the columns we defined earlier.
xml
<pnp:Provisioning xmlns:pnp=”http://schemas.dev.office.com/PnP/2016/05/ProvisioningSchema”>
<pnp:Preferences Generator=”PnP PowerShell” />
<pnp:Templates>
<pnp:ProvisioningTemplate ID=”SubscriptionRequests”>
<pnp:Lists>
<pnp:ListInstance Title=”Subscription Requests” Description=”Azure subscription requests from users” TemplateType=”100″ Url=”Lists/SubscriptionRequests”>
<pnp:ContentTypeBindings>
<pnp:ContentTypeBinding ContentTypeID=”0x01″ Default=”true” />
</pnp:ContentTypeBindings>
<pnp:Fields>
<!– Requester Information –>
<Field Type=”Text” Name=”RequesterEmail” DisplayName=”Requester Email” Required=”TRUE” />
<Field Type=”Text” Name=”CostCenter” DisplayName=”Cost Center” Required=”TRUE” />
<Field Type=”Note” Name=”Justification” DisplayName=”Business Justification” Required=”TRUE” RichText=”FALSE” NumLines=”6″ />
<!– Subscription Configuration –>
<Field Type=”Choice” Name=”LandingZoneType” DisplayName=”Landing Zone Type” Required=”TRUE”>
<CHOICES>
<CHOICE>Corp (connected to on-prem)</CHOICE>
<CHOICE>Online (internet-facing)</CHOICE>
<CHOICE>Sandbox (no production)</CHOICE>
</CHOICES>
</Field>
<Field Type=”Choice” Name=”EnvironmentPurpose” DisplayName=”Environment Purpose” Required=”TRUE”>
<CHOICES>
<CHOICE>Development/Test</CHOICE>
<CHOICE>Production</CHOICE>
<CHOICE>Shared Services</CHOICE>
<CHOICE>Disaster Recovery</CHOICE>
</CHOICES>
</Field>
<Field Type=”Choice” Name=”PrimaryRegion” DisplayName=”Primary Azure Region” Required=”TRUE”>
<CHOICES>
<CHOICE>East US</CHOICE>
<CHOICE>West Europe</CHOICE>
<CHOICE>Southeast Asia</CHOICE>
</CHOICES>
</Field>
<Field Type=”Choice” Name=”SecondaryRegion” DisplayName=”Secondary Region (DR)”>
<CHOICES>
<CHOICE>None</CHOICE>
<CHOICE>West US</CHOICE>
<CHOICE>North Europe</CHOICE>
</CHOICES>
</Field>
<Field Type=”Currency” Name=”ExpectedMonthlySpend” DisplayName=”Expected Monthly Spend (USD)” Required=”TRUE” />
<Field Type=”Text” Name=”SubscriptionAlias” DisplayName=”Subscription Alias” Required=”TRUE” />
<Field Type=”Text” Name=”SubscriptionOwners” DisplayName=”Subscription Owner(s) (emails)” Required=”TRUE” />
<Field Type=”Text” Name=”AdditionalContributors” DisplayName=”Additional Contributor(s) (emails)” />
<Field Type=”MultiChoice” Name=”ResourceProviders” DisplayName=”Requested Resource Providers”>
<CHOICES>
<CHOICE>Microsoft.Compute</CHOICE>
<CHOICE>Microsoft.ContainerService</CHOICE>
<CHOICE>Microsoft.Sql</CHOICE>
<CHOICE>Microsoft.Storage</CHOICE>
</CHOICES>
</Field>
<!– Networking & Policies –>
<Field Type=”Choice” Name=”NetworkRequirements” DisplayName=”Network Requirements” Required=”TRUE”>
<CHOICES>
<CHOICE>VNet peering to hub</CHOICE>
<CHOICE>Direct on-prem connectivity</CHOICE>
<CHOICE>No connectivity needed (isolated)</CHOICE>
</CHOICES>
</Field>
<Field Type=”MultiChoice” Name=”AdditionalPolicies” DisplayName=”Additional Azure Policies”>
<CHOICES>
<CHOICE>Deny public IPs</CHOICE>
<CHOICE>Enforce tags</CHOICE>
<CHOICE>Encrypt disks</CHOICE>
</CHOICES>
</Field>
<!– Dates –>
<Field Type=”DateTime” Name=”StartDate” DisplayName=”Start Date” Required=”TRUE” Format=”DateOnly” />
<Field Type=”DateTime” Name=”EndDate” DisplayName=”End Date (if temporary)” Format=”DateOnly” />
<!– Status & Output –>
<Field Type=”Choice” Name=”Status” DisplayName=”Status”>
<CHOICES>
<CHOICE>Submitted</CHOICE>
<CHOICE>Approved</CHOICE>
<CHOICE>Provisioned</CHOICE>
<CHOICE>Rejected</CHOICE>
</CHOICES>
<Default>Submitted</Default>
</Field>
<Field Type=”Text” Name=”SubscriptionID” DisplayName=”Subscription ID” />
<Field Type=”Note” Name=”ApproverComment” DisplayName=”Approver Comment” RichText=”FALSE” />
</pnp:Fields>
<pnp:Views>
<View Name=”All Items” DefaultView=”TRUE” />
</pnp:Views>
</pnp:ListInstance>
</pnp:Lists>
</pnp:ProvisioningTemplate>
</pnp:Templates>
</pnp:Provisioning>
- Audit Log List: Subscription Vending Log
This list records every action for complete traceability.
xml
<pnp:Provisioning xmlns:pnp=”http://schemas.dev.office.com/PnP/2016/05/ProvisioningSchema”>
<pnp:Preferences Generator=”PnP PowerShell” />
<pnp:Templates>
<pnp:ProvisioningTemplate ID=”SubscriptionVendingLog”>
<pnp:Lists>
<pnp:ListInstance Title=”Subscription Vending Log” Description=”Audit trail for subscription requests” TemplateType=”100″ Url=”Lists/SubscriptionVendingLog”>
<pnp:ContentTypeBindings>
<pnp:ContentTypeBinding ContentTypeID=”0x01″ Default=”true” />
</pnp:ContentTypeBindings>
<pnp:Fields>
<Field Type=”Number” Name=”RequestID” DisplayName=”Request ID” Required=”TRUE” />
<Field Type=”Text” Name=”RequestTitle” DisplayName=”Request Title” Required=”TRUE” />
<Field Type=”Choice” Name=”Action” DisplayName=”Action” Required=”TRUE”>
<CHOICES>
<CHOICE>Submitted</CHOICE>
<CHOICE>Approved</CHOICE>
<CHOICE>Handed off to IT</CHOICE>
<CHOICE>Provisioned</CHOICE>
<CHOICE>Rejected</CHOICE>
</CHOICES>
</Field>
<Field Type=”Text” Name=”Actor” DisplayName=”Actor (Email)” Required=”TRUE” />
<Field Type=”DateTime” Name=”Timestamp” DisplayName=”Timestamp” Required=”TRUE” Format=”DateTime” />
<Field Type=”Note” Name=”Comments” DisplayName=”Comments” RichText=”FALSE” />
<Field Type=”Text” Name=”StatusBefore” DisplayName=”Status Before” />
<Field Type=”Text” Name=”StatusAfter” DisplayName=”Status After” />
</pnp:Fields>
<pnp:Views>
<View Name=”All Items” DefaultView=”TRUE”>
<ViewFields>
<FieldRef Name=”RequestID” />
<FieldRef Name=”Action” />
<FieldRef Name=”Actor” />
<FieldRef Name=”Timestamp” />
<FieldRef Name=”Comments” />
</ViewFields>
<RowLimit>100</RowLimit>
<Query>
<OrderBy>
<FieldRef Name=”Timestamp” Ascending=”FALSE” />
</OrderBy>
</Query>
</View>
</pnp:Views>
</pnp:ListInstance>
</pnp:Lists>
</pnp:ProvisioningTemplate>
</pnp:Templates>
</pnp:Provisioning>
- How to Deploy the SharePoint Lists Using PnP PowerShell
Follow these steps to apply the XML templates above to your SharePoint site.
- Install PnP PowerShell Module (if not already installed):
powershell
Install-Module -Name PnP.PowerShell -Scope CurrentUser
- Connect to your SharePoint site:
powershell
Connect-PnPOnline -Url “https://yourtenant.sharepoint.com/sites/AzureSubscriptionVending” -Interactive
- Apply the first list template:
powershell
Invoke-PnPSiteTemplate -Path “C:\path\to\SubscriptionRequestsTemplate.xml”
- Apply the second list template:
powershell
Invoke-PnPSiteTemplate -Path “C:\path\to\SubscriptionVendingLogTemplate.xml”
💡 Pro Tip: If you prefer a CSV-driven approach to generate the XML automatically (ideal for source control), you can use a script like the one described in the PnP provisioning guide.
🧩 Part 2: Power Platform Solution Export
To package the Power Automate flows, SharePoint connection references, and other components into a single reusable unit, you need to create a Power Platform Solution.
⚠️ Important: You can only export unmanaged solutions from a development environment. Managed solutions are for production deployment and cannot be edited.
Step 1: Create a New Solution in Power Apps Maker Portal
- Navigate to Power Apps Maker Portal → Solutions → New solution
- Enter details:
- Display name: Azure Subscription Vending
- Publisher: Select the default or create a custom one
- Version: 1.0.0.0
Step 2: Add Components to Your Solution
Add all related artifacts to your solution:
Component Type | Components to Include |
Cloud flow | Subscription Vending – Approval & Handoff |
Connection reference | SharePoint connection, Outlook connection, Approvals connection, Teams connection (auto-created when adding flows) |
SharePoint site URL (if using environment variables) | Variable for the target SharePoint site |
How to add:
- Open your solution → Add existing → Cloud flow → Select your flows
- The system will automatically include required connection references.
Step 3: Export the Solution
Option A: Manual Export via Maker Portal (Simpler)
- In your solution, select Export from the top menu
- Choose Unmanaged (for development or source control)
- Download the .zip file
Option B: Automated Export via Power Platform CLI (For CI/CD)
This method is ideal for DevOps pipelines.
bash
pac solution export –name “AzureSubscriptionVending” –path “C:\exports” –managed false
For full automation in Azure DevOps pipelines, refer to the Power Platform Build Tools documentation.
Step 4: Import the Solution to Another Environment
- In the target environment, go to Solutions → Import
- Upload the .zip file
- Configure any required connection references (point them to the appropriate SharePoint site, user accounts, etc.)
- Publish all customizations
🔄 Quick Reference: Flow vs. Solution Components
What You Built | In Solution | Manual Deployment |
Approval Flow (JSON) | ✅ Yes – packaged as a cloud flow | ❌ Must paste JSON and recreate connections |
Notification Flow (JSON) | ✅ Yes – packaged as a cloud flow | ❌ Must paste JSON and recreate connections |
SharePoint List Schema | ❌ Not included – deploy separately via PnP | ✅ Use XML template above |
Audit Log Schema | ❌ Not included – deploy separately via PnP | ✅ Use XML template above |
Connection References | ✅ Yes – included | ❌ Must manually recreate |
Note: SharePoint lists are not automatically included in the solution export. You should version control the XML templates alongside your solution .zip file for a complete, reproducible deployment.
📋 Recommended Deployment Workflow
- Run PnP PowerShell script to create both SharePoint lists using the XML templates above
- Import the Power Platform Solution (.zip file) into the target environment
- Update connection references to point to the newly created SharePoint lists
- Turn on both flows
- Test the end-to-end process
💾 Sample Solution Package Files
I cannot directly send a .zip file, but I have provided all the necessary components for you to build the solution manually:
- Flow 1 JSON → SubscriptionVending_EmailHandoff.json (from previous answer)
- Flow 2 JSON → SubscriptionProvisionedNotification_Flow.json (from previous answer)
- SharePoint List 1 XML → SubscriptionRequestsTemplate.xml (included above)
- SharePoint List 2 XML → SubscriptionVendingLogTemplate.xml (included above)
- Power Platform Solution → Create via Maker Portal (steps above)
Let me know if you need me to provide the CSV-to-XML generation script for the SharePoint lists or help with setting up the connection references in your imported solution.
lastly, how can automate the capture of status of approval process back into a log in Sharepoint showing a historical list of when past approval dates, by whom, and new entries for what has been submitted and auto updated when it is approved
We need to answer the user’s final question: “lastly, how can automate the capture of status of approval process back into a log in Sharepoint showing a historical list of when past approval dates, by whom, and new entries for what has been submitted and auto updated when it is approved”
They want to know how to automate capturing approval status (dates, who approved, etc.) into a SharePoint log. The user has already been given the audit log approach earlier, but they are asking specifically for this automation. So we need to provide a concise answer focusing on the mechanism: using Power Automate to write log entries when an item is created (submitted) and when the approval outcome is received (approved/rejected). Include details like capturing approver email, timestamp, comments, and status changes. Also mention that the flow updates the log list automatically.
The answer should be practical, step-by-step, referencing the earlier flow examples but highlighting the log capture actions.
We’ll produce a final answer that directly addresses this question.
You can fully automate the capture of approval status into a SharePoint audit log using Power Automate triggered by actions on your request list. The log will record:
- When the request was submitted, approved, or rejected (timestamp)
- Who performed the action (requester or approver email)
- What changed (status before/after, approval comments)
This is already embedded in the flows I provided, but here is a focused explanation of how to implement just the audit logging piece, assuming you have the SharePoint lists from the previous steps.
📝 How the Automated Audit Log Works
You need two triggers in Power Automate to capture everything:
- When an item is created – logs the submission
- When an approval completes – logs the approval or rejection (within the same flow)
Both write entries into a separate SharePoint list called Subscription Vending Log (or similar).
🧩 Step-by-Step: Add Audit Logging to Your Approval Flow
- Create the Log List (if not already done)
Use the SharePoint list template from the previous answer, or manually create a list with these columns:
Column | Type | Purpose |
Title | Single line | Auto‑generated: Request [ID] – [Action] |
RequestID | Number | ID of the original request |
RequestTitle | Single line | Name of the request (project name) |
Action | Choice | Submitted, Approved, Rejected, Provisioned |
Actor | Single line | Email of who performed the action |
Timestamp | Date/Time | Default = current time |
Comments | Multiple lines | Justification (for submission) or approver’s reason |
StatusBefore | Single line | Previous status of the request |
StatusAfter | Single line | New status after the action |
- Modify Your Power Automate Approval Flow
In the flow that handles the request (triggered when an item is created), add these Create item actions (targeting the log list).
- a) Log the submission – right after the trigger
text
When an item is created (SharePoint)
├─ Create item in “Subscription Vending Log”
├─ Title: “Request @{triggerBody()?[‘ID’]} – Submitted”
├─ RequestID: @{triggerBody()?[‘ID’]}
├─ RequestTitle: @{triggerBody()?[‘Title’]}
├─ Action: “Submitted”
├─ Actor: @{triggerBody()?[‘RequesterEmail’]}
├─ Timestamp: @{utcNow()}
├─ Comments: @{triggerBody()?[‘Justification’]}
├─ StatusBefore: (empty)
└─ StatusAfter: “Submitted”
- b) Log the approval – inside the Approve branch
After the approval outcome is received and you update the main request status to Approved, add:
text
Create item in “Subscription Vending Log”
├─ Title: “Request @{triggerBody()?[‘ID’]} – Approved”
├─ RequestID: @{triggerBody()?[‘ID’]}
├─ RequestTitle: @{triggerBody()?[‘Title’]}
├─ Action: “Approved”
├─ Actor: @{body(‘Send_approval_email’)?[‘responder’]?[’email’]}
├─ Timestamp: @{utcNow()}
├─ Comments: @{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}
├─ StatusBefore: “Submitted” (or “Pending Approval”)
└─ StatusAfter: “Approved”
- c) Log the rejection – inside the Reject branch
Similarly, log the rejection with the approver’s comment.
🔁 Automatic Updates When Approved
Because the log entries are created immediately when the approval action occurs, the log list always reflects the current state without any manual intervention. You don’t need a separate flow to “update” the log; you simply append new entries as events happen.
The log becomes a chronological history of each request. To see all events for a single request, filter by RequestID.
📊 Example Log Output
After a request goes through submission → approval → provisioning, your log list will contain:
Title | Action | Actor | Timestamp | StatusBefore | StatusAfter |
Request 5 – Submitted | Submitted | john@contoso.com | 2025-03-15 10:00 | Submitted | |
Request 5 – Approved | Approved | cceo@contoso.com | 2025-03-15 11:30 | Submitted | Approved |
Request 5 – Provisioned | Provisioned | IT Team (manual) | 2025-03-16 09:00 | Approved | Provisioned |
This gives you a full audit trail of when each action happened, by whom, and what changed.
🛠️ Minimal Power Automate Snippet (for a new flow)
If you want to start from scratch, here is a simplified JSON snippet that shows only the audit logging actions inside an approval flow (without the full subscription vending logic). You can insert this pattern into any approval flow.
json
“Create_log_submitted”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: { “connectionName”: “shared_sharepointonline” },
“operationId”: “CreateItem”,
“parameters”: {
“siteAddress”: “YOUR_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Submitted”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Submitted”,
“Actor”: “@{triggerBody()?[‘RequesterEmail’]}”,
“Timestamp”: “@{utcNow()}”,
“StatusAfter”: “Submitted”
}
}
}
},
“Create_log_approved”: {
“type”: “ApiConnection”,
“inputs”: {
“host”: { “connectionName”: “shared_sharepointonline” },
“operationId”: “CreateItem”,
“parameters”: {
“siteAddress”: “YOUR_SITE_URL”,
“listName”: “Subscription Vending Log”,
“item”: {
“Title”: “Request @{triggerBody()?[‘ID’]} – Approved”,
“RequestID”: “@{triggerBody()?[‘ID’]}”,
“RequestTitle”: “@{triggerBody()?[‘Title’]}”,
“Action”: “Approved”,
“Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,
“Timestamp”: “@{utcNow()}”,
“Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,
“StatusBefore”: “Submitted”,
“StatusAfter”: “Approved”
}
}
}
}
✅ Summary
What you want to capture | How it is automated |
When request was submitted | Flow logs on When an item is created |
Who submitted it | RequesterEmail from the trigger |
When it was approved | Flow logs inside the Approve branch of the approval action |
Who approved it | responder[’email’] from the approval action |
Any comments from approver | result[‘comments’] from the approval action |
Status changes (before/after) | Hardcoded or dynamic values in log entry |
The audit log is append‑only – no updates needed. Every state change creates a new row, giving you a complete, immutable history.
If you need the exact Power Automate flow JSON with all audit logging actions already inserted (for both the approval flow and the provisioning notification flow), just let me know and I will provide the merged, ready‑to‑import package.