There is inevitably a certain amount of risk that comes from having a collection of PowerShell scripts stored on your network. For instance, an attacker could analyze one of your scripts to gain insight into your organization’s IT infrastructure. Similarly, an attacker (or even a well-intentioned IT staff member within your company) could make a modification to an existing script that causes general problems.
A way to potentially mitigate these risks is to create encrypted PowerShell scripts. An encrypted script requires significantly more effort to read or modify than a plain text script.
In this article, I will show you how to build such a script.
Part One: Encrypt the Original Script
The first step in building an encrypted PowerShell script is to write an plain text version of the script. Once you have the script ready, make sure to test it thoroughly and then rename the script file so that it has a .TXT file extension.
In Figure 1, I have created a simple “Hello World” script, saved as a text file named MyCode.txt.
I have created a simple PowerShell script and saved it as a text file.
You will need to read your text file into PowerShell, encrypt the file’s contents, and write those encrypted contents to a file. Here are some commands for reading, encrypting, and outputting the code that is presently contained within the text file:
$Code = Get-Content C:\Scripts\MyCode.txt $CodeSecureString = ConvertTo-SecureString $Code -AsPlainText -Force $Encrypted = ConvertFrom-SecureString -SecureString $CodeSecureString $Encrypted | Out-File -FilePath C:\Scripts\Encrypted.txt
In this block of code, we create a variable called $Code that contains the unencrypted contents of the text file. Next, we convert the script file into a secure string and store its contents in a variable called $CodeSecureString. At this point, we are essentially treating the text file like a plain text password. The third line of code converts the secure string data into an encrypted value. Finally, in the last line of code, we write the encrypted data out to a text file called Encrypted.txt.
Figure 2 demonstrates these steps. In the figure, I added some extra lines in which I output the contents of the $Code, $CodeSecureString, and $Encrypted variables so that you can see exactly what those variables are being used for. I have also output the contents of the encrypted.txt file for you to see.
I have encrypted the contents of my original text file.
Part Two: Put the Encrypted Code Into PowerShell
Now that we have encrypted the original script, we have completed the first half of the process. Unfortunately, we can’t just paste encrypted code into PowerShell and expect it to run. In addition to pasting the encrypted code into a script, we will need to include a couple of commands that tell PowerShell how to decrypt the code.
Here is the code:
$Instructions = "01000000d08c9ddf0115d1118c7a00c04fc297eb010000005acac12aa02d05439b51cec88c15f8ed00000000020000000000106600000001000020000000df27935cb01adc23f2db341c5c21f7b144669678a04cd4c5afd6a689c7f08d63000000000e80000000020000200000000bfdbff6ab9d2cf8f6a9a5a5e807f7dcbebc7083012ed3f07b7ce7f6d7e9233a4000000046c27b1d891002f89a8be44eeb8878ca477eb78bc6738649df19a7535ea74ad0b809db0e543acb33d441f3714ea248b62c050ebf8dd0642b9686acd8d60eebbd40000000630dd2c88ca48e14fc130c08aef6c81284ff7d3e54cd52890b44d21c98e2e3fd1499853cf574771b0826693eddfc987696a977b8de20e3929b2bc87205b6fac2" $Decrypt = $Instructions | ConvertTo-SecureString $Code = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Decrypt)) Invoke-Expression $Code
The first instruction writes the encrypted code to a variable called $Instructions. Next, we create a variable called $Decrypt, convert the encrypted code to a secure string, and write the result to the $Decrypt variable. From there, we use a call to .NET to perform the final decryption. The decrypted code is written to a variable called $Code. We can then use the Invoke-Expression cmdlet to execute the code.
In Figure 3, I have manually entered the instructions listed above. In doing so, I have also output the contents of the $Decrypt and $Code variables so that you can observe how the decryption process works.
The encrypted code has been decrypted.
The bottom line is that all the code shown in the example above can be embedded into a PowerShell script and used as is. The encryption makes it nearly impossible to tell what the script is designed to do without actually running the script. It also prevents anyone from making modifications to the script, as any unauthorized modification would corrupt the encrypted string.
Additional Notes About PowerShell Encryption
Before I conclude this article, there are two things that I want to quickly mention.
First, the example that I used above involved a really simple script. If you were trying to encrypt a longer, more complex script, then you might have to set up a loop to read and execute the decrypted instructions one at a time -- rather than try to execute the whole thing with a single Invoke-Expression statement.
The second thing is that you can use this same technique to decrypt secure password files created by PowerShell (using Get-Credential). As such, because password files can be decrypted, it is always important to remember they need to be stored in a secure location.