Interview PrepLesson 16 of 16

Interview Preparation — PowerShell

Comprehensive question bank covering all 15 course topics: beginner fundamentals, intermediate scripting patterns, advanced remoting and Azure automation, and scenario-based questions that probe real-world problem solving.

🎯 Beginner Questions

These questions test fundamental understanding of PowerShell as a tool and language. Expect them in DevOps Engineer, Cloud Engineer, and Windows Administrator interviews.

What is PowerShell and how does it differ from Command Prompt (cmd.exe)?

PowerShell is a cross-platform shell and scripting language built on .NET. The key difference is that PowerShell works with objects, not text. When Get-Process returns data, it returns Process objects with properties you can sort, filter, and manipulate. cmd.exe returns plain text strings that must be parsed. PowerShell has a structured language (foreach, if, functions, classes), named parameters, full error handling, and access to the entire .NET ecosystem.

What is a cmdlet? Give three examples.

A cmdlet is a compiled .NET command in PowerShell that follows the Verb-Noun naming convention. Examples: Get-Process (retrieves running processes), Stop-Service (stops a Windows service), New-Item (creates a file or directory). You can discover cmdlets with Get-Command and learn any cmdlet with Get-Help CommandName -Examples.

What is the PowerShell pipeline and why is it useful?

The pipeline passes objects from one cmdlet to the next using the | character. Each cmdlet receives the output objects of the previous one. This enables chaining: Get-Process | Where-Object CPU -gt 10 | Sort-Object CPU -Descending | Select-Object -First 5 — get all processes, filter to those using over 10% CPU, sort by CPU descending, take the top 5. No intermediate variables, no manual loops.

What is the difference between single and double quotes in PowerShell?

Double quotes ("...") perform variable interpolation and special character expansion. "Hello $name" outputs the value of $name. Single quotes ('...') are literal strings—no interpolation occurs. 'Hello $name' outputs the literal text Hello $name. Use single quotes when you want no variable expansion (especially in regex patterns where $ is a regex anchor).

What are the PowerShell comparison operators for equality, greater than, and pattern matching?

PowerShell uses alphabetic operators: -eq (equal), -ne (not equal), -gt (greater than), -lt (less than), -ge (greater or equal), -le (less or equal), -like (wildcard pattern like foo*), -match (regex match). Unlike other languages, PowerShell does NOT use == or !=.

What is an execution policy? What is RemoteSigned?

Execution policy controls which PowerShell scripts can run. It is not a full security boundary but protects against accidentally running untrusted scripts. RemoteSigned: scripts written locally run without signature; scripts downloaded from the internet require a digital signature from a trusted publisher. It is the recommended setting for most Windows servers.

How do you define a variable in PowerShell?

Use the $ sigil: $name = "Alice". Variables are not strongly typed by default, but you can type-constrain with [string], [int], [bool], etc.: [int]$count = 5. Arrays use @(): $servers = @("web01","web02"). Hashtables use @{}: $config = @{ port = 443; host = "example.com" }.

What is Get-Help and why should you use it?

Get-Help displays documentation for any cmdlet, function, or concept. Get-Help Get-Process shows the synopsis. Get-Help Get-Process -Examples shows usage examples. Get-Help Get-Process -Full shows all parameter details. It is the first command to run when you encounter an unfamiliar cmdlet—you never need to look up the internet for basic PowerShell command documentation.

🎯 Intermediate Questions

These test hands-on scripting ability. Expect them in cloud engineer, DevOps engineer, and platform engineer interviews.

What does [CmdletBinding()] do and why should every function have it?

[CmdletBinding()] promotes a function to an "advanced function" with built-in support for -Verbose, -Debug, -WhatIf (if SupportsShouldProcess is set), -ErrorAction, and other common parameters. Without it, your function does not respond to these pipeline-standard parameters. Every production function should have it—it makes functions behave like built-in cmdlets from the caller's perspective.

What is the difference between terminating and non-terminating errors?

A terminating error stops execution immediately (like a thrown exception). A non-terminating error writes to the error stream and continues execution by default. Most cmdlets produce non-terminating errors, which is why $ErrorActionPreference = 'Stop' is essential in scripts—it converts non-terminating errors to terminating ones, ensuring your script does not silently continue past failures.

How do you handle errors in PowerShell scripts?

Use try/catch/finally blocks. Set $ErrorActionPreference = 'Stop' so non-terminating errors become catchable. In the catch block, use $_ or $PSItem to access the exception. Include context in error messages. Use finally for cleanup that must always run. For external tools, check $LASTEXITCODE -ne 0 after every call and throw explicitly.

How do you create a structured object in PowerShell and why use [PSCustomObject]?

