In part one, I showed you some cool stuff you can do with PowerShell, covered the history of PowerShell, and explored in depth the capabilities of PowerShell as a strong scripting language that supports procedural, functional, and object-oriented programming.
In part two, I'll discuss the interactive shell, the profile, and the prompt, and I'll compare PowerShell to Bash.
PowerShell: The Interactive Shell
PowerShell was designed from the get-go as an interactive shell for Windows sys admins and power users. It focuses on a small number of concepts, very consistent experience, and an object pipeline to chain and combine commands, filter them and format them. Its strong help system, which also adheres to a consistent format, is a pleasure to use.
Let's see some of that in action.
Getting Help
The comprehensive help system is accessible through Get-Help
.
PS C:\WINDOWS\system32> Help Invoke-WebRequest NAME Invoke-WebRequest SYNOPSIS Gets content from a web page on the Internet. SYNTAX Invoke-WebRequest [-Uri] <Uri> [-Body <Object>] [-Certificate <X509Certificate>] [-CertificateThumbprint <String>] [-ContentType <String>] [-Credential <PSCredential>] [-DisableKeepAlive] [-Headers <IDictionary>] [-InFile <String>] [-MaximumRedirection <Int32>] [-Method {Default | Get | Head | Post | Put | Delete | Trace | Options | Merge | Patch}] [-OutFile <String>] [-PassThru] [-Proxy <Uri>] [-ProxyCredential <PSCredential>] [-ProxyUseDefaultCredentials] [-SessionVariable <String>] [-TimeoutSec <Int32>] [-TransferEncoding {chunked | compress | deflate | gzip | identity}] [-UseBasicParsing] [-UseDefaultCredentials] [-UserAgent <String>] [-WebSession <WebRequestSession>] [<CommonParameters>] DESCRIPTION The Invoke-WebRequest cmdlet sends HTTP, HTTPS, FTP, and FILE requests to a web page or web service. It parses the response and returns collections of forms, links, images, and other significant HTML elements. This cmdlet was introduced in Windows PowerShell 3.0. RELATED LINKS Online Version: http://ift.tt/2gRZ1P0 Invoke-RestMethod ConvertFrom-Json ConvertTo-Json REMARKS To see the examples, type: "get-help Invoke-WebRequest -examples". For more information, type: "get-help Invoke-WebRequest -detailed". For technical information, type: "get-help Invoke-WebRequest -full". For online help, type: "get-help Invoke-WebRequest -online"
To get more detailed help and see examples, use the proper switches: -examples
, -details
, or -full
.
If you're not sure what the command name is, just use keywords and PowerShell will show you all the available commands that contain this keyword. Let's see what cmdlets related to CSV are available:
PS C:\Users\the_g> Get-Help -Category Cmdlet csv | select name Name ---- ConvertFrom-Csv ConvertTo-Csv Export-Csv Import-Csv
I created a little pipeline where I limited the Get-Help call only to the category Cmdlet and then piped it to the "select" (alias for Select-Object) to get only the "name" property.
Working With Files and Directories
You can do pretty much everything you're used to: navigating to various directories, listing files and sub-directories, examining the content of files, creating directories and files, etc.
PS C:\Users\the_g> mkdir test_dir | select name Name ---- test_dir PS C:\Users\the_g> cd .\test_dir PS C:\Users\the_g\test_dir> "123" > test.txt PS C:\Users\the_g\test_dir> ls | name Name ---- test.txt PS C:\Users\the_g\test_dir> get-content .\test.txt 123
Working With Other Providers
With PowerShell, you can treat many things as file systems and navigate them using cd
and check their contents using ls/dir
. Here are some additional providers:
Provider Drive Data store -------- ----- ---------- Alias Alias: Windows PowerShell aliases Certificate Cert: x509 certificates for digital signatures Environment Env: Windows environment variables Function Function: Windows PowerShell functions Registry HKLM:, HKCU: Windows registry Variable Variable: Windows PowerShell variables WSMan WSMan: WS-Management configuration information
Let's check out the environment and see what Go-related environment variables are out there (on my machine):
PS C:\Users\the_g> ls env:GO* Name Value ---- ----- GOROOT C:\GO\ GOPATH C:\Users\the_g\Documents\Go
Formatting
PowerShell encourages composing cmdlets with standard switches and creating pipelines. Formatting is an explicit concept where in the end of a pipeline you put a formatter. PowerShell by default examines the type of object or objects at the end of the pipe and applies a default formatter. But you can override it by specifying a formatter yourself. Formatters are just cmdlets. Here is the previous output displayed in list format:
PS C:\Users\the_g> ls env:GO* | Format-List Name : GOROOT Value : C:\Go\ Name : GOPATH Value : c:\Users\the_g\Documents\Go
The Profile
Power users that use the command line frequently have many tasks, pipelines, and favorite combinations of commands with default switches that they favor. The PowerShell profile is a PowerShell script file that is loaded and executed whenever you start a new session. You can put all your favorite goodies there, create aliases and functions, set environment variables, and pretty much everything else.
I like to create navigation aliases to deeply nested directories, activate Python virtual environments, and create shortcuts to external commands I run frequently, like git and docker.
For me, the profile is indispensable because PowerShell's very readable and consistent commands and switches are often too verbose, and the built-in aliases are often more trouble than help (I discuss this later). Here is a very partial snippet from my profile:
#--------------------------- # # D O C K E R # #--------------------------- Set-Alias -Name d -Value docker function di { d images } #--------------------------- # # G I T # #--------------------------- Set-Alias -Name g -Value git function gs { g status } function gpu { g pull --rebase } #------------------------- # # C O N D A # #------------------------- function a { activate.ps1 $args[0] } #------------------------ # # N A V I G A T I O N # #------------------------ function cdg { cd $github_dir } # MVP function cdm { a ov; cdg; cd MVP } # backend function cdb { a ov; cdg; cd backend } # scratch function cds { a ov; cdg; cd scratch } # backend packages function cdbp { cdb; cd packages } # Go workspace function cdgo { cd $go_src_dir }
The Prompt
PowerShell lets you customize your command prompt. You need to define a function called prompt()
. You can see the built-in prompt function:
PS C:\Users\the_g> gc function:prompt "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "; # .Link # http://ift.tt/1t3sOF2 # .ExternalHelp System.Management.Automation.dll-help.xml PS C:\Users\the_g>
Here is a custom prompt function that displays the current time in addition to the current directory:
PS C:\Users\the_g> function prompt {"$(get-date) $(get-location) > "}
10/09/2016 12:42:36 C:\Users\the_g >
You can go wild, of course, and add colors and check various conditions like if you're in a particular git repository or if you're admin.
Aliases: The Dark Side
PowerShell got aliases wrong, in my opinion, on two separate fronts. First, the alias
command only allows the renaming of commands. You can't add common flags or options to make commands more useful by aliasing them to themselves.
For example, if you want to search in text line by line, you can use the Select-String
cmdlet:
# Create a little text file with 3 lines "@ ab cd ef @" > 1.txt # Search for a line containing d Get-Content 1.txt | Select-String d cd
That works, but many people would like to rename Select-String
to grep
. But grep
is by default case-sensitive, while Select-String
is not. No big deal—we'll just add the -CaseSensitive
flag, as in:
Set-Alias -Name grep -Value "Select-String -CaseSensitive"
Unfortunately, that doesn't work:
16:19:26 C:\Users\the_g> Get-Content 1.txt | grep D grep : The term 'Select-String -CaseSensitive' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:21 + Get-Content 1.txt | grep D + ~~~~ + CategoryInfo : ObjectNotFound: (Select-String -CaseSensitive:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException
The value of an alias must be either a cmdlet, a function, a script, or a program. No flags or arguments are allowed.
Now, you can do that very easily in PowerShell, but you'll have to use functions and not aliases. That pretty much constrains aliases to simple renaming, which can also be done by functions.
PowerShell vs. Bash
On the interactive shell side, PowerShell and Bash are pretty equal. Bash is more concise by default, but PowerShell's object pipeline makes complicated pipelines more manageable. ,
That said, you can probably accomplish anything with either one and if you're a power user then you'll have your own aliases, functions, and shortcuts for common tasks. On the scripting side, PowerShell goes far beyond Bash, and for system administration purposes it even beats Python, Ruby and friends.
An important aspect is availability. Bash comes pre-installed with most *nix distributions (unless specifically stripped) including macOS. It can also be installed on Windows via cygwin, git-bash, or msys. PowerShell comes pre-installed on Windows and just recently became available on Mac and Linux.
Conclusion
If you use Windows as a development machine or if you manage Windows machines then PowerShell is an indispensable tool. It is truly a well thought out superset of the Unix shells, and it comes pre-installed.
PowerShell is great software engineering at work. It evolved over a decade, and it kept innovating while maintaining its original conceptual integrity. The recent switch to open source and cross-platform signals that there is still a lot more to wait for.
No comments:
Post a Comment