-
Notifications
You must be signed in to change notification settings - Fork 7.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Best practice: import functions in a module #18740
Comments
It's a common approach, but I wouldn't call it the best approach for writing modules because it makes the module import times slower. It's better to have a build script that takes all of your separate script files and merge them into one big psm1 file.
|
I load (source) all of functions from $profile: . /path/to/functions.ps1 |
@MartinGC94, nice module but just trying to understand what it exactly does as it might indeed improve the performance by merging all the files but doesn't resolve the "freeform input"/scope issue that trying to hilight here. In fact, I see the same questionable approach of blindly including files in the shared module scope in: But let me ask: what would happen if I put |
Please explain how this approach will be safer as from my view, using the profile might even bring over a larger bad practice/(unintended) injection issue, see: |
I haven't actually used it, I just stick to my normal build scripts but I've read the ReadMe and can see it does the same as my scripts so it's just a question of how they are doing it. If they are using the parser to extract the function definitions then it shouldn't include other unrelated statements like For strict mode specifically, it is set in the scope so if you want to set it in one function and not the whole module you can simply set it inside the function like this:
|
@MartinGC94, I understand that. |
$Value = Get-Content -Raw $Function
New-Item -Path function: -Name $Name -Value $Value -Force FYI this would disable breakpoints from working correctly. I ask that you don't propagate things like this primarily because folks end up copying it blindly and then they think VSCode is broken when debugging doesn't work anymore. If you use a pattern like this in your own projects, adding a comment saying that it breaks debugging would be very appreciated. That said, this might be a better discussion for https://github.com/PoshCode/PowerShellPracticeAndStyle
|
Thanks for the feedback, I haven't implement anything like this yet, it was just a flawed possible direction which I would like to hold against you (and I am happy I did). |
There are a lot of other things that can be (and commonly are) included in a functions script file like script scope variable declarations, I can definitely understand the intent and I think you bring up some really interesting concepts that I don't want to discourage exploration of. I don't think it buys anything from a security perspective though. |
I am not aiming for a security that (fully) prevents code injection (of malicious software) but protecting a scripter from unintended execution of code that might overwrite items as general variables and settings (similar to avoiding
This exactly an example that I would like to prevent (correct me if I am wrong, but I like to state): Don't even think about putting this in the dot-sourced (included)
Yes, this is an issue in the approach I would like to see. The same limitation exist for installing ( |
I don't really see a reason to draw this line, dot sourcing is just invoking a script file as if it's in the same scope. I don't see an issue with also including tasks related to the function that aren't strictly the function definition
Sorry I mean |
I think there is a misunderstanding at either site.
In our organization, the "function scripts" are maintained by multiple developers. |
That's a fair reason for an organizational rule or personal preference. Would be nice to have a non-default PSScriptAnalyzer rule to allow folks to enforce that at the CI/CD level if desired. I understand the intent a bit more now, thank you for explaining. I still would not recommend it to everyone as a general best practice, but I can definitely see the value in the option.
Nah it can be invoked any amount of times. It doesn't exactly play well with command discovery static analysis but that doesn't matter as long as you have a manifest (and wildcards have the same issue anyway which rules out most uses). |
For what it's worth, I agree with @SeeminglyScience here, this is a "best practices" question not really addressable here. |
I have added your suggestion from
I don't think that adding the scripts to the environment path is feasible and a "better praktisch" than dot-sourcing "function scripts". Taking our companies environment where we have about 25 repositories/modules (each with 3 till around 20 "function scripts"). Your, idea about " Anyways (our environment is already life for years and it unlikely going to change based on any better practices), what I am trying to achieve with this issue is a solid definition of how exactly functions should be imported into a module before moving this to a document-issue. Personally I feel that PowerShell lacks a better praktisch for this and might even require something like a As with the Avoid using Invoke-Expression document, I think that a similar document like e.g. "Avoid dot-sourcing function scripts into a module" should exist. As you point out yourself: "Dot-sourcing has minor security risks" where I think that the risks are actually slightly higher compared to using But the thing is that if state to avoid something, you should be able to have solid definition of what you should do instead... |
The only real security risk is that someone could add a file that then gets dot sourced (which you can solve by using a fixed list of files to dot source). But if you aren't locking down the environment with CLM and allow listing via signing, that same risk is present in any of these forms. An attacker can modify the psm1 file itself, they can modify a function definition which would only delay the execution of malicious code, etc. The reason |
I think the new microsoft-github-policy-service should skip any issues that have referenced in the last 6 months ("This was referenced on Oct 4"). Besides, this issue Needs-Triage and either marked with something like Resolution-Declined or put it on a kind of wishlist "Issue we would like to prioritize, but we can't commit we will get to it yet" |
Summary of the new feature / enhancement
(if I am right in my thoughts, this will probably end up as a document issue)
For the same reasons the freedom of
Invoke-Expresssion
shouldn't be avoided...See also: How can I prevent variable injection in PowerShell?
The common accepted method to include (multiple) PowerShell functions into a module appears to dot-source them.
See e.g.: Creating powershell modules from multiple files, referencing with module
In fact, in my organization a module looks like:
(As an aside: in Windows PowerShell the
Fullname
property appears to be required for dot-sourcing a script in a module)and each PowerShell script is similar to:
But as with
Invoke-Expression
it could lead to (unintended) code executions where the possibility is even higher as it likely that different developers are involved in maintaining the module scripts.In fact I have been able to break a few things in our environment 😳 as I included
Set-StrictMode Latest
in my script which caused other script functions to break. This will actually count for everything that someone does in the module scope, aka the root of an included PowerShell script, meaning outside the actual function scope (as e.g.Add-Type
etc.).Proposed technical implementation details (optional)
I have not been able to find a formal best practice for including scripts in a module, but I think it should be something like this:
Loader:
Where each script should look like:
Documentation, possibly along with a standard command like an
Import-Function <path>
(which -validates and- creates a function in the current scope from the script with the same name as the filename and that doesn't break the debugger) might help to support the appoach.The text was updated successfully, but these errors were encountered: