0% found this document useful (0 votes)
3 views88 pages

The Powershell Scripting And Toolmaking Book Forever Edition Don Jones pdf download

The document provides information about 'The PowerShell Scripting and Toolmaking Book Forever Edition' by Don Jones and Jeff Hicks, including links for downloading various editions of the book. It emphasizes the Lean Publishing process and encourages readers to provide feedback. Additionally, it includes a brief overview of the book's contents and other related works by the authors.

Uploaded by

djaedidiozu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views88 pages

The Powershell Scripting And Toolmaking Book Forever Edition Don Jones pdf download

The document provides information about 'The PowerShell Scripting and Toolmaking Book Forever Edition' by Don Jones and Jeff Hicks, including links for downloading various editions of the book. It emphasizes the Lean Publishing process and encourages readers to provide feedback. Additionally, it includes a brief overview of the book's contents and other related works by the authors.

Uploaded by

djaedidiozu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 88

The Powershell Scripting And Toolmaking Book

Forever Edition Don Jones download

https://ebookbell.com/product/the-powershell-scripting-and-
toolmaking-book-forever-edition-don-jones-43639080

Explore and download more ebooks at ebookbell.com


Here are some recommended products that we believe you will be
interested in. You can click the link to download.

The Powershell Scripting And Toolmaking Book Forever Edition 20200630


Don Jones Jeff Hicks

https://ebookbell.com/product/the-powershell-scripting-and-toolmaking-
book-forever-edition-20200630-don-jones-jeff-hicks-22511552

The Powershell Scripting And Toolmaking Book Don Jones Jeff Hicks

https://ebookbell.com/product/the-powershell-scripting-and-toolmaking-
book-don-jones-jeff-hicks-29875700

The Powershell Scripting And Toolmaking Book Don Jones Jeff Hicks Don
Jones Jeff Hicks

https://ebookbell.com/product/the-powershell-scripting-and-toolmaking-
book-don-jones-jeff-hicks-don-jones-jeff-hicks-29875704

The Powershell Scripting And Toolmaking Book Don Jones Jeff Hicks Don
Jones And Jeff Hicks

https://ebookbell.com/product/the-powershell-scripting-and-toolmaking-
book-don-jones-jeff-hicks-don-jones-and-jeff-hicks-29875714
The Powershell Scripting And Toolmaking Book Leanpubcom Don Jones Jeff
Hicks

https://ebookbell.com/product/the-powershell-scripting-and-toolmaking-
book-leanpubcom-don-jones-jeff-hicks-11236190

Powershell Essential Guide Master The Fundamentals Of Powershell


Scripting And Automation English Edition Jayaram

https://ebookbell.com/product/powershell-essential-guide-master-the-
fundamentals-of-powershell-scripting-and-automation-english-edition-
jayaram-54937054

The Definitive Guide To Powershell Advanced Scripting And Automation


Solutions For Modern It Environments And Operations Wesley Dunne

https://ebookbell.com/product/the-definitive-guide-to-powershell-
advanced-scripting-and-automation-solutions-for-modern-it-
environments-and-operations-wesley-dunne-58262498

Windows Powershell Cookbook The Complete Guide To Scripting Microsofts


Command Shell 3rd Edition Lee Holmes

https://ebookbell.com/product/windows-powershell-cookbook-the-
complete-guide-to-scripting-microsofts-command-shell-3rd-edition-lee-
holmes-49431868

Powershell Cookbook Your Complete Guide To Scripting The Ubiquitous


Objectbased Shell 4th Edition Lee Holmes

https://ebookbell.com/product/powershell-cookbook-your-complete-guide-
to-scripting-the-ubiquitous-objectbased-shell-4th-edition-lee-
holmes-33990128
The PowerShell Scripting and Toolmaking
Book
Forever Edition

Don Jones and Jeff Hicks


This book is for sale at http://leanpub.com/powershell-scripting-toolmaking

This version was published on 2022-01-29

This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.

© 2017 - 2022 Don Jones and Jeff Hicks


Tweet This Book!
Please help Don Jones and Jeff Hicks by spreading the word about this book on Twitter!
The suggested tweet for this book is:
I got The #PowerShell #Toolmaking book http://leanpub.com/powershell-scripting-toolmaking
@JeffHicks & @concentrateddon
The suggested hashtag for this book is #PowerShellToolmaking.
Find out what other people are saying about the book by clicking on this link to search for this
hashtag on Twitter:
#PowerShellToolmaking
Also By These Authors
Books by Don Jones
Become Hardcore Extreme Black Belt PowerShell Ninja Rockstar
Instructional Design for Mortals
How to Find a Wolf in Siberia
Tales of the Icelandic Troll
The Culture of Learning
Alabaster
Power Wave
Onyx
Superior Wave
Shell of an Idea
Verdant

Books by Jeff Hicks


The PowerShell Practice Primer
The PowerShell Conference Book
#PS7Now
Contents

About This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i

Dedication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iii

Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv

About the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v


Additional Credits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v

Foreword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi

Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
Pre-Requisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
Versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
The Journey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x
Following Along . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x
Providing Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x

A Note on Code Listings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi

Lab Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii


Create a Virtualized Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Use the Windows 10 Sandbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Adding Lab Files and Configuring PowerShell . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Assumptions Going Forward . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiv

Part 1: Review PowerShell Toolmaking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

Functions, the Right Way . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2


Tool Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Start with a Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Build a Basic Function and Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Adding CmdletBinding and Parameterizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Emitting Objects as Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
CONTENTS

Using Verbose, Warning, and Informational Output . . . . . . . . . . . . . . . . . . . . . . . . 4


Comment-Based Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Handling Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Are You Ready . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

PowerShell Tool Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5


PowerShell Tools Do One Thing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
PowerShell Tools are Testable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
PowerShell Tools are Flexible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
PowerShell Tools Look Native . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
An Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

Start with a Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13


Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

Build a Basic Function and Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17


Start with a Basic Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Create a Script Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Pre-Req Check . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Running the Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

Adding CmdletBinding and Parameterizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27


About CmdletBinding and Common Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Accepting Pipeline Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Mandatory-ness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Parameter Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Parameter Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

Emitting Objects as Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38


Assembling the Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Constructing and Emitting Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
A Quick Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

An Interlude: Changing Your Approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47


The Critique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
CONTENTS

Our Take . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

Using Verbose, Warning, and Informational Output . . . . . . . . . . . . . . . . . . . . . . . . 53


Knowing the Six Channels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Adding Verbose and Warning Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Doing More With Verbose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Informational Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

Comment-Based Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Where to Put Your Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Going Further with Comment-Based Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Broken Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

Handling Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Understanding Errors and Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Bad Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Two Reasons for Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Handling Exceptions in Our Tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Handling Exceptions for Non-Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Going Further with Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Deprecated Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

Basic Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Two Kinds of Bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
The Ultimate Goal of Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Developing Assumptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Debugging Tool 1: Write-Debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Debugging Tool 2: Set-PSBreakpoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Debugging Tool 3: The PowerShell ISE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Debugging Tool 4: VS Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

Verify Yourself . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118


The Transcript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Our Read-Through . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
CONTENTS

Our Answer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122


How’d You Do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

Part 2: Professional-Grade Toolmaking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

Going Deeper with Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126


Parameter Position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Multiple Parameter Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Value From Remaining Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Help Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Alias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
More CmdletBinding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
A Demonstration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

Advanced Function Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145


Defining an Alias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Specify Output Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Adding Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Use Your Command Name Programmatically . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
ArgumentCompleter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

Dynamic Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150


Declaring Dynamic Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Using Dynamic Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154

Writing Full Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155


External Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Using Platyps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Supporting Online Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
“About” Topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Making Your Help Updatable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

Unit Testing Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170


Starting Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Sketching Out the Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Making Something to Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Expanding the Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
But Wait, There’s More . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
CONTENTS

Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176


Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178

Extending Output Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179


Understanding Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
The Extensible Type System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Extending an Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Using Update-TypeData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

Advanced Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189


Getting Fancy with Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Getting Strict . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Getting Remote . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193

Command Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194


Getting in PowerShell’s Brain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194

Analyzing Your Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197


Performing a Basic Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Analyzing the Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

Controlling Your Source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201


The Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
Tools and Technologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

Converting a Function to a Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206


Class Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
Starting Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Doing the Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Making the Class Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Coding the Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
Adding a Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Making Classes Easy To Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Wrapping Up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

Publishing Your Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221


Begin with a Manifest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Publishing to PowerShell Gallery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Publishing to Private Repositories or Galleries . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
CONTENTS

