Modern IT Automation with PowerShell
Modern IT Automation with PowerShell
Modern Automation with PowerShell
About the Book
Learning about PowerShell Automation Tools and Techniques just got easier!
Influenced by past PowerShell Conference Books, Modern IT Automation with PowerShell aims to provide you with a more academic format, worthy of use as a teaching tool. The book is divided into five domains; each section contains contributions from subject experts within the PowerShell Community. Whether you are a student, just getting started in IT, or a seasoned professional that casually uses PowerShell, you will benefit from reading this book.
Collaboration
Learn the tools and terminology used in a collaborative DevOps setting with practical examples and best practices.
Testing
There's good code, and there's great code. Learn how to build testable and maintainable PowerShell scripts that are professional grade.
PowerShell in Depth
Dive into advanced topics such as logging, refactoring, and code design. Understand what it takes to build efficient automation and solve complex problems.
Regex
From basic to deep dive topics, this section will equip you with enough knowledge to master Regex in PowerShell, no matter the OS platform.
Security
Secure your PowerShell automation through script signing, execution policies, Constrained Language Mode (CLM), and Just Enough Administration (JEA).
All proceeds go to The DevOps Collective On-Ramp Program, providing scholarships to conferences and training for under-represented demographics in IT.
About the Contributors
Nicholas is a research chemist and software developer with a background in carbon-based (organic) photovoltaics, pattern matching, and data processing. He has experience in synthetic organic chemistry, analytical chemistry, and data automation in C# and PowerShell.
I work for MOQdigital in sunny Brisbane, Australia as a Solution Specialist - DevOps. My passion is automation and using my DevOps experience to help others to make life easier.
Steven Judd is a Windows Systems Engineer at Meta Platforms Inc. with an emphasis on Enterprise Messaging and Digital Loss Prevention. He co-developed a custom PowerShell training program for a Fortune 100 organization, and is an occasional presenter at PowerShell user groups. He spends free time learning more about PowerShell, digital security, and cloud technologies, along with creating and telling dad jokes. You can find him hanging out in the PowerShell bridge channel, taking care of his family, running marathons, playing the cello, plus a handful of other hobbies he just can't seem to quit.
Kevin Laux is the Manager of a Application Platform Engineering team. He has held various roles in End User Computing, Virtualization and Application Platforms. He is passionate about Automation, Home Labs, Containers and more.
I build clouds at Fozzy.com =)
Joe Houghes is a co-leader of the Denver VMware & PowerShell User Groups and is currently a Senior Solutions Architect with Pure Storage. He focuses on automating us out of our IT operations while freeing us to perform higher-level tasks.
Joe has been the #1 speaker internationally for VMUG from 2020 to 2023 for both virtual and in-person events. He works to encourage the next community speaker(s) to take his place and is always helping get them started.
Joe believes automation should be a focus for admins & engineers, although it requires in-depth thinking beyond performing a task once. Even though it is not always someone's default method, the result is repeatable and consistent.
Joe tries to help others understand why we should do the easy tasks better, and he challenges everyone to push themselves outside of their comfort zone and learn more about any topic of interest.
He's a collector of communities as a leader for 2 User Groups, Microsoft MVP, vExpert Pro, Cisco Champion, Veeam Vanguard, Tanzu Vanguard, plus he helps host vBrownBag. He tells people not to let fear keep them from sharing their knowledge with others and teaching from their unique perspective.
You can spot him by the bright hat, big grin, and the loud "Howdy Y'all."
Kieran Jacobsen (he/him) recently joined Phocas Software as the Head of Business Systems. Kieran combines his passion for business process automation, systems integration, and cybersecurity to help organisations rapidly grow and evolve.
Kieran’s involvement in the technology community has seen him present at Microsoft’s Ignite the Tour, NDC Sydney, and CrikeyCon. Kieran is well known for his security focused presentations that blend real-world examples with storytelling.
Microsoft has recognised Kieran’s contributions to the community by awarding him with their Most Valuable Professional since 2017. Kieran is also a member of the GitKraken Ambassador Program.
Kieran lives in Melbourne, Australia with his Husband, and Burmese cat. In his spare time, Kieran enjoys computer games, Dungeons & Dragons, boardgames and Melbourne’s amazing food culture.
Table of Contents
-
- Foreword
-
Contributors
- Alain Tanguy
- Allen Chin
- Amy Zanatta
- Bill Kindle
- C.J. Zuk
- Chad Miars
- Christian Coventry
- Felipe Binotto
- Greg Onstot
- James Petty
- Joe Houghes
- John Hermes
- Jordan Borean
- Kevin Laux
- Kieran Jacobsen
- Kirill Nikolaev
- Martha Clancy
- Matt Corr
- Michael B. Smith
- Michael Lotter
- Michael Zanatta
- Nicholas Bissell
- Rob Derickson
- Steven Judd
- Wes Stahler
- Acknowledgements
- Disclaimer
-
Introduction
- About OnRamp
- Prerequisites
- A Note on Code Listings
- Feedback
-
I Collaboration
-
1. Introduction to Git
- 1.1 Understanding Terminology
- 1.2 Creating a Local Repository
- 1.3 Cloning an Existing Repository
- 1.4 Understanding the Flow of Working in Git
- 1.5 Your First Commit
- 1.6 Creating a Branch
-
1.7 Merging Branches
- 1.7.1 Merge Commits
- 1.7.2 Merge Conflicts
- 1.8 Stashing Changes
-
1.9 Rolling Back When Things Go Wrong
- 1.9.1 Hard Reset in Action
- 1.10 Connecting to a Remote Repository
-
1.11 Starting Over When Things Really Go Wrong
- 1.11.1 Starting From Scratch
- 1.12 Conclusion
- 1.13 Modern IT Automation With PowerShell Extras
- 1.14 Further Reading
-
2. Code Reviews
- 2.1 Purpose of Code Reviews
-
2.2 How to Start with Code Reviews
- 2.2.1 Define Code Conventions for Your Team or Project
- 2.2.2 Define the Code Review Process for Your Team or Project
- 2.3 Things to Consider When Performing a Code Review
-
2.4 Code Review Best Practices
- 2.4.1 Keep Your Changes Small
- 2.4.2 Provide Constructive Feedback
- 2.4.3 Balance Nit-Picks with Major Comments
- 2.4.4 Create Pull Request Templates
- 2.4.5 When to Approve
- 2.4.6 Talk to Each Other
- 2.4.7 Use Automation
-
2.5 Tools to Help with Code Reviews
- 2.5.1 PSScriptAnalyzer
- 2.5.2 PowerShell Extension for Visual Studio Code
- 2.6 Further Reading
-
1. Introduction to Git
-
II PowerShell Testing
-
3. The AAA Approach
-
3.1 Arrange, Act, and Assert
- 3.1.1 Arrange
- 3.1.2 Act
- 3.1.3 Assert
- 3.1.4 Benefits of the AAA Approach
-
3.2 Pester 5.0
- 3.2.1 Pester Installation
-
3.3 The Star Wars API Example
- 3.3.1 So How Does It Work?
- 3.3.2 Example Code
- 3.3.3 Example Code Output
-
3.4 Pester Tests
- 3.4.1 Simple Tests
- 3.4.2 Pester Verbosity
- 3.4.3 Simple Test Output
- 3.4.4 Mocked Tests
- 3.4.5 Mocked Test Output
- 3.4.6 Complex Tests
- 3.4.7 Complex Test Output
- 3.5 Conclusion
- 3.6 Further Reading
-
3.1 Arrange, Act, and Assert
-
4. Mocking
-
4.1 Mocking and Mock Testing
- 4.1.1 Stubs, Fakes, and Mocks
-
4.2 Mocking in Pester with
Mock
-
4.3 Mock Testing and Verifiable Mocks
- 4.3.1 Should -Invoke
- 4.3.2 Should -InvokeVerifiable
- 4.3.3 Running the Mock Assertion Tests
- 4.4 Mock Scoping
-
4.5 Mocking in the Module Scope with -ModuleName
- 4.5.1 Mock Testing in the Module Scope
- 4.5.2 Running the Module Scope Tests
-
4.6 Dynamic Mock Behavior with -ParameterFilter
- 4.6.1 Filtered Mock Assertions
- 4.6.2 Running the Filtered Mock Tests
- 4.6.3 Restricting Mock Calls Further with -ExclusiveFilter
- 4.7 Calling Real Dependencies While They’re Mocked
- 4.8 Removing Parameter Typecasting and Validation
- 4.9 Mocking Native Applications
- 4.10 Mocking .NET Objects with New-MockObject
- 4.11 Next Steps
- 4.12 Further Reading
-
4.1 Mocking and Mock Testing
-
5. Unit Testing
- 5.1 Why Unit Testing?
- 5.2 What Is Unit Testing?
-
5.3 Testing Frameworks
- 5.3.1 Black Box vs. White Box Testing
- 5.3.2 The AAA Approach
-
5.4 Pester
- 5.4.1 Getting Started
- 5.4.2 Defining Pester Test Files
- 5.4.3 Pester Demo Code
- 5.4.4 Pester Test Structure
- 5.4.5 Mocking
- 5.4.6 Running Pester Tests
- 5.4.7 Pester Configuration
- 5.4.8 Pester Automation
- 5.5 Conclusion
- 5.6 Further Reading
-
6. Parameterized Testing
- 6.1 Pester Versions and Parameterized Tests
-
6.2 Your First Test
- 6.2.1 -ForEach
- 6.2.2 Templates ‘<>’
- 6.2.3 BeforeDiscovery
- 6.2.4 Param
- 6.2.5 Pester Container
- 6.2.6 PesterConfiguration
- 6.3 Pester v4
- 6.4 Outputs
- 6.5 One Last Example
- 6.6 Conclusions
- 6.7 Further Reading
-
3. The AAA Approach
-
III PowerShell in Depth
-
7. Refactoring PowerShell
- 7.1 Expanding on the Pipeline
- 7.2 Expanded Splatting
-
7.3 Interpolation
- 7.3.1 Variable Substitution
-
7.3.2 Using the Format (
-f
) Operator
-
7.4 Refactoring Functions
- 7.4.1 Simplify Functions to Perform a Singular Task
- 7.4.2 Use Typecasting on Parameters
- 7.4.3 Use Advanced Function Parameters
- 7.4.4 Use Approved Verbs
- 7.4.5 Use a Singular Output Object Type
-
7.5 Writing Better Code
- 7.5.1 Simplify Nested Statements
- 7.5.2 Grouping Similar Code
- 7.5.3 Refactoring Comments and Documentation
- 7.5.4 Using Code Regions
-
7.5.5 Refactoring Logic Flow to be Implicitly
$True
or$False
-
7.6 Data Management
- 7.6.1 JSON
- 7.6.2 YAML
- 7.6.3 XML
- 7.6.4 CSV
- 7.6.5 CLIXML
- 7.6.6 Best Practices for Data Management
- 7.7 Further Reading
-
8. Advanced Conditions
- 8.1 Case Sensitive Operators
-
8.2 Using the Switch Statement
-
8.2.1 Using
-Regex
-
8.2.2 Using
-Wildcard
-
8.2.3 Using
-Exact
-
8.2.4 Using
-CaseSensitive
- 8.2.5 Using PowerShell Expressions for Matching
-
8.2.6
Default
- 8.2.7 Parsing Lists and Arrays
-
8.2.1 Using
-
8.3 Type Comparison and Conversion Operators:
-is
,-isnot
and-as
-
8.3.1 Using
-is
and-isnot
-
8.3.1 Using
-
8.4 Using
-as
to Typecast Safely -
8.5 Bitwise Operators (
-band
,-bor
,-bxor
,-bnot
,-shl
and-shr
)-
8.5.1 What is an
Enum
? - 8.5.2 Base-2 vs. Base-10 (Binary vs. Decimal)
- 8.5.3 The AND Logic Gate
- 8.5.4 The OR Logic Gate
- 8.5.5 The NOT Logic Gate
- 8.5.6 The XOR Logic Gate
-
8.5.7
-band
Bitwise AND -
8.5.8
-bor
Bitwise OR -
8.5.9
-bxor
Bitwise XOR -
8.5.10
-bnot
Bitwise NOT -
8.5.11
-shl
Shift Bits Left -
8.5.12
-shr
Shift Bits Right - 8.5.13 Practical Applications
-
8.5.1 What is an
-
8.6
-like
and-notlike
-
8.7
-match
and-notmatch
-
8.8
-in
,-contains
,-notin
and-notcontains
-
8.9
-replace
-
8.10 Ternary Operator
(condition) ? <true> : <false>
-
8.11 Null-Coalescing Operator
??
-
8.12 Null-Coalescing Assignment Operator
??=
-
8.13 Null-Conditional Operator
?.
and?[]
-
8.13.1 Examples of
?.
-
8.13.2 Examples of
?[]
-
8.13.1 Examples of
-
8.14
:parent
Loop Labels -
8.15 PowerShell Operator Precedence
-
8.15.1 Example - Operator Precedence (
,
,[]
) -
8.15.2 Example - Parentheses
()
-
8.15.3 Example - Negation Operator
-not
- 8.15.4 Example - Equal Precedence
- 8.15.5 Example - A Complex Expression
-
8.15.1 Example - Operator Precedence (
- 8.16 Further Reading
-
9. Logging
- 9.1 Why Log?
- 9.2 What Makes for Good Logging
- 9.3 What Should Never Be Logged
- 9.4 Logging Basics
-
9.5 Enable System-Level Logging
- 9.5.1 Windows
- 9.5.2 Event Log Locations
- 9.6 Linux, macOS, WSL
-
9.7 Logging for Troubleshooting
- 9.7.1 Writing Console Output
-
9.8 Persistent Logging Options
- 9.8.1 PowerShell Transcription
- 9.8.2 Logging to Files
- 9.8.3 Using Tee-Object
-
9.9 History
- 9.9.1 Built-in History
- 9.9.2 PSReadline History
- 9.9.3 Writing to Windows Event Logs
- 9.9.4 Cloud Shell
- 9.9.5 Using Third Party modules for logging
- 9.10 Summary
- 9.11 Further Reading
-
10. Infrastructure as Code (IaC)
- 10.1 Overview
- 10.2 IaC Key Concepts
- 10.3 IaC Benefits
-
10.4 IaC Principles
- 10.4.1 Source Control as the Single Source of Truth
- 10.4.2 Modular
- 10.4.3 Versioning
- 10.4.4 Repeatable
- 10.4.5 Disposable
- 10.4.6 Self-Documented
- 10.4.7 Testing and Monitoring
-
10.5 IaC in Action
- 10.5.1 Azure-SQL-Server.psm1
- 10.5.2 Azure-Storage-Account.psm1
- 10.5.3 Azure-Load-Balancer.psm1
- 10.5.4 Azure-Virtual-Machine.psm1
-
10.6 Configuration as Code (CaC)
- 10.6.1 PowerShell Desired State Configuration (DSC)
- 10.6.2 CaC in Action
- 10.7 IaC and CaC: Better Together
- 10.8 Conclusion
- 10.9 Further Reading
-
7. Refactoring PowerShell
-
IV Using Regexes
-
11. Regex 101
-
11.1 First Principles and Limitations
- 11.1.1 Wildcard Patterns vs. Regexes
- 11.1.2 Differences Between PowerShell Regexes and Others
- 11.2 Getting Started
- 11.3 Character Classes
- 11.4 Custom Character Classes
- 11.5 Quantifiers
- 11.6 Character Escape Sequences
- 11.7 Anchors (Zero-Width Assertions)
- 11.8 Captures
- 11.9 Visualizing Captures
-
11.1 First Principles and Limitations
-
12. Accessing Regexes
-
12.1 Using PowerShell Syntax
- 12.1.1 -match Operator with Strings
- 12.1.2 -match Operator with String Arrays
- 12.1.3 -cmatch and -imatch Operators and Inverses
- 12.1.4 -replace Operator with Strings
- 12.1.5 -replace Operator with String Arrays
- 12.1.6 -creplace and -ireplace Operators
- 12.1.7 -split Operator with Strings
- 12.1.8 -split Operator with String Arrays
- 12.1.9 Splitting Strings with -split and a Script Block
- 12.1.10 -csplit and -isplit Operators
- 12.1.11 Select-String Cmdlet
- 12.1.12 Where-Object Cmdlet with the -Match Parameter
- 12.1.13 switch -Regex Statement
- 12.1.14 ValidatePattern() Parameter Attribute
- 12.1.15 Pester Should -Match and -MatchExactly Assertions
-
12.2 Using the .NET Methods
- 12.2.1 Constructors
- 12.2.2 IsMatch()
- 12.2.3 Match()
- 12.2.4 Match.NextMatch() Instance Method
- 12.2.5 Matches()
- 12.2.6 Replace()
- 12.2.7 Split()
- 12.2.8 Escape() and Unescape()
- 12.2.9 GetGroupNumbers() and GetGroupNames()
- 12.2.10 GroupNameFromNumber() and GroupNumberFromName()
-
12.3 Regex Options
- 12.3.1 RegexOptions.None (0)
- 12.3.2 RegexOptions.IgnoreCase (1)
- 12.3.3 RegexOptions.Multiline (2)
- 12.3.4 RegexOptions.ExplicitCapture (4)
- 12.3.5 RegexOptions.Compiled (8)
- 12.3.6 RegexOptions.Singleline (16)
- 12.3.7 RegexOptions.IgnorePatternWhitespace (32)
- 12.3.8 RegexOptions.RightToLeft (64)
- 12.3.9 RegexOptions.ECMAScript (256)
- 12.3.10 RegexOptions.CultureInvariant (512)
- 12.3.11 Combining Regex Options
- 12.3.12 Inline Options
-
12.1 Using PowerShell Syntax
-
13. Regex Deep Dive
-
13.1 Debugging Your Regex Patterns
- 13.1.1 Regex Through the Eyes of an NFA Engine
- 13.1.2 Backtracking and Branching
- 13.1.3 Catastrophic Backtracking
- 13.1.4 Atomic Groups
-
13.2 Functionality to Consider
- 13.2.1 No Subroutines
- 13.2.2 No Recursion
- 13.2.3 Possessive Quantifiers vs. Atomic Groups
- 13.2.4 Variable-Length Lookbehinds
- 13.3 Deconstructing a Pattern
-
13.4 Advanced Syntax
- 13.4.1 Unicode Categories and Blocks
- 13.4.2 Character Class Subtraction
- 13.4.3 Using Inline Options
- 13.4.4 Using Option Spans
- 13.4.5 Comments in Regex
-
13.5 Advanced Replacement Patterns
- 13.5.1 Named and Numeric Captures
- 13.5.2 Entire Match
- 13.5.3 Match Span Prefixes and Postfixes
- 13.5.4 Entire Input
- 13.5.5 Last Capture
-
13.6 Advanced Subexpressions and Backreferences
- 13.6.1 Backreferences in Depth
- 13.6.2 Lookarounds in Depth
- 13.6.3 Conditional Logic
- 13.6.4 Balancing Groups
-
13.1 Debugging Your Regex Patterns
-
14. Regex Best Practices
- 14.1 Constrained and Unconstrained Input
- 14.2 Backtracking and Exponential Operations
- 14.3 Preventing ReDoS with Regex Time-Outs
- 14.4 Capturing Just Enough
- 14.5 Static vs. Instance Methods and Caching
- 14.6 No More CompileToAssembly()
- 14.7 Getting the Scope Right
- 14.8 Iterative Development
- 14.9 Edge Cases and Near Matches
- 14.10 Thread Safety
- 14.11 Next Steps
-
14.12 Further Reading
- 14.12.1 Official Reference Materials
- 14.12.2 Other Materials
-
11. Regex 101
-
V PowerShell Security
-
15. Script Signing
-
15.1 What Is Script Signing and How It Protects You
- 15.1.1 How Digital Signing Works
- 15.1.2 How Code Signing Works in Modern Windows Systems
- 15.2 The Anatomy of a Signed Script
-
15.3 How to Sign a Script
- 15.3.1 Acquiring a Code Signing Certificate
- 15.3.2 How to Install Code Signing Certificates Properly
- 15.3.3 Signing Process
- 15.3.4 How to Prevent Your Signatures from Expiring
- 15.3.5 What Else Can You Sign
-
15.4 How to Verify a Signature
- 15.4.1 Get-AuthenticodeSignature
- 15.4.2 Sigcheck
- 15.4.3 Signtool
- 15.4.4 Execution Errors
-
15.5 Scaling Out
- 15.5.1 Use Your Own PKI
- 15.5.2 Deploy Code Signing Certificates in a Corporate Environment
- 15.6 Summary
- 15.7 Further Reading
-
15.1 What Is Script Signing and How It Protects You
-
16. Script Execution Policies
-
16.1 Types of Execution Policies
- 16.1.1 AllSigned
- 16.1.2 RemoteSigned
- 16.1.3 Restricted
- 16.1.4 Unrestricted
- 16.1.5 Bypass
- 16.1.6 Default
- 16.1.7 Undefined
-
16.2 Execution Policy Scope
- 16.2.1 Scope Precedence
- 16.3 Security Considerations
-
16.4 Setting the Execution Policy
- 16.4.1 Set-ExecutionPolicy
- 16.4.2 Group Policy
- 16.4.3 AppLocker
- 16.4.4 Windows Defender Application Control
- 16.5 Further Reading
-
16.1 Types of Execution Policies
-
17. Constrained Language Mode
-
17.1 In Depth
- 17.1.1 Language Modes
- 17.1.2 Constrained Language Mode Features
-
17.2 Limitations of Constrained Language Mode
- 17.2.1 PowerShell Protect
-
17.3 Deep Diving into Windows Lockdown Policy
-
17.3.1
GetLockdownPolicy()
-
17.3.2
GetWldpPolicy()
-
17.3.3
GetAppLockerPolicy()
-
17.3.4
GetDebugLockdownPolicy()
-
17.3.1
-
17.4 Implementing Policies Using AppLocker Script Rules
- 17.4.1 Introduction
- 17.4.2 Getting Started
-
17.5 Implementing Policies Using WDAC
- 17.5.1 What Is WDAC?
-
17.6 Deploying WDAC Using Microsoft Intune
- 17.6.1 Prerequisites
- 17.6.2 Creating a Device Policy
- 17.7 Best Practices
- 17.8 Further Reading
-
17.1 In Depth
-
18. Just Enough Administration
-
18.1 Introduction
- 18.1.1 Requirements
-
18.2 Background of JEA
- 18.2.1 PowerShell Remoting 101
- 18.2.2 An Overview of PowerShell Session Configuration
- 18.2.3 PowerShell Remoting Authentication and Transport Encryption
-
18.3 PowerShell Role Capabilities
- 18.3.1 Implementing Windows PowerShell Role Capabilities in the Console
- 18.3.2 Implementing PowerShell (Core) Role Capabilities in the Console
- 18.3.3 Implementing PowerShell Role Capabilities Within DSC
-
18.4 Getting Started With PowerShell Session Configuration
- 18.4.1 Step 1: Enabling PowerShell Remoting
- 18.4.2 Step 2: Creating/Registering the PowerShell Session Configuration
- 18.4.3 Connecting to a PowerShell Session Configuration
- 18.4.4 Role Definition Design Considerations
- 18.4.5 Managing PowerShell Session Configurations
-
18.5 An Overview of the Security Descriptor Definition Language (SDDL)
- 18.5.1 Terms
- 18.5.2 SDDL Overview
- 18.5.3 SDDL Syntax
- 18.5.4 Reading SDDLs
- 18.5.5 Creating SDDLs from a Security Descriptor
-
18.6 Auditing PowerShell Remoting Sessions
- 18.6.1 Review Effective Rights
- 18.6.2 PowerShell Event Logs
- 18.6.3 Session Transcription Logs
- 18.6.4 Removing Existing PowerShell Sessions
- 18.7 Further Reading
-
18.1 Introduction
- Afterword
-
Index
- A, SYMBOLS
- B, C
- D, E
- F, G
- H, I
- J, K, L, M
- N
- O
- P
- R
- S
- T
- U, V, W
- Y
-
15. Script Signing
- Notes
Causes Supported
DevOps Collective Scholarships
http://devopscollective.orgSupport IT education scholarships by giving to The DevOps Collective, Inc.
The Leanpub 60 Day 100% Happiness Guarantee
Within 60 days of purchase you can get a 100% refund on any Leanpub purchase, in two clicks.
Now, this is technically risky for us, since you'll have the book or course files either way. But we're so confident in our products and services, and in our authors and readers, that we're happy to offer a full money back guarantee for everything we sell.
You can only find out how good something is by trying it, and because of our 100% money back guarantee there's literally no risk to do so!
So, there's no reason not to click the Add to Cart button, is there?
See full terms...
Earn $8 on a $10 Purchase, and $16 on a $20 Purchase
We pay 80% royalties on purchases of $7.99 or more, and 80% royalties minus a 50 cent flat fee on purchases between $0.99 and $7.98. You earn $8 on a $10 sale, and $16 on a $20 sale. So, if we sell 5000 non-refunded copies of your book for $20, you'll earn $80,000.
(Yes, some authors have already earned much more than that on Leanpub.)
In fact, authors have earnedover $14 millionwriting, publishing and selling on Leanpub.
Learn more about writing on Leanpub
Free Updates. DRM Free.
If you buy a Leanpub book, you get free updates for as long as the author updates the book! Many authors use Leanpub to publish their books in-progress, while they are writing them. All readers get free updates, regardless of when they bought the book or how much they paid (including free).
Most Leanpub books are available in PDF (for computers) and EPUB (for phones, tablets and Kindle). The formats that a book includes are shown at the top right corner of this page.
Finally, Leanpub books don't have any DRM copy-protection nonsense, so you can easily read them on any supported device.
Learn more about Leanpub's ebook formats and where to read them