You have 50 scripts. They work. Every single one does what it is supposed to do.
You wrote them, your team runs them and they solve real problems.
But here is the tension. Nobody talks about nobody knows why anymore.
Ask yourself who deployed the automation account that runs your biggest workflow,
or when it was actually set up. Think about what permissions it has and where the key
vault is that stores those connection strings. If that subscription disappeared
tomorrow, could you rebuild this in three hours? Or would it take three weeks of
reverse engineering your own scripts? This is the real problem with automation at
scale. It does not fail because the scripts are bad. It fails because automation
that scales becomes infrastructure that nobody can govern. You have built
something that works, but you have not built something that is repeatable,
auditable, or defensible. In this episode, we are moving from doing things to
defining systems. You will understand why PowerShell hits a ceiling.
Not because PowerShell is bad, but because PowerShell is designed for
actions, not for defining infrastructure. And you will see how bicep becomes the
foundation for real platform engineering. It is the language that lets you treat
your infrastructure the way software engineers treat code, versioned, reviewed,
auditable, repeatable. By the end, you will know exactly where you are on this
journey and what the next level looks like. The automation journey, how you got
here. Let me walk you through how almost every engineer ends up in this exact
place. Phase one is always the same. You are in the portal, clicking, creating
users one at a time, assigning licenses one at a time. It is repetitive and soul
crushing. So one day you decide to script it. You write your first PowerShell
script with 30 or 50 lines that does the job. You save it and run it. And suddenly
what took an hour takes five minutes. That moment feels like magic. Then phase
two starts. That one script works so well. You write another for a different
problem. Do it once in code instead of manually. Now you have two scripts, then
five, then 10. Each one solves a specific problem like user provisioning,
license assignment, group management, or exchange configuration. They all work
independently and solve real problems. By the time you hit 10 scripts, you are
already saving the organization significant time. By 20 you are a hero. Your team
depends on you and management notices. So you actually get budgeted for this
work now. Then you hit phase three. Scripts are everywhere. You have 30, 40 or
50 scripts, summer and shared folders, summer on your local drive, and summer
and git repos that nobody has touched in 18 months. You start getting asked to
modify an old script and you realize you cannot remember what it does. Or
rather you remember the script, but you do not remember the infrastructure.
It depends on which subscription is this supposed to run in? Where does it store
its credentials? Who set up the service account that runs this? Here is the
honest truth about this phase. You have automated tasks. You have not built a
platform. A platform is repeatable, documented and auditable. It is governable.
It can be deployed to different environments without manual intervention
and recreated from source control. A platform is infrastructure. Your scripts
are brilliant at doing one thing, but 50 scripts is not a platform. It is a
collection of solutions. And the moment someone asks you to rebuild all of
this in a new tenant or across Devon production or in a disaster recovery
scenario, you realize the entire thing is fragile. This is the power shell
ceiling. It is not a failure. It is a signal. It means you have outgrown the
model. Scripting is designed for tasks, but infrastructure needs a different
model entirely. And the moment you are managing dozens of scripts, multiple
automation accounts, key vaults, storage accounts, monitoring solutions and
service principles across subscriptions, you are not automating anymore. You are
operating a platform, but your toolset is built for scripting. That mismatch is
where the problem lives. What power shell actually is and what it isn't. Power
shell is imperative. That sounds like a technical buzzword, but let's make it
concrete. Imperative means you are giving commands step by step. Do this, then
do that, then do this next thing. When you write a script, you're telling the
system to create the user object, set the password and assign the license. You
tell it to wait for that license to sync, add the user to a group and finally
send a welcome email. Each line is an action and instruction. You are telling
the machine to do something and power shell is brilliant at this because it was
designed for it. If you have 100 users to onboard and want to do it in parallel,
PowerShell handles that. If you need to query 30 groups to check memberships and
report on licenses, PowerShell gets you the answer in seconds. The problem
isn't what PowerShell does. The problem is what PowerShell doesn't do. PowerShell
doesn't define infrastructure. Here is a practical example of where it breaks.
You write a script that creates a user, assigns a Microsoft 365 license and adds
them to a distribution group. The script runs, the user exists, the license is
there, they are in the group. It works. But think about what that script doesn't say.
It doesn't say who deployed it or where it runs from. It doesn't capture the
credentials it uses or where those secrets are stored. It doesn't document the
permissions it needs or define the automation account that executes the code. It
doesn't specify which keyboard holds the connection strings and it doesn't
declare what monitoring should be in place or where the logs should go. All of
those things exist. Your script depends on them. But the script itself doesn't
define them. It just assumes they're already there. That is the hidden problem
with PowerShell at scale. When you have one script, this doesn't matter because
you remember setting up the automation account last Tuesday. You know where the
credentials live and you know exactly what prerequisites had to be in place for
the code to run. But when you have 50 scripts, things change. You stop
remembering. You stop knowing. And what's worse is that when someone new joins
your team, they have to reverse engineer your infrastructure just by looking at
your scripts. Except the scripts don't actually tell them the infrastructure.
The scripts just use it. PowerShell tracks tasks. It executes actions. It moves
data around and calls APIs to get things done. What PowerShell doesn't track is the
desired state of your system. It doesn't say this is what should exist. It says go
make this happen. That distinction matters more than it sounds because when you're
managing a platform, not just running scripts, but managing the entire foundation
those scripts depend on, you need to know what should exist. You need to know what
version of the key vault should be deployed and what permissions it should have.
You need to know if diagnostic logging is enabled, what the retention policy is,
and who has access to the data. PowerShell can do any of those things, but it
does them as actions rather than declarations. If someone manually changes a
permission in the portal, PowerShell won't know it happened. If a key vault gets
deleted, PowerShell won't recreate it unless you explicitly run a command to do so.
There is no desired state that the system continuously enforces. PowerShell is a
tool for doing things. It is not a tool for defining what things should be. That
isn't a flaw. It's just what it is. And that's exactly why you need something else.
The real cost of scripts brawl. Let's look at a scenario that probably sounds
familiar. You've been building this automation platform for two years. It
works. It's solid. And you've accumulated a lot of infrastructure to keep it
running. You have 15 logic apps handling different workflows. Some trigger on
a schedule, some respond to webhooks and others orchestrate complex multi-step
processes. You have 10 automation accounts for different purposes, ranging from
schedule jobs to managed identities for Azure integrations. You have 30 scripts
spread across repositories, shared drives, and the automation accounts
themselves. Some are functions inside logic apps. Some are standalone modules.
Some are legacy scripts. You inherited that nobody wants to touch. Then you have
five key vaults for secrets, three storage accounts for logs, and multiple service
principles registered in enter ID. You're monitoring a scattered across different
log analytics workspaces, and your resources are deployed across multiple
subscriptions and resource groups. Now I'm going to ask you three questions. I
want you to sit with the answer for a moment. First, who deployed all of this?
When and why? You probably know the answer for the core pieces you built
yourself, but there are parts you won't remember. That logic app handling incident
is just a bit frustrating. Who set that up? Was it you two years ago or was it
someone who left the team? Are there undocumented dependencies where a script in
one account triggers a logic app that calls a function in another subscription?
You think so, but you aren't entirely sure. Second question. If we lose this
subscription tomorrow, can you rebuild this in three hours? I'm not asking if you
could rebuild it eventually. I'm asking if you could recreate the entire platform
from scratch with every dependency and configuration intact in a single
site. First, we have backups. We can restore full capability in a predictable
time frame. You probably can't do it. Most teams can't. You would need to
remember the exact order you deployed things and recreate the service
principles in the right way. You would have to provision the key vaults, populate
them with secrets, and remember which storage accounts are needed for which
purpose. You would need to redeploy all 15 logic apps and make sure they reference
the correct accounts and reestablish every identity permission. Could you do it?
But would it take three hours? Or would it take three weeks of reverse engineering
your own work? Third question. Are we compliant and are we secured? This one cuts
deeper because compliance and security aren't things you check once and forget
about. They are continuous. Your organization has standards. All automation
accounts should have diagnostic logging. All key vaults should have soft delete
turned on. All secrets should have expiration policies. Do your 15 logic apps and
10 automation accounts all meet these standards? You think some of them do, but
you aren't sure about the others. You would have to audit them manually. Check each
one and document what's broken. And then what? Next month someone adds a new
account and forgets to enable diagnostics and now you're out of compliance again.
This is where the real cost lives. It isn't in the effort of writing the scripts.
The scripts work. The real cost is the invisible governance problem.
You have infrastructure scattered across subscriptions with no single source of truth
that says this is what should exist. You have no way to enforce standards
automatically, no way to detect drift and no way to prove compliance. Every time
in order to ask questions, you scramble to document what you have. Every time security
reviews your work, you have to manually verify everything. Every time you
onboard a new person, you have to walk them through undocumented dependencies.
This isn't a problem with 50 scripts that work. This is a governance problem.
This is an architecture problem. This is the point where scripting stops being
enough. This is where infrastructure as code becomes non-negotiable. Enter infrastructure
as code, the declarative shift. Infrastructure as code isn't a new concept.
It's been around for years. Terraform has been doing this on AWS for a decade
but using it for Microsoft 365 automation is relatively recent.
This represents a fundamentally different way of thinking about what you're building.
Let me explain the shift with a contrast. When you write a power shell script
to deploy your automation platform, you're being imperative. You're giving orders.
You say connect to Azure, create a resource group, create a storage account in that resource group,
create a managed identity, wait for it to propagate, assign our back permissions to that identity,
create a key vault, configure soft delete on the key vault, add access policies, create a function app,
connect the function app to the storage account, enable monitoring, create a log analytics workspace,
configure diagnostic settings to send logs to the workspace. Each line is a step,
each step depends on the one before it. The order matters if you run step three before step two.
It fails. If step five times out, step six through 12 might fail silently and you own all of that complexity.
Now imagine a different model. You write a document that says,
I want a function app environment that includes a storage account, a managed identity with storage access,
a key vault with soft delete enabled and diagnostic logging to log analytics.
You don't say how to create these things or in what order, you don't say which
our back roles to assign or when to assign them, you don't say how to wait for identity propagation
or handle timing issues, you just say what should exist. That's the declarative model. That's bicep.
When you submit a bicep file to Azure, the system figures out the order and the dependencies.
It decides which steps can run in parallel and which have to wait. It even handles the timing for identity propagation.
It manages the complexity so you don't have to, but here's the problem with the old way.
It doesn't know the final state with bicep. If you run the same file twice,
the second time it only changes what's different. If someone deletes the key vault through the portal and you run bicep again,
it recreates the key vault because the declaration says it should exist.
The system becomes the source of truth, not your memory, not your scripts,
not your notes on what was deployed and when, the contract is simple. Bicep says, this is what should exist.
Azure makes sure it exists, always. This might sound like a small shift.
It's not. It changes everything about how you think about infrastructure. With PowerShell, you're writing a procedure.
Do this, then do this, then do this. If the procedure breaks halfway through,
you have a half-built environment and you have to troubleshoot. You have to figure out what ran and what didn't.
You have to decide whether to clean up and start over or try to fix it from the current state.
With bicep, you're writing a specification. This is what should exist. If a deployment fails, you fix the definition and deploy again.
The system will figure out what's already there and what needs to change. You're not managing a procedure.
You're maintaining a description of desired state. Think about the implications for your 50 scripts.
If you converted them to bicep, every piece of infrastructure would be declared in version control.
Every change would be tracked in Git. Every deployment would follow the same pattern.
Version control contains the truth and deployment brings reality into alignment with that truth.
You want to rebuild your automation platform in a different subscription? Run the same bicep against a new subscription.
It works. You want to prove compliance? Check the bicep file. It shows exactly what should exist,
what permissions should be granted, and what monitoring should be in place. This is the shift.
From how do I make this happen to? What should exist?
And it solves the governance problem that PowerShell alone can't solve.
Bicep isn't just a language, it's a mindset. Bicep is Azure's domain-specific language for defining infrastructure.
When you hear that, you might think it's just another tool, like PowerShell, but for deployments.
That misses the point entirely. Bicep is a language, yes. But more importantly,
it represents a fundamentally different way of thinking about the systems you build.
Here's what bicep does mechanically. You write files that describe resources, function apps, key vaults, storage accounts, networks, policies, anything that exists in Azure.
You declare what you want. Bicep compiles those files into ARM templates.
The format that Azure resource manager actually understands.
But the language you write in is simpler than ARM Jason. It reads like a conversation.
It reads like you're talking to someone telling them what infrastructure should exist. That simplicity matters.
But it's not the real shift. The real shift is the mindset that comes with it. The mindset is this.
Infrastructure is code. Not we're automating infrastructure deployment.
Not we're scripting resource creation. Infrastructure is code. That means it gets treated like code.
It lives in Git repositories. It gets reviewed in pull requests. It gets version controlled with commit messages that explain why something changed.
It gets branched. It gets tested before deployment. It gets reverted if something breaks.
Code review standards apply to infrastructure changes the same way they apply to application code. Code goes in version control.
Version control is the source of truth. This is the part that rewires how you operate.
In the scripting world, the portal is often the source of truth. You check the portal to see what's deployed.
You check the portal to see what permissions exist. You check the portal to see what's configured. Your scripts are tools that modify the portal state.
But the portal itself is the actual system. In the infrastructure as code world, Git is the source of truth.
Your bicep files describe what should exist. Git contains the history of changes.
If you want to know what permissions a keyboard should have, you read the bicep file. Not the portal.
If you want to know who changed something and when you check Git history, not Azure activity logs.
If you want to know why something was configured a particular way, you read the commit message in Git. This changes everything about accountability and reproducibility.
A bicep file is a contract. When you write a bicep file that says deploy a keyboard with these specific permissions,
Soft delete enabled and diagnostic logging to this log analytics workspace. That becomes the contract.
It says this is what should exist in Azure. Anyone who reads that file knows what the infrastructure should look like.
Any tool that reads that file can verify where the reality matches the contract. Any person who wants to change something knows exactly where to make the change.
In the bicep file, in Git, through a pull request with a commit message explaining why. This is radically different from PowerShell scripts.
Where the script is a procedure, but the system state is whatever happens when you run the procedure,
plus whatever manual changes people made afterward, the implication is profound.
You can recreate your entire automation platform from a Git repository.
Not from memory, not from documentation that might be outdated, not from reverse engineering, what's in the portal from Git.
You clone the repository, you run the bicep, everything gets deployed exactly as it was before.
Every permission, every configuration, every monitoring setting, that's not just a technical difference, it's a structural difference.
It means your infrastructure is reproducible, it means your infrastructure is auditable, it means your infrastructure is defensible.
It's the difference between operating a platform and managing a collection of resources.
The Microsoft Graph Breakthrough, Identity as Infrastructure. Here is the moment where everything changes.
In July of 2025, Microsoft Graph bicep support finally went generally available.
This isn't just a marketing announcement or a minor update, it is a structural shift in how we work.
Because of this change, Identity is no longer just something you script. Identity is now infrastructure.
And here is why that matters so much. For years, Identity Management lived in a completely different world from your infrastructure.
You used Azure bicep or Terraform to deploy resources like Function Apps and Storage Accounts.
But when you needed to create EntraID groups or register applications, you switched tools, you used PowerShell, you used the portal, you used Graph APIs in a custom script.
Identity was always an action, it was something you did, something you executed.
Now, it is something you declare. Inside a bicep file, you can now define your EntraID groups and your applications.
You can define your service principles and the relationships between them.
You can do all of this in the exact same file where you define your Function app and your key vault.
You write the code once, it lives in Git, it describes the state you want, then Azure makes sure that state actually exists.
Think about what this does to your automation platform.
Before this breakthrough, your Identity Management was a mess of disconnected pieces.
You had one PowerShell script to create an application registration and a second script to create the service principle.
You had a third script to assign Graph permissions, maybe you even had a manual step in the portal to click through conditional access policies.
All these pieces work together, but they weren't connected in any real way.
There was no single declaration that defined the identity structure for your platform.
Now, it works differently.
You write bicep code that tells the system to create an EntraID application and a service principle.
You tell it to grant specific Graph permissions and add that principle to security groups.
You configure every access setting in one single place.
It is versioned, it is reviewable, it is reproducible.
Let's look at a concrete example. Imagine you are setting up a new automation account that needs to manage users and groups.
Your account needs specific permissions like user.readwrite.all and group.readwrite.all.
In the old model, you would register the application and then navigate through the portal to consent to permissions.
You might miss one and have to go back, you would create a secret and then run another script to store it in a key vault.
With Graph bicep, you just declare it.
The bicep file states exactly what permissions the application needs and then Azure handles the rest of the work.
The application is created, the service principle is provisioned, the permissions are granted, the infrastructure reflects exactly what you wrote in your code.
But here is the deeper problem this solves. Identity is the control plane for everything.
In Microsoft 365, every single thing flows through identity. Access to SharePointsites is controlled by groups.
Teams channels rely on EntraID membership, licensing and delegates are tied to your identity.
Every governance control you have is at its core and identity control.
For years, we made these identity decisions through manual steps and scattered scripts.
They weren't governed like infrastructure, they weren't version controlled or auditable as a complete system.
You had scripts for groups and portal settings for permissions, but they were never connected.
There was no single source of truth for your identity model. Now there is. Identity is finally infrastructure.
You can write bicep that defines your entire model from licensing groups to automation accounts.
Everything is declared, everything is versioned, everything is auditable.
This is the bridge between basic power shell automation and true platform engineering.
Governance is no longer just about securing a server. It is about securing the identity structure and the infrastructure together as code.
When identity becomes infrastructure, your entire platform finally becomes governable.
The performance reality bicep versus power shell versus terraform. So far we have talked about structure and governance.
We have looked at how bicep gives you a source of truth that power shell cannot match.
But there is another part of this decision that matters just as much, speed.
And on the topic of speed, the data is very clear. Throughout 2024 and 2025, researchers tracked how these tools perform when provisioning Azure infrastructure.
The results were not subtle. Bicep is the fastest tool available and it consistently uses the fewest resources.
That isn't a marketing claim, it is measured performance across real world deployments. Here is why that happens.
When you submit a bicep file to Azure, the resource manager service handles all the orchestration.
It understands resource dependencies natively. It knows which parts can deploy at the same time and which parts have to wait.
It knows exactly how long to wait for identity to propagate. It was built for this.
So it works fast. When you use power shell for that same infrastructure, you are doing all that orchestration yourself.
You write the logic, you decide the order, you handle the weights and the retries.
That gives you a lot of control, but it also means you own every single failure point.
If your timing is off by one second, the script fails. If you forget to account for an asynchronous operation, things break silently.
You are managing complexity that Azure would have handled for you.
Terraform works differently than both of them. Terraform keeps an explicit state file to track what is happening.
That file is powerful because it helps with drift detection, but managing it adds a lot of operational overhead.
You have to secure it and share it across your team. For scenarios that only involve Azure, that extra work just isn't necessary.
The practical result is simple. Bicep wins on speed, power shell gives you control, but forces you to manage the mess.
Terraform offers sophisticated state management, but requires much more discipline to run. For most Microsoft 365 infrastructure, Bicep is the fastest and simplest path.
That doesn't mean the other tools are wrong. It just means if you want to deploy quickly and reliably, Bicep is the most direct way to get there.
There is also a second performance advantage that matters for your situation, as your releases new services and features constantly.
When Microsoft adds a new resource type, Bicep supports it on day one. This is because Bicep compiles into ARM templates, and those templates always support every Azure resource that exists.
There is no lag, there is no waiting for a provider update or dealing with a version mismatch. Power shell is different.
Power shell uses modules that have to be updated separately from the platform. When a new service launches, the PowerShell team has to update the modules.
It usually happens fast, but it is never immediate. There is always a delay. Terraform often has an even longer lag.
It relies on a provider maintained by the Terraform team rather than Microsoft. New Azure services can take weeks or even months to show up there.
If you need to use cutting edge features, Terraform can actually block your progress. This matters for Microsoft 365, because you are often working on the bleeding edge.
You are deploying new conditional access features and governance tools the moment they launch. Bicep lets you use them immediately. PowerShell usually can.
Terraform might make you wait. This is the practical argument for using Bicep in an organization centered on Microsoft 365.
It isn't just about the code or the source control, it is about speed. It is about supporting new features the second they are available.
It is about making sure your infrastructure can keep up with the platform. But speed only matters if the system is reliable.
That is where the governance layer comes back in. Bicep gives you both. It is fast enough to let you iterate. And it is structured enough to let you govern.
That is the combination that real platform engineering requires on the architecture that actually works Bicep plus PowerShell plus Graph.
You need to understand one thing before you choose a tool or structure your platform. Bicep, PowerShell and Graph are not competitors. They aren't alternatives.
They are layers of the same system when you stop seeing them as competing choices. And start seeing them as complementary parts. Everything becomes clearer.
Let's look at what each layer actually does. Layer one is Bicep. Bicep's job is to deploy the infrastructure, the scaffolding, the foundation.
When you write Bicep, you are declaring that a function app should exist, that a key vault should exist, and that a storage account should have specific settings.
You are defining the shape of the system. The container that everything else runs inside of. Bicep doesn't run your business logic. It doesn't call APIs. It doesn't process data.
Bicep simply says, here is the environment where those things will happen. It is the stage, not the actors. Layer two is PowerShell.
PowerShell's job is to orchestrate the operations. It runs inside the infrastructure that Bicep built. When Bicep deploys a function app, PowerShell runs inside it. When Bicep creates a managed identity, PowerShell uses that identity to authenticate.
When Bicep provisions a key vault, PowerShell pulls the secrets out. PowerShell handles the logic, the workflows, the decision trees.
It's the actor on the stage that Bicep built. Layer three is Graph Graph is the data layer. It provides the information, the users, the groups, the policies.
When PowerShell needs to know who is in a group, it asks Graph. When PowerShell needs to assign a license. It tells Graph to do it. Graph is the source of reality, the system of record for everything in Microsoft 365.
So how does this look in the real world? Imagine you're building a reporting platform for user activity. Bicep creates the infrastructure. It declares the function app and the storage account where logs will go. It sets up the managed identity so the app can talk to storage. It provisions the key vault for your credentials.
It even sets up the log analytics workspace for your monitoring. All of that is in Bicep. It's version controlled. It's reproducible.
PowerShell runs the actual logic. It lives inside that function app Bicep made. It uses the identity Bicep provisioned. It grabs the secrets Bicep stored. Then it executes the workflow.
Connecting to Graph to see who signed in yesterday. It checks for session details and access patterns. It decides if anything looks suspicious.
It writes the report to the storage account Bicep created. That is PowerShell's job. Graph provides the actual data. It tells PowerShell which users exist and when they last logged in. It provides the APIs that PowerShell calls to get the facts.
It's the authoritative source for the entire environment. This architecture works because each tool stays in its lane. Bicep doesn't try to be a scripting language.
PowerShell doesn't try to define infrastructure. Graph doesn't try to be an orchestration engine. Each one does one job. Does it well? And hands off to the next layer.
The result is a platform that is modular. You can change the PowerShell logic without touching Bicep. The infrastructure stays stable. You can update your infrastructure without rewriting your scripts. The logic stays intact. The platform is flexible because the layers are independent. This is the architecture that actually scales.
Governance is code. The real win. Governance isn't just policy. Most people think of governance as a rulebook. A document that says what's allowed. A checklist someone looks at once a quarter. That's the wrong mental model.
Real governance is a control plane. It's the set of guardrails that makes certain things impossible. And other things automatic. It's not about knowing the rules. It's about building a system where the rules enforce themselves. That's what Bicep actually enables when you declare infrastructure in Bicep. You aren't just saying what should exist.
You're embedding governance into the definition itself. Let's look at an example. Your security team says every automation account must have diagnostic logging enabled. This isn't a suggestion. It's a requirement.
Every account needs logs flowing to a central workspace for auditing in a world of manual scripts. You handle this with a policy document. You tell the team, you send an email, you hope people remember. Then you manually audit the environment every few months.
You find the accounts that don't have logs. You open a ticket. You wait for a fix. Compliance is a constant battle. You're always checking, correcting and reminding in the Bicep world. You embed the requirement into the code.
You create a Bicep module for automation accounts. That module automatically enables logging. It hard codes the destination workspace. There is no option to turn it off. There is no workaround. Every account deployed through that module is compliant by default.
Full stop. Compliance isn't something you check for. Compliance is something the infrastructure enforces. This changes your relationship with your infrastructure.
Governance stops being a set of rules people might follow. It becomes the structure of the system itself. It's not aspirational. It's mandatory.
Think about naming conventions. You want automation accounts to start with AA and key vaults to start with KV. In a script world, you rely on memory. People forget.
Resources break the pattern. You have to rename things or file tickets. In Bicep, you make the naming convention part of the logic. The module takes a purpose and an environment as parameters. It builds the name automatically.
There is no way to deploy a resource with the wrong name because the name is generated by the code. Naming conventions aren't rules to remember. They are architecture decisions that cannot be violated. The same applies to everything.
Tagging standards. Baking them into the module. Permissions. Define them once. Encryption. Network isolation. It all lives in the Bicep definition.
Governance shifts from checking to defining before you spend time discovering what was wrong. Now you define what is right and compliance is built in. The shift is profound. It's not about making more rules. It's about eliminating the possibility of breaking them. This is where Bicep becomes the foundation for platform engineering.
Because platform engineering is about making it easier to do the right thing than the wrong thing. It's about removing friction from the compliant path. Bicep is the tool that makes that possible.
The Entra ID governance layer. Identity governance is the foundation of Microsoft 365. Everything flows through it. When you control identity. You control the entire platform. You decide who exists. You decide what groups they join. You decide which permissions they hold.
And for the first time, Bicep lets you declare that identity model the same way you declare your infrastructure. Think about what identity governance actually looks like in your organization.
You need security groups for licensing tiers. You need different groups for different subscription levels. You need application registrations for every third party tool that connects to your tenant. In the old model, this was all manual. You would write a power shell script to create a group. You would write another script to register an application. You would write a third script to assign permissions. Each script was independent. They created your identity structure.
But there was no single contract. You had scripts and you had results, but you didn't have a source of truth. Now, Bicep lets you declare it. You write a template that defines the security group for your e5 licensing tier.
You define the application registration for your automation platform. You create the service principle and granted specific graph permissions for user management. It all lives in one place. It is version controlled. It is reviewable.
The benefit is that your identity model becomes repeatable. You can deploy it to multiple tenants and get the exact same result every time. You can audit the environment by reading code instead of clicking through the portal. If you need to change a permission, you submit a pull request. But here's the problem with how we used to work. Identity and infrastructure were separate concerns. Bicep handled the servers. While portal clicks handled the users, they happened in different workflows at different times by different people.
Identity decisions were never recorded the same way infrastructure decisions were. They didn't go through the same governance process. That's where things change. Now, identity is part of the infrastructure definition when someone wants to change a group or a permission. That change goes through a pull request. It gets reviewed, it gets tracked.
This matters because identity is where security actually lives. It's where you enforce compliance. It's where access control happens. When identity governance becomes code, your entire security posture becomes unified.
Infrastructure changes go through review. Identity changes go through the same review. The audit trails are automatic. This is where platform engineering actually starts. Not with the infrastructure, but with identity as infrastructure. Because if you control the identity layer, you control what the platform can and can't do. You control which applications exist. You control what service principles are allowed to touch. All declared, all reviewed, all auditable.
That is the foundation everything else builds on.
Reusability through modules, building your platform. This is where we move from theory into practice. We've talked about what bicep is. Now we need to talk about the part that actually scales your platform. Modules, a power shell script is singular. You write it for one purpose, for one problem in one environment. You can copy and paste it. But each instance is fundamentally separate. Each one carries its own hard coded values and its own quirks. Bicep modules work differently.
Module is a packaged piece of infrastructure. It's a template you can deploy once and use everywhere. You don't copy it. You use it. You deploy the same module to dev and production and you get identical results. You deploy it to five different workloads and you get five properly configured instances.
Look at a concrete example. You are deploying automation workloads. Each one needs a function app to run the code. Each one needs a storage account for logs. Each one needs a managed identity and a key vault for secrets. In most organizations, you've built these manually or with separate scripts. Each one is configured slightly differently depending on who is at the keyboard that day.
Imagine a single bicep module called standard automation workload. When you use it, you pass in a few parameters. The name, the environment, the monitoring workspace, the module handles everything else. It creates the function app with the right configuration. It sets up the storage account with the correct tags. It configures the managed identity and the key vault access policies. You deploy that module once and you have a production ready environment. You deploy it again for a different workload and you have another one. Same module, different parameters.
The power isn't in the module itself. It's in the consistency. Every workload build from this module has the same structure. It has the same security posture. It has the same naming convention when something breaks. You know how to fix it because you fixed it the same way before. When you need to update a setting, you change the module and redeploy it everywhere. This is where building platforms becomes possible.
You aren't reinventing the wheel for each deployment. You are assembling from proven building blocks. Maybe you spend two weeks designing the perfect architecture for your function apps. That knowledge doesn't disappear after the first project. It lives in the module. Every team that needs that pattern gets access to it. Every deployment benefits from the thought that went into the original design. Microsoft recognized this pattern and created Azure verified modules. These are modules that Microsoft has written and tested for you. They cover the common patterns.
Like a secure key vault or a hardened function app. When you use a verified module, you are getting architecture decisions made by specialists. You are getting code that has been validated across hundreds of organizations. You aren't starting from scratch. And this goes one level deeper. When you build modules for your own organization, you are building organizational knowledge. You are capturing decisions. You are making it. So the way your company does things isn't dependent on who is in the office. It's encoded in the modules. It's reproducible. It's teachable.
A new engineer can deploy your entire stack just by combining your proven modules. This is platform engineering, not starting from zero each time, but building from consistent reusable pieces. Each module does one thing well. Together, they compose into complete systems. Version control, the source of truth.
Version control is where the entire system becomes real. Not the portal, not your memory, not your documentation.
Git. When you put power shell scripts in Git, you are tracking code. That's good. But when you put bicep in Git, you are tracking the specification of your entire infrastructure. Everything that should exist, every permission that should be granted, every monitoring, configuration and security setting that should be enforced. That's foundational.
Because here is what changes. Your infrastructure becomes auditable at a granular level. In the old model, if someone modified a key vault permission, you had to go hunting. You'd click through the portal and check access control settings hoping to find a clue.
Now, you just look at Git history. You see exactly when it changed. You see who did it. You see the commit message explaining why you see the pull request where the change was reviewed and approved. The entire chain of custody is just there.
Before Git is truth, you had to ask questions. Who changed this? When did they do it? Why was this decision made? The portal doesn't answer those questions. As your activity logs might tell you that something changed, but they don't tell you the reasoning. They don't tell you if it was intentional or a mistake. They don't tell you who signed off on it. With bicep in Git, all of that is documented by default.
Every change goes through a pull request. Every change has a commit message. Every change is part of the permanent record. The reasoning is documented. The reviewer is documented and the approval is documented. This matters for compliance more than anything else.
Compliance auditors ask hard questions. They want to know what's deployed and who configured it. They want to see that configurations match your standards. They want proof that changes are reviewed before they ever touch production.
With scripts in the portal, you scramble to find answers. You dig through logs, you interview people to understand decisions made months ago. You hope someone remembers, you hope documentation was kept. It's chaotic.
With bicep in Git, you just hand over the repository. Here is everything that should exist. Here is when each piece was added. Here is who added it and why. Here is who reviewed it. It's all there. Compliance becomes documentation, not an investigation.
The reversibility is just as important. Mistakes happen. Someone commits a bicep change that accidentally disables monitoring on every automation account in the tenant. That's a dangerous decision.
With PowerShell scripts, you have to manually restore monitoring to each account or find the script that broke it and hope you can reverse it safely. It's manual, it's error-prone.
With bicep in Git, you revert the commit. Done. Git knows exactly what change, so it applies the opposite change. Monitoring gets reenabled on everything that shouldn't have been touched.
No manual steps, no uncertainty, no risk of only partially fixing the problem. This is why bicep in Git changes your operational model. It's not just about having code instead of portal clicks.
It's about having an immutable record of every infrastructure decision. It's an audit trail that's generated automatically. It's a way to understand your system's history without having to interview people or guess at their intent.
Your infrastructure stops being a mystery. It becomes a documented system. Everything that exists is there because it's declared in Git.
Everything that changed is there because it's tracked in commits. Everything that's been approved is there because it went through a pull request. The system doesn't hide, it doesn't have secrets. It's transparent by design.
And that transparency is what makes large-scale governance possible. The CICD pipeline, automation of automation, you have bicep files in Git. That's the foundation.
But Git alone doesn't deploy anything. Git doesn't validate. Git doesn't prevent mistakes. Git doesn't enforce standards. A pipeline does.
When you put power shell in a pipeline, the pipeline just runs scripts. It executes commands in order and deploys things. That's useful, but the pipeline itself doesn't understand what's being deployed.
It doesn't know if the configuration makes sense or if it violates your standards. It just runs the script. When you put bicep in a pipeline, the pipeline becomes a governance enforcement point. It doesn't just execute, it validates, it tests, it previews, it makes sure nothing bad reaches production. Here's how this actually works.
Write a bicep file that declares infrastructure changes. Maybe you're updating a key vault to add a new access policy or you're configuring a function app with a new environment variable.
You commit that bicep file to Git and immediately the pipeline kicks in. Step one is validation. The pipeline compiles your bicep to make sure the syntax is correct. It checks that all the resources you're referencing actually exist and verifies that your parameter values are valid. It lends the code against your organization standards.
If any of this fails, the pipeline stops. The deployment doesn't move forward. The pull request is blocked. You have to fix the bicep and commit again. Step two is testing. Depending on how sophisticated you want to be, you might run the bicep against a test subscription. You actually deploy it to see if everything works. You check that resources are created correctly, permissions are granted and monitoring is configured properly.
If tests fail, the pipeline stops again. The problem has to be fixed before you can proceed. Step three is the preview. This is where bicep shines in a way PowerShell can't match. When you deploy bicep, you can run what if mode first. This shows you exactly what will change before anything actually happens.
You see what resources will be created, modified or deleted. The pipeline runs this automatically and shows the preview to the reviewers, so they understand the impact before they hit approve.
Step four is approval. A human has to approve the deployment. This is an optional, a person or a group of people has to review the bicep changes and the what if output. They have to understand what's being changed and why. Only then does the deployment proceed.
Before you might have deployed infrastructure manually on your own schedule. Now the system enforces that every single change goes through review every time.
Step five is the actual deployment. After approval, the pipeline deploys the bicep to the environment. It uses the exact same bicep that was reviewed and approved.
No surprises, no manual changes, no one deploying a different version than what was reviewed. The pipeline handles the deployment consistently.
But here's what's powerful about this workflow. Your infrastructure can never drift without you knowing about it. Supposed someone manually deletes a key vault through the Azure portal. That's bad. That's configuration drift.
In a manual environment, you might not notice for weeks and by then you've lost your audit trail.
In a pipeline-based bicep environment, the next time anyone commits a change, the pipeline runs the what if. The what if shows that the key vault will be recreated. It's immediately visible. It's immediately obvious that something changed. The reviewer sees it. They ask what happened and the problem gets fixed.
More than that, you can run the pipeline on a schedule. Every night at midnight, the pipeline runs the bicep against your environment in what if mode. If anything is different or if any drift has occurred, the pipeline creates a report.
It shows you exactly what drifted so you can fix it immediately. Your infrastructure never gets out of sync with your declarations. This is self-healing infrastructure.
Not because it fixes itself automatically, but because every change is visible, every drift is detected, every problem surfaces immediately and gets corrected before it becomes a serious issue.
This is where your platform stops being a collection of manual decisions and becomes an automated system. The migration path. From scripts to infrastructure.
Everyone asks the same question when they stand at this threshold. They want to know if they have to throw away everything they've built with PowerShell. The answer is no, not even close.
Moving from scripts to infrastructure isn't about replacement. It's about elevation. You keep your PowerShell, you keep your investment in automation and you keep the logic that actually works.
What you're doing is adding an infrastructure layer on top to make everything governable, reproducible and scalable. The model is simple. You've been building on a foundation of loose sand, it held the house up and the house worked fine. But now you're pouring concrete underneath it.
You aren't demolishing the building. You're just strengthening the base so the structure can last. So you can add more rooms and so the whole thing stays stable for whatever you build next. The migration follows a clear sequence. It isn't complicated, but the order matters.
Start with step one. Identify what actually exists. This is the audit phase. You need to look at your Azure subscriptions and see which automation accounts are deployed, which function apps are running and where your storage accounts and key vaults are hiding.
List them out. Understand their purpose. You have to document which script or process created each piece of infrastructure before you can move forward. It takes time, but it's necessary because you can't declare infrastructure in bicep if you don't know what's already there.
While you're doing this audit, you'll probably find something unsettling. You'll find infrastructure that nobody remembers creating. Maybe it's a storage account from three years ago that nobody uses or a logic app that was deployed for a test and never removed.
You might even find duplicate function apps because someone thought the original was gone when it wasn't. This is just the reality of the scripting phase. Things get created, some get used and some get forgotten. The audit brings it all into the light.
Once you know what exists, move to step two. Write bicep for the foundation. Start with the core infrastructure that everything else depends on. This means the key vault where secrets live, the function app that runs your primary automation and the storage account for your logs.
Don't try to move everything to bicep immediately. Focus on the foundation pieces that form the base of your platform. Write clean bicep for those, test them and make sure they deploy correctly. This becomes your core infrastructure definition.
Step three is the big one. Don't try to move your operational logic to bicep. Keep power shell for what power shell is good at. Use it for graph API calls. Use a provisioning logic, reporting workflows and conditional business logic. Power shell stays. It runs inside the infrastructure that bicep deployed. It uses the managed identity that bicep provisioned and it pulls secrets from the key vault that bicep created.
The logic itself stays in power shell because that's where it belongs. Step four is validation. Deploy your bicep to a test subscription and let it build the environment from scratch. Then run your power shell against it. The script should run inside the function app, retrieve it secrets and write it's logs just like before.
Does everything work? Does power shell behave the same way it did when you built the infrastructure manually? It should. The infrastructure changed, but the operational logic shouldn't care as long as the resources exist. Once you've validated that the combination works, you can migrate at your own pace.
Some teams do everything at once, but most do it gradually. They move their core automation infrastructure to bicep while keeping the operational scripts running. Over time they build out bicep modules for different patterns and standardize the new approach. Eventually they retire the old deployment scripts because they simply aren't needed anymore.
But here's the problem people anticipate. They think they're losing flexibility. In reality, you're surrounding power shell with governance. You're defining the infrastructure layer that power shell runs on top of.
You're making your entire platform reproducible and auditable while keeping the operational freedom that power shell provides. That's the shift, not replacement.
Addition, real-world blueprint, the graph automation platform. Let's stop being abstract. Let's build something you probably need right now.
Imagine you're in charge of automating user provisioning, license assignments and audit reporting for a Microsoft 365 environment. It's a real workload that needs to run reliably and scale.
It has to be auditable and it needs to work exactly the same way in dev as it does in production. Here is what that platform actually requires. You need a function app to execute the logic on a schedule and a storage account to log activity.
You need a managed identity so the app can talk to graph without storing passwords and a key vault to hold your connection strings. Then you need a log analytics workspace and application insights for monitoring.
All these pieces have to exist. They have to be configured correctly and they have to work together. Now let's look at how you build this two different ways.
In the PowerShell approach, you write a script to create the function app and run it manually. Then you write another script for the storage account, another for the resource group and you configure the managed identity separately.
You create the key vault, manually set up access policies and then move on to the logging tools.
You run these scripts in order, hoping you remember the right sequence. Some run fine, others fail. And you spend your afternoon debugging parameters and re-running code.
Eventually everything exists, you document what you did and hope nobody asks you to do it again. Then you want to deploy the same platform to production, you copy all your scripts, modify the names and change the parameters.
You hope you didn't miss anything, but some configurations might be different because you made a different choice this time.
Months later, you need a third environment. You copy the scripts again, modify them again and now you have three slightly different versions of the same platform.
Each deployment was a manual process and each one has small variations. This is the reality of script-based infrastructure. It works and it gets the job done, but it doesn't scale. It doesn't stay consistent or documented.
Each deployment is just a one-off manual event. Now look at the bicep approach. You write one bicep file that declares exactly what should exist.
The function app, the storage account, the managed identity and the key vault are all defined in one place. You connect them through logical references, validate the file and commit it to Git.
You deploy it to Dev, three minutes later everything exists and is configured correctly. Now you want production, you don't copy the bicep, you deploy the exact same file using different parameters.
The Dev environment might use a Dev suffix while production uses prod and the resource sizes might be different, but the structure is identical. Same bicep, different parameters, three minutes later your production environment is ready.
You need a third environment for testing, same bicep, test parameters, three minutes done.
Now imagine six months from now when something needs to change. Maybe the function app needs a new environment variable or the logs need a longer retention period.
You update the bicep once, validate it and commit the change to Git with a clear note explaining why. The pull request gets reviewed and then you deploy it to all three environments automatically.
The change is consistent, it's traceable and it's reversible if things go wrong.
What would have been three separate manual chores now happens in a unified way, the impact compounds. What took weeks to deploy manually now takes minutes with bicep.
What was fragile and inconsistent becomes stable and repeatable. What was undocumented is now version controlled and auditable.
The platform scales from one environment to five without the operational burden multiplying. That's the real difference. It isn't just about speed, it's about consistency, governance and repeatability.
This is what the platform engineering layer actually enables.
The governance baseline, what bicep actually enforces. Governance stops being a theory the moment you bake it into your infrastructure.
Most people talk about governance like it's a control plane, a way to make rules that are impossible to break, but we need to look at what that actually looks like when you're working.
There is a massive gap between having a naming convention written in a PDF and having a naming convention enforced by the system itself.
Bicep handles four main areas of governance for M365 automation.
Naming, tagging, diagnostics are back. These are the four pillars where governance finally becomes real.
What about naming first? Your company probably has a rule for this already. Maybe your automation accounts have to start with a specific prefix followed by the environment name.
You have these rules in an email or a document somewhere and you've probably spent hours renaming resources because someone forgot to follow them.
That is the old model. It relies on everyone remembering the rules every single time in bicep.
The naming convention is just part of the module logic. When someone deploys an automation account using your standard module, they just provide the purpose and the environment as simple inputs.
It also takes those strings, combines them with the right prefix and creates the name automatically.
The person doing the work doesn't even make a decision about the name. Compliance isn't a choice they make. It's just what happens. Tagging works the same way.
Every resource needs a business unit, a cost center, and an owner for billing and compliance reasons.
In a manual world, you just hope people remember to add them. Usually they don't, then you have to run audits, find the missing tags, and create tickets to fix them.
It's a constant uphill battle with bicep. Tagging is baked into the foundation. Every module applies the required organizational tags to every resource it touches. The user provides the cost center as a parameter.
And the module handles the rest. There are no exceptions and no forgotten tags. Every resource is born compliant from day one.
Then you have diagnostic settings. Your organization likely requires logs for auditing and security. You could write a policy to check for this.
But policies are reactive. They tell you that you broke the rule after the resource is already live. With bicep, the diagnostic settings are inside the template.
Your module for function apps configures logging by default. So there is no way to skip it. Every app you deploy starts sending logs to your workspace immediately.
The same logic applies to RBIAC. Access control is the most sensitive part of the stack. Your automation accounts need specific permissions based on the principle of least privilege.
Instead of hoping your team understands the nuances of graph permissions, your bicep module manages it, the module creates the identity, assigns the roles, and grants the permissions.
The person deploying the code doesn't need to be an RBIAC expert because the permissions are correct by design. This changes everything for your operations. Imagine an auditor asks for a report on your infrastructure.
They want to know what's out there, who has access, and if it's being logged in the old world of scripting, you'd be scrambling. You'd be clicking through the portal and filling out spreadsheets, hoping you didn't miss a single resource.
With bicep, you just show them the repository. You point to your standard module and explain that every automation account comes from this single source.
This is your governance baseline. Every instance has the same naming, the same tags, and the same logging. Nothing deviates because the module won't allow it to.
This is a profound shift in how you work. Compliance moves from something you should do to something the system forces you to do.
You move away from hope and towards certainty. You stop auditing for mistakes and start preventing them from ever happening.
Your audit results don't get better because you got better at remembering rules. They get better because the rules are now a physical part of the system. Compliance becomes a feature of your infrastructure, not a chore you have to manage.
The career ceiling. Why platform engineers earn more? We need to talk about money because the market is sending a very clear signal about where the value is.
Platform engineers are consistently earning 20% to 40% more than traditional DevOps engineers. This isn't a fluke or a one-time trend. It's happening across every industry and every country.
The market is telling us that organizations will pay a premium for people who build systems instead of just finishing tasks.
The reason for this comes down to impact. A DevOps engineer focuses on automation. They might write a script to set up a server.
Which saves time and prevents a few manual errors. That is definitely valuable. But the value is limited. That script does one specific thing for one specific process.
A platform engineer builds the engine. They design a system that allows 50 different teams to set up their own servers consistently. They create the standards that scale across the entire company.
The value isn't found in a single script. It's found in the infrastructure that makes every other script better.
The impact isn't just one team moving faster. It's the entire organization shifting to a new level of reliability. That is why the pay gap is so large.
It isn't that platform engineers are smarter. It's that their work is a force multiplier. When a platform engineer fixes a pipeline, everyone gets faster.
When they automate governance, every future deployment is automatically cleaner. There work scales in a way that a single script never can.
The math is pretty easy to follow. If you improve one script, you might save 10 hours a week for one small team. But if you build a platform that changes how 50 teams work, you are saving thousands of hours every single year.
The economic value of that work is on a completely different scale. Companies know this. And they've structured their pay scales to reflect it.
Senior roles in cloud engineering are going to the people who think in platforms. At the biggest tech companies, senior platform roles pay between 300,000 and $575,000.
At the staff and principal levels, those numbers can climb to 900,000 or more. These aren't lottery salaries. They are the standard rates for people who solve systemic problems. This is where bicep comes in for your career.
Bicep is the language of this transition. When you move away from PowerShell and start using bicep, you are shifting from, "How do I do this to? What should exist?"
You aren't just learning a new way to type. You are building the mental model that commands those higher salaries.
Bicep acts as a credential for systems thinking it tells the market that you understand infrastructure as code. And that you value version control as the source of truth.
It shows you know how to build reusable modules and declarative governance. When you master bicep, you have mastered the exact discipline that companies are desperate to pay for.
This isn't just about being cynical, it's about being practical.
The market pays for leverage. A PowerShell script only has as much leverage as the person running it. A bicep module has leverage across the entire enterprise.
The return on investment for a platform engineer is simply higher for the business. Tasks that used to take weeks of manual effort now take minutes because of bicep.
Fragile processes that used to break are now stable and repeatable. Specialized knowledge that lived in one person's head is now documented in the code itself.
These aren't just nice improvements. They are competitive advantages for the company. Moving from PowerShell to bicep is a career defining move.
It's the difference between being useful to one team and being essential to the whole organization. It's the shift from focusing on tasks to focusing on systems.
The market rewards that shift with better pay, better opportunities and a much better long term trajectory. That isn't a coincidence.
It's just the market recognizing where the real value lives.
The skill gap. Why bicep expertise is rare. Most IT professionals know PowerShell. It is everywhere. You learned it because you had to and you probably started because you needed to automate a specific task.
You looked up the syntax, you wrote the script and you solved the problem. That is the dominant path for most people in this industry and it is exactly why PowerShell is the default language for almost everyone.
Bicep expertise is different. It is rare. The reason isn't that bicep is harder to learn in a technical sense because in reality it isn't.
The syntax is cleaner than PowerShell. The language is simpler and you can pick up the basics over a single weekend.
The problem isn't learning the language. The problem is learning the thinking. PowerShell is a tool for finishing tasks. You approach it with a specific problem in mind, like creating a user or assigning a license.
You write a script to generate a report and then you move on to the next thing.
The learning path is problem-driven meaning you encounter a hurdle, you clear it and you continue. That approach works for most people which is why the barrier to entry stays low.
The entry point is always a real immediate need. Bicep requires a different mental model. It isn't about solving today's problem but rather about defining how a system should exist.
That is abstract, that is architecture. Most people don't approach technology from that angle because they are trained to focus on the task at hand.
They aren't taught to think declaratively and they aren't exposed to infrastructure thinking early in their careers. They learn to fix problems, not to define systems.
Transitioning from task thinking to systems thinking is difficult. It isn't a skill you pick up just because you have a bicep file to edit this afternoon. It is a model you have to adopt and it requires asking entirely different questions.
Instead of asking how to provision a resource you ask what should exist in the first place. Instead of worrying about the sequence of operations you focus on the desired state.
These aren't small shifts and they require rewiring how you approach every problem you face. This creates a massive supply problem.
Organizations need platform engineers who think systemically about infrastructure and can build the abstractions that other teams depend on.
But the supply of those people is limited because very few have made the jump from task automation to systems design.
Most power shell experts stay in that task oriented mindset and while they are valuable they don't make the leap to the bicep mindset. The gap is only getting wider.
More organizations are adopting infrastructure as code and more teams are hunting for platform engineers. The demand is accelerating but the supply of qualified people isn't keeping pace.
That is the classic economic signal for a skill shortage. When demand exceeds supply prices rise and organizations are now paying huge premiums for real bicep expertise.
If you make the transition now you aren't competing with everyone else who knows power shell. You are competing with a small percentage of people who have learned to think in systems.
You are entering a market where demand exceeds supply and that is exactly the position you want to be in. But here is the reality check. This isn't a quick skill to acquire.
You can't cram bicep syntax over a weekend and call yourself an expert because knowing the language doesn't give you platform engineering expertise. The value is in the thinking.
It is an understanding how to design abstractions, how to handle governance at scale and how to build modules that work across different contexts.
That takes time. It takes practice. It takes exposure to systems that are well designed and systems that are absolute disasters. It takes failure and the depths that comes from building real platforms instead of toy projects.
The opportunity exists because most people simply won't invest that time. Most power shell experts will stay focused on their tasks and most people learning bicep will learn the syntax without ever touching the systems thinking.
If you make the shift really make it you are ahead of the vast majority. You are joining a small group and the market is more than happy to pay for membership in that group.
The AI angle, why bicep becomes more important? AI is going to write code. It isn't a maybe anymore. Large language models are already generating functional power shell and bicep and that capability is improving every single week.
Within a year or maybe just a few months, AI will generate infrastructure code reliably on its scale. A lot of people think that is bad news for engineers. If AI can write the code, they wonder why we even need humans.
It is a natural reaction to have but it misses what is actually happening. AI can generate code but it cannot decide where that code should run or what it should actually do. It doesn't know if the code aligns with your organization standards and it doesn't know what to do when the integration breaks. Those are code problems. Those are architecture problems, those are governance problems and those are the things that sit above the code.
Bicep is exactly that layer. It doesn't describe how to do something but rather what should exist. It describes the constraints, the standards and the desired outcomes.
Bicep is the specification that tells the AI where to operate and how to operate safely within your boundaries. Think about the practical reality you will face in the next few years.
Right now if you tell an AI to write power shell that provisions users, it will write functional code. But where does that code run? Does it have access to the key vault? Are the permissions configured correctly? Is there a managed identity in place? These are all infrastructure questions that power shell doesn't answer. Power shell assumes the infrastructure already exists and if it doesn't, the script just fails.
Now imagine the AI works against the bicep declaration. You tell the system what should exist including the function app, the key vault and the managed identity. When you ask the AI to write the power shell that runs inside that defined infrastructure, it suddenly has guardrails. It has a specification to work against.
The code it generates is constrained by what you have declared in bicep. The shift is massive. It moves AI from a tool that generates code in isolation to a tool that generates code within your specific architecture.
That is a completely different proposition and it is how you keep AI safe at scale. You don't stay safe by avoiding the tools but by defining the boundaries they operate within. This also changes what makes you irreplaceable.
You aren't valuable because you can write power shell faster than a machine because you can't. The AI wins that race every time. You are irreplaceable because you understand systems.
You can look at a business requirement and translate it into infrastructure declarations. You can define what should exist, how it integrates and how it is governed. That is bicep thinking, that is architecture, that is what machines can help with but cannot replace. The future workflow is clear.
You decide what infrastructure should exist and you declare it in bicep. You commit that to Git and then describe the operational logic to an AI.
The AI generates the power shell that runs on top of that infrastructure and you review it. You test it against the bicep defined environment, you approve it and you deploy it. The system works because the infrastructure was defined first and the boundaries were clear.
This is why understanding bicep becomes more important in an AI world, not less. Bicep is how you maintain control. It is how you define what is possible and how you keep the system aligned with your standards even when parts of it are generated by machines.
Organizations that understand this will move fast. Organizations that don't will end up with infrastructure they don't understand running on environments that weren't planned for it. That is chaos. And it is the exact opposite of what platform engineering is supposed to achieve.
The barrier to being irreplaceable isn't code anymore. It is architecture. It is the ability to think systemically about infrastructure. It is bicep.
Not because the language is hard to learn but because it represents the level of thinking that cannot be automated away. At least not for a very long time. The honest limitations, what bicep doesn't do. I need to be direct about what bicep isn't.
There is a risk in everything we've discussed so far. You might finish this episode thinking bicep is a universal solution. That if you just move everything over, your infrastructure problems will dissolve. That isn't how it works. Bicep is powerful but it has real boundaries. The first boundary is scope.
Bicep is Azure only. It deploys Azure resources and that's the end of the list. If your organization runs anything on AWS or on premises hardware, bicep won't touch it.
If you need a unified tool that spans every cloud, bicep isn't the answer. Terraform is. Terraform understands AWS and GCP and Kubernetes along with dozens of other platforms. Bicep understands Azure and nothing else. That isn't a flaw. It's by design.
Microsoft built bicep specifically to be optimized for Azure but it does mean you can't use it as a universal language if you operate across multiple clouds. The second boundary matters even more for m365 focused organizations.
Bicep doesn't manage Microsoft 365 workload configuration. At least not directly. You can't use bicep to configure exchange online mailbox rules.
You can't define teams policies or manage sharepoint site settings through a bicep file. Bicep deploys the infrastructure that supports those things. It handles the function app, the logging pipeline and the authentication layer.
But the actual m365 workload configuration still requires power shell or graph or the admin portal. Understanding this prevents a specific category of mistakes.
Someone new to infrastructure as code might wonder why they can't manage everything with one tool. The answer is that m365 isn't exposed through the Azure resource manager.
Exchange online teams and sharepoint are SaaS services with their own APIs and control planes. They aren't arm resources. Bicep only touches what arm exposes so everything else requires different tools.
The practical implication is that bicep becomes one layer of your platform. Not the only layer, your platform consists of bicep handling infrastructure while power shell handles operations and graph APIs provide the data. These tools are complimentary. They don't overlap.
Accepting that boundary is part of professional systems thinking. There's a third limitation worth naming. Bicep doesn't replace existing m365 admin tools like the exchange or team's admin centers. Those tools exist for a reason.
Suppose the full feature set of the services, which bicep doesn't do, bicep gives you the infrastructure substrate while the admin tools give you the service configuration. Both are necessary and neither replaces the other.
The final limitation is less technical and more about your organization. Bicep requires a different operational model. It requires Git discipline, pull request reviews and pipeline validation.
If your organization isn't ready for that, if people are used to making direct portal changes and documenting them later, bicep adoption will be harder. It's not impossible, but it's a shift. You aren't just adopting a new tool. You're changing how decisions get made and recorded.
Understanding these boundaries is a sign of mature thinking. It means you aren't treating bicep as a silver bullet. You're thinking about architecture as layers and components, each with its own purpose. That's platform engineering thinking. Knowing what a tool can't do is just as important as knowing what it can.
The bicep versus terraform decision and why it matters. At this point, someone always asks the obvious question, bicep sounds great. But what about terraform? Isn't terraform the industry standard? Should I just learn that instead? The answer requires some nuance. Both tools are legitimate and both solve real infrastructure problems. But they solve different problems.
Understanding the difference is how you make the right choice for your specific situation. Terraform is multi-cloud. That is its defining characteristic. You write terraform and it can manage resources on AWS. Or you use the same structure to manage GCP. You use the same language and the same thinking across every cloud. For organizations that operate across multiple providers, terraform is the natural choice.
It keeps your code consistent even as the underlying platforms change. That is valuable. If you're running workloads on AWS and Azure and GCP, terraform makes sense. Bicep is Azure native. It's designed for one cloud and optimized for one cloud. It compiles directly to ARM, which means it gets new features the same day as you releases them.
It integrates with the Azure CLI and the portal in ways terraform simply can't. For organizations that are entirely in Azure, that native integration is a massive advantage. You aren't paying the cost of a multi-cloud abstraction when you don't actually need it.
Now, let's look at how this works for M365 specifically. Most Microsoft 365 organizations are Azure only or heavily Azure primary. Your identity lives in Entra ID, your authentication runs through Azure AD and your automation runs on Azure functions. Microsoft 365 is tightly bound to Azure.
When you're building infrastructure to support M365, you're almost always building in Azure. If that describes your situation. If you aren't managing AWS workloads or spanning multiple clouds, terraform introduces complexity you don't need. It adds abstraction and conceptual overhead. You gain a multi-cloud capability that you'll never actually use. Bicep by contrast is purpose-built for exactly what you're doing.
The research on adoption supports this. Bicep is growing fastest in Azure only organizations. Companies that committed to Azure as their primary cloud are increasingly choosing bicep because it fits.
It's simpler, it's faster and it requires less operational overhead. The cognitive load is lower because you aren't thinking in multi-cloud abstractions. That said, there are scenarios where terraform wins for M365 shops.
If your organization runs parts of its infrastructure on AWS or if you have on-premises components that need to be managed as code, terraform becomes the right choice. You trade Azure native simplicity for multi-cloud consistency. That is a reasonable trade but it depends on your situation.
Here is the framework that should guide your decision. Ask yourself three questions. First, do you operate across multiple clouds today? Not hypothetically, but actually right now. If the answer is no, bicep is more efficient. Second, is there any realistic possibility you'll operate across multiple clouds in the next few months?
This is harder to answer but it matters for your learning investment. If your organization has committed to Azure as its strategic platform, the probability is low. If you're deliberately pursuing a multi-cloud strategy, the probability is high.
Third, do you already have terraform expertise in your organization? If you have teams that already know HCL and understand terraform workflows, extending that to Azure might be simpler than introducing a new tool.
Consistency across your tools might outweigh the advantages of biceps integration. For most M365 shops, the answer to those first two questions points toward bicep. You operate in Azure, you're planning to stay in Azure and Azure is your platform. Bicep was built for you. The practical truth is this. Don't choose your tool because it's trendy or because other people use it. Choose it based on your actual cloud strategy. If your Azure only building bicep expertise is more efficient than learning terraform.
You'll move faster, you'll have fewer abstractions to manage and you'll integrate more cleanly with your existing tooling. I'm not saying terraform is wrong, I'm saying you should choose based on your reality, not on assumptions about what you should be using.
The transition starts now. Your first steps. You're standing at the threshold. You understand why bicep matters. You've seen the architecture, you know the career implications. But now the question is, what do you actually do Monday morning when you sit down at your desk?
The answer is simpler than you think, don't try to migrate everything at once. Don't try to redesign your entire automation platform overnight. Start small, build momentum, learn by doing.
Step one is changing how you approach a problem. Right now when you see a task, you ask, how do I do this? You write a script that performs the action. That's task thinking.
What you need to practice is state thinking. Instead of asking, how do I create this resource? You ask, what should exist when I'm done?
It's a subtle shift, but it's fundamental. It rewires your brain and once you start thinking this way, bicep becomes the natural tool to express it.
Step two is writing your first bicep file. Don't start with something ambitious, start dead simple. Deploy a key vault. That's it.
Right maybe 15 lines of bicep. Create a resource group, create a key vault with a couple of basic settings.
Deploy it, see it work. You'll learn more from deploying one simple resource than from reading 10 tutorials. The goal isn't to build production infrastructure yet.
The goal is to feel how bicep works. You need to see the compilation process. You need to watch the deployment happen.
You have to understand the connection between your code and what actually appears in Azure. Step three is putting that file in Git.
Not for deployment purposes yet, just to experience version control as the source of truth. Write a clear commit message. Explain what you deployed and why.
Create a branch. Make a small change to the bicep. Commit it. Look at the history. Revert the change. Pull it back.
This is where the real power starts to sink in. Your infrastructure changes are now documented. They're traceable. They're reversible. You're not just learning bicep syntax. You're experiencing why version control is the foundation of everything we do.
Step four is combining this with PowerShell. Don't replace your scripts yet. Just wire them together. The bicep defines the stage. The PowerShell performs on it. Deploy a function app and a storage account through bicep.
Then write PowerShell that reads from that storage and logs to the function. You'll start to feel how the layers work together.
Bicep handles the what? PowerShell handles the how? Step five is building your first module. Take your key vault bicep and make it reusable. Add parameters for the name, the location and the skew. Wrap it as a module. Deploy that module twice with different parameters. Create two different key vaults using the exact same code. This is where the exponential power of infrastructure as code clicks. You don't write infrastructure twice. You write it once and use it a thousand times. Different parameters. Same structure.
This is how platform scale. None of these steps requires a massive time investment. You can do this in a couple of hours spread across a week. The point is you're learning through action, not passive study. You're building on each step. By the end of a week of genuine practice, you'll understand bicep at a level that no course can teach you. But here's the thing about the timeline. This isn't a sprint.
Learning bicep and integrating it into your workflow takes months, not days. You're not trying to become an expert in a week. You're starting a transition that compounds over time. Every infrastructure problem you face becomes an opportunity to practice state thinking. Every script you write, you ask if bicep would be better. Every module you build makes the next one easier. This is a career shift. It's not just a skill update. That's why it takes time. It's not harder than powerShell. It's just different. It requires your brain to work in a different mode that rewiring takes practice and repetition.
But once it happens, once you internalize the declarative approach, you can't unsee it. You won't want to go back to pure scripting because you'll finally understand why platforms matter. You'll see why governance scales through infrastructure. And you'll understand why the organizations paying the highest salaries are the ones thinking this way.
The powerShell ceiling isn't a failure. It's a signal. It means you've outgrown task automation. You're ready for platform engineering. Bicep is the language of that next level.
Combined with powerShell and graph, it's the architecture that scales. The market recognizes this. Organizations are paying for it. Your next move is simple. Stop writing scripts. Start defining infrastructure.
If this changed how you think. Follow me, Mirico Peters, on LinkedIn, tell me what you're building with bicep. I read every message. And if you want more of this, subscribe to the M365FM podcast.
We talk about platform strategy, architecture and the future of Microsoft 365. Leave a review. It helps more architects find this. Share this with your team. Especially if you're dealing with this right now.