3

Background: I wanted to get into powershell scripts to automate some tasks at work. I am not an admin, and am not able to run an elevated powershell process. I tend to use batch scripts to programmatically perform certain tasks with command line utilities, but as my abilities have grown it's got to the point where it's clear powershell would be a much more appropriate tool for the task. I played around with the immediate windows, and wrote a basic script just to see if I could get something working.

Once I got a grip on some test commands, I saved them to a file.

Write-Host "Let's do this"
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
[System.Windows.Forms.MessageBox]::Show("Script Successful")
calc.exe

I was surprised to find that, while I can execute whatever I want in the immediate window, to load a .ps1 (which I guess is the powershell equivalent of a .bat), it has to be signed, and I need to be an admin to change this behaviour.

However, my first thought was just "well, ok, I'll just send my commands to the immediate window from a .bat". So I looked at powershell -help, and wrote the following in the command prompt:

type test.ps1 | powershell  -

It works, and it works from a .bat too. Am I missing something here? What's the point in disallowing the calling of .ps1 files from the immediate window if all you need is a .bat that says type harmfulscript.ps1 | powershell -, and you're good?

Some_Guy
  • 484
  • 6
  • 20
  • This is a good question and i'm curious as to what the answer will be.. GPO stops the running of scripts (.ps1 files) in my environment, the workaround we use is to make a shortcut pointing towards powershell.exe with a few paramenters but it runs the script in the end. Us desktop engineers find that very useful. – cet51 Oct 19 '17 at 17:18
  • @CoryEtmund well at least I'm not crazy. I just did this and I've been staring at the screen thinking "is this *really* necessary?" on the one hand and "does this *really* work??" on the other! – Some_Guy Oct 19 '17 at 17:24
  • 3
    PowerShell's execution policy is not a security feature but rather an administrator safety feature (something like the safety on a firearm). You have to explicitly say, "yes I want to run scripts." If someone has enabled a restrictive execution policy for security reasons, IMO they are annoying legitimate users (sort of like preventing users from running `cmd.exe` via policy, which is irritating and pointless). – Bill_Stewart Oct 19 '17 at 18:22
  • @Bill_Stewart pretty sure not being able to rule .ps1 scripts is a default setting, and not being able to mess with the registry key that changes this without admin rights is also a default setting. – Some_Guy Oct 19 '17 at 18:57
  • Was that a statement or a question? – Bill_Stewart Oct 19 '17 at 19:03
  • 1
    IMHO several PS "features" are unnecessarily over-complicated, so casual users could never understand they... An even simpler solution is to directly place the code as parameters of the powershell command ending each line with semicolon; just escape each double quote with a backslash: `powershell Write-Host \"Let's do this\"; [System.Reflection.Assembly]::LoadWithPartialName(\"System.Windows.Forms\"); etc...`. You may even place the commands in separate lines as described at [this question](https://stackoverflow.com/questions/36672784/convert-a-small-ps-script-into-a-long-line-in-a-batch-file) – Aacini Oct 19 '17 at 20:05

2 Answers2

2

The ExecutionPolicy (See Get-help Get-ExecutionPolicy and Get-Help Set-ExecutionPolicy) is broken up into "Scopes".

Yes, this is trivial for a user to bypass; quite literally, create a desktop shortcut for PowerShell that calls PowerShell.Exe -ExecutionPolicy Bypass.

To answer your question; By having a general purpose, overtly restrictive scope, random processes are prevented from executing *.ps1 scripts (unless they are, in your case, digitally signed). This makes the "attack surface" of your system smaller.

Update (clarification):

The main point of the 'ExecutionPolicy' feature as a 'Security Control' is not prevention (because it's pretty easy to bypass), it's authentication - verify where a script came from (eg: Is it digitally signed?).

Primarily, this stops an uninformed user from running a script from an unknown/untrusted source.

This type of 'Security Control' is everywhere;

  • Java Runtime Environments (JREs) will only (by default) load trusted (eg: digitally signed) applets.

  • A web browser throws an error when it hits a self-signed or expired SSL Certificate.

Microsoft's PowerShell Team has a blog post with far more details behind the why for their chosen security principles.

With that in mind, remember that the 'ExecutionPolicy' has 'Scopes' (layers). If there is no 'ExecutionPolicy' defined for any scope, PowerShell will default to Restricted.

Otherwise, the top-most defined 'Scope' wins. See get-help about_Execution_Policies for additional details, such as which 'Scopes' take precedence.

PS C:\> Get-ExecutionPolicy -List | Format-Table -AutoSize

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser       Undefined
 LocalMachine    RemoteSigned


PS C:\>
Signal15
  • 558
  • 5
  • 16
  • I'm not disagreeing with you here, I'd just like to understand this a bit more about this. How does this behaviour stop random processes executing ps1 scripts? Any process can execute native commands at the command line right? So if you wanted to call a script surely you could just call the command line code `type test.ps1 | powershell -`? Or did you mean that it stops random processes from *accidentally* executing powershell scripts? – Some_Guy Oct 20 '17 at 08:23
  • Also, running `PowerShell.Exe -ExecutionPolicy Bypass` doesn't change the behavior for me: I'm still unable to run an unsigned script. – Some_Guy Oct 20 '17 at 08:24
  • @Some_Guy Create a desktop shortcut that starts a PowerShell 'session' (opens a window). Then edit the desktop shortcut properties (Specifically the 'Target' field) and append `-ExecutionPolicy Bypass` to the end. You should wind up with a 'Target' like so; `%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass` – Signal15 Oct 20 '17 at 12:29
0

There are actually now two easy ways to do this as a standard user:

From powershell, any user can run Set-ExecutionPolicy -Scope UserPolicy ...

Alternately, it's also now in settings under "Update and Security" -> "For Developers", bottom of the page on Windows 10. This is equivalent to:

Set-ExecutionPolicy -Scope UserPolicy RemoteSigned

Unless you're using scripts from network shares regularly, this is a marginally safer default for a developer workstation than "Unrestricted"

Ben

Ben Kuhn
  • 451
  • 2
  • 5
  • `PS G:\> set-executionpolicy -scope userpolicy remotesigned` gives me `Set-ExecutionPolicy : Cannot set execution policy. Execution policies at the MachinePolicy or UserPolicy scopes must be set through Group Policy.` – Some_Guy Oct 20 '17 at 08:17
  • @Some_Guy Hold the left "Shift" and right-click your PowerShell shortcut and click "Run as Administrator" - You have to have an *elevated* PowerShell session in order to change the `ExecutionPoicy` – Signal15 Oct 20 '17 at 13:00
  • @Signal15 as specified in the original question, I am not an admin. *"I was surprised to find that, while I can execute whatever I want in the immediate window, to load a .ps1 (which I guess is the powershell equivalent of a .bat), it has to be signed, and I need to be an admin to change this behaviour."* – Some_Guy Oct 20 '17 at 13:20