Part 3: Controller Scripts and Delegated Administration . . . . . . . . . . . . . . . . . . . . . . 229

Basic Controllers: Automation Scripts and Menus . . . . . . . . . . . . . . . . . . . . . . . . . . 230


Building a Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Using UIChoice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Writing a Process Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235

Graphical Controllers in WPF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236


Design First . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
WinForms or WPF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
WPF Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Using .NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
Using XAML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
A Complete Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
Just the Beginning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
Recommendations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254

Proxy Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255


For Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Creating the Proxy Base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Modifying the Proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
Adding or Removing Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

Just Enough Administration: A Primer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266


Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
Theory of Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
Roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
Endpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274

PowerShell in ASP.NET: A Primer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275


Caveats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
The Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Beyond ASP.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276

Part 4: The Data Connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277

Working with SQL Server Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278


SQL Server Terminology and Facts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
CONTENTS

Connecting to the Server and Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279


Writing a Query . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Running a Query . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
Invoke-Sqlcmd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Thinking About Tool Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
Review Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286

Working with XML Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287


Simple: CliXML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
Importing Native XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
ConvertTo-Xml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
Creating native XML from scratch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299

Working with JSON Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301


Converting to JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
Converting from JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313

Working With CSV Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314


I Want to Script Microsoft Excel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Know Your Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
Custom Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Importing Gotchas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321

Part 5: Seriously Advanced Toolmaking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322

Tools for Toolmaking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323


Editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
3rd Party . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
PowerShell Community Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Books, Blogs and Buzz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
Recommendations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327

Measuring Tool Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329


Is Performance Important . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
Measure What’s Important . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
Factors Affecting Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
Key Take-Away . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
CONTENTS

PowerShell Workflows: A Primer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334


Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
Theory of Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
A Quick Illustration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
When to Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
Sequences and Parallels are Standalone Scopes . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
Workflow Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
Workflow Common Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
Checkpointing Workflows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
Workflows and Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347

Globalizing Your Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349


Starting Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
Make a Data File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
Use the Data File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
Adding Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355

Using “Raw” .NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356


Understanding .NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
Interpreting .NET Framework Docs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
Coding .NET Framework in PowerShell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
Loading Assemblies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
Wrap It . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363

Scripting at Scale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364


To Pipeline or not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
Foreach vs ForEach-Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Write-Progress . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
Leverage Remoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
Leverage Jobs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Leverage Runspaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
Design Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387

Scaffolding a Project with Plaster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388


Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
Plaster Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
CONTENTS

Invoking a Plaster Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389


Creating a Plaster Module Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
Creating a Plaster Function Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
Integrating Plaster into your PowerShell Experience . . . . . . . . . . . . . . . . . . . . . . . 407
Creating Plaster Tooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412

Adding Auto Completion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417


ValidateSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
Argument Completer Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
Advanced Argument Completers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424

Adding Custom Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425


Format.ps1xml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
Define a TypeName . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
Defining a View Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
Update-FormatData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
New-PSFormatXML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
Adding to a Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
Your Turn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
Let’s Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439

Adding Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440


Why Are You Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
Logging or Transcript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
Structured vs Unstructured . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
Write-Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442

Toolmaking Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446


Format Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449

Part 6: Pester . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451

Why Pester Matters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452

Core Pester Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455


Installing Pester . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
What is Pester . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
Pester’s Weak Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
Understand Unit Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
Sample Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
New-Fixture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
CONTENTS

Writing Testable Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461

What to Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463

Describe Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464

Context Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466


BeforeEach and AfterEach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466

It Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468

Should and Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471


Should Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472

Mocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
Where to Mock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
How to Mock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
Verifiable Mocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
Parameter Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
Mocking the Unmockable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477

Pester’s TESTDRIVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478


Clean Slate and Auto-Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
Working with Sample Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
Using TESTDRIVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479

Pester for Infrastructure Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482


Spinning Up the Validation Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
Taking Actual Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483
Testing the Outcomes of Your Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483

Measuring Code Coverage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484


Displaying Code Coverage Metrics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484
An Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485

Test-Driven Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489

Part 7: PowerShell 7 Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490

PowerShell 7 Scripting Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491


Updating Your Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491
Ternary Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492
Chain operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493
Null-Coalescing Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
Null Conditional Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496
ForEach-Object Parallel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497
CONTENTS

Using ANSI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498

Cross Platform Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501


Know Your OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501
State Your Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
Testing Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
Watch Your Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
Leverage Remoting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
Custom Module Manifests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513

Wish List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515

Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516


About This Book
The ‘Forever Edition’ of this book is published on LeanPub¹, an “Agile” online publishing platform.
That means the book is published as we write it, and that means we’ll be able to revise it as needed in
the future. We also appreciate your patience with any typographical errors, and we appreciate you
pointing them out to us - in order to keep the book as “agile” as possible, we’re forgoing a traditional
copyedit. Our hope is that you’ll appreciate getting the technical content quickly, and won’t mind
helping us catch any errors we may have made. You paid a bit more for the book than a traditional
one, but that up-front price means you can come back whenever you like and download the latest
version. We plan to expand and improve the book pretty much forever, so it’s hopefully the last one
you’ll need to buy on this topic!
You may also find this book offered on traditional booksellers like Amazon. In those cases, the book
is sold as a specific edition, such as “Second Edition.” These represent a point-in-time snapshot of
the book, and are offered at a lower price than the Agile-published version. These traditionally
published editions do not include future updates.

If you purchased this book, thank you. Know that writing a book like this takes hundreds of hours
of effort, during which we’re not making any other income. Your purchase price is important to
keeping a roof over our families’ heads and food on our tables. Please treat your copy of the book as
your own personal copy - it isn’t to be uploaded anywhere, and you aren’t meant to give copies to
other people. We’ve made sure to provide a DRM-free file (excepting any DRM added by a bookseller
other than LeanPub) so that you can use your copy any way that’s convenient for you. We appreciate
your respecting our rights and not making unauthorized copies of this work.
If you got this book for free from someplace, know that you are making it difficult for us to write
books. When we can’t make even a small amount of money from our books, we’re encouraged to
stop writing them. If you find this book useful, we would greatly appreciate you purchasing a copy
from LeanPub.com or another bookseller. When you do, you’ll be letting us know that books like
this are useful to you, and that you want people like us to continue creating them.

Please note that this book is not authorized for classroom use unless a unique copy has been
purchased for each student. No-one is authorized or licensed to manually reproduce the PDF
version of this book for use in any kind of class or training environment.

¹https://leanpub.com
About This Book ii

This book is copyrighted (c)2017-2020 by Don Jones and Jeffery Hicks, and all rights are reserved.
This book is not open source, nor is it licensed under a Creative Commons license. This book is not
free, and the authors reserve all rights.
Dedication
This book is fondly dedicated to the many hardworking PowerShell users who have, for more than
a decade, invite us into their lives through our books, conference appearances, instructional videos,
live classes, and more. We’re always humbled and honored by your support and kindness, and you
inspire us to always try harder, and to do more. Thank you.
Acknowledgements
Thanks to Michael Bender, who has selflessly provided a technical review of the book. Any
remaining errors are, of course, still the authors’ fault, but Michael has been tireless in helping
us catch many of them.
About the Authors
Don Jones received the Microsoft MVP Award recipient for 16 consecutive years for his work with
Windows PowerShell and administrative automation. He has authored dozens of books, articles,
white papers, and instructional videos on information technology, and today is a Vice President
in the Content team at Pluralsight.com. Don was also a co-founder of The DevOps Collective²,
which offers IT education programs, scholarships, and which runs PowerShell.org and PowerShell
+ DevOps Global Summit³ and other DevOps- and automation-related events.
Don’s recent writing focuses on business, instructional design, self-improvement, and fiction, and
can be found at http://leanpub.com/u/donjones⁴. You can follow Don on Twitter @concentratedDon.
He blogs at DonJones.com.
Jeff Hicks is a grizzled IT veteran with almost 30 years of experience, much of it spent as an
IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in
automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award. He works
today as an independent author, teacher and consultant. Jeff has taught and presented on PowerShell
and the benefits of automation to IT Pros worldwide for over a decade. Jeff has authored and co-
authored a number of books, writes for numerous online sites, is a Pluralsight author, and a frequent
speaker at technology conferences and user groups world-wide.
You can keep up with Jeff on Twitter (@JeffHicks) and on his blog at https://jdhitsolutions.com⁵.

