hello friends! new(ish)!
Powershell: Difference between revisions
>Hevnoraak (Added content to format section, reorganized) |
>Hevnoraak (Added references; added data types section) |
||
Line 214: | Line 214: | ||
=== Variables and Data Types === | === Variables and Data Types === | ||
Powershell has lots of weird types (hell, everything is an object), | |||
but primitives are pretty tame, and work as expected. | |||
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:\> | |||
Strings work pretty much exactly like in Java. The backtick (`) is used for escapes, you can compare and concatenate strings, search within them, the list goes on. | |||
PS C:\> $a = "Hello World!" | |||
PS C:\> echo $a | |||
Hello World! | |||
PS C:\> $a = "Hello `n World!" | |||
PS C:\> echo $a | |||
Hello | |||
World! | |||
PS C:\> $a = "Hello`t`tWorld!" | |||
PS C:\> $a | |||
Hello World! | |||
PS C:\> $a = "Hello ``World``!" | |||
PS C:\> $a | |||
Hello `World`! | |||
PS C:\> echo "`$" | |||
$ | |||
PS C:\> $a = "Hello ``World``!" | |||
PS C:\> $a.contains("ello") | |||
True | |||
PS C:\> $a.startswith("He") | |||
True | |||
PS C:\> $a.endswith("!") | |||
True | |||
PS C:\> $a = "Hello ``World``!" | |||
PS C:\> $a + "`n`t- Babbies first words" # Concatenation! | |||
Hello `World`! | |||
- Babbies first words | |||
PS C:\> $a.CompareTo("Hello") | |||
1 | |||
PS C:\> $a.CompareTo("ZZZZZ") | |||
-1 | |||
PS C:\> $a.CompareTo($a) | |||
0 | |||
PS C:\> $a.indexof("W") | |||
7 | |||
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"] + 2 | |||
3 | |||
PS C:\> $a["Key3"] + "IsBob" | |||
YourNameIsBob | |||
PS C:\> | |||
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"; | |||
+ 22:19, 9 June 2015 (EDT)22:19, 9 June 2015 (EDT)22:19, 9 June 2015 (EDT)[[User:Hevnoraak|Hevnoraak]] ([[User talk:Hevnoraak|talk]]) | |||
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException | |||
+ FullyQualifiedErrorId : RuntimeException | |||
PS C:\> [int32](0.0001) | |||
0 | |||
PS C:\> | |||
=== Conditionals === | === Conditionals === | ||
Line 357: | Line 484: | ||
== References == | == References == | ||
* http://www.tomsitpro.com/articles/powershell-variables,2-797.html | |||
* http://softwaresalariman.blogspot.com/2007/12/slicing-powershell-arrays-and-ranges.html |
Revision as of 02:19, 10 June 2015
Powershell
Windows Powershell is a shell / scripting environment created by Microsoft. You can read more about the technical stuff here. 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
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.
Get-Help works with any command and any alias. 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
Scripting Stuff
Variables and Data Types
Powershell has lots of weird types (hell, everything is an object), but primitives are pretty tame, and work as expected.
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:\>
Strings work pretty much exactly like in Java. The backtick (`) is used for escapes, you can compare and concatenate strings, search within them, the list goes on.
PS C:\> $a = "Hello World!" PS C:\> echo $a Hello World! PS C:\> $a = "Hello `n World!" PS C:\> echo $a Hello World! PS C:\> $a = "Hello`t`tWorld!" PS C:\> $a Hello World! PS C:\> $a = "Hello ``World``!" PS C:\> $a Hello `World`! PS C:\> echo "`$" $
PS C:\> $a = "Hello ``World``!" PS C:\> $a.contains("ello") True PS C:\> $a.startswith("He") True PS C:\> $a.endswith("!") True
PS C:\> $a = "Hello ``World``!" PS C:\> $a + "`n`t- Babbies first words" # Concatenation! Hello `World`! - Babbies first words PS C:\> $a.CompareTo("Hello") 1 PS C:\> $a.CompareTo("ZZZZZ") -1 PS C:\> $a.CompareTo($a) 0 PS C:\> $a.indexof("W") 7
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"] + 2 3 PS C:\> $a["Key3"] + "IsBob" YourNameIsBob PS C:\>
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"; + 22:19, 9 June 2015 (EDT)22:19, 9 June 2015 (EDT)22:19, 9 June 2015 (EDT)Hevnoraak (talk) + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException PS C:\> [int32](0.0001) 0 PS C:\>
Conditionals
Loops
Working with Data
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-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