We are still actively working on the spam issue.
Difference between revisions of "Powershell"
m (added some stuff) |
(Fix Wikitext formatting, add Cleanup Template add to category Shells) |
||
(14 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
− | + | {{cleanup|This article's header structure is somewhat confused}} | |
− | Windows Powershell is a shell / scripting environment created by Microsoft. You can read more about the technical stuff | + | {{TOCright|limit=2}} |
+ | '''Windows Powershell''' is a shell / scripting environment created by | ||
+ | Microsoft. You can read | ||
+ | [[Wikipedia:Windows_PowerShell |more about the technical stuff]]. This page | ||
+ | serves as not a complete description of Powershell or its history, but | ||
+ | a guide on how to use it. Some programming knowledge is expected but | ||
+ | not absolutely required. Experience with bash is also probably | ||
+ | helpful, but you could learn something even if you have zero | ||
+ | experience with any kind of shell or scripting environment. | ||
== Rationale == | == Rationale == | ||
Line 20: | Line 28: | ||
- Anon, June 9th 2015 | - Anon, June 9th 2015 | ||
− | == Getting Started | + | == Getting Started == |
− | Here is a chart that I made. [[File:PsQuickReference-20150609.pdf]] (I made it as a .pdf because I can't be assed | + | Here is a chart that I made. [[File:PsQuickReference-20150609.pdf]] (I |
− | to learn how to use WikiMedia properly, so if you don't like that | + | made it as a .pdf because I can't be assed to learn how to use |
− | please contribute yourself.) It was designed to get someone familiar | + | WikiMedia properly, so if you don't like that please contribute |
− | with the *NIX shell up and scripting as fast as possible, and includes | + | yourself.) It was designed to get someone familiar with the *NIX shell |
− | all the common commands I remember using often on *NIX. | + | up and scripting as fast as possible, and includes all the common |
+ | commands I remember using often on *NIX. | ||
Let's do a quick analysis of this chart and come up with some pros and cons. | Let's do a quick analysis of this chart and come up with some pros and cons. | ||
Pros of Powershell: | Pros of Powershell: | ||
+ | |||
* Syntax is sometimes much clearer than bash. Powershell's syntax is also much more consistent. This makes it much easier to compose and read scripts. | * Syntax is sometimes much clearer than bash. Powershell's syntax is also much more consistent. This makes it much easier to compose and read scripts. | ||
* Syntax is generally not case sensitive. Some people might put this as a con but I like it and I think many others do too. | * Syntax is generally not case sensitive. Some people might put this as a con but I like it and I think many others do too. | ||
Line 36: | Line 46: | ||
* Familiar object-oriented conventions are baked in. If you come from a Java, C#, or even Ruby background, lots of things should feel familiar. | * Familiar object-oriented conventions are baked in. If you come from a Java, C#, or even Ruby background, lots of things should feel familiar. | ||
* Decently fast, both performance-wise and to learn. | * Decently fast, both performance-wise and to learn. | ||
− | * .NET environment, meaning its extensible with your own .NET objects. | + | * .NET environment, meaning its extensible with your own .NET objects. * Lots of juicy default aliases for juicy shortcuts. You can tell whoever wrote this shit actually uses a shell. |
− | * Lots of juicy default aliases for juicy shortcuts. You can tell whoever wrote this shit actually uses a shell. | ||
* Access to lots of Windows APIs/features such as the registry and Internet Explorer. | * Access to lots of Windows APIs/features such as the registry and Internet Explorer. | ||
* Powershell Community Extensions and/or PsGet. | * Powershell Community Extensions and/or PsGet. | ||
Line 43: | Line 52: | ||
Cons of Powershell: | Cons of Powershell: | ||
+ | |||
* Windows only, whereas bash or sh is on basically every OS (including Windows with Cygwin). | * Windows only, whereas bash or sh is on basically every OS (including Windows with Cygwin). | ||
− | * Cannot run scripts by default, and Powershell only comes by default with Win7 and up. Makes scripts unportable because they are not | + | * Cannot run scripts by default, and Powershell only comes by default with Win7 and up. Makes scripts unportable because they are not necessarily guarunteed to run on another machine. |
* Sometimes the commands are quite verbose. It can be especially annoying to type out very verbose arguments, such as '-Recurse' as opposed to '-r'. | * Sometimes the commands are quite verbose. It can be especially annoying to type out very verbose arguments, such as '-Recurse' as opposed to '-r'. | ||
* Fairly slow autocomplete (hopefully will be fixed in Windows 10). | * Fairly slow autocomplete (hopefully will be fixed in Windows 10). | ||
Line 51: | Line 61: | ||
* Binary logs (Get-History is an example, I think). | * Binary logs (Get-History is an example, I think). | ||
− | + | == Initial Configuration == | |
− | First thing you're gonna wanna do is fix Microsoft's idiocy and make scripts executable. To do that, run this command: | + | |
+ | First thing you're gonna wanna do is fix Microsoft's idiocy and make | ||
+ | scripts executable. To do that, run this command: | ||
Set-ExecutionPolicy -CurrentUser RemoteSigned | Set-ExecutionPolicy -CurrentUser RemoteSigned | ||
− | You might need to do it in an elevated prompt. To do that, open the Start Menu, type 'Windows Powershell', right-click the link, and select 'Run as Administrator'. Then enter the command. | + | You might need to do it in an elevated prompt. To do that, open the |
+ | Start Menu, type 'Windows Powershell', right-click the link, and | ||
+ | select 'Run as Administrator'. Then enter the command. | ||
− | Next, you'll probably want a config file to store custom aliases, functions, and the like. To do this, run this little snippet: | + | Next, you'll probably want a config file to store custom aliases, |
+ | functions, and the like. To do this, run this little snippet: | ||
if ( -Not (Test-Path $profile)) { | if ( -Not (Test-Path $profile)) { | ||
Line 67: | Line 82: | ||
This will be where you store your customized Powershell configuration. | This will be where you store your customized Powershell configuration. | ||
− | + | == Some Helpful Default Aliases == | |
Here are some useful aliases that are baked into Powershell. You'll | Here are some useful aliases that are baked into Powershell. You'll | ||
Line 113: | Line 128: | ||
Alias where -> Where-Object | Alias where -> Where-Object | ||
+ | To view aliases, use ''Get-Alias''. To edit them, use ''New-Alias'' | ||
+ | and ''Set-Alias''. | ||
− | + | == Getting Help == | |
− | === Ricer Bullshit === | + | As you can see above, ''man'' is an alias for a |
+ | command called ''Get-Help''. It does exactly what | ||
+ | you think it does. | ||
+ | |||
+ | PS C:\> get-help get-help | ||
+ | NAME | ||
+ | Get-Help | ||
+ | |||
+ | SYNTAX | ||
+ | Get-Help [[-Name] <string>] [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | General | FAQ | ||
+ | | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | Workflow}] | ||
+ | [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [-Full] [<CommonParameters>] | ||
+ | |||
+ | Get-Help [[-Name] <string>] -Detailed [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | | ||
+ | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | | ||
+ | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] | ||
+ | |||
+ | Get-Help [[-Name] <string>] -Examples [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | | ||
+ | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | | ||
+ | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] | ||
+ | |||
+ | Get-Help [[-Name] <string>] -Parameter <string> [-Path <string>] [-Category <string[]> {Alias | Cmdlet | | ||
+ | Provider | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | | ||
+ | DefaultHelp | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] | ||
+ | [<CommonParameters>] | ||
+ | |||
+ | Get-Help [[-Name] <string>] -Online [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | | ||
+ | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | | ||
+ | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] | ||
+ | |||
+ | Get-Help [[-Name] <string>] -ShowWindow [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | | ||
+ | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | | ||
+ | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] | ||
+ | |||
+ | ALIASES | ||
+ | None | ||
+ | |||
+ | REMARKS | ||
+ | Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help. | ||
+ | -- To download and install Help files for the module that includes this cmdlet, use Update-Help. | ||
+ | -- To view the Help topic for this cmdlet online, type: "Get-Help Get-Help -Online" or | ||
+ | go to http://go.microsoft.com/fwlink/?LinkID=113316. | ||
+ | |||
+ | And we get a nice little description of ''Get-Help'' and its | ||
+ | parameters. It resembles a man page, quite intentionally. ''Get-Help'' | ||
+ | works with any command and any alias, and is aliased to ''man''. Some useful parameters to | ||
+ | ''Get-Help'' are ''-Online'' and ''-ShowWindow'' for the GUI babbies | ||
+ | and ''-Example'' for hands-on learners. | ||
+ | |||
+ | If you notice in the 'Remarks' section, Powershell has the unhelpful | ||
+ | feature of not actually coming with complete documentation. To fix | ||
+ | this, use the cmdlet ''Update-Help'', either standalone or with a | ||
+ | cmdlet passed as a parameter, to download the online help files to | ||
+ | your local machine. | ||
+ | |||
+ | Another great tool for getting help is ''Get-Member''. Unsure of how | ||
+ | to use an object? Piping it to ''Get-Member'' will display all the | ||
+ | object's data members and methods so that you can find and use the one | ||
+ | you want. | ||
+ | |||
+ | PS C:\> "abcd" | get-member | ||
+ | TypeName: System.String | ||
+ | |||
+ | Name MemberType Definition | ||
+ | ---- ---------- ---------- | ||
+ | Clone Method System.Object Clone(), System.Object ICloneable.Clone() | ||
+ | CompareTo Method int CompareTo(System.Object value), int CompareTo(string strB), int IComp... Contains Method bool Contains(string value) | ||
+ | CopyTo Method void CopyTo(int sourceIndex, char[] destination, int destinationIndex, in... EndsWith Method bool EndsWith(string value), bool EndsWith(string value, System.StringCom... Equals Method bool Equals(System.Object obj), bool Equals(string value), bool Equals(st... GetEnumerator Method System.CharEnumerator GetEnumerator(), System.Collections.Generic.IEnumer... GetHashCode Method int GetHashCode() | ||
+ | GetType Method type GetType() | ||
+ | GetTypeCode Method System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTypeCode() | ||
+ | IndexOf Method int IndexOf(char value), int IndexOf(char value, int startIndex), int Ind... IndexOfAny Method int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int startIndex... Insert Method string Insert(int startIndex, string value) | ||
+ | IsNormalized Method bool IsNormalized(), bool IsNormalized(System.Text.NormalizationForm norm... LastIndexOf Method int LastIndexOf(char value), int LastIndexOf(char value, int startIndex),... LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf, int st... Normalize Method string Normalize(), string Normalize(System.Text.NormalizationForm normal... PadLeft Method string PadLeft(int totalWidth), string PadLeft(int totalWidth, char paddi... PadRight Method string PadRight(int totalWidth), string PadRight(int totalWidth, char pad... Remove Method string Remove(int startIndex, int count), string Remove(int startIndex) | ||
+ | Replace Method string Replace(char oldChar, char newChar), string Replace(string oldValu... Split Method string[] Split(Params char[] separator), string[] Split(char[] separator,... StartsWith Method bool StartsWith(string value), bool StartsWith(string value, System.Strin... Substring Method string Substring(int startIndex), string Substring(int startIndex, int le... ToBoolean Method bool IConvertible.ToBoolean(System.IFormatProvider provider) | ||
+ | ToByte Method byte IConvertible.ToByte(System.IFormatProvider provider) | ||
+ | ... | ||
+ | |||
+ | == Ricer Bullshit == | ||
+ | |||
+ | Right now I use Cmder as my | ||
+ | Windows shell. Its portable, has some sane defaults, and you can | ||
+ | download a version that includes msysgit, so you can carry around | ||
+ | unix-like binaries with you on a USB stick. (Obviously for the | ||
+ | powershell parts, you wouldn't be needing those.) | ||
+ | |||
+ | If (God Forbid) you want to use the default shell and ```customize``` | ||
+ | it to your liking, be my guest. Simply dropping a function in your | ||
+ | ''$profile'' will allow you to customize your prompt, example below: | ||
+ | |||
+ | function prompt | ||
+ | { | ||
+ | Write-Host ("PS " + $(get-date) +">") -nonewline -foregroundcolor White | ||
+ | return " " | ||
+ | } | ||
+ | |||
+ | Surprisingly enough, ''Write-Host'' can be used to put foreground | ||
+ | colors, background colors, bold text, and many other features at any | ||
+ | point anywhere in the shell, so writing scripts to colorize output is | ||
+ | easy. The full list of colors can be found in ''Get-Help Write-Host''. | ||
+ | |||
+ | Foreground and background colors can be set in the actual shell with | ||
+ | some variables. There's also a built-in properties dialog if you | ||
+ | right-click the title bar. | ||
+ | |||
+ | # OH MY GOD ANON ARE YOU A HACKER?! | ||
+ | $console = $host.UI.RawUI | ||
+ | $console.ForegroundColor = "Green" | ||
+ | $console.BackgroundColor = "Black" | ||
+ | Clear-Host | ||
+ | |||
+ | Other miscellaneous plugins/editors/colors stuff: | ||
+ | * [http://poshcode.org/notepad++lexer/ | NPP Plugin] | ||
+ | * [http://www.viveksharma.com/techlog/attache/powershell-mode.el.txt | Powershell-Mode] | ||
+ | * [http://blogs.msdn.com/b/dotnetinterop/archive/2008/04/10/run-powershell-as-a-shell-within-emacs.aspx | Powershell embedded in Emacs] | ||
+ | * [http://www.vim.org/scripts/script.php?script_id=1327 | ViM syntax hilighting] | ||
+ | * [http://juliankay.com/development/setting-up-vim-to-work-with-powershell/ | More about Powershell and ViM] | ||
+ | * [https://technet.microsoft.com/en-us/library/dd315244.aspx | Powershell ISE, Msft's own editor for PS1 scripts] | ||
== Scripting Stuff == | == Scripting Stuff == | ||
+ | |||
+ | Overall, I'd say Powershell shines as a scripting language over being | ||
+ | a shell environment. It works fine in the shell, but its verbose | ||
+ | syntax lends itself better towards I've been working on trying to find | ||
+ | a way to use Emacs for writing powershell scripts, but so far it isn't | ||
+ | going well, and I don't have a great setup yet. If you really want | ||
+ | syntax hilighting and IDE-like features, use Powershell ISE, which I | ||
+ | discuss in the section [[Powershell#Ricer Bullshit]]. | ||
+ | |||
+ | Also make sure your shell can run scripts as discussed in | ||
+ | [[Powershell#Initial Configuration]]. | ||
+ | |||
+ | === Variables and Data Types === | ||
+ | |||
+ | Variables in Powershell are prefixed with the $ symbol. There is | ||
+ | technically a command to create variables, ''Set-Variable'', but I | ||
+ | don't see why - Powershell seems to declare and instantiate on | ||
+ | assignment, similar to languages like Python and Ruby. so | ||
+ | |||
+ | Set-Variable -Name a -Value 1 | ||
+ | |||
+ | is equivalent to | ||
+ | |||
+ | $a = 1; | ||
+ | |||
+ | which seems strange but I suppose there is a purpose, hidden within | ||
+ | the documentation for ''Set-Variable'', which probably lies outside | ||
+ | the scope of this guide anyways. | ||
+ | |||
+ | ==== Objects ==== | ||
+ | |||
+ | Custom objects can be created and manipulated easily with ''New-Object'', ''Add-Member'', and ''Get-Member''. | ||
+ | |||
+ | PS C:\> $myobj = New-Object System.Object | ||
+ | PS C:\> Add-Member -Name "Name" -MemberType NoteProperty -Value "Anon" | ||
+ | PS C:\> Add-Member -Name "Score" -MemberType NoteProperty -Value 12 | ||
+ | PS C:\> $myobj | Format-List | ||
+ | Name: Anon | ||
+ | Score: 12 | ||
+ | |||
+ | New definitions of objects can be created with either ''Add-Type'' and | ||
+ | the ''-Typedef'' flag, or by loading pre-defined C# classes into Powershell. | ||
+ | |||
+ | === Numbers === | ||
+ | |||
+ | Powershell has lots of weird types (hell, everything is an object), | ||
+ | but primitives like ints and doubles are pretty tame, and work as | ||
+ | one might expect. | ||
+ | |||
+ | PS C:\> $a = 1 | ||
+ | PS C:\> $a++ | ||
+ | PS C:\> echo $a | ||
+ | 2 | ||
+ | PS C:\> 1 + 3 / 2 | ||
+ | 2.5 | ||
+ | PS C:\> (1+3)/2 | ||
+ | 2 | ||
+ | PS C:\> 4 % 2 | ||
+ | 0 | ||
+ | PS C:\> | ||
+ | PS C:\> 0.001 + 0.001 | ||
+ | 0.002 | ||
+ | PS C:\> 5.0 / 2 | ||
+ | 2.5 | ||
+ | PS C:\> | ||
+ | |||
+ | === Strings === | ||
+ | |||
+ | Strings work pretty much exactly like in Java with a few quirks. The | ||
+ | backtick (`) is used for escapes, you can compare and concatenate | ||
+ | strings, search within them, index ranges, the list goes on. | ||
+ | |||
+ | PS C:\> $a = "Hello" + " World!" | ||
+ | PS C:\> echo $a | ||
+ | Hello World! | ||
+ | PS C:\> $a = "Hello `nWorld!" ; echo $a | ||
+ | Hello | ||
+ | World! | ||
+ | PS C:\> $a = "Hello`t`tWorld!" ; echo $a | ||
+ | Hello World! | ||
+ | PS C:\> $a = "Hello ``World``!" ; echo $a | ||
+ | Hello `World`! | ||
+ | |||
+ | The dollar sign must be escaped inside a Powershell string because | ||
+ | variables and code can be inserted directly into strings, like in | ||
+ | bash. | ||
+ | |||
+ | PS C:\> $a = "Hello"; echo "$a World!" | ||
+ | Hello World! | ||
+ | PS C:\> echo "I have $(1 + 2) apples." | ||
+ | I have 3 apples. | ||
+ | PS C:\> echo "`$" | ||
+ | $ | ||
+ | |||
+ | Other examples: | ||
+ | |||
+ | # These functions all return true. | ||
+ | $a.contains("ello") | ||
+ | $a.startswith("He") | ||
+ | $a.endswith("!") | ||
+ | |||
+ | PS C:\> $a.indexof("W") | ||
+ | 7 | ||
+ | PS C:\> $a[0] | ||
+ | H | ||
+ | PS C:\> $a[1..4] | ||
+ | e | ||
+ | l | ||
+ | l | ||
+ | o | ||
+ | |||
+ | $a.CompareTo("Hello") # Returns 1 | ||
+ | $a.CompareTo("ZZZZZ") # Returns -1 | ||
+ | $a.CompareTo($a) # Returns 0 | ||
+ | |||
+ | Multi-line strings can be created with this syntax: ''' @" "@ '''. Note | ||
+ | that this is really only useful for scripts because in a shell, | ||
+ | pressing enter without putting a closing " will allow you to continue | ||
+ | writing the command on a new line. | ||
+ | |||
+ | === Arrays and Hash Tables === | ||
+ | |||
+ | Arrays are declared either purely with commas or with the ''@( )'' | ||
+ | syntax, and can contain mixed types. | ||
+ | |||
+ | PS C:\> $a = $(1, 2, 3, 4) | ||
+ | PS C:\> $a = 1,2,3,4 | ||
+ | PS C:\> $a = "a",1,"b",2 | ||
+ | PS C:\> $a.Length | ||
+ | 4 | ||
+ | |||
+ | They can also be indexed as you would expect and sliced with ranges: | ||
+ | |||
+ | PS C:\> $a[0] | ||
+ | a | ||
+ | PS C:\> $a[1..2] | ||
+ | 1 | ||
+ | b | ||
+ | |||
+ | Hash tables, or dictionaries, are also implemented in Powershell, and | ||
+ | work similarly to arrays and dictionaries in other languages: | ||
+ | |||
+ | PS C:\> $a = @{Key1=1;Key2=2;Key3="YourName"} | ||
+ | PS C:\> $a.Key1 | ||
+ | 1 | ||
+ | PS C:\> $a["Key1"] + 2 | ||
+ | 3 | ||
+ | PS C:\> $a["Key3"] + "IsBob" | ||
+ | YourNameIsBob | ||
+ | PS C:\> | ||
+ | |||
+ | Of course, hash tables and arrays can be nested. | ||
+ | |||
+ | PS C:\> $grid = @(0, 1, 2),@(3, 4, 5),@(6, 7, 8) | ||
+ | PS C:\> $grid.getType() | ||
+ | |||
+ | IsPublic IsSerial Name BaseType | ||
+ | -------- -------- ---- -------- | ||
+ | True True Object[] System.Array | ||
+ | PS C:\> $grid[0][0] | ||
+ | 0 | ||
+ | PS C:\> $grid[0][2] | ||
+ | 2 | ||
+ | PS C:\> $grid[0] | ||
+ | 0 | ||
+ | 1 | ||
+ | 2 | ||
+ | |||
+ | PS C:\> $student = @{Name="Anon";GPA=3.5;Classes=@("Programming 101","Shitposting 400","Free Software 101")} | ||
+ | PS C:\> foreach ($class in $student.Classes) { Write-Host "$($student.Name) is taking $class this semester." } | ||
+ | Anon is taking Programming 101 this semester. | ||
+ | Anon is taking Shitposting 400 this semester. | ||
+ | Anon is taking Free Software 101 this semester. | ||
+ | PS C:\> | ||
+ | |||
+ | === Types === | ||
+ | |||
+ | Most everything implements ''.getType()'': | ||
+ | |||
+ | PS C:\> $a = "asdf" | ||
+ | PS C:\> $a.getType() | ||
+ | IsPublic IsSerial Name BaseType | ||
+ | -------- -------- ---- -------- | ||
+ | True True String System.Object | ||
+ | |||
+ | PS C:\> (1).getType() | ||
+ | IsPublic IsSerial Name BaseType | ||
+ | -------- -------- ---- -------- | ||
+ | True True Int32 System.ValueType | ||
+ | |||
+ | PS C:\> ("asdf").getType() | ||
+ | IsPublic IsSerial Name BaseType | ||
+ | -------- -------- ---- -------- | ||
+ | True True String System.Object | ||
+ | |||
+ | |||
+ | PS C:\> (@{}).getType() | ||
+ | IsPublic IsSerial Name BaseType | ||
+ | -------- -------- ---- -------- | ||
+ | True True Hashtable System.Object | ||
+ | |||
+ | and types can be casted and declared with square brackets. | ||
+ | |||
+ | PS C:\> [int32]$i = 40; | ||
+ | PS C:\> [int32]$j = "asdf"; | ||
+ | Cannot convert value "asdf" to type "System.Int32". Error: "Input string was not in a correct format." | ||
+ | At line:1 char:1 | ||
+ | + [int32]$j = "asdf"; | ||
+ | + 13:48, 11 June 2015 (EDT)13:48, 11 June 2015 (EDT)13:48, 11 June 2015 (EDT)[[User:Hevnoraak|Hevnoraak]] ([[User talk:Hevnoraak|talk]]) | ||
+ | + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException | ||
+ | + FullyQualifiedErrorId : RuntimeException | ||
+ | PS C:\> [int32](0.0001) | ||
+ | 0 | ||
+ | PS C:\> | ||
+ | |||
+ | === Conditionals === | ||
+ | |||
+ | In Powershell, if statements are exactly what is expected from a | ||
+ | C-style language. | ||
+ | if ($true -And $true) { | ||
+ | Write-Host "Horray, boolean logic!" | ||
+ | } | ||
+ | |||
+ | However comparison operators look like flags or parameters, which is a | ||
+ | little weird but not hard to get used to. ''-And'' and ''-Or'' are | ||
+ | obviously your bread and butter: | ||
+ | $a = $true | ||
+ | $b = $true | ||
+ | $c = $false | ||
+ | $a -And $b # True | ||
+ | $a -Or $c # True | ||
+ | |||
+ | If you followed along with those two, ''-Not'' is pretty easy also. | ||
+ | $a = $false | ||
+ | $b = -Not $a # True | ||
+ | $c = -Not 0 # True | ||
+ | |||
+ | ''-is'' can be used to check types. | ||
+ | $a = "HI" | ||
+ | $a -is [String] # True | ||
+ | $a -is [Int32] # False | ||
=== Loops === | === Loops === | ||
− | == | + | The simplest type of loop uses the ''ForEach-Object'' command (aliased to 'foreach') to cycle |
+ | through arrays of objects. | ||
+ | |||
+ | foreach ($i in (1..10)) { | ||
+ | Write-Host $i; | ||
+ | } | ||
+ | |||
+ | There are also while, do-while, and do-until loops. The syntax there | ||
+ | is pretty cut and dry: | ||
+ | |||
+ | $a = 0; | ||
+ | while ($a -lt 10) { Write-Host $a; a++ } | ||
+ | |||
+ | $a = 10; | ||
+ | do { Write-Host $a; $a--; } until ($a -eq 0) | ||
− | + | (Note: do-until is basically just the opposite of do-while, they work | |
+ | the same way, however it might be cleaner to use do-until in some | ||
+ | cases depending on your condition.) | ||
== Working with Data == | == Working with Data == | ||
+ | |||
+ | When manipulating data on the command line, you have to always | ||
+ | remember the paradigm: '''Objects''', ''not'' text. We work with data in | ||
+ | structured form instead of in plaintext. This is very evident in how | ||
+ | Powershell filters and formats data; instead of using tools like | ||
+ | ''awk'', ''regex'' and ''sort'', arrays of objects are piped between commands | ||
+ | which select, reject, or print them based off of their data members. | ||
=== Format Commands === | === Format Commands === | ||
− | Powershell provides several commands for changing the way that it displays data within the shell. | + | |
+ | Powershell provides several commands for changing the way that it | ||
+ | displays data within the shell. | ||
PS C:\> get-command | ? { $_.Verb -eq "Format" -and $_.ModuleName -eq "Microsoft.Powershell.Utility" } | PS C:\> get-command | ? { $_.Verb -eq "Format" -and $_.ModuleName -eq "Microsoft.Powershell.Utility" } | ||
Line 140: | Line 538: | ||
Cmdlet Format-Wide Microsoft.PowerShell.Utility | Cmdlet Format-Wide Microsoft.PowerShell.Utility | ||
− | ==== Format- | + | For now I'm only going to cover ''Format-Table'', ''Format-Wide'', and ''Format-List''. |
+ | |||
+ | === Format-Table === | ||
+ | |||
+ | Running ''Format-Table'' on just about anything will produce results | ||
+ | which look familiar. I'm not 100% sure about this (need to find a | ||
+ | source), but I'm pretty sure Powershell runs every object that goes | ||
+ | into stdout through ''Format-Table'' before printing it. So just the | ||
+ | cmdlet standalone will give you nothing; its the parameters that go | ||
+ | into making the magic happen. Look at this example, taken | ||
+ | [https://technet.microsoft.com/en-us/library/ee692794.aspx | straight | ||
+ | from the horse's mouth]: | ||
+ | |||
+ | PS C:\> $a = @{Expression={$_.Name};Label="Process Name";width=25}, ` | ||
+ | >>> @{Expression={$_.ID};Label="Process ID";width=15}, ` | ||
+ | >>> @{Expression={$_.MainWindowTitle};Label="Window Title";width=40} | ||
+ | |||
+ | PS C:\> Get-Process | Format-Table $a | ||
+ | Process Name Process ID Window Title | ||
+ | ------------ ---------- ------------ | ||
+ | lsass 1284 | ||
+ | LSSrvc 2112 | ||
+ | MDM 2240 | ||
+ | notepad 2348 Untitled - Notepad | ||
+ | notepad 3944 Untitled - Notepad | ||
+ | OUTLOOK 1192 Inbox - Microsoft Outlook | ||
+ | powershell 1348 Script Center | ||
+ | |||
+ | The assignment to ''$a'' looks incredibly confusing until you realize | ||
+ | that ''@{}'' is how Powershell does hash tables and/or dictionaries, | ||
+ | and that arrays are defined simply with commas. (Read the Variables | ||
+ | and Data Types section if you haven't already). ''Format-Table'' | ||
+ | simply takes in hash tables which describe how each column of the | ||
+ | table is going to look with different keys and values inside the hash | ||
+ | table. ''Format-Table'' allows you to make really rich representations | ||
+ | of what would otherwise be flat and uninteractive data. | ||
+ | |||
+ | === Format-Wide === | ||
− | The most boring | + | The most boring format command: it simply puts the data in multiple columns to |
+ | make better use of horizontal screen space, like so: | ||
PS C:\> get-process | PS C:\> get-process | ||
− | |||
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName | Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName | ||
------- ------ ----- ----- ----- ------ -- ----------- | ------- ------ ----- ----- ----- ------ -- ----------- | ||
Line 157: | Line 592: | ||
180 16 2428 38256 202 600 csrss | 180 16 2428 38256 202 600 csrss | ||
314 17 3880 10912 44 1728 dasHost | 314 17 3880 10912 44 1728 dasHost | ||
− | |||
PS C:\> get-process | format-wide | PS C:\> get-process | format-wide | ||
− | |||
armsvc ConEmu | armsvc ConEmu | ||
ConEmuC64 conhost | ConEmuC64 conhost | ||
conhost csrss | conhost csrss | ||
csrss dasHost | csrss dasHost | ||
− | |||
− | |||
Note that this seems to kill your use of Select-Object: | Note that this seems to kill your use of Select-Object: | ||
PS C:\> ps | select-object -Property Name,ID,Handles | PS C:\> ps | select-object -Property Name,ID,Handles | ||
− | |||
Name Id Handles | Name Id Handles | ||
---- -- ------- | ---- -- ------- | ||
armsvc 1672 82 | armsvc 1672 82 | ||
audiodg 5320 126 | audiodg 5320 126 | ||
− | |||
PS C:\> ps | select-object -Property Name,ID,Handles | fw | PS C:\> ps | select-object -Property Name,ID,Handles | fw | ||
− | |||
armsvc ConEmu | armsvc ConEmu | ||
ConEmuC64 conhost | ConEmuC64 conhost | ||
conhost csrss | conhost csrss | ||
csrss dasHost | csrss dasHost | ||
− | |||
− | + | === Format-List === | |
− | Format-List takes an object or an array of objects and gives a | + | ''Format-List'' takes an object or an array of objects and gives a |
descriptive output of the object's (or objects') properties and values | descriptive output of the object's (or objects') properties and values | ||
associated with said properties. To be honest, Format-List is kind of | associated with said properties. To be honest, Format-List is kind of | ||
a crappy name; the output doesn't really look like a list to me, more | a crappy name; the output doesn't really look like a list to me, more | ||
− | like a table. This command is similar to Get-Member but doesn't | + | like a table. This command is similar to ''Get-Member'' but doesn't |
produce as much output and gives you the data instead of just what | produce as much output and gives you the data instead of just what | ||
data members the object has. | data members the object has. | ||
PS C:\> get-date | PS C:\> get-date | ||
− | |||
Tuesday, June 9, 2015 8:58:23 PM | Tuesday, June 9, 2015 8:58:23 PM | ||
PS C:\> get-date | format-list | PS C:\> get-date | format-list | ||
− | |||
DisplayHint : DateTime | DisplayHint : DateTime | ||
Date : 6/9/2015 12:00:00 AM | Date : 6/9/2015 12:00:00 AM | ||
Line 218: | Line 643: | ||
DateTime : Tuesday, June 9, 2015 8:58:27 PM | DateTime : Tuesday, June 9, 2015 8:58:27 PM | ||
− | === Tips and Tricks === | + | == Filtering == |
+ | |||
+ | === Where-Object === | ||
+ | |||
+ | ''Where-Object'' is an incredibly useful command which functions | ||
+ | similar to piping output to grep. It filters objects based off of | ||
+ | specified conditionals. The ? symbol is an alias to ''Where-Object''. | ||
+ | |||
+ | PS C:\> $a = 1,2,3,4,15,6,1,2,6,124,68 # Random ints | ||
+ | PS C:\> $b = $a | Where-Object { $_ -gt 6 } # Select anything greater than 6 | ||
+ | PS C:\> $b | ||
+ | 15 | ||
+ | 124 | ||
+ | 68 | ||
+ | |||
+ | More examples: | ||
+ | |||
+ | 1..100 | ? { -Not ($_ % 2) } # Pick even numbers out of a range | ||
+ | get-command | ? Noun -eq "Alias" # See all commands which operate on aliases | ||
+ | |||
+ | === Select-Object === | ||
+ | |||
+ | ''Select-Object'' can be used to limit the amount of information | ||
+ | Powershell displays or processes. | ||
+ | |||
+ | For instance, if you only care about the names and sizes of a | ||
+ | file, the ''-Property'' command can be combined with ''Get-ChildItem'' | ||
+ | to display this information, ignoring other things like LastWriteTime. | ||
+ | |||
+ | # Displays table of files in directory and their size | ||
+ | gci | Select-Object -Property Name,Length | ||
+ | |||
+ | Other useful (and fairly intuitively named) flags to ''Select-Object'' include: | ||
+ | * ''-ExcludeProperty <String[]>'' - Removes the specified property from the selection. | ||
+ | * ''-First <int>'' - Displays only the first <int> elements. | ||
+ | * ''-Last <int>'' - Displays only the last <int> elements. | ||
+ | * ''-Skip <int>'' - Skips the first <int> elements. | ||
+ | * ''-SkipLast <int>'' - Skips the last <int> elements. | ||
+ | * ''-Unique'' - Makes the selection into a set with only one of every element. | ||
+ | |||
+ | === Command-based Filtering === | ||
+ | |||
+ | While ''Where-Object'' and ''Select-Object'' are really neat, many | ||
+ | commands have built-in kinds of filtering, for example the | ||
+ | ''Get-Process'' command: | ||
+ | |||
+ | PS C:\> # This is much simpler than get-process | ? Name -eq "firefox" | ||
+ | PS C:\> get-process -name firefox | ||
+ | Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName | ||
+ | ------- ------ ----- ----- ----- ------ -- ----------- | ||
+ | 1281 185 476300 577120 1557 2,471.92 1792 firefox | ||
+ | |||
+ | If you're curious about a command, check its help page before | ||
+ | over-using either filtering tool. | ||
+ | |||
+ | == Tips and Tricks == | ||
+ | |||
+ | === Regular Expressions === | ||
+ | |||
+ | Regexp in Powershell is fairly ho-hum, and if you're already familiar | ||
+ | with regex in other languages its a breeze. Matching is done with the | ||
+ | ''-Match'' or ''-NoMatch'' operators; ''-Replace'' also takes regex as | ||
+ | an argument. | ||
+ | |||
+ | PS C:\> "The Thick Brown Fox" -match "The ..ick Brown \w" | ||
+ | True | ||
+ | PS C:\> "The Quick Brown Fox" -match "The ..ick Brown \w" | ||
+ | True | ||
+ | PS C:\> "The Quick Brown Fox, The Lazy Dog" -replace "^The","A" | ||
+ | A Quick Brown Fox, The Lazy Dog | ||
+ | PS C:\> | ||
+ | |||
+ | = Working with Windows = | ||
+ | |||
+ | == Environment Variables == | ||
+ | |||
+ | Environment variables are stored in ''Env'': | ||
+ | |||
+ | PS C:\> get-childitem Env: | ||
+ | Name Value | ||
+ | ---- ----- | ||
+ | ALLUSERSPROFILE C:\ProgramData | ||
+ | APPDATA <REDACTED> | ||
+ | CommonProgramFiles C:\Program Files (x86)\Common Files | ||
+ | CommonProgramFiles(x86) C:\Program Files (x86)\Common Files | ||
+ | CommonProgramW6432 C:\Program Files\Common Files | ||
+ | COMPUTERNAME <REDACTED> | ||
+ | ComSpec C:\Windows\system32\cmd.exe | ||
+ | FP_NO_HOST_CHECK NO | ||
+ | GIT_SSH C:\Program Files (x86)\PuTTY\plink.exe | ||
+ | HOME <REDACTED> | ||
+ | HOMEDRIVE C: | ||
+ | HOMEPATH <REDACTED> | ||
+ | LOCALAPPDATA <REDACTED> | ||
+ | LOGONSERVER \\MicrosoftAccount | ||
+ | NUMBER_OF_PROCESSORS 8 | ||
+ | OS Windows_NT | ||
+ | Path C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System3... | ||
+ | PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL | ||
+ | PROCESSOR_ARCHITECTURE x86 | ||
+ | PROCESSOR_ARCHITEW6432 AMD64 | ||
+ | PROCESSOR_IDENTIFIER Intel64 Family 6 Model 60 Stepping 3, GenuineIntel | ||
+ | PROCESSOR_LEVEL 6 | ||
+ | PROCESSOR_REVISION 3c03 | ||
+ | ProgramData C:\ProgramData | ||
+ | ProgramFiles C:\Program Files (x86) | ||
+ | ProgramFiles(x86) C:\Program Files (x86) | ||
+ | ProgramW6432 C:\Program Files | ||
+ | PSModulePath <REDACTED> | ||
+ | PUBLIC C:\Users\Public | ||
+ | SESSIONNAME Console | ||
+ | SVN_SSH C:\Program Files (x86)\PuTTY\plink.exe | ||
+ | SystemDrive C: | ||
+ | SystemRoot C:\Windows | ||
+ | TEMP <REDACTED> | ||
+ | TMP <REDACTED> | ||
+ | USERDOMAIN <REDACTED> | ||
+ | USERDOMAIN_ROAMINGPROFILE <REDACTED> | ||
+ | USERNAME <REDACTED> | ||
+ | USERPROFILE <REDACTED> | ||
+ | VBOX_MSI_INSTALL_PATH C:\Program Files\Oracle\VirtualBox\ | ||
+ | windir C:\Windows | ||
+ | |||
+ | PS C:\> echo $env:Path | ||
+ | C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\Windows | ||
+ | PowerShell\v1.0\;C:\Program Files (x86)\Skype\Phone\;C:\Git\cmd;C:\Git\bin;C:\Program Files\MiKTeX 2.9\miktex\bin\x64\ | ||
+ | |||
+ | = References = | ||
+ | |||
+ | * http://g o o seberrycreative.com/cmder/ | ||
+ | * http://www.tomsitpro.com/articles/powershell-variables,2-797.html | ||
+ | * http://softwaresalariman.blogspot.com/2007/12/slicing-powershell-arrays-and-ranges.html | ||
+ | * https://technet.microsoft.com/en-us/library/ff406264.aspx | ||
+ | * http://windowsitpro.com/powershell/powershell-basics-console-configuration | ||
+ | * http://stackoverflow.com/questions/5725888/windows-powershell-changing-the-command-prompt | ||
+ | * https://technet.microsoft.com/en-us/library/ff730964.aspx | ||
+ | * https://technet.microsoft.com/en-us/magazine/hh750381.aspx | ||
+ | * http://stackoverflow.com/questions/3666337/how-to-use-new-object-of-a-class-present-in-a-c-sharp-dll-using-powershell | ||
+ | * http://ss64.com/ps/syntax-regex.html | ||
− | |||
− | + | [[Category:Windows]] | |
+ | [[Category:Terms]] | ||
+ | [[Category:Software]] | ||
+ | [[Category:HowTo]] | ||
+ | [[Category:Shells]] |
Latest revision as of 21:44, 20 February 2022
Windows Powershell is a shell / scripting environment created by Microsoft. You can read more about the technical stuff. This page serves as not a complete description of Powershell or its history, but a guide on how to use it. Some programming knowledge is expected but not absolutely required. Experience with bash is also probably helpful, but you could learn something even if you have zero experience with any kind of shell or scripting environment.
Rationale
I think Powershell is pretty neat. I used Linux as my main OS for about 5 years and had to switch to Windows very recently for a myriad of reasons. Ironically I might have to switch back soon (taking a *NIX Systems Programming class), but in the meantime I wanted a scripting language for Windows that was better for the everyday grind than Python, so I did some research and found Powershell. Its no bash, but its close, and I think if it was embraced by the world and the Internet (re: people give M$ a reason to care about it) then it could be really great. The fact that Microsoft is actively trying to make Windows a more dev-friendly environment shows that exciting things are happening (See: SSH on Windows), and I believe those changes will start begin with the upcoming changes to Powershell in Windows 10.
- Anon, June 9th 2015
Getting Started
Here is a chart that I made. File:PsQuickReference-20150609.pdf (I made it as a .pdf because I can't be assed to learn how to use WikiMedia properly, so if you don't like that please contribute yourself.) It was designed to get someone familiar with the *NIX shell up and scripting as fast as possible, and includes all the common commands I remember using often on *NIX.
Let's do a quick analysis of this chart and come up with some pros and cons.
Pros of Powershell:
- Syntax is sometimes much clearer than bash. Powershell's syntax is also much more consistent. This makes it much easier to compose and read scripts.
- Syntax is generally not case sensitive. Some people might put this as a con but I like it and I think many others do too.
- Familiar conventions to get *NIX people started, such as $ for variables, cp, mv, mkdir, etc.
- Familiar object-oriented conventions are baked in. If you come from a Java, C#, or even Ruby background, lots of things should feel familiar.
- Decently fast, both performance-wise and to learn.
- .NET environment, meaning its extensible with your own .NET objects. * Lots of juicy default aliases for juicy shortcuts. You can tell whoever wrote this shit actually uses a shell.
- Access to lots of Windows APIs/features such as the registry and Internet Explorer.
- Powershell Community Extensions and/or PsGet.
- Its not cmd.exe ! ! !
Cons of Powershell:
- Windows only, whereas bash or sh is on basically every OS (including Windows with Cygwin).
- Cannot run scripts by default, and Powershell only comes by default with Win7 and up. Makes scripts unportable because they are not necessarily guarunteed to run on another machine.
- Sometimes the commands are quite verbose. It can be especially annoying to type out very verbose arguments, such as '-Recurse' as opposed to '-r'.
- Fairly slow autocomplete (hopefully will be fixed in Windows 10).
- No reverse i-search by default.
- Capitals everywhere. Why? I know it usually doesn't matter but its still kind of ugly.
- Binary logs (Get-History is an example, I think).
Initial Configuration
First thing you're gonna wanna do is fix Microsoft's idiocy and make scripts executable. To do that, run this command:
Set-ExecutionPolicy -CurrentUser RemoteSigned
You might need to do it in an elevated prompt. To do that, open the Start Menu, type 'Windows Powershell', right-click the link, and select 'Run as Administrator'. Then enter the command.
Next, you'll probably want a config file to store custom aliases, functions, and the like. To do this, run this little snippet:
if ( -Not (Test-Path $profile)) { New-Item -Type File $profile } Notepad $profile
This will be where you store your customized Powershell configuration.
Some Helpful Default Aliases
Here are some useful aliases that are baked into Powershell. You'll probably find yourself using them often, and they may seem familiar, so take a good, long look.
CommandType Name ----------- ---- Alias % -> ForEach-Object Alias % -> ForEach-Object Alias ? -> Where-Object Alias h -> Get-History Alias r -> Invoke-History Alias ac -> Add-Content Alias cd -> Set-Location Alias compare -> Compare-Object Alias cp -> Copy-Item Alias curl -> Invoke-WebRequest Alias diff -> Compare-Object Alias foreach -> ForEach-Object Alias ft -> Format-Table Alias fw -> Format-Wide Alias gc -> Get-Content Alias kill -> Stop-Process Alias ls -> Get-ChildItem Alias man -> help Alias measure -> Measure-Object Alias nal -> New-Alias Alias nv -> New-Variable Alias ps -> Get-Process Alias pwd -> Get-Location Alias r -> Invoke-History Alias ren -> Rename-Item Alias rm -> Remove-Item Alias rmdir -> Remove-Item Alias rv -> Remove-Variable Alias sc -> Set-Content Alias select -> Select-Object Alias sort -> Sort-Object Alias start -> Start-Process Alias sv -> Set-Variable Alias tee -> Tee-Object Alias type -> Get-Content Alias wget -> Invoke-WebRequest Alias where -> Where-Object
To view aliases, use Get-Alias. To edit them, use New-Alias and Set-Alias.
Getting Help
As you can see above, man is an alias for a command called Get-Help. It does exactly what you think it does.
PS C:\> get-help get-help NAME Get-Help SYNTAX Get-Help [[-Name] <string>] [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [-Full] [<CommonParameters>] Get-Help [[-Name] <string>] -Detailed [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] Get-Help [[-Name] <string>] -Examples [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] Get-Help [[-Name] <string>] -Parameter <string> [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] Get-Help [[-Name] <string>] -Online [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] Get-Help [[-Name] <string>] -ShowWindow [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [<CommonParameters>] ALIASES None REMARKS Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help. -- To download and install Help files for the module that includes this cmdlet, use Update-Help. -- To view the Help topic for this cmdlet online, type: "Get-Help Get-Help -Online" or go to http://go.microsoft.com/fwlink/?LinkID=113316.
And we get a nice little description of Get-Help and its parameters. It resembles a man page, quite intentionally. Get-Help works with any command and any alias, and is aliased to man. Some useful parameters to Get-Help are -Online and -ShowWindow for the GUI babbies and -Example for hands-on learners.
If you notice in the 'Remarks' section, Powershell has the unhelpful feature of not actually coming with complete documentation. To fix this, use the cmdlet Update-Help, either standalone or with a cmdlet passed as a parameter, to download the online help files to your local machine.
Another great tool for getting help is Get-Member. Unsure of how to use an object? Piping it to Get-Member will display all the object's data members and methods so that you can find and use the one you want.
PS C:\> "abcd" | get-member TypeName: System.String Name MemberType Definition ---- ---------- ---------- Clone Method System.Object Clone(), System.Object ICloneable.Clone() CompareTo Method int CompareTo(System.Object value), int CompareTo(string strB), int IComp... Contains Method bool Contains(string value) CopyTo Method void CopyTo(int sourceIndex, char[] destination, int destinationIndex, in... EndsWith Method bool EndsWith(string value), bool EndsWith(string value, System.StringCom... Equals Method bool Equals(System.Object obj), bool Equals(string value), bool Equals(st... GetEnumerator Method System.CharEnumerator GetEnumerator(), System.Collections.Generic.IEnumer... GetHashCode Method int GetHashCode() GetType Method type GetType() GetTypeCode Method System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTypeCode() IndexOf Method int IndexOf(char value), int IndexOf(char value, int startIndex), int Ind... IndexOfAny Method int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int startIndex... Insert Method string Insert(int startIndex, string value) IsNormalized Method bool IsNormalized(), bool IsNormalized(System.Text.NormalizationForm norm... LastIndexOf Method int LastIndexOf(char value), int LastIndexOf(char value, int startIndex),... LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf, int st... Normalize Method string Normalize(), string Normalize(System.Text.NormalizationForm normal... PadLeft Method string PadLeft(int totalWidth), string PadLeft(int totalWidth, char paddi... PadRight Method string PadRight(int totalWidth), string PadRight(int totalWidth, char pad... Remove Method string Remove(int startIndex, int count), string Remove(int startIndex) Replace Method string Replace(char oldChar, char newChar), string Replace(string oldValu... Split Method string[] Split(Params char[] separator), string[] Split(char[] separator,... StartsWith Method bool StartsWith(string value), bool StartsWith(string value, System.Strin... Substring Method string Substring(int startIndex), string Substring(int startIndex, int le... ToBoolean Method bool IConvertible.ToBoolean(System.IFormatProvider provider) ToByte Method byte IConvertible.ToByte(System.IFormatProvider provider) ...
Ricer Bullshit
Right now I use Cmder as my Windows shell. Its portable, has some sane defaults, and you can download a version that includes msysgit, so you can carry around unix-like binaries with you on a USB stick. (Obviously for the powershell parts, you wouldn't be needing those.)
If (God Forbid) you want to use the default shell and ```customize``` it to your liking, be my guest. Simply dropping a function in your $profile will allow you to customize your prompt, example below:
function prompt { Write-Host ("PS " + $(get-date) +">") -nonewline -foregroundcolor White return " " }
Surprisingly enough, Write-Host can be used to put foreground colors, background colors, bold text, and many other features at any point anywhere in the shell, so writing scripts to colorize output is easy. The full list of colors can be found in Get-Help Write-Host.
Foreground and background colors can be set in the actual shell with some variables. There's also a built-in properties dialog if you right-click the title bar.
# OH MY GOD ANON ARE YOU A HACKER?! $console = $host.UI.RawUI $console.ForegroundColor = "Green" $console.BackgroundColor = "Black" Clear-Host
Other miscellaneous plugins/editors/colors stuff:
- | NPP Plugin
- | Powershell-Mode
- | Powershell embedded in Emacs
- | ViM syntax hilighting
- | More about Powershell and ViM
- | Powershell ISE, Msft's own editor for PS1 scripts
Scripting Stuff
Overall, I'd say Powershell shines as a scripting language over being a shell environment. It works fine in the shell, but its verbose syntax lends itself better towards I've been working on trying to find a way to use Emacs for writing powershell scripts, but so far it isn't going well, and I don't have a great setup yet. If you really want syntax hilighting and IDE-like features, use Powershell ISE, which I discuss in the section Powershell#Ricer Bullshit.
Also make sure your shell can run scripts as discussed in Powershell#Initial Configuration.
Variables and Data Types
Variables in Powershell are prefixed with the $ symbol. There is technically a command to create variables, Set-Variable, but I don't see why - Powershell seems to declare and instantiate on assignment, similar to languages like Python and Ruby. so
Set-Variable -Name a -Value 1
is equivalent to
$a = 1;
which seems strange but I suppose there is a purpose, hidden within the documentation for Set-Variable, which probably lies outside the scope of this guide anyways.
Objects
Custom objects can be created and manipulated easily with New-Object, Add-Member, and Get-Member.
PS C:\> $myobj = New-Object System.Object PS C:\> Add-Member -Name "Name" -MemberType NoteProperty -Value "Anon" PS C:\> Add-Member -Name "Score" -MemberType NoteProperty -Value 12 PS C:\> $myobj | Format-List Name: Anon Score: 12
New definitions of objects can be created with either Add-Type and the -Typedef flag, or by loading pre-defined C# classes into Powershell.
Numbers
Powershell has lots of weird types (hell, everything is an object), but primitives like ints and doubles are pretty tame, and work as one might expect.
PS C:\> $a = 1 PS C:\> $a++ PS C:\> echo $a 2 PS C:\> 1 + 3 / 2 2.5 PS C:\> (1+3)/2 2 PS C:\> 4 % 2 0 PS C:\> PS C:\> 0.001 + 0.001 0.002 PS C:\> 5.0 / 2 2.5 PS C:\>
Strings
Strings work pretty much exactly like in Java with a few quirks. The backtick (`) is used for escapes, you can compare and concatenate strings, search within them, index ranges, the list goes on.
PS C:\> $a = "Hello" + " World!" PS C:\> echo $a Hello World! PS C:\> $a = "Hello `nWorld!" ; echo $a Hello World! PS C:\> $a = "Hello`t`tWorld!" ; echo $a Hello World! PS C:\> $a = "Hello ``World``!" ; echo $a Hello `World`!
The dollar sign must be escaped inside a Powershell string because variables and code can be inserted directly into strings, like in bash.
PS C:\> $a = "Hello"; echo "$a World!" Hello World! PS C:\> echo "I have $(1 + 2) apples." I have 3 apples. PS C:\> echo "`$" $
Other examples:
# These functions all return true. $a.contains("ello") $a.startswith("He") $a.endswith("!")
PS C:\> $a.indexof("W") 7 PS C:\> $a[0] H PS C:\> $a[1..4] e l l o
$a.CompareTo("Hello") # Returns 1 $a.CompareTo("ZZZZZ") # Returns -1 $a.CompareTo($a) # Returns 0
Multi-line strings can be created with this syntax: @" "@ . Note that this is really only useful for scripts because in a shell, pressing enter without putting a closing " will allow you to continue writing the command on a new line.
Arrays and Hash Tables
Arrays are declared either purely with commas or with the @( ) syntax, and can contain mixed types.
PS C:\> $a = $(1, 2, 3, 4) PS C:\> $a = 1,2,3,4 PS C:\> $a = "a",1,"b",2 PS C:\> $a.Length 4
They can also be indexed as you would expect and sliced with ranges:
PS C:\> $a[0] a PS C:\> $a[1..2] 1 b
Hash tables, or dictionaries, are also implemented in Powershell, and work similarly to arrays and dictionaries in other languages:
PS C:\> $a = @{Key1=1;Key2=2;Key3="YourName"} PS C:\> $a.Key1 1 PS C:\> $a["Key1"] + 2 3 PS C:\> $a["Key3"] + "IsBob" YourNameIsBob PS C:\>
Of course, hash tables and arrays can be nested.
PS C:\> $grid = @(0, 1, 2),@(3, 4, 5),@(6, 7, 8) PS C:\> $grid.getType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Object[] System.Array PS C:\> $grid[0][0] 0 PS C:\> $grid[0][2] 2 PS C:\> $grid[0] 0 1 2
PS C:\> $student = @{Name="Anon";GPA=3.5;Classes=@("Programming 101","Shitposting 400","Free Software 101")} PS C:\> foreach ($class in $student.Classes) { Write-Host "$($student.Name) is taking $class this semester." } Anon is taking Programming 101 this semester. Anon is taking Shitposting 400 this semester. Anon is taking Free Software 101 this semester. PS C:\>
Types
Most everything implements .getType():
PS C:\> $a = "asdf" PS C:\> $a.getType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object PS C:\> (1).getType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Int32 System.ValueType PS C:\> ("asdf").getType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object PS C:\> (@{}).getType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Hashtable System.Object
and types can be casted and declared with square brackets.
PS C:\> [int32]$i = 40; PS C:\> [int32]$j = "asdf"; Cannot convert value "asdf" to type "System.Int32". Error: "Input string was not in a correct format." At line:1 char:1 + [int32]$j = "asdf"; + 13:48, 11 June 2015 (EDT)13:48, 11 June 2015 (EDT)13:48, 11 June 2015 (EDT)Hevnoraak (talk) + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException PS C:\> [int32](0.0001) 0 PS C:\>
Conditionals
In Powershell, if statements are exactly what is expected from a C-style language.
if ($true -And $true) { Write-Host "Horray, boolean logic!" }
However comparison operators look like flags or parameters, which is a little weird but not hard to get used to. -And and -Or are obviously your bread and butter:
$a = $true $b = $true $c = $false $a -And $b # True $a -Or $c # True
If you followed along with those two, -Not is pretty easy also.
$a = $false $b = -Not $a # True $c = -Not 0 # True
-is can be used to check types.
$a = "HI" $a -is [String] # True $a -is [Int32] # False
Loops
The simplest type of loop uses the ForEach-Object command (aliased to 'foreach') to cycle through arrays of objects.
foreach ($i in (1..10)) { Write-Host $i; }
There are also while, do-while, and do-until loops. The syntax there is pretty cut and dry:
$a = 0; while ($a -lt 10) { Write-Host $a; a++ }
$a = 10; do { Write-Host $a; $a--; } until ($a -eq 0)
(Note: do-until is basically just the opposite of do-while, they work the same way, however it might be cleaner to use do-until in some cases depending on your condition.)
Working with Data
When manipulating data on the command line, you have to always remember the paradigm: Objects, not text. We work with data in structured form instead of in plaintext. This is very evident in how Powershell filters and formats data; instead of using tools like awk, regex and sort, arrays of objects are piped between commands which select, reject, or print them based off of their data members.
Format Commands
Powershell provides several commands for changing the way that it displays data within the shell.
PS C:\> get-command | ? { $_.Verb -eq "Format" -and $_.ModuleName -eq "Microsoft.Powershell.Utility" } CommandType Name ModuleName ----------- ---- ---------- Cmdlet Format-Custom Microsoft.PowerShell.Utility Cmdlet Format-List Microsoft.PowerShell.Utility Cmdlet Format-Table Microsoft.PowerShell.Utility Cmdlet Format-Wide Microsoft.PowerShell.Utility
For now I'm only going to cover Format-Table, Format-Wide, and Format-List.
Format-Table
Running Format-Table on just about anything will produce results which look familiar. I'm not 100% sure about this (need to find a source), but I'm pretty sure Powershell runs every object that goes into stdout through Format-Table before printing it. So just the cmdlet standalone will give you nothing; its the parameters that go into making the magic happen. Look at this example, taken [https://technet.microsoft.com/en-us/library/ee692794.aspx | straight from the horse's mouth]:
PS C:\> $a = @{Expression={$_.Name};Label="Process Name";width=25}, ` >>> @{Expression={$_.ID};Label="Process ID";width=15}, ` >>> @{Expression={$_.MainWindowTitle};Label="Window Title";width=40}
PS C:\> Get-Process | Format-Table $a Process Name Process ID Window Title ------------ ---------- ------------ lsass 1284 LSSrvc 2112 MDM 2240 notepad 2348 Untitled - Notepad notepad 3944 Untitled - Notepad OUTLOOK 1192 Inbox - Microsoft Outlook powershell 1348 Script Center
The assignment to $a looks incredibly confusing until you realize that @{} is how Powershell does hash tables and/or dictionaries, and that arrays are defined simply with commas. (Read the Variables and Data Types section if you haven't already). Format-Table simply takes in hash tables which describe how each column of the table is going to look with different keys and values inside the hash table. Format-Table allows you to make really rich representations of what would otherwise be flat and uninteractive data.
Format-Wide
The most boring format command: it simply puts the data in multiple columns to make better use of horizontal screen space, like so:
PS C:\> get-process Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName ------- ------ ----- ----- ----- ------ -- ----------- 82 7 1076 4216 44 1672 armsvc 135 9 5800 8480 39 0.09 5320 audiodg 316 25 15748 23808 200 6.48 2776 ConEmu 130 11 2952 6520 91 7.09 3660 ConEmuC64 51 6 964 4008 49 0.02 4936 conhost 55 7 1404 4628 50 7.23 5828 conhost 212 12 1792 3756 44 524 csrss 180 16 2428 38256 202 600 csrss 314 17 3880 10912 44 1728 dasHost
PS C:\> get-process | format-wide armsvc ConEmu ConEmuC64 conhost conhost csrss csrss dasHost
Note that this seems to kill your use of Select-Object:
PS C:\> ps | select-object -Property Name,ID,Handles Name Id Handles ---- -- ------- armsvc 1672 82 audiodg 5320 126
PS C:\> ps | select-object -Property Name,ID,Handles | fw armsvc ConEmu ConEmuC64 conhost conhost csrss csrss dasHost
Format-List
Format-List takes an object or an array of objects and gives a descriptive output of the object's (or objects') properties and values associated with said properties. To be honest, Format-List is kind of a crappy name; the output doesn't really look like a list to me, more like a table. This command is similar to Get-Member but doesn't produce as much output and gives you the data instead of just what data members the object has.
PS C:\> get-date Tuesday, June 9, 2015 8:58:23 PM PS C:\> get-date | format-list DisplayHint : DateTime Date : 6/9/2015 12:00:00 AM Day : 9 DayOfWeek : Tuesday DayOfYear : 160 Hour : 20 Kind : Local Millisecond : 922 Minute : 58 Month : 6 Second : 27 Ticks : 635694803079228445 TimeOfDay : 20:58:27.9228445 Year : 2015 DateTime : Tuesday, June 9, 2015 8:58:27 PM
Filtering
Where-Object
Where-Object is an incredibly useful command which functions similar to piping output to grep. It filters objects based off of specified conditionals. The ? symbol is an alias to Where-Object.
PS C:\> $a = 1,2,3,4,15,6,1,2,6,124,68 # Random ints PS C:\> $b = $a | Where-Object { $_ -gt 6 } # Select anything greater than 6 PS C:\> $b 15 124 68
More examples:
1..100 | ? { -Not ($_ % 2) } # Pick even numbers out of a range get-command | ? Noun -eq "Alias" # See all commands which operate on aliases
Select-Object
Select-Object can be used to limit the amount of information Powershell displays or processes.
For instance, if you only care about the names and sizes of a file, the -Property command can be combined with Get-ChildItem to display this information, ignoring other things like LastWriteTime.
# Displays table of files in directory and their size gci | Select-Object -Property Name,Length
Other useful (and fairly intuitively named) flags to Select-Object include:
- -ExcludeProperty <String[]> - Removes the specified property from the selection.
- -First <int> - Displays only the first <int> elements.
- -Last <int> - Displays only the last <int> elements.
- -Skip <int> - Skips the first <int> elements.
- -SkipLast <int> - Skips the last <int> elements.
- -Unique - Makes the selection into a set with only one of every element.
Command-based Filtering
While Where-Object and Select-Object are really neat, many commands have built-in kinds of filtering, for example the Get-Process command:
PS C:\> # This is much simpler than get-process | ? Name -eq "firefox" PS C:\> get-process -name firefox Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName ------- ------ ----- ----- ----- ------ -- ----------- 1281 185 476300 577120 1557 2,471.92 1792 firefox
If you're curious about a command, check its help page before over-using either filtering tool.
Tips and Tricks
Regular Expressions
Regexp in Powershell is fairly ho-hum, and if you're already familiar with regex in other languages its a breeze. Matching is done with the -Match or -NoMatch operators; -Replace also takes regex as an argument.
PS C:\> "The Thick Brown Fox" -match "The ..ick Brown \w" True PS C:\> "The Quick Brown Fox" -match "The ..ick Brown \w" True PS C:\> "The Quick Brown Fox, The Lazy Dog" -replace "^The","A" A Quick Brown Fox, The Lazy Dog PS C:\>
Working with Windows
Environment Variables
Environment variables are stored in Env:
PS C:\> get-childitem Env: Name Value ---- ----- ALLUSERSPROFILE C:\ProgramData APPDATA <REDACTED> CommonProgramFiles C:\Program Files (x86)\Common Files CommonProgramFiles(x86) C:\Program Files (x86)\Common Files CommonProgramW6432 C:\Program Files\Common Files COMPUTERNAME <REDACTED> ComSpec C:\Windows\system32\cmd.exe FP_NO_HOST_CHECK NO GIT_SSH C:\Program Files (x86)\PuTTY\plink.exe HOME <REDACTED> HOMEDRIVE C: HOMEPATH <REDACTED> LOCALAPPDATA <REDACTED> LOGONSERVER \\MicrosoftAccount NUMBER_OF_PROCESSORS 8 OS Windows_NT Path C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System3... PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL PROCESSOR_ARCHITECTURE x86 PROCESSOR_ARCHITEW6432 AMD64 PROCESSOR_IDENTIFIER Intel64 Family 6 Model 60 Stepping 3, GenuineIntel PROCESSOR_LEVEL 6 PROCESSOR_REVISION 3c03 ProgramData C:\ProgramData ProgramFiles C:\Program Files (x86) ProgramFiles(x86) C:\Program Files (x86) ProgramW6432 C:\Program Files PSModulePath <REDACTED> PUBLIC C:\Users\Public SESSIONNAME Console SVN_SSH C:\Program Files (x86)\PuTTY\plink.exe SystemDrive C: SystemRoot C:\Windows TEMP <REDACTED> TMP <REDACTED> USERDOMAIN <REDACTED> USERDOMAIN_ROAMINGPROFILE <REDACTED> USERNAME <REDACTED> USERPROFILE <REDACTED> VBOX_MSI_INSTALL_PATH C:\Program Files\Oracle\VirtualBox\ windir C:\Windows PS C:\> echo $env:Path C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\Windows PowerShell\v1.0\;C:\Program Files (x86)\Skype\Phone\;C:\Git\cmd;C:\Git\bin;C:\Program Files\MiKTeX 2.9\miktex\bin\x64\
References
- http://g o o seberrycreative.com/cmder/
- http://www.tomsitpro.com/articles/powershell-variables,2-797.html
- http://softwaresalariman.blogspot.com/2007/12/slicing-powershell-arrays-and-ranges.html
- https://technet.microsoft.com/en-us/library/ff406264.aspx
- http://windowsitpro.com/powershell/powershell-basics-console-configuration
- http://stackoverflow.com/questions/5725888/windows-powershell-changing-the-command-prompt
- https://technet.microsoft.com/en-us/library/ff730964.aspx
- https://technet.microsoft.com/en-us/magazine/hh750381.aspx
- http://stackoverflow.com/questions/3666337/how-to-use-new-object-of-a-class-present-in-a-c-sharp-dll-using-powershell
- http://ss64.com/ps/syntax-regex.html