Chapter 01Lesson 04~65 minutes

Hosts, Sessions, Runspaces, Processes, and the Execution Model

Build a practical execution model from terminal and PowerShell host through pwsh process, runspace, session state, command parsing and binding, output streams, and native child processes.

BeginnerExecution modelProcess boundaries

Learning objectives

By the end of this lesson

  • Differentiate a terminal, PowerShell host, pwsh process, runspace, and session state.
  • Explain why interactive terminals and non-interactive CI runners can behave differently.
  • Inspect host, PID, working directory, process path, and process environment state.
  • Describe the high-level parse → resolve → bind → execute → emit execution path.
  • Predict which state persists inside one session and which state crosses or disappears at a new-process boundary.

1. Build the execution model from the outside inward

When you type a PowerShell command, several layers cooperate. Beginners often call all of them “PowerShell,” which makes failures hard to localize. A useful mental model starts outside the engine and moves inward.

A terminal is the interface presenting the session. A PowerShell host is the program or component that connects the PowerShell engine to an environment such as a console, editor, or application. A normal pwsh launch creates an operating-system process: an isolated running instance with its own process ID, environment, memory, and lifetime.

Inside a PowerShell process, code executes in a runspace. A runspace is a PowerShell execution environment containing the engine state needed to run commands. It has session state: variables, functions, aliases, loaded modules, current location, and other state visible to that runspace. Advanced applications can host multiple runspaces in one process; Chapter 17 studies that in detail. For now, one interactive pwsh process with one main runspace is the right model.

Commands executed in that runspace can remain inside PowerShell or start a child process when you invoke a native executable such as git, docker, or another pwsh.

2. Follow one command through the engine

High-level PowerShell execution path
flowchart TD
  A["Terminal or automation runner"] --> B["PowerShell host / pwsh process"]
  B --> C["Runspace and session state"]
  C --> D["Parse input"]
  D --> E["Resolve command name"]
  E --> F["Bind arguments to parameters"]
  F --> G["Execute command"]
  G --> H["Emit objects and streams"]
  H --> I["Pipeline continues or host renders output"]
  G --> J["Native child process when invoked"]

Terminal or automation runner: a human terminal sends keystrokes interactively, while a CI runner may start pwsh with a script file and no human attached.

Host and process: the host presents engine services, while the operating system owns the pwsh process, gives it a PID, and controls resources and environment inheritance.

Runspace and session state: this is where PowerShell variables, functions, modules, aliases, providers, and current state live for execution.

Parse: PowerShell reads the input and determines its syntactic structure. Parsing is why quotation marks, parentheses, variables, and operators have defined meanings rather than being arbitrary text.

Resolve: PowerShell determines what command name refers to—a cmdlet, function, alias, script, application, or another command type. Chapter 02 teaches the resolution rules and discovery tools.

Bind: PowerShell matches supplied arguments and pipeline input to command parameters. Chapter 03 explores pipeline parameter binding in depth.

Execute and emit: the command runs and can write success output objects or other streams such as errors, warnings, verbose messages, and information. Later chapters examine those streams formally.

Render or continue: output can move into another pipeline command or eventually reach a host that formats and displays it. If the command launches a native executable, part of the work crosses into a separate process with different conventions.

3. Inspect the current process, host, location, and environment

PowerShell exposes each layer through different evidence. $Host tells you about the PowerShell host interface; it does not tell you the operating system. $PID identifies the current operating-system process. Get-Location reports the current PowerShell location. $env:NAME accesses a process environment variable.

$Host | Select-Object Name, Version

Get-Process -Id $PID |
    Select-Object Id, ProcessName, Path, StartTime

Get-Location

[pscustomobject]@{
    ProcessId    = $PID
    HostName     = $Host.Name
    UserName     = [System.Environment]::UserName
    MachineName  = [System.Environment]::MachineName
    PSHome       = $PSHOME
    PathEntries  = ($env:PATH -split [IO.Path]::PathSeparator).Count
}

These values have different lifetimes. The process ID exists only for this process. A PowerShell variable normally lives in session state and disappears when the process ends. Environment variables exist in the process environment; a child process normally receives a copy of the parent's current environment when it starts. The working directory is also normally inherited when a child process is created, although applications can deliberately change it.

Important distinction

“Session state” and “machine state” are not the same thing. Assigning $Name = 'value' changes a PowerShell variable in the current runspace. Assigning $env:NAME = 'value' changes the environment of the current process and can affect subsequently launched child processes. Neither assignment automatically creates a permanent machine-wide setting.