Additional Credits
Technical editing has been helpfully provided not only by our readers, but by Michael Bender. We’re
grateful to Michael for not only catching a lot of big and little problems, but for fixing most of them
for us. Michael rocks, and you should watch his Pluralsight videos. However, anything Michael
didn’t catch is still firmly the authors’ responsibility.
²https://devopscollective.org
³https://events.devopscollective.org/
⁴http://leanpub.com/u/donjones_
⁵https://jdhitsolutions.com
Foreword
After the success of Learn PowerShell in a Month of Lunches, Jeff and I wanted to write a book that
took people down the next step, into actual scripting. The result, of course, was Learn PowerShell
Toolmaking in a Month of Lunches. In the intervening years, as PowerShell gained more traction
and greater adoption, we realized that there was a lot more of the story that we wanted to tell. We
wanted to get into help authoring, unit testing, and more. We wanted to cover working with different
data sources, coding in Visual Studio, and so on. These were really out of scope for the Month of
Lunches series’ format. And even in the “main” narrative of building a proper tool, we wanted to go
into more depth. So while the Month of Lunches book was still a valuable tutorial in our minds, we
wanted something with more tooth.
At the same time, this stuff is changing really fast these days. Fast enough that a traditional
publishing process - which can add as much as four months to a book’s publication - just can’t keep
up. Not only are we kind of constantly tweaking our narrative approach to explaining these topics,
but the topics themselves are constantly evolving, thanks in part to an incredibly robust community
building add-ons like Pester, Platyps, and more.
So after some long, hard thinking, we decided to launch this effort. As an Agile-published book on
LeanPub, we can continuously add new content, update old content, fix the mistakes you point out
to us, and so on. We can then take major milestones and publish them as “snapshots” on places like
Amazon, increasing the availability of this material. We hope you find the project as exciting and
dynamic as we do, and we hope you’re generous with your suggestions - which may be sent to us
via the author contact form from this book’s page on LeanPub.com. We’ll continue to use traditional
paper publishing, but through a self-publishing outlet that doesn’t impose as much process overhead
on getting the book in print. These hard copy editions will be a “snapshot” or “milestone edition” of
the electronic version.
It’s important to know that we still think traditional books have their place. PowerShell Scripting in
a Month of Lunches, the successor to Learn PowerShell Toolmaking in a Month of Lunches, covers
the kind of long-shelf-life narrative that is great for traditionally published books. It’s an entry-level
story about the right way to create PowerShell tools, and it’s very much the predecessor to this book.
If Month of Lunches is about getting your feet under you and putting them on the right path, this
book is about refining your approach and going a good bit further on your journey.
Toolmaking, for us, is where PowerShell has always been headed. It’s the foundation of a well-de-
signed automation infrastructure, of a properly built DSC model, and of pretty much everything else
you might do with PowerShell. Toolmaking is understanding what PowerShell is, how PowerShell
wants to work, and how the world engages with PowerShell. Toolmaking is a big responsibility.
My first job out of high school was as an apprentice for the US Navy. In our first six weeks, we
rotated through various shops - electronics, mechanical, and so on - to find a trade that we thought
Foreword vii

we’d want to apprentice for. For a couple of weeks, I was in a machine shop. Imagine a big, not-
climate-controlled warehouse full of giant machines, each carving away at a piece of metal. There’s
lubrication and metal chips flying everywhere, and you wash shavings out of yourself every evening
when you go home. It was disgusting, and I hated it. It was also boring - you set a block of metal
into the machine, which might take hours to get precisely set up, and then you just sat back and
kind of watched it happen. Ugh. Needless to say, I went into the aircraft mechanic trade instead.
Anyway, in the machine shop, all the drill bits and stuff in the machine were called tools and dies.
Back in the corner of the shop, in an enclosed, climate-controlled room, sat a small number of nicely-
dressed guys in front of computers. They were using CAD software to design new tools and dies for
specific machining purposes. These were the tool makers, and I vowed that if I was ever going to
be in this hell of a workplace, I wanted to be a toolmaker and not a tool user. And that’s really the
genesis of this book’s title. All of us - including the organizations we work for - will have happier,
healthier, more comfortable lives as high-end, air-conditioned toolmakers rather than the sweaty,
soaked, shavings-filled tool users out on the shop floor.
Enjoy!
Don Jones
Feedback
We’d love your feedback. Found a typo? Discovered a code bug? Have a content suggestion? Wish
we’d answered a particular question? Let us know.
Zeroth, make sure you’re not using Leanpub’s online reader, as it omits some of the front matter
from the book. Use the PDF, EPUB, or MOBI version, or a printed edition you bought someplace
else.
First, please have a chapter name, heading reference, and a brief snippet of text for us to refer to.
We can’t easily use page numbers, because our source documents don’t have any.
Second, understand that due to time constraints like having full-time jobs, we can’t personally
answer technical questions and so forth. If you have a question, please hop on the forums at
PowerShell.org⁶, where we and a big community of enthusiasts will do our best to help.
Third, keep in mind that the EPUB and MOBI formats in particular allow little control over things
like code formatting. So we can’t usually address those for you.
Then, head to the LeanPub website and use their email link⁷ to email us. We can’t always reply
personally to every email, but know that we’re doing our best to incorporate feedback into the
book.
Finally, accept our thanks!
⁶http://powershell.org
⁷https://leanpub.com/powershell-scripting-toolmaking/email_author/new
Introduction
Pre-Requisites
We’re assuming that you’ve already finished reading an entry-level tutorial like, Learn Windows
PowerShell in a Month of Lunches, or that you’ve got some solid PowerShell experience already
under your belt. Specifically, nothing on this list should scare you:

• Find commands and learn to use them by reading help


• Write very basic “batch file” style scripts
• Use multiple commands together in the pipeline
• Query WMI/CIM classes
• Connect to remote computers by using Remoting
• Manipulate command output to format it, export it, or convert it, using PowerShell commands
to perform those tasks

If you’ve already done things like written functions in PowerShell, that’s marvelous - but, you may
need to be open to un-learning some things. Some of PowerShell’s best practices and patterns aren’t
immediately obvious, and especially if you know how to code in another language, it’s easy to go
down a bad path in PowerShell. We’re going to teach you the right way to do things, but you need
to be willing to re-do some of your past work if you’ve been following the Wrong Ways.
We also assume that you’ve read PowerShell Scripting in a Month of Lunches, a book we wrote for
Manning. It provides the core narrative of “the right way to write PowerShell functions and tools,”
this book essentially picks up where that one leaves off. Look for that book in late 2017 from Manning
or your favorite bookseller. Part 1 of this book briefly slams through this “the right way” narrative
just to make sure you’ve got it in your mind, but the Month of Lunches title really digs into those
ideas in detail.

Versioning
This book is primarily written against Windows PowerShell v5/v5.1 running on Microsoft Windows.
In January 2018, Microsoft announced the General Availability of PowerShell Core 6.0, which
is a distinct cross-platform “branch” of PowerShell. This branch has now become PowerShell 7,
which was released in early 2020. As far as we can tell, everything we teach in this book applies
to PowerShell 7, too - although some of our specific examples may still only work on Windows
PowerShell, the concepts and techniques are applicable to PowerShell 7. However, PowerShell 7
includes some new scripting features which we’ll cover in a dedicated chapter or two.
Introduction x

The Journey
This book is laid out into seven parts:

1. A quick overview of “the right way” to write functions.


2. Professional-grade toolmaking, where you amp up your skills, comes next in a second narrative.
This part is less tightly coupled than the first, so you can just read what you think you need,
but we still recommend reading the chapters in order.
3. Moving on from toolmaking for a moment, we’ll cover different kinds of controller scripts that
can put your tools to use. Read these in whatever order you like.
4. Data sources are often a frustrating point in PowerShell, and so this part is dedicated to those.
Again, read whichever ones you think you need.
5. More advanced topics complete the book, and again you can just read these as you encounter
a need for them.
6. A high-level introduction to using Pester in your toolmaking development.
7. Scripting for the PowerShell 7 and cross-platform world.

Following Along
We’ve taken some pains to provide review Q&A at the end of most chapters, and to provide lab
exercises (and example answers) at the end of many chapters. We strongly, strongly encourage you
to follow along and complete those exercises - doing is a lot more effective than just reading. And
if you get stuck, hop onto the Q&A forums on PowerShell.org and we’ll try and unstick you. We’ve
tried to design the labs so that they only need a Windows client computer - so you won’t need a
complex, multi-machine lab setup. Of course, if you have more than one computer to play with,
some of the labs can be more interesting since you can write tools that query multiple computers
and so forth. But the code’s the same even if you’re just on a single Windows client, so you’ll be
learning what you need to learn.

