{"id":14295,"date":"2018-08-14T13:39:18","date_gmt":"2018-08-14T20:39:18","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/?p=14295"},"modified":"2019-02-18T12:37:45","modified_gmt":"2019-02-18T19:37:45","slug":"powershell-module-function-export-in-constrained-language","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/powershell-module-function-export-in-constrained-language\/","title":{"rendered":"PowerShell Module Function Export in Constrained Language"},"content":{"rendered":"<div class=\"markdown-body\">\n<h2><a href=\"#powershell-module-exporting-functions-in-constrained-language\" id=\"user-content-powershell-module-exporting-functions-in-constrained-language\" class=\"anchor\"><span class=\"octicon octicon-link\"><\/span><\/a>PowerShell Module Exporting Functions in Constrained Language<\/h2>\n<p>PowerShell offers a number of ways to expose functions in a script module. But some options have serious performance or security drawbacks. In this blog I describe these issues and provide simple guidance for creating performant and secure script modules. Look for a module soon in <a href=\"https:\/\/www.powershellgallery.com\/\" rel=\"nofollow\">PSGallery<\/a> that helps you update your modules to be compliant with this guidance.<\/p>\n<p>When PowerShell is running in <a href=\"https:\/\/blogs.msdn.microsoft.com\/powershell\/2017\/11\/02\/powershell-constrained-language-mode\/\" rel=\"nofollow\">Constrained Language<\/a> mode it adds some restrictions in how module functions can be exported. Normally, when PowerShell is not running in Constrained Language, all script functions defined in the module are exported by default.<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre><span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psm1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F1<\/span> { }\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F2<\/span> { }\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F3<\/span> { }\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psd1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-k\">@<\/span>{ <span class=\"pl-smi\">ModuleVersion<\/span> <span class=\"pl-k\">=<\/span> <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>1.0<span class=\"pl-pds\">'<\/span><\/span>; <span class=\"pl-smi\">RootModule<\/span> <span class=\"pl-k\">=<\/span> <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>TestModule.psm1<span class=\"pl-pds\">'<\/span><\/span> }\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> All functions (Function1, Function2, Function3) are exported and available<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">Get-Module<\/span> <span class=\"pl-k\">-<\/span>Name TestModule <span class=\"pl-k\">-<\/span>List <span class=\"pl-k\">|<\/span> Select <span class=\"pl-k\">-<\/span>ExpandProperty ExportedFunctions\n\nF1\nF2\nF3<\/pre>\n<\/div>\n<p>This is handy and works well for simple modules. However, it can cause problems for more complex modules.<\/p>\n<h2><a href=\"#performance-degradation\" id=\"user-content-performance-degradation\" class=\"anchor\"><span class=\"octicon octicon-link\"><\/span><\/a>Performance Degradation<\/h2>\n<p>Command discovery is much slower when script functions are exported implicitly or explicitly using wildcard characters. This is because PowerShell has to parse all module script content to look for available functions and then match the found function names with a wildcard pattern. If the module uses explicit function export lists, then this parsing during discovery is not necessary. If you have a lot of custom script modules with many functions, the performance hit can become very noticeable. This principal also applies to exporting any other script element such as cmdlets, variables, aliases, and DSC resources.<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre><span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psm1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F1<\/span> { }\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F2<\/span> { }\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F3<\/span> { }\n...\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> This wildcard function export has the same behavior as the default behavior, all module functions are exported and PowerShell has to parse all script to discover available functions<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">Export-ModuleMember<\/span> <span class=\"pl-k\">-<\/span>Function <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>*<span class=\"pl-pds\">'<\/span><\/span><\/pre>\n<\/div>\n<h2><a href=\"#confused-intent\" id=\"user-content-confused-intent\" class=\"anchor\"><span class=\"octicon octicon-link\"><\/span><\/a>Confused Intent<\/h2>\n<p>For large complex modules, exporting all defined functions is confusing to users as to how the module is intended to be used. The number of defined functions can be very large and the handful of user cmdlets can get lost in the noise. It is much better to export just the functions intended for the user and hide all helper functions.<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre><span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psm1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">Invoke-Program<\/span> { }\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F1<\/span> { }\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F2<\/span> { }\n...\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">F100<\/span> { }\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psd1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-k\">@<\/span>{ <span class=\"pl-smi\">ModuleVersion<\/span> <span class=\"pl-k\">=<\/span> <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>1.0<span class=\"pl-pds\">'<\/span><\/span>; <span class=\"pl-smi\">RootModule<\/span> <span class=\"pl-k\">=<\/span> <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>TestModule.psm1<span class=\"pl-pds\">'<\/span><\/span>; <span class=\"pl-smi\">FunctionsToExport<\/span> <span class=\"pl-k\">=<\/span> <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>Invoke-Program<span class=\"pl-pds\">'<\/span><\/span> }\n\n<span class=\"pl-c1\">Get-Module<\/span> <span class=\"pl-k\">-<\/span>Name TestModule <span class=\"pl-k\">-<\/span>List <span class=\"pl-k\">|<\/span> Select <span class=\"pl-k\">-<\/span>ExpandProperty ExportedFunctions\n\n<span class=\"pl-c1\">Invoke-Program<\/span><\/pre>\n<\/div>\n<h2><a href=\"#security\" id=\"user-content-security\" class=\"anchor\"><span class=\"octicon octicon-link\"><\/span><\/a>Security<\/h2>\n<p>PowerShell runs in <a href=\"https:\/\/blogs.msdn.microsoft.com\/powershell\/2017\/11\/02\/powershell-constrained-language-mode\/\" rel=\"nofollow\">Constrained Language<\/a> mode when a DeviceGuard or AppLocker policy is enforced on the system. This provides a good user shell experience while allowing trusted script modules to run in Full Language so that system management can still be done. For example, a user from the command line cannot use Add-Type to create and run arbitrary C# types, but a trusted script can.<\/p>\n<p>So, it is important that a trusted script does not expose any vulnerabilities such as <a href=\"https:\/\/blogs.msdn.microsoft.com\/powershell\/2018\/08\/03\/powershell-injection-hunter-security-auditing-for-powershell-scripts\/\" rel=\"nofollow\">script injection<\/a> or arbitrary code execution. Another type of vulnerability is leaking dangerous module functions not intended for public use. A helper function might take arbitrary source code and create a type intended to be used privately in a trusted context. But, if that helper function becomes publically available it exposes a code execution vulnerability.<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre><span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psm1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">Invoke-Program<\/span> { }\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> Private helper function<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">Get-Type<\/span>\n{\n    <span class=\"pl-k\">param<\/span>( [<span class=\"pl-k\">string<\/span>] <span class=\"pl-smi\">$source<\/span> )\n    <span class=\"pl-c1\">Add-Type<\/span> <span class=\"pl-k\">-<\/span>TypeDefinition <span class=\"pl-smi\">$source<\/span> <span class=\"pl-k\">-<\/span>PassThru\n}\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> Exposes *all* module functions!<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">Export-ModuleMember<\/span> <span class=\"pl-k\">-<\/span>Function <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>*<span class=\"pl-pds\">'<\/span><\/span>\n\n<span class=\"pl-c1\">Get-Module<\/span> <span class=\"pl-k\">-<\/span>Name TestModule <span class=\"pl-k\">-<\/span>List <span class=\"pl-k\">|<\/span> Select <span class=\"pl-k\">-<\/span>ExpandProperty ExportedFunctions\n\n<span class=\"pl-c1\">Invoke-Program<\/span>\n<span class=\"pl-c1\">Get-Type<\/span><\/pre>\n<\/div>\n<p>In the above example, <code>Get-Type<\/code> module helper function is exported via wildcard along with the intended <code>Invoke-Program<\/code> function. Since this is a trusted module <code>Get-Type<\/code> runs in Full Language and exposes the ability to create arbitrary types.<\/p>\n<h3><a href=\"#unintended-consequences\" id=\"user-content-unintended-consequences\" class=\"anchor\"><span class=\"octicon octicon-link\"><\/span><\/a>Unintended Consequences<\/h3>\n<p>A major problem with exporting module functions using wildcards is that you may end up exporting functions unintentionally. For example, your module may specify other nested modules, or it may explicitly import other modules, or it may dot source script files into the module scope. All of those script functions will become publicly available if wild cards are used to export module functions.<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre><span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psm1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">import-Module<\/span> HelperMod1\n<span class=\"pl-k\">.<\/span> .\\CSharpHelpers.ps1\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">Invoke-Program<\/span> { }\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> Exposes *all* module functions!<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">Export-ModuleMember<\/span> <span class=\"pl-k\">-<\/span>Function <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>*<span class=\"pl-pds\">'<\/span><\/span>\n\n<span class=\"pl-c1\">Get-Module<\/span> <span class=\"pl-k\">-<\/span>Name TestModule <span class=\"pl-k\">-<\/span>List <span class=\"pl-k\">|<\/span> Select <span class=\"pl-k\">-<\/span>ExpandProperty ExportedFunctions\n<span class=\"pl-c1\">Invoke-Program<\/span>\nHelperFn1\nHelperFn2\nCompile<span class=\"pl-k\">-<\/span>CSharp<\/pre>\n<\/div>\n<h3><a href=\"#module-function-export-restrictions\" id=\"user-content-module-function-export-restrictions\" class=\"anchor\"><span class=\"octicon octicon-link\"><\/span><\/a>Module Function Export Restrictions<\/h3>\n<p>When PowerShell detects that an application whitelisting policy is enforced it runs in Constrained Language mode as mentioned previously, but it also applies some function export restrictions for imported modules. Remember that these restrictions only apply when PowerShell is running under DeviceGuard or AppLocker policy enforcement mode. Otherwise module function export works as before.<\/p>\n<ul>\n<li>Wildcards <em>are not<\/em> allowed with the FunctionsToExport keyword in a module manifest (.psd1 file). If a wildcard is found in the keyword argument then no functions are exported in that module.<\/li>\n<li>Wildcards <em>are<\/em> allowed in a module script file (.psm1). This is to provide backward compatibility but we strongly discourage it.<\/li>\n<li>A module that uses wildcards to export functions, and at the same time dot sources script files into the module scope, will throw an error during module loading time. Note that if a psm1 file exports functions via wildcard, but it is imported under a manifest (psd1 file) that exports functions explicitly by name, then no error is thrown because the psd1 overrides any function export done within a psm1 file associated with the manifest. But if the psm1 file is imported directly (without the psd1 manifest file) then the error is thrown (see example below). Basically, the dot source operator cannot be used in module script along with wildcard based function export. It is too easy to inadvertently expose unwanted functions.<\/li>\n<\/ul>\n<p>These restrictions are to help prevent inadvertent exposure of functions. By using wildcard based function export, you may be exposing dangerous functions without knowing it.<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre><span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psm1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">Import-Module<\/span> HelperMod1\n<span class=\"pl-k\">.<\/span> .\\CSharpHelpers.ps1\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">Invoke-Program<\/span> { }\n<span class=\"pl-c1\">Export-ModuleMember<\/span> <span class=\"pl-k\">-<\/span>Function <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>*<span class=\"pl-pds\">'<\/span><\/span>\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psd1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-k\">@<\/span>{ <span class=\"pl-smi\">ModuleVersion<\/span><span class=\"pl-k\">=<\/span><span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>1.0<span class=\"pl-pds\">'<\/span><\/span>; <span class=\"pl-smi\">RootModule<\/span><span class=\"pl-k\">=<\/span><span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>TestModule.psm1<span class=\"pl-pds\">'<\/span><\/span>; <span class=\"pl-smi\">FunctionsToExport<\/span><span class=\"pl-k\">=<\/span><span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>Invoke-Program<span class=\"pl-pds\">'<\/span><\/span> }\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> Importing the psm1 file directly results in error because of the wildcard function export and use of dot source operator<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">Import-Module<\/span> <span class=\"pl-k\">-<\/span>Name TestModule\\TestModule.psm1\nError:\n<span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>This module uses the dot-source operator while exporting functions using wildcard characters, and this is disallowed when the system is under application verification enforcement.<span class=\"pl-pds\">'<\/span><\/span>\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> But importing using the module manifest succeeds since the manifest explicitly exports functions by name without wildcards<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">Import-Module<\/span> TestModule\n<span class=\"pl-c1\">Get-Module<\/span> <span class=\"pl-k\">-<\/span>Name TestModule <span class=\"pl-k\">|<\/span> Select <span class=\"pl-k\">-<\/span>ExpandProperty ExportedFunctions\n<span class=\"pl-c1\">Invoke-Program<\/span><\/pre>\n<\/div>\n<h2><a href=\"#module-function-export-best-practices\" id=\"user-content-module-function-export-best-practices\" class=\"anchor\"><span class=\"octicon octicon-link\"><\/span><\/a>Module Function Export Best Practices<\/h2>\n<p>Best practices for module function exporting is pretty simple. Always export module functions explicitly by name. Never export using wild card names. This will yield the best performance and ensure you don&#8217;t expose functions you don&#8217;t intend to expose. It makes your module safer to use as trusted in a DeviceGuard policy enforcement environment.<\/p>\n<div class=\"highlight highlight-source-powershell\">\n<pre><span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psm1<span class=\"pl-c\"><\/span><\/span>\n<span class=\"pl-c1\">Import-Module<\/span> HelperMod1\n<span class=\"pl-k\">.<\/span> .\\CSharpHelpers.ps1\n<span class=\"pl-k\">function<\/span> <span class=\"pl-en\">Invoke-Program<\/span> { }\n\n<span class=\"pl-c\"><span class=\"pl-c\">#<\/span> TestModule.psd1<span class=\"pl-c\"><\/span><\/span>\n@ { ModuleVersion<span class=\"pl-k\">=<\/span><span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>1.0<span class=\"pl-pds\">'<\/span><\/span>; RootModule<span class=\"pl-k\">=<\/span><span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>TestModule.psm1<span class=\"pl-pds\">'<\/span><\/span>; FunctionsToExport<span class=\"pl-k\">=<\/span><span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>Invoke-Program<span class=\"pl-pds\">'<\/span><\/span> }\n\n<span class=\"pl-c1\">Get-Module<\/span> <span class=\"pl-k\">-<\/span>Name TestModule <span class=\"pl-k\">-<\/span>List <span class=\"pl-k\">|<\/span> Select <span class=\"pl-k\">-<\/span>ExpandProperty ExportedFunctions\n<span class=\"pl-c1\">Invoke-Program<\/span><\/pre>\n<\/div>\n<p>Paul Higinbotham\nSenior Software Engineer\nPowerShell Team<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>PowerShell Module Exporting Functions in Constrained Language PowerShell offers a number of ways to expose functions in a script module. But some options have serious performance or security drawbacks. In this blog I describe these issues and provide simple guidance for creating performant and secure script modules. Look for a module soon in PSGallery that [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-14295","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell"],"acf":[],"blog_post_summary":"<p>PowerShell Module Exporting Functions in Constrained Language PowerShell offers a number of ways to expose functions in a script module. But some options have serious performance or security drawbacks. In this blog I describe these issues and provide simple guidance for creating performant and secure script modules. Look for a module soon in PSGallery that [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/14295","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=14295"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/14295\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=14295"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=14295"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=14295"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}