1

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Joe B
  • 692
  • 8
  • 18
  • 2
    If you want to "protect the source code", I'd strongly suggest picking a language that compiles to machine code, PowerShell is really not a good fit for what you're trying to do – Mathias R. Jessen Jun 11 '20 at 16:57
  • PowerShell is a good choice because, except for my functions, the code may have to change frequently. Scripting makes this easy to do on the fly. But point taken, I could look into creating my functions as library of cmdlets in C#. It would still be very interesting to be able to dot source a variable containing code, or Import-Module from a pipeline. – Joe B Jun 11 '20 at 17:10
  • 1
    Same problem, C# is compiled in 2 steps, and anyone with access to the assembly/DLL produced by the first compilation pass will be able to reverse engineer it. That being said, I think you can solve your problem _without_ using `Invoke-Expression`, but it'd probably be easier if you can show an example of an obfuscated function that you're trying to define and invoke – Mathias R. Jessen Jun 11 '20 at 17:12
  • It comes down to encrypting a credential that I need to share. The end user should be only able to use the credential for the purpose it is intended, and not see the actual password. I have a key file and an encrypted credential file. To add a layer of protection, the 256 bit key is placed inside a 1024 byte file, the position determined by an algorithm. The "Decrypt" credential function uses the same algorithm to determine where to read within the large file for the 256 bit key. One function creates the key and credential file, another uses those files, returning a credential obj. – Joe B Jun 11 '20 at 17:20
  • Sounds like you need [PowerShell JEA](https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/jea/overview) – Mathias R. Jessen Jun 12 '20 at 10:44

3 Answers3

3

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:

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dwettstein
  • 667
  • 1
  • 7
  • 17
0

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.

immobile2
  • 489
  • 2
  • 15
-4

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

Joe B
  • 692
  • 8
  • 18
  • 1
    Could you please add why this is not possible and what your references are? – dwettstein Feb 09 '21 at 14:20
  • 1
    I don't have any references. What is NOT possible is often not documented. There is NO documentation in dot sourcing that references DOT sourcing a variable, a stream input or the like, only a file or a literal code block. Do you have anything that implies it is possible? – Joe B Feb 11 '21 at 19:36
  • Thanks @dwettstein for demonstrating that it IS POSSIBLE! – Joe B Apr 18 '21 at 14:13
  • Although I don't understand why you answered your own question, and I certainly don't agree with your worldview of _that which is not documented is likely not possible_ - you're correct that you can't dot source a _string_ – immobile2 Nov 25 '21 at 11:09