Providing Feedback
Finally, we hope that you’ll feel encouraged to give us feedback on this book. There’s a “Contact
the Authors” form on this book’s page⁸ on LeanPub.com, and you’re also welcome to contact us on
Twitter @concentratedDon and @JeffHicks. You can also post in the Q&A forums on PowerShell.org,
which frankly is a lot easier to respond to than Twitter. If you purchased the “Forever Edition” of
this book on LeanPub, then you’ll see us incorporating suggestions and releasing a new build of the
book all the time. If you obtained the book elsewhere, we can’t turn your purchase into a LeanPub
account for you. However, when the book changes enough for us to publish a new “edition” to other
booksellers, that might be a time to pick it up on LeanPub instead, provided you understand the
“Agile publishing” model and are comfortable with it.
⁸http://leanpub.com/powershell-scripting-toolmaking
A Note on Code Listings
The code formatting in this book only allows for about 60-odd characters per line. We’ve tried our
best to keep our code within that limit, although sometimes you may see some awkward formatting
as a result.
For example:

Invoke-CimMethod -ComputerName $computer-MethodName Change -Query "SELECT * FROM Win\


32_Service WHERE Name = '$ServiceName'"

Here, you can see the default action for a too-long line - it gets word-wrapped, and a backslash
inserted at the wrap point to let you know. We try to avoid those situations, but they may sometimes
be unavoidable. When we do avoid them, it may be with awkward formatting, such as using
backticks (‘):