[PSCustomObject]@{} creates a structured .NET object with named properties. Unlike a hashtable, it preserves insertion order, works cleanly with Format-Table and Export-Csv, and supports Get-Member. It is the right choice whenever you want to represent a row of data or return a rich result from a function. Hashtables are better for key-value lookups; PSCustomObject is better for tabular/structured data.

Why does ConvertTo-Json sometimes output @{} strings instead of nested objects?

ConvertTo-Json defaults to -Depth 2. Any object nested deeper than 2 levels is converted to its ToString() representation, which for hashtables and PSCustomObjects prints as @{Key=Value; ...}. Fix: always use ConvertTo-Json -Depth 10 (or higher) when serializing objects with nested structure. There is almost never a reason to use the default depth in production code.

What is a PowerShell module and how do you create one?

A module is a collection of functions, variables, and aliases packaged as a .psm1 (script module) or compiled .dll (binary module). To create one: place your functions in a .psm1 file, create a .psd1 manifest with New-ModuleManifest that lists exported functions, and import with Import-Module. The directory name must match the .psd1 filename. Modules are the standard way to share reusable PowerShell automation across a team.

What does the $_ (or $PSItem) variable represent?

$_ (alias: $PSItem) is the current pipeline object. In a ForEach-Object block, {$_} refers to the current item. In a Where-Object filter, {$_.CPU -gt 10}, $_ is each object being tested. In a catch block, $_ is the current exception. It is PowerShell's context-sensitive "current item" variable.

How does Set-StrictMode -Version Latest improve script quality?

Set-StrictMode -Version Latest enforces strict syntax rules: accessing a variable that has never been defined is an error (not silently $null), calling methods on $null is an error, and functions must not use $? implicitly. This catches a large class of subtle bugs like typos in variable names that would otherwise silently produce $null and cause logic errors later. Use it at the top of every production script.

🎯 Advanced Questions

These probe depth of knowledge in large-scale automation, Azure, and CI/CD scenarios.

What is PowerShell Remoting and what problem does Invoke-Command solve?

PowerShell Remoting uses WinRM (WS-Management protocol) to run commands on remote machines. Invoke-Command solves the problem of managing Windows server fleets at scale: you can run the same script block on 30 servers simultaneously with one command, instead of logging into each server individually. Results return as deserialized objects you can inspect and export.

What is the double-hop problem and how do you resolve it?

The double-hop problem occurs when a PowerShell remote session on Server A tries to access a second network resource (Server B, a file share). Kerberos cannot forward the authentication credentials a second time by default. Resolutions: (1) copy required files to the remote machine with Copy-Item -ToSession before running remote commands, (2) configure CredSSP credential delegation (security implications—use carefully), (3) use service accounts with pre-authorized access to the third resource, or (4) use resource-based Kerberos constrained delegation.

How do you authenticate to Azure in a CI/CD pipeline without storing credentials in scripts?

Three options in order of preference: (1) Managed Identity with Connect-AzAccount -Identity for Azure-hosted agents/VMs—no credentials anywhere. (2) Azure DevOps service connection with AzurePowerShell@5 task—the platform injects the auth token from the configured service principal automatically. (3) Service principal credentials stored as pipeline secret variables, accessed as $env:SP_SECRET in the script. Never hardcode credentials in script files or YAML.

Your PowerShell pipeline step shows "Succeeded" but the deployment failed. How do you diagnose?

Check: (1) Is $ErrorActionPreference = 'Stop' set at the top? (2) Are all external tool calls followed by $LASTEXITCODE checks? (3) Are any catch blocks using Write-Warning instead of throw/exit 1? (4) Is Write-Error being used without -ErrorAction Stop upstack? Run locally with step-by-step tracing (Set-PSDebug -Trace 1) to find the silent exit path. Add explicit exit 1 in every failure branch and remove -ErrorAction SilentlyContinue from any critical calls.

How do you pass local variables into a remote Invoke-Command script block?

Use the $Using: scope modifier. Local variables are not automatically available inside remote script blocks. $Using:threshold inside a script block serializes and passes the local $threshold variable to the remote session. This works for simple types (strings, ints, arrays). Complex objects may lose methods during serialization—pass primitive values and reconstruct on the remote side.

🎯 Scenario-Based Questions

These are the "tell me about a time when..." and "how would you..." questions interviewers use to probe real experience.

You need to deploy an application to 20 IIS web servers during a 30-minute maintenance window. Walk me through your approach using PowerShell.

Stage the build artifact on a network share or Azure Blob. Create a $servers array of all 20 hostnames. Use a persistent session approach or Invoke-Command with $servers in the -ComputerName array. Script block: stop W3SVC, copy the new app folder from the network share (or use Copy-Item -ToSession), verify file hash matches the source, extract/replace application files, start W3SVC, return the service status as a PSCustomObject. With ThrottleLimit 20, all 20 servers run in parallel. Collect results, check for any failures, and exit 1 if any server failed. Log results to CSV for the audit trail.

