Is it possible to dot source a string variable in PowerShell?

2.1k Views Asked by At

I know I can dot source a file:

. .\MyFunctions.ps1

But, I would like to dot source the commands in a string variable:

. $myFuctions

I see that this is possible:

.{$x=2}

And $x equals 2 after the script block is sourced.

But... .{$myFunctions} does not work.

I tried $myFunctions | Invoke-Expression, but it doesn't keep the source function in the current scope. The closest I have been able to come up with is to write the variable to a temporary file, dot source the file, and then remove the file.

Inevitably, someone will ask: "What are you trying to do?" So here is my use case:

I want to obfuscate some functions I intend to call from another script. I don't want to obfuscate the master script, just my additional functions. I have a user base that will need to adjust the master script to their network, directory structure and other local factors, but I don't want certain functions modified. I would also like to protect the source code. So, an alternate question would be: What are some good ways to protect PowerShell script code?

I started with the idea that PowerShell will execute a Base64-encoded string, but only when passed on the command line with -EncodedCommand. I first wanted to dot source an encoded command, but I couldn't figure that out. I then decided that it would be "obfuscated" enough for my purposes if I converted by Base64 file into a decode string and dot sourced the value of the string variable. However, without writing the decoded source to a file, I cannot figure out how to dot source it.

It would satisfy my needs if I could Import-Module -EncodedCommand .\MyEncodedFile.dat

3

There are 3 best solutions below

0
On BEST ANSWER

Actually, there is a way to achieve that and you were almost there.

First, as you already stated, the source or dot operator works either by providing a path (as string) or a script block. See also: . (source or dot operator).

So, when trying to dot-source a string variable, PowerShell thinks it is a path. But, thanks to the possibility of dot-sourcing script blocks, you could do the following:

# Make sure everything is properly escaped.
$MyFunctions = "function Test-DotSourcing { Write-Host `"Worked`" }"

. { Invoke-Expression $MyFunctions }

Test-DotSourcing

Dot-Sourced Functions as String

And you successfully dot-sourced your functions from a string variable!

Explanation:

  • With Invoke-Expression the string is evaluated and run in the child scope (script block).
  • Then with . the evaluated expressions are added to the current scope.

See also:

0
On

While @dwettstein's answer is a viable approach using Invoke-Expression to handle the fact that the function is stored as a string, there are other approaches that seem to achieve the same result below.

One thing I'm not crystal clear on is the scoping itself, Invoke-Expression doesn't create a new scope so there isn't exactly a need to dot source at that point...

#Define your function as a string
PS> $MyUselessFunction = "function Test-WriteSomething { 'It works!' }"

#Invoke-Expression would let you use the function
PS> Invoke-Expression $MyUselessFunction
PS> Test-WriteSomething
It works!

#Dot sourcing works fine if you use a script block
PS> $ScriptBlock = [ScriptBlock]::Create($MyUselessFunction)
PS> . $ScriptBlock
PS> Test-WriteSomething
It works!

#Or just create the function as a script block initially
PS> $MyUselessFunction = {function Test-WriteSomething { 'It works!' }}
PS> . $MyUselessFunction
PS> Test-WriteSomething
It works!

In other words, there are probably a myriad of ways to get something similar to what you want - some of them documented, and some of them divined from the existing documentation. If your functions are defined as strings, then Invoke-Expression might be needed, or you can convert them into script blocks and dot source them.

4
On

At this time it is not possible to dot source a string variable. I stand corrected! . { Invoke-Expression $MyFunctions } definitely works!