Invoke-CimMethod -ComputerName $computer `


-MethodName Change `
-Query "SELECT * FROM Win32_Service WHERE Name = '$ServiceName'" `

Here, we’ve given up on neatly aligning everything to prevent a wrap situation. Ugly, but oh well.
You may also see this crop up in inline code snippets, especially the backslash.

If you are reading this book on a Kindle, tablet or other e-reader, then we hope you’ll
understand that all code formatting bets are off the table. There’s no telling what the
formatting will look like due to how each reader might format the page. We trust you know
enough PowerShell to not get distracted by odd line breaks or whatever.

When you write PowerShell code, you should not be limited by these constraints. There’s no reason
for you to have to use a backtick to “break” a command. Simply type out your command. If you
want to break a long line to make it easier to read without a lot of horizontal scrolling, you can hit
Enter after any of these characters:

• Open parenthesis (
• Open curly brace {
• Pipe |
• Comma ,
• Semicolon ;
A Note on Code Listings xii

• Equal sign =

This is probably not a complete list, but breaking after any of these characters makes the most sense.
Anyway, we apologize for these artifacts. Keep in mind that you can, and should, use Install-Module
PowerShell-Toolmaking to download and install the code samples from the PowerShell Gallery.
They’ll end up in \Program Files\WindowsPowerShell\Modules\PowerShell-Toolmaking, typically
broken down by chapter. We try to update that download often, so if you don’t have the latest
version installed, do that.
Lab Setup
We hope that you plan to follow along with us in this book, and to help you do so we’ve provided
hands-on exercises at the end of most chapters. To complete those, you won’t need much of a lab
environment - just a Windows 10 (or later) computer to which you have Administrator access, and
which has Internet connectivity. Business editions (not “Home”) of Windows are recommended.
We’ve built the labs so that there’s no need for a domain controller, servers, or anything else.
We assume that your lab computer (or virtual machine) will have Internet access.

Create a Virtualized Environment


We know that most of our readers are technically savvy and more than likely have a preferred
virtualization tool. You might prefer Hyper-V or big a VMware fan. Or maybe something completely
different. If you would like to have a separate Windows 10 environment, we suggest downloading
the evaluation edition of Windows 10 from https://www.microsoft.com/en-us/evalcenter/evaluate-
windows-10-enterprise⁹. You should be able to use your virtualization tool of choice to create a new
virtual machine from the ISO file.

Use the Windows 10 Sandbox


Another option if you are running a recent Pro or Enterprise version of Windows 10 is to enable
the Windows Sandbox feature. You need a machine that supports virtualization and is enabled in
the BIOS. The sandbox is a completely separate Windows 10 instance that you can play in without
disturbing your main desktop. Although be aware that it is not persistent like a virtual machine. You
get a fresh experience every time you launch it.
To install, open up Control Panel and go to Add/Remove Windows Features to enable the feature. Or
run Enable-WindowsOptionalFeature -FeatureName Containers-DisposableClientVM. You’ll most
likely need to reboot.

Adding Lab Files and Configuring PowerShell


We have published all of the lab files for this book on the PowerShell Gallery, to make it easier to
install them.
⁹https://www.microsoft.com/en-us/evalcenter/evaluate-windows-10-enterprise
Lab Setup xiv

1. On your Windows computer, press Windows+R, type powershell, and press Enter.
2. Right-click the PowerShell icon on the Task Bar, and select Run as Administrator.
3. Click Yes.
4. In the new PowerShell window (which must say “Administrator: Windows PowerShell” in the
title bar), type Install-Module PowerShell-Toolmaking and press Enter.
5. You may be notified that “NuGet provider is required to continue.” Type Y and press Enter.
6. You may be notified of an “Untrusted repository.” Type Y and press Enter.
7. Type Set-ExecutionPolicy Bypass and press Enter.
8. Type Y and press Enter.

If the installation fails, or if you see an error or warning when setting the execution policy, ensure
that PowerShell is running as Administrator and that the computer has unrestricted Internet access.
On a company-owned computer, restrictions may be in place that prevent the installation of files or
the changing of the execution policy. You will need to consult your company’s IT administrators to
remedy that.
If you are new to scripting, you may also want to install the free Visual Studio Code, often referred to
as VS Code, from https://code.visualstudio.com/¹⁰. The PowerShell ISE that ships with Windows 10
isn’t going away, and we used it a lot to develop the material in this book. But it should be considered
deprecated. Microsoft is no longer developing it. All of their efforts are directed toward VS Code.
This product is updated frequently and has a rich ecosystem of extensions. In fact, after you install
it and launch it, click the gear icon in the lower left and then Extensions. Search for powershell and
install the extension.
We won’t lie. VS Code has a learning curve. But if you are new to scripting, you most likely would
have to learn the PowerShell ISE. If you have to spend time learning a tool you might as well learn
the tool that will be around for a while and as a bonus works cross-platform!

Assumptions Going Forward


Because scripting and toolmaking are not entry-level tasks, we assume that readers are already
aware of the need to run PowerShell “as Administrator” when developing scripts and tools. We
assume a basic level of familiarity with the PowerShell Integrated Scripting Environment (ISE), and
we assume an intermediate or higher level of familiarity with PowerShell itself. If you don’t feel
you meet these expectations, we suggest first completing Learn Windows PowerShell in a Month of
Lunches¹¹ available from most booksellers or from Manning.com.

¹⁰https://code.visualstudio.com
¹¹https://www.manning.com/books/learn-windows-powershell-in-a-month-of-lunches-third-edition
Part 1: Review PowerShell
Toolmaking
This first Part of the book is essentially a light-speed refresher of what PowerShell Scripting in a
Month of Lunches covers. If you’ve read that book, or feel you have equivalent experience, then this
short Part will help refresh you on some core terminology and techniques. If you haven’t… well, we
really recommend you get that fundamental information under your belt first.
Functions, the Right Way
This chapter is essentially meant to be a warp-speed review of the material we presented in the core
narrative of Learn PowerShell Toolmaking in a Month of Lunches (and its successor, PowerShell
Scripting in a Month of Lunches). This material is, for us, “fundamental” in nature, meaning it
remains essentially unchanged from version to version of PowerShell. Consider this chapter a kind
of “pre-req check;” if you can blast through this, nodding all the while and going, “yup,” then you’re
good to skip to the next Part this book. If you run across something where you’re like, “wait, what?”
then a review of those foundational, prerequisite books might be in order, along with a thorough
reading of this Part of this book.

By the way, you’ll notice that our downloadable code samples for this book (the “PSTool-
making” module in PowerShell Gallery) contain the same code samples as the core “Part 2”
narrative from PowerShell Scripting in a Month of Lunches. Those code samples also align
to this book, and we use them in this chapter as illustrations.

Tool Design
We strongly advocate that you always begin building your tools by first designing them. What
inputs will they require? What logical decisions will they have to make? What information will
they output? What inputs might they consume from other tools, and how might their output be
consumed? We try to answer all of these questions - often in writing! - up front. Doing so helps us
think through the ways in which our tool will be used, by different people at different times, and to
make good decisions about how to build the tool when it comes time to code.

Start with a Command


Once we know what the tool’s going to do, we begin a console-based (never in a script editor) process
of discovery and prototyping. Or, in plain English, we figure out the commands we’re going to need
to run, figure out how to run them correctly, and figure out what they produce and how we’re going
to consume it. This isn’t a lightweight step - it can often be time-consuming, and it’s where all of
your experimentation can occur.
A user in PowerShell.org’s forums once posted a request for help with the following:

I need a PowerShell script that will check a complete DFS Root, and report all targets and
access based enumeration for each. I then need the script to check all NTFS permissions
on all the targets and list the security groups assigned. I then need this script to search 4
domains and report on the users in these groups.
Functions, the Right Way 3

And yup - that’s what “Start with a Command” means. We’d probably start by planning that out -
inputs are clearly some kind of DFS root name or server name, and an output path for the reports
to be written. Then the discovery process would begin: how can PowerShell connect to a DFS root?
How can it enumerate targets? How can it resolve the target physical location and query NTFS
permissions? Good ol’ Google, and past experience, would be our main tool here, and we wouldn’t
go an inch further until we had a text file full of answers, sample commands, and notes.

Build a Basic Function and Module


With all the functional bits in hand, we begin building tools. We almost always start with a basic
function (no [CmdletBinding()] attribute) located in a script module. Why a script module? It’s the
end goal for us, and it’s easier to test. We’d fill in our parameters, and start adding the functional bits
to the function itself. We tend to add things in stages. So, taking that DFS example, we’d first write a
function that simply connected to a DFS root and spewed out its targets. Once that was working, we’d
add the bit for enumerating the targets’ physical locations. Then we’d add permission querying…
and so on, and so on, until we were done. None of that along-the-way output would be pretty - it’d
just be verifying that our code was working.

Adding CmdletBinding and Parameterizing


We’d then professional-ize the function, adding [CmdletBinding()] to enable the common parame-
ters. If we’d hard coded any changeable values (we do that sometimes, during development), we’d
move those into the Param() block. We’d also dress up our parameters, specifying data [types],
mandatory-ness, pipeline input, validation attributes, and so on. We’d obviously re-test.

Emitting Objects as Output


Next, we work on cleaning up our output. We remove any “development” output created by
Write-Output or Write-Host (yeah, it happens when you’re hacking away). Our function’s only
output would be an object, and in the DFS example it’d probably include stuff like the DFS root
name, target, physical location, and a “child object” with permissions.

If you’re really reading that DFS example, we’d probably stop our function at the point
where it gets the permissions on the DFS targets. The results of that operation could be used
to unwind the users who were in the resulting groups - a procedure we’d write as a separate
tool, in all likelihood.
Functions, the Right Way 4

Using Verbose, Warning, and Informational Output


If we hadn’t already done so, we’d take the time to add Write-Verbose calls to our function so that we
could track its progress. We tend to do that habitually as we write, almost in lieu of comments a lot
of the time, but we have built that up as a habit. We’d add warning output as needed, and potentially
add Write-Information calls if we wanted to create structured, queryable “sidebar” output.

Comment-Based Help
We’d definitely “dress up” our code using comment-based help, if not full help (we cover that later
in the book). We’d make sure to provide usage examples, documentation for each parameter, and a
pretty detailed description about what the tool did.

Handling Errors
Finally, and again if we hadn’t habitually done so already, we’d anticipate errors and try to handle
them gracefully. “Permission Denied” querying permissions on a file? Handled - perhaps outputting
an object, for that file, indicating the error.

Are You Ready


That’s our process. The entire way through, we make sure we’re conforming as much as possible to
PowerShell standards. Input via parameters only; output only to the pipeline, and only as objects.
Standardized naming, including Verb-Noun naming for the function, and parameter names that
reflect existing patterns in native PowerShell commands. We try to get our command to look and
feel as much like a “real” PowerShell command as possible, and we do that by carefully observing
what “real” PowerShell commands do.
Ok, if you’ve gotten this far and you’re still thinking, “yup, got all that and good to go,” then you’re…
well, you’re good to go. Proceed.
PowerShell Tool Design
Before you sit down and start whipping up a PowerShell function or class-based module, you need
to seriously think about its design. We almost constantly see toolmaking newcomers start charging
into their code, and before long they’ve made some monstrosity that is harder to work with than
it should be. Or they are totally lost and don’t know what to do next. In this chapter, we’re going
to lay out some core PowerShell tool design principles that we think, based on our experience, will
help keep you the path of PowerShell Toolmaking Righteousness.

PowerShell Tools Do One Thing


When you buy a wrench or a hammer, they are designed to fill a specific need. You wouldn’t use a
wrench to pound in a nail much less use a hammer to tighten a bolt. This philosophy carries over into
our world. The Prime Directive for a PowerShell tool is that it onlyt does one thing. You can see this
in almost every single PowerShell tool - that is, command - that ships with PowerShell. Get-Service
gets services. It doesn’t stop them. It doesn’t read computer names from a text file. It doesn’t modify
them. For that we can use Set-Service or Stop-Service. Commands in PowerShell do one thing.
This critical concept is one we see newcomers violate the most. For example, you’ll see folks build
a command that has a -ComputerName parameter for accepting a remote machine name, as well as
a -FilePath parameter so that you can alternately read computer names from a file. That’s Dead
Wrong, because it means the tool is doing two things instead of just one. A correct design would be to
stick with the -ComputerName parameter, and let it accept strings (computer names) from the pipeline.
You could also feed it names from a file by using a -ComputerName (Get-Content filename.txt)
parenthetical construct. The Get-Content command reads text files; you shouldn’t duplicate that
functionality without a really strong reason.

PowerShell Tools are Testable


Another thing to bear in mind is that - if you’re trying to make tools like a real pro - you’re going
to want to create automated units tests for your tools. We’ll actually get into how that’s done later
in this book, but from a design perspective, you want to make sure you’re designing tools that are,
in fact, testable. And trust us. In the long run you’ll be glad that you’ve designed your tools with
testing in mind.
One way to do that is, again, to focus on tightly-scoped tools that do just one thing. The fewer pieces
of functionality a tool introduces, the fewer things and permutations you’ll have to test. The fewer
logic branches within your code, the easier it will be to thoroughly test your code using automated
PowerShell Tool Design 6

unit tests. This also means when someone reports a bug in your code, it will be easier to find and
resolve.
For example, suppose you decide to design a tool that will query a number of remote computers.
Within that tool, you might decide to implement a check to make sure each computer is online and
reachable, perhaps by pinging it with Test-NetConnection. It makes sense in your head. But it might
be a bad idea. First, your tool is now doing two things: querying whatever it is you’re querying, but
also pinging computers. That’s two distinct sets of functionality. The pinging part, in particular, is
likely to be code you’d use in many different tools, suggesting it should, in fact, be its own tool.
Having the pinging built into the same querying tool will make testing harder, too, because you’ll
have to explicitly write tests to make sure that the pinging part works the way it’s supposed to.
An alternate approach would be to write that “Test-PCConnection” functionality as a distinct tool.
This code could use existing PowerShell commands wrapped up with features that make sense
in your environment. So, if your “querying” tool is something like “Get-SystemData,” you might
concoct a pattern like:

Get-Content computernames.txt | Test-PCConnection | Get-SystemData

The idea being that Test-PCConnection would filter out whatever computers weren’t reachable,
perhaps logging the failed ones in some fashion, so that Get-SystemData could just focus on its one
job of querying something. Both tools would then become easier to independently test, since they’d
each have a tightly scoped set of functionality.

If you needed to take this a step further, say by automating this task for the help desk, you
can put this pattern into a control script. Which is something we’ll cover later.

You also want to avoid building functionality into your tools that will be difficult to test. For example,
you might decide to implement some error logging in a tool. That’s great - but if that logging is
going to a SQL Server database, it’s going to be trickier to test and make sure that the logging is
working as desired. Logging to a file might be easier, since a file would be easier to check. An even
better approach would be to write a separate tool that handles logging. You could then test that tool
independently, and simply use it within your other tools. This gets back to the idea of having each
tool do one thing, and one thing only, as a good design pattern.

PowerShell Tools are Flexible


You want to design PowerShell tools that can be used in a variety of scenarios. This often means
wiring up parameters to accept pipeline input. For example, suppose you write a tool named
Set-MachineStatus that changes some setting on a computer. You might specify a -ComputerName
parameter to accept computer names. Will it accept one computer name, or many? Where will those
computer names come from? The correct answers are, “always assume there will be more than one,
PowerShell Tool Design 7

if you can” and “don’t worry about where they come from.” You want to enable, from a design
perspective, a variety of approaches.
It can help to actually sit down and write some examples of using your command that you intend to
work. These can become help file examples later, but in the design stage can help make sure you’re
designing to allow all of these. For example:

Get-Content names.txt | Set-MachineStatus


Get-ADComputer -filter * | Select -Expand Name | Set-MachineStatus
Get-ADComputer -filter * | Set-MachineStatus
Set-MachineStatus -ComputerName (Get-Content names.txt)

That third example is going to require some careful design, because you’re not going to be able to
pipe an Active Directory Computer object to the same -ComputerName parameter that also accepts a
String object from Get-Content! You may have identified a need for two parameter sets, perhaps one
using -ComputerName <string[]> and another using -InputObject <ADComputer> to accommodate
both scenarios. Now, creating two parameter sets is going to make the coding, and the automated
unit testing, a bit harder - so you’ll need to decide if the tradeoff is worth it. Will that third example
be used so frequently that it justifies the extra coding and test development? Or will it be a rare
enough scenario that you can exclude it, and instead rely on the similar second example?
The point is that every design decision you make will have downstream impact on your tool’s code,
its unit tests, and so on. It’s worth thinking about those decisions up front, which is why it’s called
the design phase!

Who and How


A lot of the ideas we’re discussing here come down to a fundamental set of questions. Who
will be using your tools and what are their expectations? Are you writing a command for the
help desk to use but they have minimal PowerShell experience? Are you creating something
that you will be using? Will the use be importing Excel spreadsheets to pass as parameter
values? What type of output do you need and how might it be used? Will your tool be used
in conjunction with something else you are developing? The more you understand who will
be using your tool and their expectations, the better your result.

PowerShell Tools Look Native


Finally, be very careful with tool and parameter names. Tools should always adopt the standard
PowerShell Verb-Noun pattern, and should only use the most appropriate verb from the list returned
by Get-Verb. Microsoft also publishes that list online¹² and the online list includes incorrect
variations and explanations that you can use to check yourself.
¹²https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands
PowerShell Tool Design 8

When you run Get-Verb in PowerShell 7, Microsoft has added a description for each verb.

Don’t beat yourself up too hard over fine distinctions between approved verbs, like the difference
between Get and Read. If you check out that website, you’ll realize that Get-Content should probably
be Read-Content; likely a distinction Microsoft came up with after Get-Content was already in the
wild.
The noun portion of your name should be singular, although we have been known to bend
this rule from time to time. What you should consider is the potential for a naming conflict.
Yes, there are ways to call the right PowerShell command but it can be a bit cumbersome so
why not avoid it altogether. We suggest you get in the habit of using a short prefix on your
command’s noun. For example, if you work for DonCo, Inc., then you might design commands
named Get-DCISystemStatus rather than just Get-SystemStatus. The prefix helps prevent your
command name from conflicting with those written by other people and it will make it easier to
discover and identify commands and tools created for your organization.
Parameter names should also follow native PowerShell patterns. Whenever you need a parameter,
take a look at native PowerShell commands and see what parameter name they use for similar
purposes. For example, if you need to accept computer names, you should use -ComputerName (notice
it’s singular!) and not some variation like -MachineName. If you need a filename, that’s usually
-FilePath or -Path on most native commands. Later in the book we’ll show you how to create a
parameter alias. This let’s you use the official and proper parameter name, like -Computername but
still let users of your tool use something like -Server.

An Example
Before we even start thinking about our design decisions, we like to review the business requirements
for a new tool. We try to translate those business requirements to usage examples, so it’s clearer to us
how a tool might be used. If there are other stakeholders to involve - such as the people who might
consume this tool, once it’s done - we get them to sign off on this “functional specification,” so that
we can go into the design phase knowing with clear, mutual expectations for the new tool. We also
try to capture problem statements that this new tool is meant to solve, because those sometimes
offer a clearer business perspective than a specification that someone else may have written. The
discussion might go something like this:

We’ve been managing servers in our data center with PowerShell and PowerShell remoting.
With the arrival of PowerShell 7, we will be able to use SSH for PowerShell remoting.
We won’t switch every server to SSH because some servers may rely on Just Enough
Administration. We need to inventory servers and identify which servers have PowerShell
remoting enabled. And if it is enabled, is it also configured to use SSL. Long term, we need
to move servers that must use WSMan remoting to use SSL. We also need to know if a server
already has ssh installed.
PowerShell Tool Design 9

That statement would drive some more detailed questions from us, asking for specifics on what the
tool needs to query. Suppose the answer came back as:

• Computer host name


• WSMan remoting enabled
• WSMan ports in use
• WSMan protocols
• Is SSH enabled
• A report date

There are a number of PowerShell commands to use, although Test-NetConnection might be a good
choice. We can plan on writing a tools called Get-RemoteListeningConfiguration. It is of course
going to have a -ComputerName parameter that accepts one or more computer names as strings.
Looking ahead with a PowerShell 7 migration coming, it might also be helpful to know the operating
system and current PowerShell version. That information could be part of this command, but since
the information doesn’t really apply to remoting, it might be best to keep that as a separate tool. We
might also take into account how computer names will be fed to the command and what we might
do with the output. We’ll assume that some computers won’t respond, so we’ll design a way to deal
with that situation.
Our design usage examples might be pretty simple:

Get-RemoteListeningConfiguration -Computername SRV1


Get-RemoteListeningConfiguration -Computername SRV1,SRV2
Get-Content servers.txt | Get-RemoteListeningConfiguration
Import-CSV servers.csv | Get-RemoteListeningConfiguration
Get-RemoteListeningConfiguration (Get-ADComputer -filter *).Name

The output of the command should be structured and predictable. That is, given a specific set of
inputs, we should get the same output, which will make this a fairly straightforward design to write
unit tests for. Our command is only doing one thing, and has very few parameters, which gives us
a good feeling about the design’s tight scope.
So we’d take that back to the team and ask what they thought. Almost invariably, that will generate
questions.

How will we know if a machine fails? Will the tool keep going? Will it log that information?
Does it need to log anything?

OK - we might need to evolve the design a bit. We know that we need to keep going in the event
of a failure, and give the user the option to log failures to, perhaps, a text file. Provided the team
was happy with a text file as the error log, we’re good including that in the design. If they wanted
something more complicated - the option to log to a database, or to an event log - then we’d design
a separate logging tool to do all of that. For the sake of argument, though, let’s say they’re OK with
the text file.
PowerShell Tool Design 10

Get-Content servers.txt | Get-RemoteListeningConfiguration -LogPath errorlog.txt

Let’s say that the team is satisfied with these additions, and that we have our desired usage examples
locked down. We can now get into the coding. But before we do, why don’t you take a stab at your
own design exercise?

Your Turn
If you’re working with a group, this will make a great discussion exercise. You won’t need a computer,
just a whiteboard or some pen and paper. The idea is to read through the business requirements and
come up with some usage examples that meet the requirements. We’ll provide all of the business
requirements in a single statement, so that you don’t have to “go back to the team” and gather more
information.

Start Here
Your team has come to you and asked you to design a PowerShell tool that will help them automate
a repetitive and critical, task. Team members are skilled in using PowerShell, so they just need a
command, or set of commands, that will help automate this task.

Members of the HelpDesk, as well as the Server Management Team, periodically manually
run a set of commands to get performance information that can be used to assess the status
or health of system. This information is often used to generate reports and to populate a
trend database. The information gathered includes these values:

• Computer name
• Total number of processes
• Total processor load
• % free physical memory
• % free space on drive C:
• The computer’s uptime

It would be helpful to have a single command to run that would generate a unified result. It
needs to be able to process multiple computers. And it will need to take credentials into
account. It would also be helpful to have some sort of optional logging mechanism for
failures.

Your Task
Your job is to design the tool that will meet the team’s business requirements. You are not writing any
code at this point. When creating a new tool, you have to consider who will use the tool, how they
PowerShell Tool Design 11

might use it and their expectations. And the user might be you! The end-result of your design will be
a list of command usage examples (like we have shown you previously), which should illustrate how
each of the team’s business needs will be solved by the tool. It’s fine to include existing PowerShell
commands in your examples, if those commands play a role in meeting the requirements.
Stop reading here and complete the task before resuming.

Our Take
We’ll design the command name as Get-TMComputerStatus. The “TM” stands for “Toolmaking,”
which is part of this book’s name, since we don’t have a specific company or organizational name
to use. We’ll design the following use cases:

Get-TMComputerStatus SRV1,SRV2
Get-Content servers.txt | Get-TMComputerStatus -credential company\administrator
(Get-ADComputer -filter *).name | Get-TMComputerStatus -ErrorLogFilePath err.log

Our intent here is that -Verbose will generate on-screen warnings about failures, while -ErrorLogFilePath
will write failed computer names to a file. It might also be nice to append errors to the same log.
Notice that, to make this “specification” easier to read, we’ve put each parameter on its own line.
The command won’t actually execute exactly like that, but that’s fine - clarity is the idea at this
point.

Get-TMComputerStatus -Computername SRV1,SRV2,SRV3 `


