I feel your pain. I've run into this many, many times. Unfortunately there's no great, native PowerShell solution that solves all of it. A few possible options:
Write Tests
Simply: use Pester, write tests. This doesn't help you reduce the amount of copy/pasting you have to do, or re-typing the same parameter blocks, but what it does do is ensure that if you do change a parameter in one place, and forget to change it somewhere else, or make an incompatible change, the tests will fail.
Of course that means you have to write tests in a way that will catch those problems, but you should be anyway.
I still don't write tests nearly as often as I should, but I think this option provides the best overall outcome, though it has a high-ish barrier to entry.
Use Strongly-Typed Custom Classes for Params
At some point, you might realize that a group of parameters needs to be passed all over the place, and really, those parameters are all describing different aspects (properties) of a certain unit or concept (a class).
You'll recognize that this is the case when you start realizing that the parameters depend on each other (more than you describe on a parameter set), so you might start writing validation for it and realize that it's getting very complicated.
The solution here is that these parameters should be properties of a class, so that the class takes care of validating the values of and relationships between the properties.
This will become especially apparent and important when you realize that you have more than one of these "groups" in your parameters, and you need multiple objects. Writing parameter sets and validation becomes exponentially more complicated with any more than 1 of these, and breaking them out into classes will alleviate that in a huge way.
Drawbacks
Writing classes in PowerShell kind of sucks. Additionally, there's no good way to export a class that's defined in the PowerShell module, which means your functions are aware of it, but the consumer of the module is not.
That in turn, means that you cannot use the class as a parameter of a public function. There are janky ways to export it, so you could do that, but...
Alternatively
Write the classes in C#. You don't need to do anything special with an assembly (.dll) to use it in PowerShell, as long as the class is public. Import-Module
just works.
But of course, that's an entirely different development pipeline, build process, distribution, etc.
Templating / Code-gen
You touched on it, but.. seriously, don't do it.