You have 200 Azure VMs across 40 resource groups. You need to enforce required tags (team, project, environment) and auto-remediate missing ones. How do you do it?

Write a PowerShell runbook in an Azure Automation Account using Managed Identity. Get-AzResource across all resource groups (no -ResourceGroupName filter). For each resource, check .Tags for the required keys. Build a compliance report as a CSV. For remediation, use Update-AzTag with -Operation Merge to add only the missing tags with placeholder values (flagging them for human review). Schedule the runbook to run daily. Export the compliance report to an Azure Blob as a governance artifact. Send alerts via webhook if non-compliant count exceeds a threshold.

A CI/CD pipeline runs a PowerShell script that calls 'az' CLI commands. Sometimes the pipeline fails at odd places. How would you make it more robust?

Add $ErrorActionPreference = 'Stop' at the top. After every az command, check $LASTEXITCODE and throw explicitly if non-zero: if ($LASTEXITCODE -ne 0) { throw "az deployment failed: $LASTEXITCODE" }. Wrap major operations in try/catch blocks with Write-Error (not Write-Warning) and exit 1 in catch. Add Write-Host output before and after each major step for log traceability. Consider moving complex logic to a .ps1 file and using -FilePath in the YAML task rather than inline scripts for better maintainability.

Describe how you would build an automated disk space alert system using only PowerShell and Azure services.

Create an Azure Automation Account. Write a runbook that uses Invoke-Command in parallel across all Windows VMs to collect disk usage via Get-PSDrive. Build PSCustomObjects per drive with usage percentage. Filter results for drives over 85% full. For alerting, use Invoke-RestMethod to call a Teams Webhook or Logic App HTTP trigger with the alert payload. Schedule the runbook every 30 minutes. Store historical results in Azure Table Storage using the Az.Storage module for trending. Alternatively, push to Log Analytics via the REST API for integration with Azure Monitor alerting rules.

A team member's PowerShell script works on their laptop but fails on the CI/CD agent with "module not found." What are the possible causes and how do you fix them permanently?

Possible causes: (1) module installed in CurrentUser scope on the developer's laptop but not present on the agent image, (2) PowerShell version mismatch—module installed in PS 7's path but agent runs PS 5, (3) PSModulePath on the agent does not include the module's install location. Permanent fixes: add an Install-Module guard at the top of the script that installs if not found, pin the module version to avoid future drift, or add the Install-Module command as a pipeline step before the main script runs. Best practice: specify the module version in #Requires -Modules Az.Accounts@2.15 to make version requirements explicit.

How do you structure a PowerShell automation codebase for a team of 6 engineers?

Organize as a module: shared functions in a .psm1 with a .psd1 manifest that explicitly exports public functions. Keep one function per file under a Functions/ subfolder. Separate scripts (entry points that accept parameters) from functions (reusable logic). Store all scripts in source control. Use Pester for unit tests. Set up a PowerShell module CI pipeline that runs Pester tests, validates module imports cleanly, and publishes to an internal NuGet/PowerShell Gallery on merge to main. Document public functions with comment-based help (.SYNOPSIS, .PARAMETER, .EXAMPLE). Engineers install the team module from the internal gallery — no copy-pasting between repos.

📝 Quick Reference Card

powershell
# Pattern: production script header (always use this)
#Requires -Version 7.0
#Requires -Modules Az.Accounts
[CmdletBinding(SupportsShouldProcess)]
param( [Parameter(Mandatory)][string]$Environment )
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

# Pattern: safe file copy
if (-not (Test-Path $Destination)) { New-Item -ItemType Directory -Path $Destination -Force }
Copy-Item -Path $Source -Destination $Destination -Recurse -Force

# Pattern: safe service management
try { Stop-Service $svcName -Force } catch { Write-Warning "Could not stop $svcName: $_" }

# Pattern: external tool call with exit code check
& dotnet publish .\src -o .\out
if ($LASTEXITCODE -ne 0) { throw "dotnet publish failed: $LASTEXITCODE" }

# Pattern: parallel remote fleet check
$results = Invoke-Command -ComputerName $servers -ThrottleLimit 20 -ScriptBlock {
    [PSCustomObject]@{ Host = $env:COMPUTERNAME; Status = (Get-Service W3SVC).Status }
}
$failed = $results | Where-Object Status -ne 'Running'
if ($failed) { throw "IIS not running on: $($failed.Host -join ', ')" }

# Pattern: Azure resource provision
$tag = @{ team = "platform"; env = $Environment }
New-AzResourceGroup -Name "rg-$Project-$Environment" -Location "uksouth" -Tag $tag -Force