-Credential "company\administrator" `
-ErrorLogFilePath "statuserrors.txt" `
-ErrorAppend

This example uses -ErrorLogFilePath and -ErrorAppend to indicate logging errors to a text file and
appending.
And because the output might be used to generate reports or be consumed by other applications,
we’ll want to make sure our code will meet these scenarios:

Import-CSV servers.csv | Get-TMComputerStatus -credential $cred |


Export-CSV status.csv

Get-Content group1.txt | Get-TMComputerStatus |


ConvertTo-HTML <parameters>

Get-TMComputerStatus (Get-ADComputer -filter *).name |


Sort-Object Computername |
Format-Table -GroupBy Computername -property Date,Uptime,Pct* |
Out-File report.txt
PowerShell Tool Design 12

We’re illustrating two things here. First is that we can accept an imported CSV file, assuming it has
a Computername column. Our output is also consumable by standard PowerShell commands like
ConvertTo-HTML, which implies that Format- commands and Export- commands will also work.

Let’s Review
Let’s quickly review some of the key concepts from this chapter, just to make sure you’ve got them
all firmly in mind. See if you can answer these questions:

1. What’s the “prime directive” of PowerShell tool design?


2. What verb should you use instead of “Ping” in a command name?
3. What verb should you use instead of “Delete” in a command name?
4. What’s the most important output from a tool design process?
5. What is one downside of having an overly complex tool?