4. Interactive and non-interactive execution have different assumptions

An interactive session expects a person to be present. It may provide command history, tab completion, predictions, colored output, prompts, and profile customizations. You can inspect an error and immediately try another command.

A non-interactive execution is launched to perform work without a conversation. CI/CD runners, scheduled jobs, containers, deployment agents, and remote automation frequently start PowerShell this way. They may begin in a clean workspace, use a service account, omit your profile, inject environment variables, impose a timeout, collect streams into logs, and destroy the worker after the job finishes.

This is why “it worked in my terminal” is incomplete evidence. Your personal session may contain a module imported by your profile, a modified PATH, a credential cached by a developer tool, a variable created ten minutes ago, or a working directory that a CI runner never uses.

# Inspect some state that often differs between an interactive workstation and CI.
[pscustomobject]@{
    HostName          = $Host.Name
    ProcessId         = $PID
    WorkingDirectory  = (Get-Location).Path
    HasUserProfile    = Test-Path $PROFILE
    CI                = $env:CI
    PathEntryCount    = ($env:PATH -split [IO.Path]::PathSeparator).Count
}

$env:CI is not a universal PowerShell variable; many CI systems set an environment variable with that name, but you must read your provider's contract. The lesson is to inspect supplied state rather than assume it.

5. Command resolution happens before execution

Suppose you type Get-Process. PowerShell first parses the command and then resolves the name to something executable. If the name is unknown, execution cannot begin. If several command types share a name, precedence rules determine which one wins. That is why production code should be understandable about what it invokes.

Get-Command Get-Process |
    Select-Object Name, CommandType, Source, Version

You will use Get-Command extensively in Chapter 02. For now, notice that discovery is a distinct phase from running the command. A reliable diagnostic question is: What did PowerShell resolve this name to in this environment?

After resolution, PowerShell performs parameter binding. Parameters are named inputs such as -Id in Get-Process -Id $PID. The engine converts and associates supplied values with a valid parameter set before the command body performs its work. Binding errors therefore happen before the requested operation can succeed.

6. Commands can emit more than one kind of output

PowerShell commands can produce normal success output and several diagnostic streams. You will later study the success, error, warning, verbose, debug, information, and progress channels in detail. The high-level point in Chapter 01 is that “what appeared in the terminal” may combine information with different purposes.

Write-Output "success output"
Write-Warning "warning output"
Write-Verbose "verbose output" -Verbose

Success output is usually the data intended for pipeline processing. Warning and verbose output carry diagnostic meaning. A CI system may capture or display these streams differently. Designing automation becomes easier when you do not treat every visible line as one undifferentiated text stream.

7. Native executables create a process boundary

When PowerShell invokes a native executable, the operating system starts another process. That child does not receive PowerShell variables, functions, aliases, or in-memory objects. It receives operating-system process inputs such as command-line arguments, inherited environment variables, standard input/output/error handles, and a working directory.

This boundary explains many cross-shell bugs. PowerShell may hold a rich object, but a native program normally expects strings as command-line arguments. A native program may return text and a numeric exit code rather than a PowerShell error object. Chapter 02 examines that boundary carefully.

# This starts another PowerShell process, making the boundary easy to observe.
"Parent PID: $PID"

pwsh -NoProfile -Command '"Child PID: $PID"'

The two PIDs should differ. The child process exists temporarily, performs the command, and exits. The parent PowerShell process continues.

8. Experiment: what persists, what is inherited, and what disappears?

This experiment distinguishes three kinds of state: a PowerShell variable, a process environment variable, and the working directory. It makes no permanent configuration changes.

$SessionMarker = "created in parent PID $PID"
$env:PS_ACADEMY_SESSION_TEST = "parent-environment"
$parentLocation = (Get-Location).Path

"--- parent before child ---"
"SessionMarker: $SessionMarker"
"Environment marker: $env:PS_ACADEMY_SESSION_TEST"
"Location: $parentLocation"

"--- child process ---"
pwsh -NoProfile -Command @'
"Child PID: $PID"
$marker = Get-Variable SessionMarker -ErrorAction SilentlyContinue
"SessionMarker exists: $([bool]$marker)"
"Environment marker: $env:PS_ACADEMY_SESSION_TEST"
"Location: $((Get-Location).Path)"
$env:PS_ACADEMY_SESSION_TEST = "changed-in-child"
"Child changed marker to: $env:PS_ACADEMY_SESSION_TEST"
'@

