PowerShell
Written August 24, 2021
So you want to run a PowerShell script and you're getting:
echo "echo hi" > test.ps1
.\test.ps1
.\test.ps1 : File test.ps1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ .\test.ps1
+ ~~~~~~~~~~
+ CategoryInfo : SecurityError: (:) [], PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess`
This is similar to macOS running untrusted binaries, or on Windows running an installer from an unknown developer.
One workaround is to disable the restricted policy...but that reduces the security of your computer.
There is a way to temporarily disable it, for the duration of the parent PowerShell Process
.
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
.\test.ps1
# hi
You'll notice if you run another instance of Windows PowerShell, it won't run the script, so you're only vulnerable within that one window until you close it.
Not bad, but there's got to be a better way...
Signed PowerShell scripts
Sign your own PowerShell scripts so Windows will trust YOUR scripts, but not anyone's scripts.
# check your current execution policy for your user, undefined by default:
Get-ExecutionPolicy -Scope CurrentUser
# change it for your user only, to allow only signed scripts
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy AllSigned -Force
Generate a signing key
# I would be ok doing this once every 3 years
New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -Type CodeSigningCert -Subject CN=me -NotAfter (Get-Date).AddYears(3)
Export the public certificate
Get-ChildItem Cert:\CurrentUser\My | Where-Object -Property Subject -EQ "CN=me" | Export-Certificate -FilePath public.der
Trust your public certificate
# import the certificate into the root store, i.e. treat it as a Certificate Authority (CA)
Import-Certificate -CertStoreLocation Cert:\CurrentUser\Root .\public.der
You'll be prompted with a warning
click Yes
.
Sign your PowerShell script
Set-AuthenticodeSignature -Certificate (Get-ChildItem Cert:\CurrentUser\My | Where -Property Subject -EQ "CN=me") -TimestampServer http://timestamp.digicert.com -FilePath .\test.ps1
# need to trust the certificate the first time
.\test.ps1
Type
A
for Always run.
There, now you can run your own PowerShell scripts without compromising your security.
.bashrc equivalent for PowerShell
In bash, there is a .bashrc/.bash_profile script that will run everytime you instantiate a shell. The PowerShell equivalent of bashrc is a file called Profile.ps1 in your Documents\WindowsPowerShell
directory.
# create the WindowsPowerShell directory if it doesn't already exist
New-Item -Type Directory "$([Environment]::GetFolderPath("MyDocuments"))\WindowsPowerShell" -ErrorAction Ignore
# put stuff you want in there
code "$([Environment]::GetFolderPath("MyDocuments"))\WindowsPowerShell\Profile.ps1"
# sign it
Set-AuthenticodeSignature -Certificate (Get-ChildItem Cert:\CurrentUser\My | Where -Property Subject -EQ "CN=me") -TimestampServer http://timestamp.digicert.com -FilePath "$([Environment]::GetFolderPath("MyDocuments"))\WindowsPowerShell\Profile.ps1"