Review Answers
Not all of our questions lend themselves to easy, black-and-white answers, so if you didn’t answer
exactly the way we did, it doesn’t necessarily mean you’re wrong. But here’s how we’d have
answered:

1. Make tools that do one thing, and one thing only.


2. Test.
3. Remove.
4. A comprehensive set of usage examples for the proposed tool.
5. It will be harder to write comprehensive unit tests for it.
Start with a Command
Before we ever open up a script editor, we start in the basic PowerShell command-line window.
This is your “lowest common denominator” for testing, and it’s a perfect way to make sure that the
commands your tool will run are actually correct. It’s way easier to debug or troubleshoot a single
command in the window than it is to debug an entire script. And by “single command” we mean a
PowerShell expression.
If you’ve already read the previous chapter, then you know that we’ve been asked to develop a tool
that will query the following information:

• Computer name
• Total number of processes
• Total processor load
• % free physical memory
• % free space on drive C:
• The computer’s uptime
• a time stamp

We’ll plan to use CIM or CIM-related commands for much of this. We also know we’re going to
need to write a text log file in the event of errors. There’s more in terms of the tool itself we’ll need
to do, like adding a datetime stamp, but these are the basic units of functionality we need to figure
out.
We’re going to assume that you already know how to run PowerShell commands. If that’s not your
strong suit, please stop and go read Learn Windows PowerShell in a Month of Lunches, because it’s
all about discovering and running commands. Our point here is that we want to test and make sure
we know how to actually accomplish everything our tool needs to accomplish, by manually running
commands in the command-line window.
In our specific case, we want to also make sure we know how to reliably retrieve all of the
information in our list, which is going to involve more than one WMI/CIM class. We’ll need
Win32_OperatingSystem and Win32_Processor at the least. We could use Win32_LogicalDisk to get
C: drive information. Or we can use CIM-related commands like Get-Volume. Again - you should
know how to do these things already if you’re reading this book, so we’re not going to walk through
that entire “discovery” process.
We’re planning to use Get-CimInstance to do the actual querying, and because we’ll eventually
end up querying multiple classes, we’ll use New-CimSession and Remove-CimSession to create (and
then remove) a persistent connection to each computer, so that we can run all the queries over one
Start with a Command 14

connection. We’ll need to be able to detect errors in case the connection doesn’t work. Review the
help for New-CimSession if you’re not familiar with those tasks.
For now we’ll assume that all computers can be reached using the CIM cmdlets. If they can’t, that
probably means the server is in need of a major upgrade, and we’ll want to be able to log those
failures.

Since so much of this tool is getting performance related data, you may be wondering about
Get-Counter. This is a command designed to get performance information and can probably
gather most of what we need. For us there are a few potential gotchas. First, Get-Counter
relies on legacy remoting protocols like RPC and DCOM. It is not firewall friendly. Second,
the output from Get-Counter is a little convoluted and would take a few extra steps to get
the values we’re looking for. Get-CimInstance is a better (read that as modern) approach.
And it will be easier to get the values we need. But this is exactly the type of discussion you
need to have. What are the best PowerShell tools to use? What are the implications if we go
with one over another?

Your Turn
The previous chapter also included an exercise for you, and this one picks up where it left off. This
is where you’ll get to practice what we’ve preached in this chapter: making sure you know how to
accomplish everything that your tool will need to do, by starting in the PowerShell command-line
window.

Start Here
Remember that you are designing a tool that will get remoting configuration information for a
remote server. You don’t have to write any code at this point. Instead, mock up a sample output.
What PowerShell cmdlets do you think you will need to run? Come up with a list of examples on
how the command might be used. List what requirements you might need in order for your code to
run.

Your Task
Stop reading here and complete the task before resuming.

Our Take
For our exercise, we are creating a tool to get status information about a server. We know that we
assume at a minimum that the command can be run passing a single computername and writing an
object to the pipeline.
Start with a Command 15

PS C:\> Get-TMComputerStats -Computername SRV1

Computername : SRV1
Processes : 275
CPULoad : 13
PctFreeMemory : 50.9874975465509
PctFreeDrive : 39.1990451499511
Uptime : 1.20:48:21.2817144
Date : 7/20/2020 2:09:16 PM

We also assume the person running the script will import a list of computernames and want to be
able to export to a CSV file. If there are errors they should be written to a log file.

PS C:\> Get-Content c:\work\servers.txt |


Get-TMComputerstatus -ErrorLog c:\work\tmstatus-error.log -errorappend |
Export-CSV D:\status.csv -append

We’ll need commands like these to generate the necessary results:

• Get-Date
• Get-Volume
• Get-CimInstance -class win32_OperatingSystem
• Get-CimInstance -class win32_processor
• Get-CimInstance -class win32_process
• Out-File

Let’s Review
Here are a few questions you can answer to make sure you’ve picked up the key elements of this
chapter:

1. What is the value of testing commands in the command-line before you start writing a script?
2. Why is it important to understand how your command might be used?
3. Why is it critical that your command write an object to the pipeline?

Review Answers
Here are our answers to the questions. Note that these aren’t necessarily the only correct answers,
but hopefully they’ll help you understand if you grasped the chapter’s material or not.
Start with a Command 16

1. Individual commands are easier to test and fix in the command-line window. Using tested
commands in your script will help reduce the number of bugs that you introduce while coding.
Remember, that if you command fails at the console it won’t work in your script any better.
2. If you don’t know who your command will be used, you won’t be able to include necessary
features like input from the pipeline.
3. If your command doesn’t write an object to the pipeline, than you can’t process the results
with other PowerShell commands like Where-Object, Sort-Object or Out-Gridview.
Build a Basic Function and Module
In this chapter, we’ll start creating the tool that we designed in “Tool Design,” using some of the
commands that we figured out and tested in the previous chapter. It’s very important to understand
that this chapter isn’t going to attempt to build the entire tool, or attempt to solve the entire business
statement from our Design chapter. We’ll be taking things one step at a time, because it’s really the
process of toolmaking that we want to demonstrate for you.