"--- parent after child ---"
"SessionMarker: $SessionMarker"
"Environment marker: $env:PS_ACADEMY_SESSION_TEST"
"Location: $((Get-Location).Path)"

Three observations matter. First, $SessionMarker does not appear in the child because ordinary PowerShell variables live in the parent's session state. Second, the child normally does see PS_ACADEMY_SESSION_TEST because environment variables are inherited when the process starts. Third, when the child changes its copy of that environment variable, the parent's value remains parent-environment. Child processes cannot normally rewrite the already-running parent's process environment.

The child also normally begins in the parent's current working directory. That is inherited process context, not shared live session state. If the child changes its location, the parent's location does not change.

Clean up the temporary environment variable from the current process after the experiment:

Remove-Item Env:PS_ACADEMY_SESSION_TEST
Remove-Variable SessionMarker, parentLocation

9. Apply the model to a CI runner

Imagine a pipeline step launches pwsh -NoProfile -File ./deploy.ps1. The runner process prepares a workspace and environment variables, then starts a PowerShell child process. PowerShell creates session state, parses the script, resolves commands, binds parameters, executes commands, emits data and diagnostics, and eventually exits with a process status.

If the next CI step launches a new pwsh process, ordinary variables from the first step are gone. To transfer state, the pipeline must use a documented mechanism: an artifact, a file in a preserved workspace, a CI output variable, a cache, a database, an external service, or another explicit channel. Session state is not a durable database.

This model is the foundation for later topics such as jobs, remoting, runspaces, containers, and CI orchestration. Each technology introduces a boundary; reliable automation makes those boundaries visible.

10. Common execution-model mistakes

Confusing $Host with the operating system. The host represents the interface through which PowerShell is running. Use runtime/platform information for the OS.

Expecting a PowerShell variable to exist in a new process. Ordinary variables are session state. Pass required inputs explicitly.

Assuming environment variables are globally shared live state. A child generally inherits a snapshot. Later changes in the child do not update its parent.

Assuming CI starts in your preferred directory. Use explicit paths or inspect Get-Location; do not depend on an interactive workstation's current location.

Assuming native tools participate in PowerShell's object model automatically. Native execution crosses a process boundary with its own argument, text-stream, and exit-code conventions.

11. Hands-on lab: map your current execution environment

Run the following read-only report in an interactive session, then run the same report through a clean child process. Compare the results instead of expecting them to match exactly.

function Show-ExecutionContext {
    [pscustomobject]@{
        PID              = $PID
        Host             = $Host.Name
        PowerShell       = $PSVersionTable.PSVersion.ToString()
        Edition          = $PSVersionTable.PSEdition
        WorkingDirectory = (Get-Location).Path
        ProcessPath      = (Get-Process -Id $PID).Path
        Runtime          = [System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription
    }
}

"Current session:"
Show-ExecutionContext | Format-List

"Clean child process:"
pwsh -NoProfile -Command @'
[pscustomobject]@{
    PID              = $PID
    Host             = $Host.Name
    PowerShell       = $PSVersionTable.PSVersion.ToString()
    Edition          = $PSVersionTable.PSEdition
    WorkingDirectory = (Get-Location).Path
    ProcessPath      = (Get-Process -Id $PID).Path
    Runtime          = [System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription
} | Format-List
'@

The PIDs must differ. The engine version and executable may be the same if pwsh resolves to the same installation. The working directory is normally inherited. Profile-dependent state is intentionally absent in the child because -NoProfile was used.

Verification checklist

12. Knowledge check

Question 1. What is a runspace at a beginner-friendly level?

Question 2. Does a new pwsh process automatically inherit ordinary PowerShell variables from its parent?

Question 3. Why can a child process see an environment variable set by its parent?

Question 4. What happens before a resolved command actually performs its operation?

Question 5. Why can CI behavior differ from a personal terminal even when both run PowerShell 7?

13. Summary

A PowerShell session sits inside a layered execution system. The terminal presents interaction; a host connects the engine to an environment; an operating-system process owns lifetime and inherited environment; a runspace holds PowerShell session state; the engine parses, resolves, binds, executes, and emits objects or diagnostic streams; native commands create child-process boundaries. This model explains why state persists in one session but disappears—or must be explicitly transferred—across new processes and CI steps.

14. Further reading

Next

Turn this mental model into a safe working routine

Lesson 5 builds a disposable course workspace and teaches safe discovery, help, WhatIf, history awareness, verification, and cleanup conventions you will use throughout the remaining 95 lessons.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.