I was under the impression that module manifests allow only DATA stuff. In fact, if you try to use cmdlets or variables in them, you get the usual Data-language errors, like this:

Import-Module : The module manifest ‘C:\Modules\Test\Test.psd1’ could not be processed because it is not a valid PowerShell restricted language file. Please remove the elements that are not permitted by the restricted language: The command ‘Get-ChildItem’ is not in allowed in restricted language mode or a Data section.


Import-Module : The module manifest ‘C:\Modules\Test\Test.psd1’ could not be processed because it is not a valid PowerShell restricted language file. Please remove the elements that are not permitted by the restricted language: A variable that cannot be referenced in restricted language mode or a Data section is being referenced. Variables that can be referenced include the following: $PSCulture, $PSUICulture, $true, $false, and $null.

BUT THEN I came across this in the Windows 7 built-in BitsTransfer module:

RequiredAssemblies=Join-Path $psScriptRoot “Microsoft.BackgroundIntelligentTransfer.Management.Interop.dll”

AND IT WORKS?!

Well, that’s very weird, because Join-Path is certainly not allowed in a normal “restricted language” file, and (as you can tell from above) neither is $PsScriptRoot — in fact, as far as I know, you shouldn’t have to do that at all, since RequiredAssemblies knows enough to look in your module folder… but nevermind that, why does it work?

The Rest of the Story

So I went digging, and it turns out that although they are parsed as Restricted Language (like a “data section,” see about_Data_Sections), module manifests are allowed extra cmdlets: “Import-LocalizedData”, “ConvertFrom-StringData”, “Write-Host”, “Out-Host”, “Join-Path” and even special variables that aren’t normally allowed in data sections: specifically $PsScriptRoot which is the ModuleBase (the parent folder of the psd1) and environment variables ($Env:), plus the usual $PSCulture, $PSUICulture, and of course $true, $false, and $null.

However, although you can use those variables, you can’t embed them in strings, so if you wanted to use $Env:Windir or $Env:Temp as part of a path (for instance), you need to take advantage of the availability of Join-Path.

Now, I can’t find this documented anywhere (although I did add it to the module manifest documentation on MSDN), but it’s true, nonetheless — you’ll just have to trust me :) Yeah, PowerShell is starting to drive me crazy again.

Reblog this post [with Zemanta]

One Response to “PowerShell Module Manifests Tip: allowed cmdlets and variables”