Effective Windows PowerShell Keith Hill Windows PowerShell MVP keith.hill@outlook.com http://rkeithhill.wordpress.com twitter: @r_keith_hill
Goals Provide you with tools & knowledge to make you effective using PowerShell Teach someone to fish and they can feed themselves We’ll focus on broad understanding & using commands Along the way Provide a mental model of how PowerShell works Discuss where transfer of learning helps (and hinders) Point out some gotchas Show where to get help from the community
PowerShell Mental Model PowerShell is an automation engine for Windows PowerShell.exe / PowerShell_ISE.exe are just host apps Engine can be hosted in other applications PowerShell is a shell and a scripting language Commands Providers Type system Programming constructs
PowerShell Architecture Host process: PowerShell.exe, PowerShell_ISE.exe, etc Process Env Block – includes environment variables Implementation of PSHost* interfaces – used by engine for UI I/O PowerShell Engine (SMA.dll) – Parses and executes script Built-in commands Runspace(s) Pipeline executes script Variables Functions Aliases Module import table
Simple C# PowerShell Host App using System; using System.Collections.ObjectModel; using System.Management.Automation; namespace PowerShellHosting { class Program { static void Main() { using (var ps = PowerShell.Create()) { while (true) { Console.WriteLine("Enter an expression:"); string input = Console.ReadLine(); if (String.IsNullOrWhiteSpace(input)) break; ps.AddScript(input); Collection<PSObject> results = ps.Invoke(); foreach (var result in results) { Console.WriteLine(result); } } } } } }
Mental Model – Commands PowerShell provides “monadic” commands that can be composed in pipeline to accomplish complex tasks Production-oriented: verify destructive ops before executing PowerShell commands output objects NOT text PowerShell commands run “in-process” (not exes) PowerShell provides: A common param parsing engine – set of common parameters An extensible formatting & output engine Commands are named <verb>-<noun> for consistency Commands can be verbose for readability Get-Process | Where-Object {$_.PagedMemorySize –gt 100MB} | Foreach-Object {$_.Name} Or pithy for your wrists (and ego) gps | ? PM –gt 100MB | % Name
Mental Model – Providers Windows has various data stores: File system, registry, certificate store, environment vars A Provider is an abstraction over a data store Instances of providers look like file system drives C:\, D:\, HKLM:\, Cert:\ Standard set of commands to manipulate Set-Location (cd), Get-ChildItem, Get/Set-Item, Move-Item, Rename-Item, Copy-Item, Remove-Item PowerShell exposes some of its own “data stores” via providers: alias, variable, function
Mental Model – Type System ETS – extended type system Augments objects with new properties & methods necessary to provide better admin experience .NET types were not designed with admins in mind FileInfo gets BaseName, VersionInfo Process gets Company, Cpu, FileVersion, ProductVersion Other object representations are adapted into PowerShell WMI, COM, ADSI, ADO Promiscuously typed language Tries hard to turn what you have into what you need
Type System Demo TypeSystemDemo.ps1
Mental Model – Scripting Language Provides very useful, C# like programming constructs: if/elseif/else, for, foreach, while, do while, switch Provides many useful operators: -eq/ne/gt/lt/ge/le (why not ==, !=, >, <, >=, <= ?) -match, -notmatch, -contains, -notcontains, -replace, -split, -join, -and, -or, -not Users can create their own commands – functions Users can create their own types – [pscustomobject] Users can easily create scripts by copying commands they execute in the console into a .ps1 file Remember, PowerShell does all the hard parameter parsing work for our function.
#1 PowerShell Runs Exes Start simple, use PowerShell instead of CMD to run your favorite utilities: PS C:\> ipconfig /all PS C:\> netsh dump PS C:\> vaultcmd /listcreds:"Web Credentials" /all Up/down arrows and F7 still work – recalls history PowerShell tab completes path just as CMD does PowerShell tab completion is way more extensive PowerShell follows UNIX rule – you have to use .\foo.exe to run from current directory
#2 Four Commands of Discovery How do you get past the “blank screen of death”? #1 Get-Command: discover available commands #2 Get-Help: learn how to use commands #3 Get-Member: discover what objects can do #4 Get-PSDrive: discover available data stores
Four Commands Demo GetCommandDemo.ps1 GetHelpDemo.ps1 GetMemberDemo.ps1 GetPSDriveDemo.ps1
#3 How the Pipeline Works Piping in other shells pipes text (sometimes binary): $ ps axu | grep python | cut -d' ' -f2 PowerShell pipes pass .NET objects Each line executed at the console executes in a pipeline Pipe operator "|" is not what makes it a pipeline Entire scripts are executed in a pipeline Objects pass from one stage of pipeline to another: PS C:\> Get-Process python | Foreach-Object {$_.Id} The automatic variable $_ represents the current pipeline object
End of the (Pipe)line You can specify output formatter and destination: PS C:\> Get-Process | Format-Table | Out-Host Or let PowerShell choose for you: PS C:\> Get-Process In this case PowerShell implicitly pipes to Out-Default which selects a default formatter and uses Out-Host Default formatter selected based on first object If subsequent objects don’t match format they are displayed using Format-List
PowerShell Pipeline in Action Get-Process | Where {$_.PM –gt 60MB} | Sort ProcessName System.Diagnostics.Process Where Process.PagedMemorySize > 60*1024*1024 No Yes Sort on Process.ProcessName Get-Process out-default Handles NPM … ------- --- --- 105 111 89 99 Console.Write
Pipeline Object Types Can Change You may know what type the initial command outputs but the next command may output a different type This works: PS C:\> Get-ChildItem *.ps1 | Where {$_.LastWriteTime -gt (Get-Date).AddMonths(-1)} But this doesn’t: PS C:\> Get-ChildItem *.ps1 | Select-String psdrive | Where {$_.LastWriteTime -gt (Get-Date).AddMonths(-1)} Use Get-Member at various pipeline stages to examine the output object type
Pipeline Demo PipelineDemo.ps1
#4 Formatting & Output Formatting – rendering object to formatted text Determine what parts of the object are to be displayed Determine what display format to use: Table, list, wide and custom User can explicitly choose: Format-Table/List/Wide/Custom Output – sending formatted text to desired location Out-File, Out-String, Out-Printer, Out-Host (default) Output sent to Host goes through HOST UI interface: PSHostUserInterface.WriteLine (String)
How Objects Get Rendered as Text Formatting directions Format (ps1xml) files provide directions on what properties to display and what format to use Reflection over public properties Public properties are display Number of properties determines the formatter used <= 4 displays data in a table > 5 displays data in a list Object.ToString() – last ditch if no public properties
Formatting Demo FormattingDemo.ps1
Format & Type Data Files Format data file instructs PowerShell how to display a particular object type in various formats Type data file instructs PowerShell what properties to display and specifies new properties: AliasProperty, NoteProperty, ScriptProperty Examine Format data file: $pshome\DotNetTypes.format.ps1xml Type data file: $pshome\types.ps1xml
#5 Understanding Parsing Modes PowerShell parses for both command execution & expression evaluation String isn’t the only literal type parsed: int, double, decimal, bool, array, hashtable Command execution: must feel natural e.g.: PS C:\> Select-String xyzzy c:\foo.txt PS C:\> notepad.exe c:\foo.txt Expression evaluation: scripting must feel natural e.g.: PS C:\> $sum = 6*7 PS C:\> if ($sum –eq 42) {"What's the question"} PS C:\> 'Select-String xyzzy c:\foo.txt' >> foo.log PS C:\> [Math]::Max($sum, 100) PS C:\> [int]::Parse('2A8D', 'HexNumber') # quote strings
The Two Parsing Modes Argument (command) parsing mode Strings don’t need to quoted Numbers are parsed as strings Certain characters kick parsing into expression mode: $ @ ' " and ( Expression parsing mode Strings must be quoted Numbers not in quotes are treated a numerical values Certain characters kick into argument parsing mode \/ - path characters e.g. $pwd\foo.txt – no quoting necessary = - the value on the right can be either a command or expression Within expression, start new parsing context with ( or $(
Parsing Mode Determination By initial characters of line and after: (, $( , { and = Parsing mode Patterns Argument/Command [_aA-zZ] # command name & # call operator .\s+ # dot source operator [./\]+ # start of a path .[^0-9./\ ] # .n7.exe ok, .7 & .7kb are nums [0-9]+[_aA-zZ] # except for d, kb, mb, gb, tb Expression [0-9]*\.?[0-9]+(d|kb|mb|gb|tb|pb)? ' " $ # variable reference or subexpression start @ # hashtable and splatting (
PowerShell Parsing Gotcha Interop with executables taking complex arguments can be very problematic in PowerShell Quotes get lost PowerShell interprets certain chars: $ @ ( { ; ` Stop parser symbol kicks into dumb parsing mode: icacls --% X:\VMS /grant Dom\HVAdmin:(CI)(OI)F Can use env variables: $env:table = 'AdventureWorks.Person.Contact' sqlcmd -S .\SQLEXPRESS -v lname="Gates" --% -Q "SELECT FirstName,LastName FROM %table% WHERE LastName = '$(lname)'"
Parsing Modes Demo ParsingModedDemo.ps1
#6 Error Handling Two flavors Non-terminating Terminating Non-terminating errors don’t alter control flow Can be converted to terminating errors with: ErrorAction common parameter $ErrorActionPreference variable Terminating errors alter control flow Use try/catch to handle terminating errors Or let the script error out on a terminating error
Error Related Variables $Error - PowerShell stores all errors in this collection $Error[0] always contains the most recent error $MaximumErrorCount – max size of $Error collection $? – boolean execution status of last command True indicates command succeeded without any errors False indicates complete or partial failure True for exes returning 0 and False any other exit code $LastExitCode – int containing last exe’s exit code
Error Handling Demo ErrorHandlingDemo.ps1
Popular Modules / Tools / Repos PowerShell Community Extensions http://pscx.codeplex.com & PSGet Gallery PSReadline https://github.com/lzybkr/PSReadLine & PSGet Gallery PowerShell Tools for Visual Studio http://visualstudiogallery.msdn.microsoft.com/c9eb3ba8-0c59-4944-9a62-6eee37294597 ISESteriods 2.0 http://www.powertheshell.com/isesteroids2/ PoshCode.org http://poshcode.org
Help Resources StackOverflow http://stackoverflow.com/tags/powershell PowerShell.org http://powershell.org/wp/forums/ MS TechNet ScriptCenter forums http://social.technet.microsoft.com/Forums/scriptcenter/en-US/home Effective Windows PowerShell (free) eBook https://onedrive.live.com/view.aspx?cid=5A8D2641E0963A97&resid=5A8D2641E0963A97%216929&app=WordPdf
Make PowerShell Better Report a bug Submit a suggestion (enhancement request) Vote on already submitted bugs & suggestions https://connect.microsoft.com/PowerShell/Feedback
Questions?