Protect powershell script from being opened, edited or modifed in Windows

I have the below powershell myscript.ps1 which I use to ask for username and password and depending on it it copies a file to a certain destination. I wanted to make this myscript.ps1 protected so no one can edit it and see the username and password and I found the solution found here which converts the powershell script to an .exe file. When I originally run the script using powershell the below credentials form appears allowing me to enter the username and password. But after the .exe is generated and when I run it the credentials form no longer appears, instead the cosole appears saying "Credential:" I don't know why? I want the credentials form to still appear when running the exe. Anythoughts please?

$credentials = Get-Credential
if ($credentials.Username -eq "user1" -And $credentials.GetNetworkCredential().password -eq "pass1") 
{ Copy-Item "test1.pdf" "\test\test1.pdf"; } 
else 
{ Copy-Item "test2.pdf" "\test\test2.pdf"; }

Output when running the script through powershell: enter image description here

Output when running the generated exe file:

enter image description here


Solution 1:

Keeping passwords secret within source code

First, I'll try to address your direct question:

I wanted to make this myscript.ps1 protected so no one can edit it and see the username and password

I assume you don't really care about people actually editing/changing the script, but only want to keep the password secure. As Ben said, transforming it into an exe really doesn't do much to prevent extraction because you are still embedding the password in it.

What you really want is a password hash, which is a one-way function that transforms a password into a hash you can embed. Given only the hash, an attacker cannot reverse the process, but you can verify a password attempt by hashing the entered password and comparing it with the known hash of the correct password.

For example, pseudocode:

$authorisedHash = 'thehashedpassword';
$password = (Get-Credential).Password;
if ((Get-Hash $password) -eq $authorisedHash)
{
    echo 'Password correct';
}

Where $authorisedHash is the precalculated result of (pseudocode) Get-Hash that you store for later comparison.

Ideally, you'd use an algorithm such as Bcrypt or PBKDF2, with a high work factor (i.e. slow it down) so brute force attacks (guessing by trying every possible password) take too long to be feasible.

By this method, the only string you ever store in your code is the original output of whichever "Get-Hash" (pseudocode) function you happen to use, which makes it very difficult if not impossible to get the original password out of your source code.


Protecting a file with a password

However, while this keeps the password secret, it really doesn't offer any security advantage. As Ben said, there's really nothing stopping the user from manually running the Copy-Item, or even just copying the file themselves with Windows Explorer.

For this kind of security, you'd need to use Windows' Access Control Lists and a separate user account that's actually authenticated elsewhere (e.g. via Windows OS login/runas commands). You need an external service or account to perform the copy, because you need to make sure the user doesn't have direct access to bypass the script.

If this isn't possible for you (e.g. because you distribute the files along with the script, but you are not an admin of the machine), then what you should be doing is encrypting the file. By encrypting the file with the password, you make sure the file is useless without the password (and therefore copying the file is useless because it remains unreadable until decrypted).

Now, this could be done via PowerShell, but there are other, easier, ways. An easy generic method is to store the file within an encrypted archive, such as ZIP1, RAR, 7z, etc., where the user must provide the password to extract. Alternatively, PDFs themselves include support for encryption, requiring a password before they can be read.


1 Note that Windows' built-in crypto support for ZIP in XP to 7, possibly 8 and 10, does not support AES. It only supports the insecure legacy ZIP encryption. So you'll need third-party tools to extract, or a self-extracting archive (exe).