Step 9. Execution Policy and Your First Script — Meeting Windows’ Safety Lock Head-On
Level 0 — Understanding Computer Operation and Structure | Difficulty ★★☆☆☆ | Estimated time 2–3 hours
Prerequisite: Step 8 complete. We will work in Windows PowerShell. No internet connection is required.
- What you need: a Windows PC, PowerShell, Notepad.
- Caution: Today we change one security setting. Make sure you understand both "why we change it" and "what becomes riskier" before moving on. That attitude itself is the core of studying security.
- Heads-up: This chapter contains an intentional failure. In Section 3-2, the script is guaranteed to fail, and that red error is the star of today’s lesson. You will practice reading failure messages precisely.
In 2000, an email titled "ILOVEYOU" swept across the globe. The subject line looked like a love letter, but the attachment was a script — and the moment you clicked it, it infected files on your computer and mailed itself to everyone in your address book. The lesson is simple: a script is not a document; it is a "bundle of commands that gets executed." That’s why Windows keeps PowerShell script files (.ps1) in an "execution forbidden" state by default. This is today’s topic: Execution Policy.
1. Learning Objectives
By the end of this chapter, you will be able to:
- Save a bundle of commands as a
.ps1script file and run it - Explain what Execution Policy is and why it exists
- Read the error message when a script is blocked by policy and identify the cause
- Safely adjust and restore your own account’s policy with
Set-ExecutionPolicy - Add comments to a script so that "future you" can read the file
2. Background Knowledge — Today’s Tools and Concepts
Today’s Tools at a Glance
| Category | Details |
|---|---|
| Language & environment | PowerShell 5.1 (built into Windows), writing .ps1 files in Notepad |
| Today’s commands | .\filename (run a script), Get-ExecutionPolicy (check the policy), Set-ExecutionPolicy -Scope CurrentUser (change the policy) |
| Concepts needed | Scripts vs. programs, the four levels of execution policy, Scope, comments (#) |
2-1. Scripts — The Unit of Reusable Commands
Until now, you typed commands one line at a time, and everything vanished when you closed the window. A script is those commands saved into a file. PowerShell scripts use the .ps1 extension. Once saved as a file, you can run it again anytime — and hand it to someone else, too.
The advantages are clear:
- Reuse — a job you’d otherwise type a hundred times becomes a single execution
- Sharing — a colleague can run the exact same task, the exact same way
- Automation — the basic unit of scheduled execution (covered in Step 30)
2-2. Execution Policy — "Can This Script Be Trusted?"
The catch is that this convenience is just as convenient for attackers. A malicious script can sneak in through an email attachment or a downloaded file. So before Windows runs a script, it asks: "Where did this file come from? Can it be trusted?" That judgment criterion is the execution policy. There are four main levels:
| Policy | Meaning |
|---|---|
| Restricted | Everything forbidden. Not a single line of script runs (the Windows client default) |
| RemoteSigned | Files from the internet require a signature; local files you created yourself are allowed |
| AllSigned | Only signed files allowed, no matter where they came from |
| Unrestricted | Everything allowed (dangerous!) |
Here, a "signature" is a digital seal stating "this file was made by this publisher and has not been tampered with since release." For now, just knowing it exists is enough.
Our choice today is RemoteSigned — "run files I created myself, but stay wary of unfamiliar files from the internet." It’s a well-balanced setting for learning purposes.
2-3. Scope — "Who Does This Apply To?"
When you change a policy, you decide its scope: the whole computer (LocalMachine), or just your account (CurrentUser). Today we use CurrentUser — your account only. It’s the minimal change, leaving other users and system defaults untouched, and it doesn’t require administrator privileges.
"When changing a setting, keep the scope as small as possible" — this, too, is the everyday version of a fundamental security principle (the principle of least privilege).
3. Follow Along
3-1. Creating Your First Script File
Not on the Desktop — let’s work in the practice folder you’ve been using (create C:\security-lab if you don’t have one yet). Open Notepad and write this one line:
Get-Date
Then use File → Save As and save the file as hello.ps1.
Check two things when saving:
- Set the file type to "All Files" — otherwise you may end up with
hello.ps1.txt - Set the encoding to "UTF-8 with BOM" — the default "UTF-8" in recent versions of Notepad has no BOM, and if your script contains Korean text, PowerShell will misread the file and throw errors. Today’s single line is English, so it works either way, but build the habit now (see Wall 5 for hands-on details)
After saving, make sure the extension really is .ps1. Turning on View → File name extensions in File Explorer makes this impossible to fake.
3-2. The Intentional Failure — Blocked by Policy
Open PowerShell and move to that folder (cd C:\security-lab). Now let’s run it:
.\hello.ps1
On a default Windows setup (policy set to Restricted), you’ll see an error like this:
.\hello.ps1 : 이 시스템에서 스크립트를 실행할 수 없으므로 C:\security-lab\hello.ps1 파일을
로드할 수 없습니다. 자세한 내용은 about_Execution_Policies(https://go.microsoft.com/fwlink/?LinkID=135170)를 참조하십시오.
+ CategoryInfo : 보안 오류: (:) [], PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess
(Verified on 2026-09-09. If the date printed without an error, your computer’s policy has already been relaxed. Check it yourself in Section 3-3.)
A red error — and that’s normal. You didn’t fail; Windows’ safety lock did its job precisely.
How to read the output: "scripts cannot be run on this system" — the system isn’t broken; a policy is blocking it. Look at the error categories: PSSecurityException (security exception) and UnauthorizedAccess (no permission) — kindly classified, plus a hint pointing to the reference document (about_Execution_Policies).
Why the .\ prefix: .\ means "in the current folder." For security, PowerShell refuses to run even a script in the current folder by name alone. This blocks the trick of disguising a malicious file with the same name as a system command. From now on, running a script always looks like .\filename.
3-3. Checking the Current Policy — Get-ExecutionPolicy
Let’s confirm why we were blocked:
Get-ExecutionPolicy
Restricted
How to read the output: Restricted = "full ban" — the first level in the table from Section 2-2, and the Windows client default. Your environment may show a different value. Whatever it is, find it in the table from Section 2-2 and confirm what it means.
For more detail, print the list by scope:
Get-ExecutionPolicy -List
Scope ExecutionPolicy
----- ---------------
MachinePolicy Undefined
UserPolicy Undefined
Process Undefined
CurrentUser Undefined
LocalMachine Undefined
Undefined means "no value set." When nothing is set anywhere, the Windows default (Restricted) applies. In Section 3-4, we’ll put a value into CurrentUser, and you’ll see that cell of the table change.
Why do this: Recording the current state before changing a security setting — make this a habit. It becomes your starting point when you later need to roll back, or when investigating "who changed this setting?"
3-4. Relaxing Only My Account — Set-ExecutionPolicy
Now let’s change the policy:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
실행 정책 변경
실행 정책을 변경하면 보안 위험에 노출될 수 있습니다. 실행 정책을 변경하시겠습니까?
[Y] 예(Y) [A] 모두 예(A) [N] 아니오(N) [L] 모두 아니오(L) [S] 일시 중지(S) [?] 도움말
(기본값은 "N"입니다):
How to read the output: Windows itself asks, "This could expose you to risk — do you really want to do it?" The very fact that a confirmation prompt appears is a signal that "you are making a security-related change right now." Read the message and type Y.
What each part means: RemoteSigned (the balanced setting from Section 2-2), -Scope CurrentUser (my account only). In other words: "for me only, only scripts I made, make them runnable."
Let’s verify:
Get-ExecutionPolicy -List
Scope ExecutionPolicy
----- ---------------
MachinePolicy Undefined
UserPolicy Undefined
Process Undefined
CurrentUser RemoteSigned
LocalMachine Undefined
Only the CurrentUser cell changed to RemoteSigned. The whole-machine setting (LocalMachine) is still untouched — the minimal change was applied exactly.
3-5. Second Attempt — Success at Last
.\hello.ps1
2026년 9월 9일 수요일 오전 8:55:03
(The date will differ depending on when you run it.)
Success. Same file — a single policy decided whether it could run.
Pause and think — why is this security-relevant?: We just unlocked this lock "for learning purposes." But malware tries to unlock the very same lock with the very same command. In real-world breaches, one of the first commands an attacker runs is relaxing the execution policy. That’s why security monitoring watches for "who ran Set-ExecutionPolicy?" Today you used this command to learn, but somewhere an analyst is tracking the same command as a trace of an attack. It’s not the tool but the context that separates legitimate use from attack.
3-6. Growing the Script — The Power of Multiple Lines
A one-liner feels underwhelming, so let’s put in the skills from Steps 7–8. Reopen hello.ps1 in Notepad and change it to:
$today = Get-Date
"오늘은 $today"
"이 스크립트는 파일에서 실행되었습니다."
Before you save: the file now contains Korean text, so be sure to save with the encoding set to "UTF-8 with BOM." Save and run again:
.\hello.ps1
오늘은 09/09/2026 08:55:03
이 스크립트는 파일에서 실행되었습니다.
Three lines run in order. This is a script — close the window and the file remains, ready to reproduce the exact same behavior anytime.
Predict this: If you put this file on a USB stick and move it to another computer, will it run? (Answer: if the other computer’s execution policy is Restricted, it’s blocked. And if the file carries the "came from the internet or an external source" mark, RemoteSigned may require an extra check. The reason script distribution isn’t as simple as you’d think — each computer holds its own policy.)
3-7. Adding Comments — Notes to Future You
As a script grows, the moment arrives when you ask, "What was this line again?" That’s what comments are for — explanations tucked between code. In PowerShell, everything after # is a comment; the computer ignores it entirely:
# 작성일: 2026-09-09
# 용도: 매일 아침 컴퓨터 상태 점검
$today = Get-Date
"오늘은 $today" # 화면에 날짜 출력
The rule is simple: from # to the end of the line is a note for humans only. Put it at the top of the file to explain "what this file is," or at the end of a line as a note for that line.
Why this matters: There’s a saying — "A comment is a letter to yourself six months from now." And six months from now, you are practically a stranger. In real security work, deciphering scripts written by others is itself a core task — reading what commands are hidden inside a script an attacker left behind. Well-commented code analyzes fast; uncommented code confuses even its own author.
A professional habit to adopt: starting today, make it a habit to write three lines at the top of every script — ① the date you made it, ② what the file does, ③ what to check before running (e.g., "run from C:\security-lab"). Those three lines are the file’s ID card.
4. Missions & Exercises
Mission — Your Own Checkup Script
Combining everything you’ve learned, let’s build checkup.ps1. Requirements:
- Create the file and save it as
.ps1(check the extension and encoding!) - Content in the report style of Step 5: print the current time, the number of running processes, and the free space on the C: drive
- Add a conditional message
"프로세스가 많습니다"if there are more than 200 processes (Step 8 review) - Run it with
.\checkup.ps1and check the result
Exercises
Question 1. Explain the difference between Restricted and RemoteSigned.
Question 2. You typed hello.ps1 and it didn’t run. What part of the command was missing?
Question 3. You ran Set-ExecutionPolicy RemoteSigned and got a permission error. What’s the problem?
Question 4. You changed the policy to RemoteSigned, but a script downloaded from the internet still won’t run. Why?
5. Model Answers & Completion Criteria
Mission Model Answer
# checkup.ps1 - 매일 아침 컴퓨터 상태 점검
"지금 시각: $(Get-Date)"
$proc = (Get-Process).Count
"실행 중인 프로세스: $proc 개"
if ($proc -gt 200) { "프로세스가 많습니다" }
$free = [math]::Round((Get-PSDrive C).Free / 1GB, 1)
"C: 드라이브 여유 공간: $free GB"
Example output (verified on 2026-09-09):
지금 시각: 09/09/2026 09:05:33
실행 중인 프로세스: 446 개
프로세스가 많습니다
C: 드라이브 여유 공간: 375.8 GB
(Numbers will differ from computer to computer. In the verification environment there were 446 processes, so the conditional message printed. If yours is 200 or fewer, it’s normal for just that line to be absent.)
How to verify: If code that worked when typed line by line fails after you move it into a file, check in order: ① is the extension really .ps1, ② did you include .\, ③ is your current folder where the file lives (move with cd). This three-point check resolves most beginner script problems.
Advanced: you can also restore the original state with Set-ExecutionPolicy Restricted -Scope CurrentUser. When you’re done studying on a computer — especially one shared with family — putting it back is a good habit. "Anyone who can change a setting should also be able to restore it" — that’s a professional principle, too.
Exercise Answers
Answer 1. Restricted is the Windows default that forbids all script execution. RemoteSigned runs local scripts you created yourself while requiring signatures for files from the internet and other external sources, keeping its guard up. For learning purposes, RemoteSigned is the well-balanced choice.
Answer 2. The .\ was missing. For security, PowerShell will not run a script in the current folder by name alone. You must always specify the address explicitly — "this file, in this folder" — like .\hello.ps1.
Answer 3. You omitted -Scope CurrentUser. Without a scope, the command tries to change the whole-computer setting (LocalMachine), which requires administrator privileges. Adding -Scope CurrentUser changes only your account and works without admin rights.
Answer 4. Because RemoteSigned only allows "local files I created," and files from the internet carry an "external file" mark that requires a signature — that is precisely this policy’s reason for existing. If you trust the file, you can right-click it → Properties and check "Unblock," but if you don’t know what’s inside the script, staying blocked is the correct answer.
Completion Criteria Checklist
- [ ] I can save a .ps1 file with the correct extension and encoding (UTF-8 with BOM)
- [ ] I can see a policy-blocked error and explain its cause
- [ ] I can explain why execution policy exists (to prevent malicious scripts)
- [ ] I can explain the difference between RemoteSigned and Restricted
- [ ] I can change, verify, and restore my account’s setting with Set-ExecutionPolicy
- [ ] I can add comments to a script
- [ ] Mission: I completed checkup.ps1
6. Common Pitfalls & Fixes
Wall 1. I saved the file, but it’s missing or won’t run
Symptom: you ran hello.ps1 and got "file not found."
Cause: Notepad most likely saved it as hello.ps1.txt. If Explorer is hiding extensions, it looks perfectly fine on the surface.
Fix: turn on View → File name extensions in Explorer and check the real name. If .txt is attached, rename the file to remove it.
Wall 2. You forgot the .\
Symptom: typing just hello.ps1 does nothing or says the command was not found.
Cause: PowerShell will not run a script in the current folder by name alone (a security design).
Fix: always use the form .\hello.ps1. Remember "dot slash" as the address notation meaning "run this file in this folder."
Wall 3. Permission error on Set-ExecutionPolicy
Symptom: a red error along the lines of "access to the registry key is denied."
Cause: if you omit -Scope CurrentUser, the command tries to change the whole-computer setting and demands administrator privileges.
Fix: always include -Scope CurrentUser. If you truly need to change the machine-wide setting, you’d need an elevated PowerShell, but at this stage CurrentUser is enough.
Wall 4. I changed the policy and it still won’t run
Symptom: you switched to RemoteSigned but execution still fails.
Three candidate causes: ① the file was downloaded from the internet and carries the "external file" mark, ② it’s a company/school computer where Group Policy overrides your setting, ③ you’re running it in a different window or a different account than where you made the change.
Fix: for ①, right-click the file → Properties and check "Unblock" if it appears. For ②, the organization’s management policy takes precedence, so use a personal practice computer. For ③, run Get-ExecutionPolicy -List to see the actual value applied per scope — the cause will reveal itself.
Wall 5. A script containing Korean text throws strange errors
Symptom: running a script saved with Korean text produces a parsing error like 문자열에 " 종결자가 없습니다 ("the string is missing the terminator"). Yet you clearly closed the quotes.
Cause: an encoding problem (verified on 2026-09-09). Recent Notepad saves by default as "UTF-8 (no BOM)," but PowerShell 5.1 reads a BOM-less .ps1 file using the old ANSI code page of a Korean Windows system. The Korean text gets mangled, the quote positions shift, and that error appears.
Fix: in Notepad, use Save As → set the encoding to "UTF-8 with BOM" and save again. An all-English script doesn’t care, but the moment you use Korean text, this setting is mandatory.
Wall 6. The script only opens — it never runs
Symptom: you double-clicked it and Notepad opened.
Cause: the double-click action for .ps1 files is "edit," not "run." This, too, is an intentional safety design — an attachment must never execute just from being double-clicked.
Fix: run scripts only from a PowerShell window, with .\filename. That single rule — "it can never run from a double-click alone" — has prevented countless infections from emailed script attachments. In security, things that are "slightly inconvenient" almost always exist for a reason.
7. Summary
Today’s Concepts
| Concept | One-line description |
|---|---|
| Script (.ps1) | A file storing commands — the unit of reuse, sharing, and automation |
| Execution Policy | Windows’ safety lock that decides whether a script may run |
| Restricted / RemoteSigned | Full ban / wary of external files, allows local files |
| Scope CurrentUser | Applies to my account only — the minimal change |
| Comment (#) | A note the computer ignores and only humans read |
Today’s Commands
| Command | What it does |
|---|---|
.\hello.ps1 |
Runs a script in the current folder (.\ required) |
Get-ExecutionPolicy |
Checks the current policy |
Get-ExecutionPolicy -List |
Checks the policy per scope |
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser |
Relaxes the policy for my account only |
Set-ExecutionPolicy Restricted -Scope CurrentUser |
Restores the original state |
A Sense That Matters More Than Commands
Execution policy grew out of the lessons of the script-malware era epitomized by ILOVEYOU. Today we relaxed it for learning purposes, but in the field, changing this setting is itself something to be monitored. "When you unlock a lock for convenience, know what becomes riskier before you turn the key" — this principle will repeat across countless security settings ahead.
And one more thing: execution policy is not a perfect shield but a "first gate." Attackers know bypass techniques, and Microsoft itself describes this policy not as a security boundary but as a device that prevents accidents. Real defense is the combination of policy + monitoring (recording who changed what) + least privilege — the first instance of the idea that runs through this entire book: "there is no single perfect defense."
Once every box is checked, Step 9 is complete. Click the checkbox in the sidebar to save your progress.