Start with a Basic Function


Basic functions have existed in PowerShell since v1, and they are one of the many types of commands
that PowerShell understands (some of the others being cmdlets, applications, workflows, and so on).
Functions make a great unit of work for toolmaking, so long as you follow a basic principle of
keeping your function tightly scoped and self-contained. We’ve written already about the need to
have tightly scoped functions - that is, functions that do just one thing. Self-contained means that
the function needs to live in its own little world, and become a kind of little black box. Practically
speaking, that means two things:
Information to be used inside the function should come only from declared input parameters. Of
course, some functions may “look up” data from elsewhere, like a database or a registry, and that’s
fine if it’s what the function does. But functions shouldn’t rely on external variables or other sources.
You want them as self-contained as possible.* Output from a function should be to the PowerShell
pipeline only. Stuff like creating a file on disk, updating a database, and other actions aren’t output,
they’re actions. Obviously, a function can perform one of those actions if that’s what the function
does.

Design the Input Parameters


Looking back through the design for your function to get computer status details, what information
will the function need? Your usage examples should already provide pretty clear guidance on what
parameters you’ll have to create, which is one reason we recommend creating usage examples as
tht primary design deliverable. So now let’s create basic versions of those parameters.
Build a Basic Function and Module 18

Function Get-TMComputerStatus {
Param(
[string[]]$Computername,
[string]$ErrorLogFilePath,
[switch]$ErrorAppend
)
}

Notice how careful we’re being with the formatting of this code? In order to conserve space in this
book, we’re only indenting the code a little bit within the function and within the Param() block,
but you’ll typically indent four spaces (which, in most code editors, is what the Tab key will insert).
Do not get lazy about your code formatting. Lazy formatting is a sign of the devil, and is a sure
sign of code that probably has bugs - and will be hard to debug.
In the Param() block, we’ve only had to declare a few parameters. The Computername is pretty
straightforward. Although thinking ahead, we might need to take alternate credentials into account.
for the computer to query. We also have parameters related to the logging we want to do.

For those of you looking for some nits to pick, yeah, there’s probably one here. An argument
could be made that logging is a second thing the command is doing and it should not be
part of this command. On the other hand, a counter argument might be that the task of
getting computer status information by design includes logging. Semantics. But if nothing
else, including these parameters offers us some “teachable moments” so we’re going to go
with it.

Parameter definitions are very simple declarations, and we’ll build on these in upcoming chapters.
For now, here are some things to notice:

• Data types are enclosed in square brackets. Common ones include [string], [int], and
[datetime].
• Parameters become variables inside the function, so their names are preceded with a $. And
for God’s sake, don’t try to create a parameter name with spaces!
• Each parameter is separated from the next by a comma. You don’t have to put them one-per-
line as we’ve done, but when we start building on these, it’ll be a lot easier to read if they’re
broken out one per line.
• The -ComputerName parameter will accept one or more values in an array, which is what
[string[]] denotes.

Write the Code


Now let’s insert some basic functional code. Again this will not complete the tool’s entire mission
- we’re just getting started, and we want to walk you through each step.
Build a Basic Function and Module 19

Function Get-TMComputerStatus {
Param(
[string[]]$Computername,
[string]$ErrorLogFilePath,
[switch]$ErrorAppend
)

foreach ($computer in $Computername) {


# get data via Get-CimInstance and Get-Volume
# create output object
} #foreach #computer

} #Get-TMComputerStatus

Notice that we tagged a #Get-TMComputerStatus comment on the closing bracket of the function?
That’s a good habit to get into when you have a closing bracket, as it can help remind you which
construct the bracket closes. You’ll appreciate this when you have a script file with multiple functions
defined.
We know we’ll need to run Get-CimInstance and maybe Get-Volume. At some point all of these
outputs will need to be condensed down to a simple, unified object. The basic command also doesn’t
include any error handling at this point. But this should be enough to give us a feel for how the
command will be structured and how the execution will flow internally.

Details: The ForEach Construct

Our code uses a ForEach construct. It works a bit like PowerShell’s ForEach-Object command, but
it has a different syntax:

ForEach ($item in $collection) {


# code
}

The second variable - $collection here, and $ComputerName in our preliminary function - is
expected to contain zero or more items. The ForEach loop will execute its {script block} one time
for each item that is contained in the second variable. So, in Get-RemoteListeningConfiguration,
if we provided three computer names to the -ComputerName parameter, the ForEach loop would run
three times. Each time the loop runs, one item is taken from the second variable and placed into the
first. So, within the script block above, $item will contain one thing at a time from $collection. In
the defined function, $computer will contain one string at a time, taken from $ComputerName.
You’ll often see people use singular and plural words in their ForEach loops:
Build a Basic Function and Module 20

$names = Get-Content names.txt


ForEach ($name in $names) {
# code
}

That approach makes it easier to remember that $name contains one thing from $names, but that’s
purely for human readability. PowerShell doesn’t magically know that “name” is the singular of
“names,” and it doesn’t care. The above could easily be rewritten as:

$unicorns = Get-Content names.txt


ForEach ($purple in $unicorns) {
# code
}

And PowerShell would be perfectly happy. That code would be a lot harder to read and keep track
of, though. In our sample function, you’ll notice that our second variable is not plural, right?

foreach ($computer in $computername) {

That’s because $ComputerName is one of our function’s input parameters. PowerShell’s convention
is to use singular words for command and parameter names. You won’t see -ComputerNames; you
only see -ComputerName as a parameter. We stuck with the convention, and so our ForEach loop
doesn’t follow a singular/plural pattern. Again, PowerShell itself doesn’t care, and we feel it’s more
important that our “outward-facing” elements - command and parameter names - follow PowerShell
naming conventions. And, honestly, using $computer as our one-item-at-a-time variable name saves
a little space in this book.

Design the Output


Finally, we need to have the command output something. We’ll add that in this version.

Function Get-TMComputerStatus {
Param(
[string[]]$Computername,
[string]$ErrorLogFilePath,
[switch]$ErrorAppend
)

foreach ($computer in $Computername) {


$OS = Get-CimInstance win32_operatingsystem -computername $computer |
Select-Object -property CSName,TotalVisibleMemorySize,FreePhysicalMemory,
NumberOfProcesses,
Build a Basic Function and Module 21

@{Name="PctFreeMemory";Expression = {($_.freephysicalmemory/`
($_.TotalVisibleMemorySize))*100}},
@{Name="Uptime";Expression = { (Get-Date) - $_.lastBootUpTime}}

$cpu = Get-CimInstance win32_processor -ComputerName $computer |


Select-Object -Property LoadPercentage

$vol = Get-Volume -CimSession $computer -DriveLetter C |


Select-Object -property @{Name = "PctFreeC";Expression = `
{($_.SizeRemaining/$_.size)*100 }}

$os,$cpu,$vol

} #foreach $computer

} #Get-TMComputerStatus

The output in the book has been formatted to fit the page.Normally you wouldn’t need to break
lines using the back tick. This code works and writes results to the pipeline. However, this version is
breaking the cardinal rule of writing more than 1 type of object to the pipeline. We’ll need to refine
this code to get a single object type out of it. That’s coming up in the next few chapters.

Create a Script Module


Our last step will be to save all of this code as a script module. These are supported on PowerShell v2
and later, and should ideally be stored in one of the paths specified in the PSModulePath environment
variable. On PowerShell v4 and later, the default path includes C:Program FilesWindowsPower-
ShellModules, so that’s where we’ll create our module. Specifically, we’ll save it as C:Program
FilesWindowsPowerShellModulesToolmakingToolmaking.psm1. Notice that the subfolder name
and the filename must match in order for PowerShell to automatically discover our module and
load it on-demand.
We’re also going to create a module manifest. This isn’t strictly required, but it’s a good idea. A
properly designed manifest can speed up PowerShell’s module auto-discovery, and as our module
becomes more complex will offer us some useful features. To create the manifest, we’ll run:
Another Random Document on
Scribd Without Any Related Topics
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
back
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.

More than just a book-buying platform, we strive to be a bridge


connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.

Join us on a journey of knowledge exploration, passion nurturing, and


personal growth every day!

ebookbell.com

You might also like