From c518beae09eafa02a392a1ea35782871f85c6311 Mon Sep 17 00:00:00 2001 From: derek-austin Date: Tue, 22 Nov 2016 12:45:45 +0100 Subject: Add syntax highlight (#2581) Only the first chunk of code was highlighted --- powershell.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index f34d5b4e..573b5440 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -35,7 +35,7 @@ $PSVersionTable Getting help: -``` +```powershell # Find commands Get-Command about_* # alias: gcm Get-Command -Verb Add @@ -52,7 +52,7 @@ Update-Help # Run as admin The tutorial starts here: -``` +```powershell # As you already figured, comments start with # # Simple hello world example: @@ -300,7 +300,7 @@ $Shortcut.Save() Configuring your shell -``` +```powershell # $Profile is the full path for your `Microsoft.PowerShell_profile.ps1` # All code there will be executed when the PS session starts if (-not (Test-Path $Profile)) { -- cgit v1.2.3 From 152fddbd9245c6380f7113eb7639fbf0d1fd1c2c Mon Sep 17 00:00:00 2001 From: Samantha McVey Date: Wed, 23 Nov 2016 09:43:37 -0800 Subject: Fix backtick that was messing up syntax highlighting on powershell. --- powershell.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 573b5440..bd46051c 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -74,7 +74,7 @@ $aHashtable = @{name1='val1'; name2='val2'} # Using variables: echo $aString echo "Interpolation: $aString" -echo "`$aString has length of $($aString.Length)" +echo "$aString has length of $($aString.Length)" echo '$aString' echo @" This is a Here-String -- cgit v1.2.3 From 67e2ff0162a8c386a51ee2cc49e36a39ad57c0f0 Mon Sep 17 00:00:00 2001 From: Adam Bard Date: Tue, 12 Sep 2017 22:00:31 -0700 Subject: Try a backslash to fix formatting --- powershell.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index bd46051c..5a5050b4 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -244,7 +244,7 @@ function New-Website() { 'string' | gm # Syntax for calling static .NET methods -[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') +\[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') # Note that .NET functions MUST be called with parentheses # while PS functions CANNOT be called with parentheses. -- cgit v1.2.3 From d7cd776eee4b6d3187ffa50d7d3b2c243885adc5 Mon Sep 17 00:00:00 2001 From: Renze Yu Date: Thu, 8 Nov 2018 10:48:33 +0800 Subject: add list syntax example in for powershell --- powershell.html.markdown | 1 + 1 file changed, 1 insertion(+) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 5a5050b4..f9c20607 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -68,6 +68,7 @@ $aString="Some string" # Or like this: $aNumber = 5 -as [double] $aList = 1,2,3,4,5 +$anEmptyList = @() $aString = $aList -join '--' # yes, -split exists also $aHashtable = @{name1='val1'; name2='val2'} -- cgit v1.2.3 From 8847563b08d3d3ab4492d9a12564dd60c8c77e97 Mon Sep 17 00:00:00 2001 From: dee-see Date: Sat, 2 Feb 2019 20:41:28 -0500 Subject: Fix typo in powershell page --- powershell.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index f9c20607..db29bf96 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -245,7 +245,7 @@ function New-Website() { 'string' | gm # Syntax for calling static .NET methods -\[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') +[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') # Note that .NET functions MUST be called with parentheses # while PS functions CANNOT be called with parentheses. -- cgit v1.2.3 From 2d39fed244d12aa53b6031b607e707482b5b401c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=AD=E4=B9=9D=E9=BC=8E?= <109224573@qq.com> Date: Sun, 12 Jan 2020 16:43:09 +0800 Subject: [powershell/en] Update url --- powershell.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index db29bf96..06fa7977 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -15,7 +15,7 @@ in the shell. A key difference with Bash is that it is mostly objects that you manipulate rather than plain text. -[Read more here.](https://technet.microsoft.com/en-us/library/bb978526.aspx) +[Read more here.](https://docs.microsoft.com/zh-cn/powershell/scripting/overview) If you are uncertain about your environment: @@ -321,7 +321,7 @@ Interesting Projects * [PSake](https://github.com/psake/psake) Build automation tool * [Pester](https://github.com/pester/Pester) BDD Testing Framework * [Jump-Location](https://github.com/tkellogg/Jump-Location) Powershell `cd` that reads your mind -* [PowerShell Community Extensions](http://pscx.codeplex.com/) (Dead) +* [PowerShell Community Extensions](https://github.com/Pscx/Pscx) Not covered -- cgit v1.2.3 From aa35d1c5f3008f77c5825c9966ab94fde4b17627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=AD=E4=B9=9D=E9=BC=8E?= <109224573@qq.com> Date: Sun, 12 Jan 2020 16:44:21 +0800 Subject: Update powershell.html.markdown --- powershell.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 06fa7977..5d74024d 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -15,7 +15,7 @@ in the shell. A key difference with Bash is that it is mostly objects that you manipulate rather than plain text. -[Read more here.](https://docs.microsoft.com/zh-cn/powershell/scripting/overview) +[Read more here.](https://docs.microsoft.com/powershell/scripting/overview) If you are uncertain about your environment: -- cgit v1.2.3 From 6151e30b6b7d069095611ceab616a04eed4b2782 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Sat, 16 May 2020 19:26:29 -0700 Subject: [powershell/en] Adding some things I find useful --- powershell.html.markdown | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 5d74024d..75645bbb 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -55,6 +55,11 @@ The tutorial starts here: ```powershell # As you already figured, comments start with # +<# + Multi-line comments + like so +#> + # Simple hello world example: echo Hello world! # echo is an alias for Write-Output (=cmdlet) @@ -68,6 +73,8 @@ $aString="Some string" # Or like this: $aNumber = 5 -as [double] $aList = 1,2,3,4,5 +# Reverse an array *Note this is a mutation on the existing array +[array]::Reverse($aList) $anEmptyList = @() $aString = $aList -join '--' # yes, -split exists also $aHashtable = @{name1='val1'; name2='val2'} @@ -100,6 +107,10 @@ echo "Bound arguments in a function, script or code block: $PSBoundParameters" echo "Unbound arguments: $($Args -join ', ')." # More builtins: `help about_Automatic_Variables` +# Find the datatype of variables or properties you're working with +$true.GetType() +$aHashtable.name2.GetType() + # Inline another file (dot operator) . .\otherScriptName.ps1 @@ -184,7 +195,7 @@ Get-Process | Sort-Object ID -Descending | Select-Object -First 10 Name,ID,VM ` Get-EventLog Application -After (Get-Date).AddHours(-2) | Format-List # Use % as a shorthand for ForEach-Object -(a,b,c) | ForEach-Object ` +('a','b','c') | ForEach-Object ` -Begin { "Starting"; $counter = 0 } ` -Process { "Processing $_"; $counter++ } ` -End { "Finishing: $counter" } @@ -198,12 +209,13 @@ ps | Format-Table ID,Name,@{n='VM(MB)';e={'{0:n2}' -f ($_.VM / 1MB)}} -autoSize ### Functions # The [string] attribute is optional. -function foo([string]$name) { +# Function names should follow Verb-Noun convention +function Get-Foo([string]$name) { echo "Hey $name, have a function" } # Calling your function -foo "Say my name" +Get-Foo "Say my name" # Functions with named parameters, parameter attributes, parsable documentation <# @@ -283,7 +295,22 @@ Pop-Location # change back to previous working directory # Unblock a directory after download Get-ChildItem -Recurse | Unblock-File +# You can also pass arguments to a Function with a hash table +# This is called Splatting +# Normal Command +Export-Csv -InputObject $csv -Path 'c:\mypath' -Encoding UTF8 -NoTypeInformation +# With Splatting +$csvArguments = @{ + InputObject = $csv + Path = 'c:\mypath' + Encoding = 'UTF8' + NoTypeInformation = $true +} +Export-Csv @csvArguments + # Open Windows Explorer in working directory +Invoke-Item . +# Or the alias ii . # Any key to exit @@ -318,6 +345,7 @@ Interesting Projects * [PSGet](https://github.com/psget/psget) NuGet for PowerShell * [PSReadLine](https://github.com/lzybkr/PSReadLine/) A bash inspired readline implementation for PowerShell (So good that it now ships with Windows10 by default!) * [Posh-Git](https://github.com/dahlbyk/posh-git/) Fancy Git Prompt (Recommended!) +* [Oh-My-Posh](https://github.com/JanDeDobbeleer/oh-my-posh) * [PSake](https://github.com/psake/psake) Build automation tool * [Pester](https://github.com/pester/Pester) BDD Testing Framework * [Jump-Location](https://github.com/tkellogg/Jump-Location) Powershell `cd` that reads your mind -- cgit v1.2.3 From 0f19d90383916c72fa1872e192538ef6c2f7dc5d Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Sun, 17 May 2020 00:18:21 -0700 Subject: Adding comment next to new link at bottom It seems I didn't add the details of the link initially. --- powershell.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 75645bbb..6efd984c 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -345,7 +345,7 @@ Interesting Projects * [PSGet](https://github.com/psget/psget) NuGet for PowerShell * [PSReadLine](https://github.com/lzybkr/PSReadLine/) A bash inspired readline implementation for PowerShell (So good that it now ships with Windows10 by default!) * [Posh-Git](https://github.com/dahlbyk/posh-git/) Fancy Git Prompt (Recommended!) -* [Oh-My-Posh](https://github.com/JanDeDobbeleer/oh-my-posh) +* [Oh-My-Posh](https://github.com/JanDeDobbeleer/oh-my-posh) Shell customization similar to the popular Oh-My-Zsh on Mac * [PSake](https://github.com/psake/psake) Build automation tool * [Pester](https://github.com/pester/Pester) BDD Testing Framework * [Jump-Location](https://github.com/tkellogg/Jump-Location) Powershell `cd` that reads your mind -- cgit v1.2.3 From b30a88cd3115e100fa34deeedffed206882947a0 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Mon, 3 Aug 2020 02:22:18 -0700 Subject: Revamping Powershell Changing to reflect current capabilities and draw similarities to other languages in terms of capabilities --- powershell.html.markdown | 871 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 610 insertions(+), 261 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 6efd984c..f2f2be61 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -3,6 +3,7 @@ category: tool tool: powershell contributors: - ["Wouter Van Schandevijl", "https://github.com/laoujin"] + - ["Andrew Ryan Davis", "https://github.com/AndrewDavis1191"] filename: LearnPowershell.ps1 --- @@ -13,116 +14,347 @@ Nearly all examples below can be a part of a shell script or executed directly in the shell. A key difference with Bash is that it is mostly objects that you manipulate -rather than plain text. +rather than plain text. After years of evolving, it resembles Python a bit. [Read more here.](https://docs.microsoft.com/powershell/scripting/overview) -If you are uncertain about your environment: - +Powershell as a Language: ```powershell -Get-ExecutionPolicy -List -Set-ExecutionPolicy AllSigned -# Execution policies include: -# - Restricted: Scripts won't run. -# - RemoteSigned: Downloaded scripts run only if signed by a trusted publisher. -# - AllSigned: Scripts need to be signed by a trusted publisher. -# - Unrestricted: Run all scripts. -help about_Execution_Policies # for more info -# Current PowerShell version: -$PSVersionTable -``` +# Single line comments start with a number symbol. -Getting help: +<# + Multi-line comments + like so +#> -```powershell -# Find commands -Get-Command about_* # alias: gcm -Get-Command -Verb Add -Get-Alias ps -Get-Alias -Definition Get-Process +#################################################### +## 1. Primitive Datatypes and Operators +#################################################### + +# Numbers +3 # => 3 + +# Math +1 + 1 # => 2 +8 - 1 # => 7 +10 * 2 # => 20 +35 / 5 # => 7.0 + +# Powershell uses banker's rounding +# Meaning [int]1.5 would round to 2 but so would [int]2.5 +# division always returns a float. You must cast result to [int] to round +[int]5 / [int]3 # => 1.66666666666667 +[int]-5 / [int]3 # => -1.66666666666667 +5.0 / 3.0 # => 1.66666666666667 +-5.0 / 3.0 # => -1.66666666666667 +[int]$result = 5 / 3 # => 2 + +# Modulo operation +7 % 3 # => 1 + +# Exponentiation requires longform or the built-in [Math] class +[Math]::Pow(2,3) # => 8 + +# Enforce order of operations with parentheses +1 + 3 * 2 # => 7 +(1 + 3) * 2 # => 8 + +# Boolean values are primitives (Note: the $) +$True # => True +$False # => False + +# negate with ! +!$True # => False +!$False # => True + +# Boolean Operators +# Note "-and" and "-or" usage +$True -and $False # => False +$False -or $True # => True + +# True and False are actually 1 and 0 but only support limited arithmetic +# However, casting the bool to int resolves this +$True + $True # => 2 +$True * 8 # => '[System.Boolean] * [System.Int32]' is undefined +[int]$True * 8 # => 8 +$False - 5 # => -5 + +# Comparison operators look at the numerical value of True and False +0 -eq $False # => True +1 -eq $True # => True +2 -eq $True # => False +-5 -ne $False # => True + +# Using boolean logical operators on ints casts them to booleans for evaluation +# but their non-cast value is returned +# Don't mix up with bool(ints) and bitwise and/or (&,|) +[bool](0) # => False +[bool](4) # => True +[bool](-6) # => True +0 -and 2 # => 0 +-5 -or 0 # => -5 + +# Equality is -eq (equals) +1 -eq 1 # => True +2 -eq 1 # => False + +# Inequality is -ne (notequals) +1 -ne 1 # => False +2 -ne 1 # => True + +# More comparisons +1 -lt 10 # => True +1 -gt 10 # => False +2 -le 2 # => True +2 -ge 2 # => True + +# Seeing whether a value is in a range +1 -lt 2 -and 2 -lt 3 # => True +2 -lt 3 -and 3 -lt 2 # => False + +# (-is vs. -eq) -is checks if two objects are the same type +# -eq checks if the objects have the same values. +[System.Collections.ArrayList]$a = @() # Point a at a new list +$a = (1,2,3,4) +$b = $a # => Point b at what a is pointing to +$b -is $a.getType() # => True, a and b equal same type +$b -eq $a # => True, a and b values are equal +[System.Collections.Hashtable]$b = @{} # => Point a at a new hash table +$b = @{'one' = 1 + 'two' = 2} +$b -is $a.GetType() # => False, a and b types not equal + +# Strings are created with " or ' but " is required for string interpolation +"This is a string." +'This is also a string.' + +# Strings can be added too! But try not to do this. +"Hello " + "world!" # => "Hello world!" + +# A string can be treated like a list of characters +"Hello world!"[0] # => 'H' + +# You can find the length of a string +("This is a string").Length # => 16 + +# You can also format using f-strings or formatted string literals +$name = "Steve" +$age = 22 +"He said his name is $name." # => "He said his name is Steve" +“{0} said he is {1} years old.” -f $name, $age # => "Steve said he is 22 years old" +"$name's name is $($name.Length) characters long." # => "Steve's name is 5 characters long." + +# $null is not an object +$null # => None + +# $null, 0, and empty strings and arrays all evaluate to False. +# All other values are True +function test ($value) { + if ($value) {Write-Output 'True'} + else {Write-Output 'False'} +} +test ($null) # => False +test (0) # => False +test ("") # => False +test [] # => True +test ({}) # => True +test @() # => False + +#################################################### +## 2. Variables and Collections +#################################################### + +# Powershell uses the "Write-Output" function to print +Write-Output "I'm Powershell. Nice to meet you!" # => I'm Powershell. Nice to meet you! + +# Simple way to get input data from console +$userInput = Read-Host "Enter some data: " # Returns the data as a string + +# There are no declarations, only assignments. +# Convention is to use camelCase or PascalCase, whatever your team uses. +$someVariable = 5 +$someVariable # => 5 + +# Accessing a previously unassigned variable does not throw exception. +# The value is $null by default + +# Ternary Operators exist in Powershell 7 and up +0 ? 'yes' : 'no' # => no + +# The default array object in Powershell is an immutable array +$defaultArray = "thing","thing2","thing3" +# you are unable to add or remove objects +$defaultArray.Add("thing4") # => Exception "Collection was of a fixed size." +# To have a mutable array, you will need to use the .NET ArrayList class + +# ArrayLists store sequences +[System.Collections.ArrayList]$array = @() +# You can start with a prefilled ArrayList +[System.Collections.ArrayList]$otherArray = @(4, 5, 6) -Get-Help ps | less # alias: help -ps | Get-Member # alias: gm +# Add stuff to the end of a list with add (Note: it produces output, so append to $null) +$array.add(1) > $null # $array is now [1] +$array.add(2) > $null # $array is now [1, 2] +$array.add(4) > $null # $array is now [1, 2, 4] +$array.add(3) > $null # $array is now [1, 2, 4, 3] +# Remove from the end with index of count of objects-1 as arrays are indexed starting 0 +$array.RemoveAt($array.Count-1) # => 3 and array is now [1, 2, 4] +# Let's put it back +$array.Add(3) > $null # array is now [1, 2, 4, 3] again. -Show-Command Get-EventLog # Display GUI to fill in the parameters +# Access a list like you would any array +$array[0] # => 1 +# Look at the last element +$array[-1] # => 3 -Update-Help # Run as admin -``` +# Looking out of bounds returns nothing +$array[4] # blank line returned -The tutorial starts here: +# You can look at ranges with slice syntax. +# The start index is included, the end index is not +# (It's a closed/open range for you mathy types.) +$array[1..3] # Return array from index 1 to 3 => [2, 4] +$array[2..-1] # Return array starting from index 2 => [4, 3] +$array[0..3] # Return array from beginning until index 3 => [1, 2, 4] +$array[0..2] # Return array selecting every second entry => [1, 4] +$array.Reverse() # mutates array to reverse order => [3, 4, 2, 1] +# Use any combination of these to make advanced slices + +# Remove arbitrary elements from a array with "del" +$array.Remove($array[2]) # $array is now [1, 2, 3] + +# Insert an element at a specific index +$array.Insert(1, 2) # $array is now [1, 2, 3] again + +# Get the index of the first item found matching the argument +$array.IndexOf(2) # => 1 +$array.IndexOf(6) # Returns -1 as "outside array" + +# You can add arrays +# Note: values for $array and for $otherArray are not modified. +$array + $otherArray # => [1, 2, 3, 4, 5, 6] + +# Concatenate arrays with "AddRange()" +$array.AddRange($otherArray) # Now $array is [1, 2, 3, 4, 5, 6] + +# Check for existence in a array with "in" +1 -in $array # => True + +# Examine the length with "Count" (Note: Length method on arrayList = each items length) +$array.Count # => 6 + + +# Tuples are like arrays but are immutable. +# To use Tuples in powershell, you must use the .NET tuple class +$tuple = [System.Tuple]::Create(1, 2, 3) +$tuple.Item(0) # => 1 +$tuple.Item(0) = 3 # Raises a TypeError + +# You can do some of the array methods on tuples, but they are limited +$tuple.Length # => 3 +$tuple + (4, 5, 6) # => Exception +$tuple[0..2] # => $null +2 -in $tuple # => False + + +# Hashtables store mappings from keys to values, similar to Dictionaries +$emptyHash = @{} +# Here is a prefilled dictionary +$filledHash = @{"one"= 1 + "two"= 2 + "three"= 3} + +# Look up values with [] +$filledHash["one"] # => 1 + +# Get all keys as an iterable with ".Keys". +# items maintain the order at which they are inserted into the dictionary. +$filledHash.keys # => ["one", "two", "three"] + + + +# Get all values as an iterable with ".Values". +$filledHash.values # => [1, 2, 3] + +# Check for existence of keys or values in a hash with "-in" +"one" -in $filledHash.Keys # => True +1 -in $filledHash.Values # => False + +# Looking up a non-existing key returns $null +$filledHash["four"] # $null + +# Adding to a dictionary +$filledHash.Add("five",5) # $filledHash["five"] is set to 5 +$filledHash.Add("five",6) # exception "Item with key "five" has already been added" +$filledHash["four"] = 4 # $filledHash["four"] is set to 4, run again and it does nothing + +# Remove keys from a dictionary with del +$filledHash.Remove("one") # Removes the key "one" from filled dict + + + +#################################################### +## 3. Control Flow and Iterables +#################################################### + +# Let's just make a variable +$someVar = 5 + +# Here is an if statement. +# This prints "$someVar is smaller than 10" +if ($someVar -gt 10) { + Write-Output "$someVar is bigger than 10." +} +elseif ($someVar -lt 10) { # This elseif clause is optional. + Write-Output "$someVar is smaller than 10." +} +else { # This is optional too. + Write-Output "$someVar is indeed 10." +} -```powershell -# As you already figured, comments start with # <# - Multi-line comments - like so +Foreach loops iterate over arrays +prints: + dog is a mammal + cat is a mammal + mouse is a mammal +#> +foreach ($animal in ("dog", "cat", "mouse")) { + # You can use -f to interpolate formatted strings + "{0} is a mammal" -f $animal +} + +<# +For loops iterate over arrays and you can specify indices +prints: + 0 a + 1 b + 2 c + 3 d + 4 e + 5 f + 6 g + 7 h #> +$letters = ('a','b','c','d','e','f','g','h') +for($i=0; $i -le $letters.Count-1; $i++){ + Write-Host $i, $letters[$i] +} -# Simple hello world example: -echo Hello world! -# echo is an alias for Write-Output (=cmdlet) -# Most cmdlets and functions follow the Verb-Noun naming convention - -# Each command starts on a new line, or after a semicolon: -echo 'This is the first line'; echo 'This is the second line' - -# Declaring a variable looks like this: -$aString="Some string" -# Or like this: -$aNumber = 5 -as [double] -$aList = 1,2,3,4,5 -# Reverse an array *Note this is a mutation on the existing array -[array]::Reverse($aList) -$anEmptyList = @() -$aString = $aList -join '--' # yes, -split exists also -$aHashtable = @{name1='val1'; name2='val2'} - -# Using variables: -echo $aString -echo "Interpolation: $aString" -echo "$aString has length of $($aString.Length)" -echo '$aString' -echo @" -This is a Here-String -$aString -"@ -# Note that ' (single quote) won't expand the variables! -# Here-Strings also work with single quote - -# Builtin variables: -# There are some useful builtin variables, like -echo "Booleans: $TRUE and $FALSE" -echo "Empty value: $NULL" -echo "Last program's return value: $?" -echo "Exit code of last run Windows-based program: $LastExitCode" -echo "The last token in the last line received by the session: $$" -echo "The first token: $^" -echo "Script's PID: $PID" -echo "Full path of current script directory: $PSScriptRoot" -echo 'Full path of current script: ' + $MyInvocation.MyCommand.Path -echo "FUll path of current directory: $Pwd" -echo "Bound arguments in a function, script or code block: $PSBoundParameters" -echo "Unbound arguments: $($Args -join ', ')." -# More builtins: `help about_Automatic_Variables` - -# Find the datatype of variables or properties you're working with -$true.GetType() -$aHashtable.name2.GetType() - -# Inline another file (dot operator) -. .\otherScriptName.ps1 - - -### Control Flow -# We have the usual if structure: -if ($Age -is [string]) { - echo 'But.. $Age cannot be a string!' -} elseif ($Age -lt 12 -and $Age -gt 0) { - echo 'Child (Less than 12. Greater than 0)' -} else { - echo 'Adult' +<# +While loops go until a condition is no longer met. +prints: + 0 + 1 + 2 + 3 +#> +$x = 0 +while ($x -lt 4) { + Write-Output $x + $x += 1 # Shorthand for x = x + 1 } # Switch statements are more powerful compared to most languages @@ -137,85 +369,52 @@ switch($val) { default { "Others" } } -# The classic for -for($i = 1; $i -le 10; $i++) { - "Loop number $i" +# Handle exceptions with a try/catch block +try { + # Use "throw" to raise an error + throw "This is an error" } -# Or shorter -1..10 | % { "Loop number $_" } - -# PowerShell also offers -foreach ($var in 'val1','val2','val3') { echo $var } -# while () {} -# do {} while () -# do {} until () - -# Exception handling -try {} catch {} finally {} -try {} catch [System.NullReferenceException] { - echo $_.Exception | Format-List -Force +catch { + Write-Output $Error.ExceptionMessage +} +finally { + Write-Output "We can clean up resources here" } -### Providers -# List files and directories in the current directory -ls # or `dir` -cd ~ # goto home - -Get-Alias ls # -> Get-ChildItem -# Uh!? These cmdlets have generic names because unlike other scripting -# languages, PowerShell does not only operate in the current directory. -cd HKCU: # go to the HKEY_CURRENT_USER registry hive - -# Get all providers in your session -Get-PSProvider - -### Pipeline -# Cmdlets have parameters that control their execution: -Get-ChildItem -Filter *.txt -Name # Get just the name of all txt files -# Only need to type as much of a parameter name until it is no longer ambiguous -ls -fi *.txt -n # -f is not possible because -Force also exists -# Use `Get-Help Get-ChildItem -Full` for a complete overview +# Writing to a file +$contents = @{"aa"= 12 + "bb"= 21} +$contents | Export-CSV "$env:HOMEDRIVE\file.csv" # writes to a file -# Results of the previous cmdlet can be passed to the next as input. -# `$_` is the current object in the pipeline object. -ls | Where-Object { $_.Name -match 'c' } | Export-CSV export.txt -ls | ? { $_.Name -match 'c' } | ConvertTo-HTML | Out-File export.html +$contents = "test string here" +$contents | Out-File "$env:HOMEDRIVE\file.txt" # writes to another file -# If you get confused in the pipeline use `Get-Member` for an overview -# of the available methods and properties of the pipelined objects: -ls | Get-Member -Get-Date | gm +# Read file contents and convert to json +Get-Content "$env:HOMEDRIVE\file.csv" | ConvertTo-Json -# ` is the line continuation character. Or end the line with a | -Get-Process | Sort-Object ID -Descending | Select-Object -First 10 Name,ID,VM ` - | Stop-Process -WhatIf -Get-EventLog Application -After (Get-Date).AddHours(-2) | Format-List -# Use % as a shorthand for ForEach-Object -('a','b','c') | ForEach-Object ` - -Begin { "Starting"; $counter = 0 } ` - -Process { "Processing $_"; $counter++ } ` - -End { "Finishing: $counter" } +#################################################### +## 4. Functions +#################################################### -# Get-Process as a table with three columns -# The third column is the value of the VM property in MB and 2 decimal places -# Computed columns can be written more verbose as: -# `@{name='lbl';expression={$_}` -ps | Format-Table ID,Name,@{n='VM(MB)';e={'{0:n2}' -f ($_.VM / 1MB)}} -autoSize +# Use "function" to create new functions +# Keep the Verb-Noun naming convention for functions +function Add-Numbers { + $args[0] + $args[1] +} +Add-Numbers 1 2 # => 3 -### Functions -# The [string] attribute is optional. -# Function names should follow Verb-Noun convention -function Get-Foo([string]$name) { - echo "Hey $name, have a function" +# Calling functions with parameters +function Add-ParamNumbers { + param( [int]$FirstNumber, [int]$SecondNumber ) + $FirstNumber + $SecondNumber } -# Calling your function -Get-Foo "Say my name" +Add-ParamNumbers -FirstNumber 1 -SecondNumber 2 # => 3 # Functions with named parameters, parameter attributes, parsable documentation <# @@ -232,111 +431,268 @@ New-Website siteName 2000 # ERROR! Port argument could not be validated ('name1','name2') | New-Website -Verbose #> function New-Website() { - [CmdletBinding()] - param ( - [Parameter(ValueFromPipeline=$true, Mandatory=$true)] - [Alias('name')] - [string]$siteName, - [ValidateSet(3000,5000,8000)] - [int]$port = 3000 - ) - BEGIN { Write-Verbose 'Creating new website(s)' } - PROCESS { echo "name: $siteName, port: $port" } - END { Write-Verbose 'Website(s) created' } + [CmdletBinding()] + param ( + [Parameter(ValueFromPipeline=$true, Mandatory=$true)] + [Alias('name')] + [string]$siteName, + [ValidateSet(3000,5000,8000)] + [int]$port = 3000 + ) + BEGIN { Write-Verbose 'Creating new website(s)' } + PROCESS { echo "name: $siteName, port: $port" } + END { Write-Verbose 'Website(s) created' } } -### It's all .NET -# A PS string is in fact a .NET System.String -# All .NET methods and properties are thus available -'string'.ToUpper().Replace('G', 'ggg') -# Or more powershellish -'string'.ToUpper() -replace 'G', 'ggg' - -# Unsure how that .NET method is called again? -'string' | gm - -# Syntax for calling static .NET methods -[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') - -# Note that .NET functions MUST be called with parentheses -# while PS functions CANNOT be called with parentheses. -# If you do call a cmdlet/PS function with parentheses, -# it is the same as passing a single parameter list -$writer = New-Object System.IO.StreamWriter($path, $true) -$writer.Write([Environment]::NewLine) -$writer.Dispose() - -### IO -# Reading a value from input: -$Name = Read-Host "What's your name?" -echo "Hello, $Name!" -[int]$Age = Read-Host "What's your age?" - -# Test-Path, Split-Path, Join-Path, Resolve-Path -# Get-Content filename # returns a string[] -# Set-Content, Add-Content, Clear-Content -Get-Command ConvertTo-*,ConvertFrom-* - - -### Useful stuff -# Refresh your PATH -$env:PATH = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + - ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") - -# Find Python in path -$env:PATH.Split(";") | Where-Object { $_ -like "*python*"} - -# Change working directory without having to remember previous path -Push-Location c:\temp # change working directory to c:\temp -Pop-Location # change back to previous working directory -# Aliases are: pushd and popd - -# Unblock a directory after download -Get-ChildItem -Recurse | Unblock-File - -# You can also pass arguments to a Function with a hash table -# This is called Splatting -# Normal Command -Export-Csv -InputObject $csv -Path 'c:\mypath' -Encoding UTF8 -NoTypeInformation -# With Splatting -$csvArguments = @{ - InputObject = $csv - Path = 'c:\mypath' - Encoding = 'UTF8' - NoTypeInformation = $true +#################################################### +## 5. Modules +#################################################### + +# You can import modules and install modules +# The Install-Module is similar to pip or npm, pulls from Powershell Gallery +Install-Module dbaTools +Import-Module dbaTools + +$query = "SELECT * FROM dbo.sometable" +$queryParams = @{ + SqlInstance = 'testInstance' + Database = 'testDatabase' + Query = $query +} +Invoke-DbaQuery @queryParams + +# You can get specific functions from a module +Import-Module -Function Invoke-DbaQuery + + +# Powershell modules are just ordinary Posh files. You +# can write your own, and import them. The name of the +# module is the same as the name of the file. + +# You can find out which functions and attributes +# are defined in a module. +Get-Command -module dbaTools +Get-Help dbaTools -Full + + + +#################################################### +## 6. Classes +#################################################### + +# We use the "class" statement to create a class +class Instrument { + [string]$Type + [string]$Family +} + +$instrument = [Instrument]::new() +$instrument.Type = "String Instrument" +$instrument.Family = "Plucked String" + +$instrument + +<# Output: +Type Family +---- ------ +String Instrument Plucked String +#> + + +#################################################### +## 6.1 Inheritance +#################################################### + +# Inheritance allows new child classes to be defined that inherit methods and +# variables from their parent class. + +class Guitar : Instrument +{ + [string]$Brand + [string]$SubType + [string]$ModelType + [string]$ModelNumber +} + +$myGuitar = [Guitar]::new() +$myGuitar.Brand = "Taylor" +$myGuitar.SubType = "Acoustic" +$myGuitar.ModelType = "Presentation" +$myGuitar.ModelNumber = "PS14ce Blackwood" + +$myGuitar.GetType() + +<# +IsPublic IsSerial Name BaseType +-------- -------- ---- -------- +True False Guitar Instrument +#> + + +#################################################### +## 7. Advanced +#################################################### + +# The powershell pipeline allows us to do things like High-Order Functions + +# Group Object is a handy command that does incredible things for us +# It works much like a GROUP BY in SQL would + +<# + The following will get all the running processes + Group them by Name + And tell us how many instances of each process we have running + Tip: Chrome and svcHost are usually big numbers in this regard +#> +Get-Process | Foreach ProcessName | Group-Object + +<# + Asynchronous functions exist in the form of jobs + Typically a procedural language + Powershell can operate many non-blocking functions when invoked as Jobs +#> + +# This function is commonly known to be non-optimized, and therefore slow +$installedApps = Get-CimInstance -ClassName Win32_Product + +# If we had a script, it would hang at this func for a period of time +$scriptBlock = {Get-CimInstance -ClassName Win32_Product} +Start-Job -ScriptBlock $scriptBlock + +# This will start a background job that runs the command +# You can then obtain the status of jobs and their returned results +$allJobs = Get-Job +$JobResponse = Get-Job | Receive-Job + + +# Math is built in to powershell and has many functions +$r=2 +$pi=[math]::pi +$r2=[math]::pow( $r, 2 ) +$Area = $pi*$r2 +$Area + +# To see all possibilities, check the members +[System.Math] | Get-Member -Static -MemberType All + +<# + This is a silly one + You may one day be asked to create a func that could take $start and $end + and reverse anything in an array within the given range + based on an arbitrary array + Let's see one way to do that +#> + +$testArray = 'a','b','c','d','e','f','g','h','i','j','k','l','m','n' + +function Reverse-Range ($start, $end) { +[System.Collections.ArrayList]$newArray = @() +[System.Collections.ArrayList]$secondArray = @() +[System.Collections.Stack]$stack = @() + for ($i = 0; $i -lt $testArray.Length; $i++) { + if ($i -lt $start) { + $newArray.Add($testArray[$i]) > $null + } + elseif ($i -ge $start -and $i -le $end) { + $stack.push($testArray[$i]) + } + elseif ($i -gt $end) { + $secondArray.Add($testArray[$i]) > $null + } + } + $endArray = $newArray + $stack.ToArray() + $secondArray + Write-Output $endArray } -Export-Csv @csvArguments - -# Open Windows Explorer in working directory -Invoke-Item . -# Or the alias -ii . - -# Any key to exit -$host.UI.RawUI.ReadKey() -return - -# Create a shortcut -$WshShell = New-Object -comObject WScript.Shell -$Shortcut = $WshShell.CreateShortcut($link) -$Shortcut.TargetPath = $file -$Shortcut.WorkingDirectory = Split-Path $file -$Shortcut.Save() ``` +Powershell as a Tool: +Getting Help: +```Powershell +# Find commands +Get-Command about_* # alias: gcm +Get-Command -Verb Add +Get-Alias ps +Get-Alias -Definition Get-Process + +Get-Help ps | less # alias: help +ps | Get-Member # alias: gm -Configuring your shell +Show-Command Get-EventLog # Display GUI to fill in the parameters -```powershell -# $Profile is the full path for your `Microsoft.PowerShell_profile.ps1` -# All code there will be executed when the PS session starts -if (-not (Test-Path $Profile)) { - New-Item -Type file -Path $Profile -Force - notepad $Profile +Update-Help # Run as admin +``` + +If you are uncertain about your environment: +```Powershell +Get-ExecutionPolicy -List +Set-ExecutionPolicy AllSigned +# Execution policies include: +# - Restricted: Scripts won't run. +# - RemoteSigned: Downloaded scripts run only if signed by a trusted publisher. +# - AllSigned: Scripts need to be signed by a trusted publisher. +# - Unrestricted: Run all scripts. +help about_Execution_Policies # for more info + +# Current PowerShell version: +$PSVersionTable +``` + +```Powershell +# Remoting into computers is easy +Enter-PSSession -ComputerName RemoteComputer +# Once remoted in, you can run commands as if you're local +RemoteComputer\PS> Get-Process powershell +<# +Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName +------- ------ ----- ----- ------ -- -- ----------- + 1096 44 156324 179068 29.92 11772 1 powershell + 545 25 49512 49852 25348 0 powershell +#> +RemoteComputer\PS> Exit-PSSession + +<# + Powershell is an incredible tool for Windows management and Automation + Let's take the following scenario + You have 10 servers + You need to check whether a service is running on all of them + You can RDP and log in, or PSSession to all of them, but why? + Check out the following +#> + +$serverList = @( + 'server1', + 'server2', + 'server3', + 'server4', + 'server5', + 'server6', + 'server7', + 'server8', + 'server9', + 'server10' +) + +[scriptblock]$Script = { + Get-Service -DisplayName 'Task Scheduler' } -# More info: `help about_profiles` -# For a more useful shell, be sure to check the project PSReadLine below + +foreach ($server in $serverList) { + $CmdSplat = @{ + ComputerName = $Server + JobName = 'checkService' + ScriptBlock = $Script + AsJob = $true + ErrorAction = 'SilentlyContinue' + } + Invoke-Command @CmdSplat | Out-Null +} + +<# + Here we've invoked jobs across many servers + We can now Receive-Job and see if they're all running + Now scale this up 100x as many servers :) +#> ``` Interesting Projects @@ -350,10 +706,3 @@ Interesting Projects * [Pester](https://github.com/pester/Pester) BDD Testing Framework * [Jump-Location](https://github.com/tkellogg/Jump-Location) Powershell `cd` that reads your mind * [PowerShell Community Extensions](https://github.com/Pscx/Pscx) - -Not covered - -* WMI: Windows Management Intrumentation (Get-CimInstance) -* Multitasking: Start-Job -scriptBlock {...}, -* Code Signing -* Remoting (Enter-PSSession/Exit-PSSession; Invoke-Command) -- cgit v1.2.3 From 11db56b81cf860ce161d148e82f606e70406ebf4 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Wed, 5 Aug 2020 19:13:35 -0700 Subject: Making some minor fixes Adjusting some inconsistent names. Changing Remove-Array to Format-Array since Remove is not an approved Posh verb. Adding Kevin Marquette's blog because it's awesome Adding a simpler array reversal example --- powershell.html.markdown | 70 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 16 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index f2f2be61..99f5de97 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -41,6 +41,26 @@ Powershell as a Language: 10 * 2 # => 20 35 / 5 # => 7.0 +# Single line comments start with a number symbol. + +<# + Multi-line comments + like so +#> + +#################################################### +## 1. Primitive Datatypes and Operators +#################################################### + +# Numbers +3 # => 3 + +# Math +1 + 1 # => 2 +8 - 1 # => 7 +10 * 2 # => 20 +35 / 5 # => 7.0 + # Powershell uses banker's rounding # Meaning [int]1.5 would round to 2 but so would [int]2.5 # division always returns a float. You must cast result to [int] to round @@ -440,7 +460,7 @@ function New-Website() { [int]$port = 3000 ) BEGIN { Write-Verbose 'Creating new website(s)' } - PROCESS { echo "name: $siteName, port: $port" } + PROCESS { Write-Output "name: $siteName, port: $port" } END { Write-Verbose 'Website(s) created' } } @@ -545,7 +565,7 @@ True False Guitar Instrument And tell us how many instances of each process we have running Tip: Chrome and svcHost are usually big numbers in this regard #> -Get-Process | Foreach ProcessName | Group-Object +Get-Process | Foreach-Object ProcessName | Group-Object <# Asynchronous functions exist in the form of jobs @@ -581,28 +601,45 @@ $Area You may one day be asked to create a func that could take $start and $end and reverse anything in an array within the given range based on an arbitrary array - Let's see one way to do that + Let's see one way to do that and introduce another data structure #> -$testArray = 'a','b','c','d','e','f','g','h','i','j','k','l','m','n' +$targetArray = 'a','b','c','d','e','f','g','h','i','j','k','l','m','n' -function Reverse-Range ($start, $end) { -[System.Collections.ArrayList]$newArray = @() -[System.Collections.ArrayList]$secondArray = @() +function Format-Range ($start, $end) { +[System.Collections.ArrayList]$firstSectionArray = @() +[System.Collections.ArrayList]$secondSectionArray = @() [System.Collections.Stack]$stack = @() - for ($i = 0; $i -lt $testArray.Length; $i++) { - if ($i -lt $start) { - $newArray.Add($testArray[$i]) > $null + for ($index = 0; $index -lt $targetArray.Count; $index++) { + if ($index -lt $start) { + $firstSectionArray.Add($targetArray[$index]) > $null } - elseif ($i -ge $start -and $i -le $end) { - $stack.push($testArray[$i]) + elseif ($index -ge $start -and $index -le $end) { + $stack.Push($targetArray[$index]) } - elseif ($i -gt $end) { - $secondArray.Add($testArray[$i]) > $null + elseif ($index -gt $end) { + $secondSectionArray.Add($targetArray[$index]) > $null } } - $endArray = $newArray + $stack.ToArray() + $secondArray - Write-Output $endArray + $returnArray = $firstSectionArray + $stack.ToArray() + $secondSectionArray + Write-Output $returnArray +} + +# The previous method works, but it uses extra memory by allocating new arrays +# It's also kind of lengthy +# Let's see how we can do this without allocating a new array +# This is slightly faster as well + +function Format-Range ($start, $end) { + while ($start -lt $end) + { + $temp = $targetArray[$start] + $targetArray[$start] = $targetArray[$end] + $targetArray[$end] = $temp + $start++ + $end-- + } + return $targetArray } ``` Powershell as a Tool: @@ -698,6 +735,7 @@ foreach ($server in $serverList) { Interesting Projects * [Channel9](https://channel9.msdn.com/Search?term=powershell%20pipeline#ch9Search&lang-en=en) PowerShell tutorials +* [KevinMarquette's Powershell Blog](https://powershellexplained.com/) Really excellent blog that goes into great detail on Powershell * [PSGet](https://github.com/psget/psget) NuGet for PowerShell * [PSReadLine](https://github.com/lzybkr/PSReadLine/) A bash inspired readline implementation for PowerShell (So good that it now ships with Windows10 by default!) * [Posh-Git](https://github.com/dahlbyk/posh-git/) Fancy Git Prompt (Recommended!) -- cgit v1.2.3 From 8df9aa061f3cd63f868ceb34bae2e4e8b53ed3af Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Sat, 15 Aug 2020 20:05:08 -0700 Subject: Removing duped section There was a duplicate section --- powershell.html.markdown | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 99f5de97..2777820a 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -19,27 +19,8 @@ rather than plain text. After years of evolving, it resembles Python a bit. [Read more here.](https://docs.microsoft.com/powershell/scripting/overview) Powershell as a Language: -```powershell - -# Single line comments start with a number symbol. -<# - Multi-line comments - like so -#> - -#################################################### -## 1. Primitive Datatypes and Operators -#################################################### - -# Numbers -3 # => 3 - -# Math -1 + 1 # => 2 -8 - 1 # => 7 -10 * 2 # => 20 -35 / 5 # => 7.0 +```powershell # Single line comments start with a number symbol. -- cgit v1.2.3 From 12c7b6cd59aa03f95f6745829b7e66a828c9dad4 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Sun, 16 Aug 2020 14:42:49 -0700 Subject: Update powershell.html.markdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 谭九鼎 <109224573@qq.com> --- powershell.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 2777820a..3de8d07e 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -143,7 +143,7 @@ $b -is $a.GetType() # => False, a and b types not equal $name = "Steve" $age = 22 "He said his name is $name." # => "He said his name is Steve" -“{0} said he is {1} years old.” -f $name, $age # => "Steve said he is 22 years old" +"{0} said he is {1} years old." -f $name, $age # => "Steve said he is 22 years old" "$name's name is $($name.Length) characters long." # => "Steve's name is 5 characters long." # $null is not an object -- cgit v1.2.3 From f67ae9b31195a0bf30a18e892e755884aa54b1aa Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Sun, 16 Aug 2020 14:46:42 -0700 Subject: Addressing bitwise and/or Mistakenly left "and/or", changed to "-band/-bor" --- powershell.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 3de8d07e..45c47017 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -89,12 +89,12 @@ $False - 5 # => -5 # Using boolean logical operators on ints casts them to booleans for evaluation # but their non-cast value is returned -# Don't mix up with bool(ints) and bitwise and/or (&,|) +# Don't mix up with bool(ints) and bitwise -band/-bor [bool](0) # => False [bool](4) # => True [bool](-6) # => True -0 -and 2 # => 0 --5 -or 0 # => -5 +0 -band 2 # => 0 +-5 -bor 0 # => -5 # Equality is -eq (equals) 1 -eq 1 # => True -- cgit v1.2.3 From 5c79b4288c9c1de5db6e1eb3856191f9381f7d4f Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Sun, 16 Aug 2020 14:58:29 -0700 Subject: Adjusting array section to be more accurate The default array object is mutable, but is of a fixed length. Changing comments to better reflect that. --- powershell.html.markdown | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 45c47017..7c54dc44 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -183,11 +183,12 @@ $someVariable # => 5 # Ternary Operators exist in Powershell 7 and up 0 ? 'yes' : 'no' # => no -# The default array object in Powershell is an immutable array +# The default array object in Powershell is an fixed length array $defaultArray = "thing","thing2","thing3" -# you are unable to add or remove objects +# you can add objects with '+=', but cannot remove objects $defaultArray.Add("thing4") # => Exception "Collection was of a fixed size." -# To have a mutable array, you will need to use the .NET ArrayList class +# To have a more workable array, you'll want the .NET [ArrayList] class +# It is also worth noting that ArrayLists are significantly faster # ArrayLists store sequences [System.Collections.ArrayList]$array = @() -- cgit v1.2.3 From e6a53387bee66c4315c22354cd5a3edbbb0c6018 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Sun, 16 Aug 2020 21:14:26 -0700 Subject: Addressing comments 1. Clarifying '[]' and null-assigned expressions. 2. Removing "-contains" on switch example from Wouter, it does not appear to be true anymore 3. Adding comments and adjusting some func examples a bit --- powershell.html.markdown | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 7c54dc44..2d4c65b7 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -149,25 +149,49 @@ $age = 22 # $null is not an object $null # => None +# $null, 0, and empty strings and arrays all evaluate to False. +# All other values are True # $null, 0, and empty strings and arrays all evaluate to False. # All other values are True function test ($value) { - if ($value) {Write-Output 'True'} - else {Write-Output 'False'} + if ($value) { + Write-Output 'True' + } + else { + Write-Output 'False' + } } + test ($null) # => False test (0) # => False test ("") # => False -test [] # => True +test [] # => True *[] Not valid in Powershell, creates null-valued expression test ({}) # => True test @() # => False +<# +IsPublic IsSerial Name BaseType +-------- -------- ---- -------- +True True Int32 System.ValueType +True True Int32 System.ValueType +True True String System.Object +You cannot call a method on a null-valued expression. +At line:4 char:1 ++ $test3.getType() ++ ~~~~~~~~~~~~~~~~ + + CategoryInfo : InvalidOperation: (:) [], RuntimeException + + FullyQualifiedErrorId : InvokeMethodOnNull + +True True ScriptBlock System.Object +True True Object[] System.Array +#> + #################################################### ## 2. Variables and Collections #################################################### # Powershell uses the "Write-Output" function to print -Write-Output "I'm Powershell. Nice to meet you!" # => I'm Powershell. Nice to meet you! +Write-Output "I'm Posh. Nice to meet you!" # => I'm Posh. Nice to meet you! # Simple way to get input data from console $userInput = Read-Host "Enter some data: " # Returns the data as a string @@ -367,7 +391,6 @@ switch($val) { { $_ -like 's*' } { "Case insensitive"; break } { $_ -clike 's*'} { "clike, ceq, cne for case sensitive"; break } { $_ -notmatch '^.*$'} { "Regex matching. cnotmatch, cnotlike, ..."; break } - { 'x' -contains 'x'} { "FALSE! -contains is for lists!"; break } default { "Others" } } @@ -384,7 +407,6 @@ finally { } - # Writing to a file $contents = @{"aa"= 12 "bb"= 21} @@ -532,6 +554,7 @@ True False Guitar Instrument #> + #################################################### ## 7. Advanced #################################################### @@ -582,7 +605,7 @@ $Area This is a silly one You may one day be asked to create a func that could take $start and $end and reverse anything in an array within the given range - based on an arbitrary array + based on an arbitrary array without mutating the original array Let's see one way to do that and introduce another data structure #> @@ -599,7 +622,7 @@ function Format-Range ($start, $end) { elseif ($index -ge $start -and $index -le $end) { $stack.Push($targetArray[$index]) } - elseif ($index -gt $end) { + else { $secondSectionArray.Add($targetArray[$index]) > $null } } @@ -607,6 +630,8 @@ function Format-Range ($start, $end) { Write-Output $returnArray } +Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m','n' + # The previous method works, but it uses extra memory by allocating new arrays # It's also kind of lengthy # Let's see how we can do this without allocating a new array @@ -623,10 +648,13 @@ function Format-Range ($start, $end) { } return $targetArray } + +Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m','n' ``` Powershell as a Tool: Getting Help: + ```Powershell # Find commands Get-Command about_* # alias: gcm -- cgit v1.2.3 From 2e9734975e3a12d37ea3a899c3d98b2a565e0a40 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Mon, 17 Aug 2020 01:53:41 -0700 Subject: Removing duped entry --- powershell.html.markdown | 2 -- 1 file changed, 2 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 2d4c65b7..166b67a0 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -149,8 +149,6 @@ $age = 22 # $null is not an object $null # => None -# $null, 0, and empty strings and arrays all evaluate to False. -# All other values are True # $null, 0, and empty strings and arrays all evaluate to False. # All other values are True function test ($value) { -- cgit v1.2.3 From cf5b2a36e0e89dc576cc66e0878ec3d24a8ab8c2 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Mon, 17 Aug 2020 02:09:14 -0700 Subject: Adjusting truthy falsy section --- powershell.html.markdown | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 166b67a0..be8311b7 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -163,26 +163,10 @@ function test ($value) { test ($null) # => False test (0) # => False test ("") # => False -test [] # => True *[] Not valid in Powershell, creates null-valued expression +test [] # => True *[] calls .NET classes; creates '[]' string when passed to func test ({}) # => True test @() # => False -<# -IsPublic IsSerial Name BaseType --------- -------- ---- -------- -True True Int32 System.ValueType -True True Int32 System.ValueType -True True String System.Object -You cannot call a method on a null-valued expression. -At line:4 char:1 -+ $test3.getType() -+ ~~~~~~~~~~~~~~~~ - + CategoryInfo : InvalidOperation: (:) [], RuntimeException - + FullyQualifiedErrorId : InvokeMethodOnNull - -True True ScriptBlock System.Object -True True Object[] System.Array -#> #################################################### ## 2. Variables and Collections -- cgit v1.2.3 From eeaff3bc70a640ffc8fa20a7b3b202640f8d6d67 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Wed, 19 Aug 2020 14:14:47 -0700 Subject: Adding changes discussed 1. Added info on scoping with dot sourcing, IEX, and call operator 2. Added comments about .NET class calling 3. Changed Get-EventLog to Get-WinEvent 4. Added info on Pipeline caveats related to passing bytes and speed 5. Added in a couple more pipeline examples to iteration and filtering And some formatting changes --- powershell.html.markdown | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index be8311b7..b9f56861 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -18,7 +18,7 @@ rather than plain text. After years of evolving, it resembles Python a bit. [Read more here.](https://docs.microsoft.com/powershell/scripting/overview) -Powershell as a Language: +

Powershell as a Language:

```powershell @@ -116,6 +116,8 @@ $False - 5 # => -5 # (-is vs. -eq) -is checks if two objects are the same type # -eq checks if the objects have the same values. +# Note: we called '[Math]' from .NET previously without the preceeding +# namespaces. We can do the same with [Collections.ArrayList] if preferred [System.Collections.ArrayList]$a = @() # Point a at a new list $a = (1,2,3,4) $b = $a # => Point b at what a is pointing to @@ -541,7 +543,7 @@ True False Guitar Instrument ## 7. Advanced #################################################### -# The powershell pipeline allows us to do things like High-Order Functions +# The powershell pipeline allows things like High-Order Functions # Group Object is a handy command that does incredible things for us # It works much like a GROUP BY in SQL would @@ -554,6 +556,16 @@ True False Guitar Instrument #> Get-Process | Foreach-Object ProcessName | Group-Object +# Useful pipeline examples are iteration and filtering +1..10 | ForEach-Object { "Loop number $PSITEM" } +1..10 | where {$PSITEM -gt 5} | Format-Table + +# A noteable pitfall of the pipeline is it's performance when +# compared with other options +# additionally, raw bytes are not passed through the piipeline +# so passing an image causes some issues +# See more on that in the links at the bottom + <# Asynchronous functions exist in the form of jobs Typically a procedural language @@ -633,7 +645,7 @@ function Format-Range ($start, $end) { Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m','n' ``` -Powershell as a Tool: +

Powershell as a Tool:

Getting Help: @@ -647,7 +659,7 @@ Get-Alias -Definition Get-Process Get-Help ps | less # alias: help ps | Get-Member # alias: gm -Show-Command Get-EventLog # Display GUI to fill in the parameters +Show-Command Get-WinEvent # Display GUI to fill in the parameters Update-Help # Run as admin ``` @@ -668,10 +680,32 @@ $PSVersionTable ``` ```Powershell +# Calling external commands, executables, and functions with the call operator. +# the call operator (&) is similar to Invoke-Expression, but IEX runs in current scope. +# Standard usage of '&' would be to invoke a scriptblock inside of your script. +# Notice the variables are scoped +$i = 2 +$scriptblock = { $i=5; Write-Output $i } +& $scriptblock # => 5 +$i # => 2 + +invoke-expression ' $i=5; Write-Output $i ' # => 5 +$i # => 5 + +# Alternatively, to preserve changes to public variables +# you can use "Dot-Sourcing". This will run in the current scope +$x=1 +&{$x=2};$x # => 1 + +. {$x=2};$x # => 2 + + # Remoting into computers is easy Enter-PSSession -ComputerName RemoteComputer + # Once remoted in, you can run commands as if you're local RemoteComputer\PS> Get-Process powershell + <# Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- @@ -727,7 +761,7 @@ foreach ($server in $serverList) { Interesting Projects * [Channel9](https://channel9.msdn.com/Search?term=powershell%20pipeline#ch9Search&lang-en=en) PowerShell tutorials -* [KevinMarquette's Powershell Blog](https://powershellexplained.com/) Really excellent blog that goes into great detail on Powershell +* [KevinMarquette's Powershell Blog](https://powershellexplained.com/) Excellent blog that goes into great detail on Powershell * [PSGet](https://github.com/psget/psget) NuGet for PowerShell * [PSReadLine](https://github.com/lzybkr/PSReadLine/) A bash inspired readline implementation for PowerShell (So good that it now ships with Windows10 by default!) * [Posh-Git](https://github.com/dahlbyk/posh-git/) Fancy Git Prompt (Recommended!) @@ -736,3 +770,4 @@ Interesting Projects * [Pester](https://github.com/pester/Pester) BDD Testing Framework * [Jump-Location](https://github.com/tkellogg/Jump-Location) Powershell `cd` that reads your mind * [PowerShell Community Extensions](https://github.com/Pscx/Pscx) +* [More on the Powershell Pipeline Issue](https://github.com/PowerShell/PowerShell/issues/1908) -- cgit v1.2.3 From ea49b693cca150335ee20df5b97b1f5aaec3634c Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Wed, 19 Aug 2020 14:19:02 -0700 Subject: I don't think CI was happy about those header tags Changing back to the way they were --- powershell.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index b9f56861..6a850028 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -18,7 +18,7 @@ rather than plain text. After years of evolving, it resembles Python a bit. [Read more here.](https://docs.microsoft.com/powershell/scripting/overview) -

Powershell as a Language:

+Powershell as a Language: ```powershell @@ -645,7 +645,7 @@ function Format-Range ($start, $end) { Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m','n' ``` -

Powershell as a Tool:

+Powershell as a Tool: Getting Help: -- cgit v1.2.3 From c0a8574825e24a924a693c8b74941a65f25683ec Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Wed, 19 Aug 2020 23:23:53 -0700 Subject: Fixing typo and some other formatting Doubled input on 'pipeline' spaces between commented sections expand alias on where --- powershell.html.markdown | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 6a850028..da4dcd5c 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -29,6 +29,7 @@ Powershell as a Language: like so #> + #################################################### ## 1. Primitive Datatypes and Operators #################################################### @@ -191,6 +192,7 @@ $someVariable # => 5 # Ternary Operators exist in Powershell 7 and up 0 ? 'yes' : 'no' # => no + # The default array object in Powershell is an fixed length array $defaultArray = "thing","thing2","thing3" # you can add objects with '+=', but cannot remove objects @@ -282,8 +284,6 @@ $filledHash["one"] # => 1 # items maintain the order at which they are inserted into the dictionary. $filledHash.keys # => ["one", "two", "three"] - - # Get all values as an iterable with ".Values". $filledHash.values # => [1, 2, 3] @@ -303,7 +303,6 @@ $filledHash["four"] = 4 # $filledHash["four"] is set to 4, run again and it does $filledHash.Remove("one") # Removes the key "one" from filled dict - #################################################### ## 3. Control Flow and Iterables #################################################### @@ -403,7 +402,6 @@ $contents | Out-File "$env:HOMEDRIVE\file.txt" # writes to another file Get-Content "$env:HOMEDRIVE\file.csv" | ConvertTo-Json - #################################################### ## 4. Functions #################################################### @@ -484,7 +482,6 @@ Get-Command -module dbaTools Get-Help dbaTools -Full - #################################################### ## 6. Classes #################################################### @@ -538,7 +535,6 @@ True False Guitar Instrument #> - #################################################### ## 7. Advanced #################################################### @@ -558,13 +554,13 @@ Get-Process | Foreach-Object ProcessName | Group-Object # Useful pipeline examples are iteration and filtering 1..10 | ForEach-Object { "Loop number $PSITEM" } -1..10 | where {$PSITEM -gt 5} | Format-Table +1..10 | Where-Object { $PSITEM -gt 5 } | ConvertTo-Json # A noteable pitfall of the pipeline is it's performance when # compared with other options -# additionally, raw bytes are not passed through the piipeline +# Additionally, raw bytes are not passed through the pipeline # so passing an image causes some issues -# See more on that in the links at the bottom +# See more on that in the link at the bottom <# Asynchronous functions exist in the form of jobs -- cgit v1.2.3 From fc9b23f3571f8b3f67c83ad7814ec3c579ece22e Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Thu, 20 Aug 2020 00:10:08 -0700 Subject: Adding in escape chars and more info on call operator with exe's escape chars like newlines, tabs, negating affects call operator and dot-sourcing for paths to exes with spaces in them and arguments passed. --- powershell.html.markdown | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index da4dcd5c..027320d5 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -677,6 +677,19 @@ $PSVersionTable ```Powershell # Calling external commands, executables, and functions with the call operator. +# Executables with arguments passed create issues +C:\Program Files\dotnet\dotnet.exe +The term 'C:\Program' is not recognized as a name of a cmdlet, function, script file, or executable program. +Check the spelling of the name, or if a path was included, verify that the path is correct and try again + +"C:\Program Files\dotnet\dotnet.exe" +C:\Program Files\dotnet\dotnet.exe # returns the string rather than execute it + +&"C:\Program Files\dotnet\dotnet.exe --help" # fail +&"C:\Program Files\dotnet\dotnet.exe" --help # success +# Alternatively, you can use dot-sourcing here +."C:\Program Files\dotnet\dotnet.exe" --help # success + # the call operator (&) is similar to Invoke-Expression, but IEX runs in current scope. # Standard usage of '&' would be to invoke a scriptblock inside of your script. # Notice the variables are scoped @@ -693,7 +706,20 @@ $i # => 5 $x=1 &{$x=2};$x # => 1 -. {$x=2};$x # => 2 +.{$x=2};$x # => 2 + + +# Escape Characters in Powershell +# Many languages use the '\', but Windows uses this character for +# file paths. Powershell thus uses '`' to escape characters +# Take caution when working with files, as '`' is a +# valid character in NTFS filenames. +"Showing`nEscape Chars" # => new line between Showing and Escape +"Making`tTables`tWith`tTabs" # +> Format things with tabs + +# Negate pound sign to prevent comment +# Note that the function of '#' is removed, but '#" is still present +`#Get-Process # => Fail: not a recognized cmdlet # Remoting into computers is easy -- cgit v1.2.3 From a1b13e3757a452658ae4ee10fe4bf0b1f11dbe98 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Thu, 20 Aug 2020 00:11:48 -0700 Subject: Moving Escape chars section to string section --- powershell.html.markdown | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 027320d5..e210d40a 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -149,6 +149,18 @@ $age = 22 "{0} said he is {1} years old." -f $name, $age # => "Steve said he is 22 years old" "$name's name is $($name.Length) characters long." # => "Steve's name is 5 characters long." +# Escape Characters in Powershell +# Many languages use the '\', but Windows uses this character for +# file paths. Powershell thus uses '`' to escape characters +# Take caution when working with files, as '`' is a +# valid character in NTFS filenames. +"Showing`nEscape Chars" # => new line between Showing and Escape +"Making`tTables`tWith`tTabs" # => Format things with tabs + +# Negate pound sign to prevent comment +# Note that the function of '#' is removed, but '#" is still present +`#Get-Process # => Fail: not a recognized cmdlet + # $null is not an object $null # => None @@ -709,19 +721,6 @@ $x=1 .{$x=2};$x # => 2 -# Escape Characters in Powershell -# Many languages use the '\', but Windows uses this character for -# file paths. Powershell thus uses '`' to escape characters -# Take caution when working with files, as '`' is a -# valid character in NTFS filenames. -"Showing`nEscape Chars" # => new line between Showing and Escape -"Making`tTables`tWith`tTabs" # +> Format things with tabs - -# Negate pound sign to prevent comment -# Note that the function of '#' is removed, but '#" is still present -`#Get-Process # => Fail: not a recognized cmdlet - - # Remoting into computers is easy Enter-PSSession -ComputerName RemoteComputer -- cgit v1.2.3 From 88f7de0db064b61d0020bc69b9ca73f506cff14e Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Thu, 20 Aug 2020 10:46:03 -0700 Subject: Final comments --- powershell.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index e210d40a..41f5b5ae 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -122,7 +122,7 @@ $False - 5 # => -5 [System.Collections.ArrayList]$a = @() # Point a at a new list $a = (1,2,3,4) $b = $a # => Point b at what a is pointing to -$b -is $a.getType() # => True, a and b equal same type +$b -is $a.GetType() # => True, a and b equal same type $b -eq $a # => True, a and b values are equal [System.Collections.Hashtable]$b = @{} # => Point a at a new hash table $b = @{'one' = 1 @@ -158,7 +158,7 @@ $age = 22 "Making`tTables`tWith`tTabs" # => Format things with tabs # Negate pound sign to prevent comment -# Note that the function of '#' is removed, but '#" is still present +# Note that the function of '#' is removed, but '#' is still present `#Get-Process # => Fail: not a recognized cmdlet # $null is not an object -- cgit v1.2.3 From b46242c13882ec41d8ea0f8ae3aa3b867d0c47e1 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Thu, 20 Aug 2020 12:12:01 -0700 Subject: Final look-over and adjusting carriage returns Reducing line length Adjusting grammar Fixing some inconsistencies in variables and properties --- powershell.html.markdown | 224 +++++++++++++++++++++++++---------------------- 1 file changed, 117 insertions(+), 107 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 41f5b5ae..42a8338f 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -43,9 +43,10 @@ Powershell as a Language: 10 * 2 # => 20 35 / 5 # => 7.0 -# Powershell uses banker's rounding -# Meaning [int]1.5 would round to 2 but so would [int]2.5 -# division always returns a float. You must cast result to [int] to round +# Powershell uses banker's rounding, +# meaning [int]1.5 would round to 2 but so would [int]2.5 +# Division always returns a float. +# You must cast result to [int] to round. [int]5 / [int]3 # => 1.66666666666667 [int]-5 / [int]3 # => -1.66666666666667 5.0 / 3.0 # => 1.66666666666667 @@ -55,10 +56,10 @@ Powershell as a Language: # Modulo operation 7 % 3 # => 1 -# Exponentiation requires longform or the built-in [Math] class +# Exponentiation requires longform or the built-in [Math] class. [Math]::Pow(2,3) # => 8 -# Enforce order of operations with parentheses +# Enforce order of operations with parentheses. 1 + 3 * 2 # => 7 (1 + 3) * 2 # => 8 @@ -75,20 +76,20 @@ $False # => False $True -and $False # => False $False -or $True # => True -# True and False are actually 1 and 0 but only support limited arithmetic -# However, casting the bool to int resolves this +# True and False are actually 1 and 0 but only support limited arithmetic. +# However, casting the bool to int resolves this. $True + $True # => 2 $True * 8 # => '[System.Boolean] * [System.Int32]' is undefined [int]$True * 8 # => 8 $False - 5 # => -5 -# Comparison operators look at the numerical value of True and False +# Comparison operators look at the numerical value of True and False. 0 -eq $False # => True 1 -eq $True # => True 2 -eq $True # => False -5 -ne $False # => True -# Using boolean logical operators on ints casts them to booleans for evaluation +# Using boolean logical operators on ints casts to booleans for evaluation. # but their non-cast value is returned # Don't mix up with bool(ints) and bitwise -band/-bor [bool](0) # => False @@ -115,10 +116,10 @@ $False - 5 # => -5 1 -lt 2 -and 2 -lt 3 # => True 2 -lt 3 -and 3 -lt 2 # => False -# (-is vs. -eq) -is checks if two objects are the same type +# (-is vs. -eq) -is checks if two objects are the same type. # -eq checks if the objects have the same values. # Note: we called '[Math]' from .NET previously without the preceeding -# namespaces. We can do the same with [Collections.ArrayList] if preferred +# namespaces. We can do the same with [Collections.ArrayList] if preferred. [System.Collections.ArrayList]$a = @() # Point a at a new list $a = (1,2,3,4) $b = $a # => Point b at what a is pointing to @@ -142,12 +143,15 @@ $b -is $a.GetType() # => False, a and b types not equal # You can find the length of a string ("This is a string").Length # => 16 -# You can also format using f-strings or formatted string literals +# You can also format using f-strings or formatted string literals. $name = "Steve" $age = 22 -"He said his name is $name." # => "He said his name is Steve" -"{0} said he is {1} years old." -f $name, $age # => "Steve said he is 22 years old" -"$name's name is $($name.Length) characters long." # => "Steve's name is 5 characters long." +"He said his name is $name." +# => "He said his name is Steve" +"{0} said he is {1} years old." -f $name, $age +# => "Steve said he is 22 years old" +"$name's name is $($name.Length) characters long." +# => "Steve's name is 5 characters long." # Escape Characters in Powershell # Many languages use the '\', but Windows uses this character for @@ -166,7 +170,7 @@ $null # => None # $null, 0, and empty strings and arrays all evaluate to False. # All other values are True -function test ($value) { +function Test-Value ($value) { if ($value) { Write-Output 'True' } @@ -175,12 +179,13 @@ function test ($value) { } } -test ($null) # => False -test (0) # => False -test ("") # => False -test [] # => True *[] calls .NET classes; creates '[]' string when passed to func -test ({}) # => True -test @() # => False +Test-Value ($null) # => False +Test-Value (0) # => False +Test-Value ("") # => False +Test-Value [] # => True +# *[] calls .NET class; creates '[]' string when passed to function +Test-Value ({}) # => True +Test-Value @() # => False #################################################### @@ -205,9 +210,9 @@ $someVariable # => 5 0 ? 'yes' : 'no' # => no -# The default array object in Powershell is an fixed length array +# The default array object in Powershell is an fixed length array. $defaultArray = "thing","thing2","thing3" -# you can add objects with '+=', but cannot remove objects +# you can add objects with '+=', but cannot remove objects. $defaultArray.Add("thing4") # => Exception "Collection was of a fixed size." # To have a more workable array, you'll want the .NET [ArrayList] class # It is also worth noting that ArrayLists are significantly faster @@ -217,12 +222,12 @@ $defaultArray.Add("thing4") # => Exception "Collection was of a fixed size." # You can start with a prefilled ArrayList [System.Collections.ArrayList]$otherArray = @(4, 5, 6) -# Add stuff to the end of a list with add (Note: it produces output, so append to $null) -$array.add(1) > $null # $array is now [1] -$array.add(2) > $null # $array is now [1, 2] -$array.add(4) > $null # $array is now [1, 2, 4] -$array.add(3) > $null # $array is now [1, 2, 4, 3] -# Remove from the end with index of count of objects-1 as arrays are indexed starting 0 +# Add to the end of a list with 'Add' (Note: produces output, append to $null) +$array.Add(1) > $null # $array is now [1] +$array.Add(2) > $null # $array is now [1, 2] +$array.Add(4) > $null # $array is now [1, 2, 4] +$array.Add(3) > $null # $array is now [1, 2, 4, 3] +# Remove from end with index of count of objects-1; array index starts at 0 $array.RemoveAt($array.Count-1) # => 3 and array is now [1, 2, 4] # Let's put it back $array.Add(3) > $null # array is now [1, 2, 4, 3] again. @@ -265,24 +270,24 @@ $array.AddRange($otherArray) # Now $array is [1, 2, 3, 4, 5, 6] # Check for existence in a array with "in" 1 -in $array # => True -# Examine the length with "Count" (Note: Length method on arrayList = each items length) +# Examine length with "Count" (Note: "Length" on arrayList = each items length) $array.Count # => 6 # Tuples are like arrays but are immutable. -# To use Tuples in powershell, you must use the .NET tuple class +# To use Tuples in powershell, you must use the .NET tuple class. $tuple = [System.Tuple]::Create(1, 2, 3) $tuple.Item(0) # => 1 $tuple.Item(0) = 3 # Raises a TypeError -# You can do some of the array methods on tuples, but they are limited -$tuple.Length # => 3 +# You can do some of the array methods on tuples, but they are limited. +$tuple.Length # => 3 $tuple + (4, 5, 6) # => Exception -$tuple[0..2] # => $null +$tuple[0..2] # => $null 2 -in $tuple # => False -# Hashtables store mappings from keys to values, similar to Dictionaries +# Hashtables store mappings from keys to values, similar to Dictionaries. $emptyHash = @{} # Here is a prefilled dictionary $filledHash = @{"one"= 1 @@ -294,14 +299,14 @@ $filledHash["one"] # => 1 # Get all keys as an iterable with ".Keys". # items maintain the order at which they are inserted into the dictionary. -$filledHash.keys # => ["one", "two", "three"] +$filledHash.Keys # => ["one", "two", "three"] # Get all values as an iterable with ".Values". -$filledHash.values # => [1, 2, 3] +$filledHash.Values # => [1, 2, 3] # Check for existence of keys or values in a hash with "-in" "one" -in $filledHash.Keys # => True -1 -in $filledHash.Values # => False +1 -in $filledHash.Values # => False # Looking up a non-existing key returns $null $filledHash["four"] # $null @@ -309,7 +314,7 @@ $filledHash["four"] # $null # Adding to a dictionary $filledHash.Add("five",5) # $filledHash["five"] is set to 5 $filledHash.Add("five",6) # exception "Item with key "five" has already been added" -$filledHash["four"] = 4 # $filledHash["four"] is set to 4, run again and it does nothing +$filledHash["four"] = 4 # $filledHash["four"] is set to 4, running again does nothing # Remove keys from a dictionary with del $filledHash.Remove("one") # Removes the key "one" from filled dict @@ -428,8 +433,8 @@ Add-Numbers 1 2 # => 3 # Calling functions with parameters function Add-ParamNumbers { - param( [int]$FirstNumber, [int]$SecondNumber ) - $FirstNumber + $SecondNumber + param( [int]$firstNumber, [int]$secondNumber ) + $firstNumber + $secondNumber } Add-ParamNumbers -FirstNumber 1 -SecondNumber 2 # => 3 @@ -457,9 +462,9 @@ function New-Website() { [ValidateSet(3000,5000,8000)] [int]$port = 3000 ) - BEGIN { Write-Verbose 'Creating new website(s)' } + BEGIN { Write-Output 'Creating new website(s)' } PROCESS { Write-Output "name: $siteName, port: $port" } - END { Write-Verbose 'Website(s) created' } + END { Write-Output 'Website(s) created' } } @@ -521,8 +526,8 @@ String Instrument Plucked String ## 6.1 Inheritance #################################################### -# Inheritance allows new child classes to be defined that inherit methods and -# variables from their parent class. +# Inheritance allows new child classes to be defined that inherit +# methods and variables from their parent class. class Guitar : Instrument { @@ -533,9 +538,9 @@ class Guitar : Instrument } $myGuitar = [Guitar]::new() -$myGuitar.Brand = "Taylor" -$myGuitar.SubType = "Acoustic" -$myGuitar.ModelType = "Presentation" +$myGuitar.Brand = "Taylor" +$myGuitar.SubType = "Acoustic" +$myGuitar.ModelType = "Presentation" $myGuitar.ModelNumber = "PS14ce Blackwood" $myGuitar.GetType() @@ -551,67 +556,68 @@ True False Guitar Instrument ## 7. Advanced #################################################### -# The powershell pipeline allows things like High-Order Functions +# The powershell pipeline allows things like High-Order Functions. -# Group Object is a handy command that does incredible things for us -# It works much like a GROUP BY in SQL would +# Group-Object is a handy cmdlet that does incredible things. +# It works much like a GROUP BY in SQL. <# - The following will get all the running processes - Group them by Name - And tell us how many instances of each process we have running - Tip: Chrome and svcHost are usually big numbers in this regard + The following will get all the running processes, + group them by Name, + and tell us how many instances of each process we have running. + Tip: Chrome and svcHost are usually big numbers in this regard. #> Get-Process | Foreach-Object ProcessName | Group-Object -# Useful pipeline examples are iteration and filtering +# Useful pipeline examples are iteration and filtering. 1..10 | ForEach-Object { "Loop number $PSITEM" } 1..10 | Where-Object { $PSITEM -gt 5 } | ConvertTo-Json -# A noteable pitfall of the pipeline is it's performance when -# compared with other options -# Additionally, raw bytes are not passed through the pipeline -# so passing an image causes some issues -# See more on that in the link at the bottom +# A notable pitfall of the pipeline is it's performance when +# compared with other options. +# Additionally, raw bytes are not passed through the pipeline, +# so passing an image causes some issues. +# See more on that in the link at the bottom. <# - Asynchronous functions exist in the form of jobs - Typically a procedural language - Powershell can operate many non-blocking functions when invoked as Jobs + Asynchronous functions exist in the form of jobs. + Typically a procedural language, + Powershell can operate non-blocking functions when invoked as Jobs. #> -# This function is commonly known to be non-optimized, and therefore slow +# This function is known to be non-optimized, and therefore slow. $installedApps = Get-CimInstance -ClassName Win32_Product -# If we had a script, it would hang at this func for a period of time +# If we had a script, it would hang at this func for a period of time. $scriptBlock = {Get-CimInstance -ClassName Win32_Product} Start-Job -ScriptBlock $scriptBlock -# This will start a background job that runs the command -# You can then obtain the status of jobs and their returned results +# This will start a background job that runs the command. +# You can then obtain the status of jobs and their returned results. $allJobs = Get-Job -$JobResponse = Get-Job | Receive-Job +$jobResponse = Get-Job | Receive-Job -# Math is built in to powershell and has many functions +# Math is built in to powershell and has many functions. $r=2 $pi=[math]::pi $r2=[math]::pow( $r, 2 ) -$Area = $pi*$r2 -$Area +$area = $pi*$r2 +$area -# To see all possibilities, check the members +# To see all possibilities, check the members. [System.Math] | Get-Member -Static -MemberType All + <# - This is a silly one + This is a silly one: You may one day be asked to create a func that could take $start and $end and reverse anything in an array within the given range - based on an arbitrary array without mutating the original array - Let's see one way to do that and introduce another data structure + based on an arbitrary array without mutating the original array. + Let's see one way to do that and introduce another data structure. #> -$targetArray = 'a','b','c','d','e','f','g','h','i','j','k','l','m','n' +$targetArray = 'a','b','c','d','e','f','g','h','i','j','k','l','m' function Format-Range ($start, $end) { [System.Collections.ArrayList]$firstSectionArray = @() @@ -628,16 +634,16 @@ function Format-Range ($start, $end) { $secondSectionArray.Add($targetArray[$index]) > $null } } - $returnArray = $firstSectionArray + $stack.ToArray() + $secondSectionArray - Write-Output $returnArray + $finalArray = $firstSectionArray + $stack.ToArray() + $secondSectionArray + Write-Output $finalArray } -Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m','n' +Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m' -# The previous method works, but it uses extra memory by allocating new arrays -# It's also kind of lengthy -# Let's see how we can do this without allocating a new array -# This is slightly faster as well +# The previous method works, but uses extra memory by allocating new arrays. +# It's also kind of lengthy. +# Let's see how we can do this without allocating a new array. +# This is slightly faster as well. function Format-Range ($start, $end) { while ($start -lt $end) @@ -651,7 +657,7 @@ function Format-Range ($start, $end) { return $targetArray } -Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m','n' +Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m' ``` Powershell as a Tool: @@ -688,22 +694,26 @@ $PSVersionTable ``` ```Powershell -# Calling external commands, executables, and functions with the call operator. -# Executables with arguments passed create issues +# Calling external commands, executables, +# and functions with the call operator. +# Exe paths with arguments passed or containing spaces can create issues. C:\Program Files\dotnet\dotnet.exe -The term 'C:\Program' is not recognized as a name of a cmdlet, function, script file, or executable program. -Check the spelling of the name, or if a path was included, verify that the path is correct and try again +# The term 'C:\Program' is not recognized as a name of a cmdlet, +# function, script file, or executable program. +# Check the spelling of the name, or if a path was included, +# verify that the path is correct and try again "C:\Program Files\dotnet\dotnet.exe" -C:\Program Files\dotnet\dotnet.exe # returns the string rather than execute it +C:\Program Files\dotnet\dotnet.exe # returns string rather than execute &"C:\Program Files\dotnet\dotnet.exe --help" # fail &"C:\Program Files\dotnet\dotnet.exe" --help # success # Alternatively, you can use dot-sourcing here ."C:\Program Files\dotnet\dotnet.exe" --help # success -# the call operator (&) is similar to Invoke-Expression, but IEX runs in current scope. -# Standard usage of '&' would be to invoke a scriptblock inside of your script. +# the call operator (&) is similar to Invoke-Expression, +# but IEX runs in current scope. +# One usage of '&' would be to invoke a scriptblock inside of your script. # Notice the variables are scoped $i = 2 $scriptblock = { $i=5; Write-Output $i } @@ -714,17 +724,17 @@ invoke-expression ' $i=5; Write-Output $i ' # => 5 $i # => 5 # Alternatively, to preserve changes to public variables -# you can use "Dot-Sourcing". This will run in the current scope +# you can use "Dot-Sourcing". This will run in the current scope. $x=1 &{$x=2};$x # => 1 .{$x=2};$x # => 2 -# Remoting into computers is easy +# Remoting into computers is easy. Enter-PSSession -ComputerName RemoteComputer -# Once remoted in, you can run commands as if you're local +# Once remoted in, you can run commands as if you're local. RemoteComputer\PS> Get-Process powershell <# @@ -736,10 +746,10 @@ Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName RemoteComputer\PS> Exit-PSSession <# - Powershell is an incredible tool for Windows management and Automation - Let's take the following scenario - You have 10 servers - You need to check whether a service is running on all of them + Powershell is an incredible tool for Windows management and Automation. + Let's take the following scenario: + You have 10 servers. + You need to check whether a service is running on all of them. You can RDP and log in, or PSSession to all of them, but why? Check out the following #> @@ -757,24 +767,24 @@ $serverList = @( 'server10' ) -[scriptblock]$Script = { +[scriptblock]$script = { Get-Service -DisplayName 'Task Scheduler' } foreach ($server in $serverList) { - $CmdSplat = @{ - ComputerName = $Server + $cmdSplat = @{ + ComputerName = $server JobName = 'checkService' - ScriptBlock = $Script + ScriptBlock = $script AsJob = $true ErrorAction = 'SilentlyContinue' } - Invoke-Command @CmdSplat | Out-Null + Invoke-Command @cmdSplat | Out-Null } <# - Here we've invoked jobs across many servers - We can now Receive-Job and see if they're all running + Here we've invoked jobs across many servers. + We can now Receive-Job and see if they're all running. Now scale this up 100x as many servers :) #> ``` -- cgit v1.2.3 From d221d56c60e83fa2dbec3c8ce3a903e20bf04d23 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Thu, 20 Aug 2020 12:26:48 -0700 Subject: Adjusting last items before land --- powershell.html.markdown | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 42a8338f..32d2e667 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -51,7 +51,8 @@ Powershell as a Language: [int]-5 / [int]3 # => -1.66666666666667 5.0 / 3.0 # => 1.66666666666667 -5.0 / 3.0 # => -1.66666666666667 -[int]$result = 5 / 3 # => 2 +[int]$result = 5 / 3 +$result # => 2 # Modulo operation 7 % 3 # => 1 @@ -716,8 +717,8 @@ C:\Program Files\dotnet\dotnet.exe # returns string rather than execute # One usage of '&' would be to invoke a scriptblock inside of your script. # Notice the variables are scoped $i = 2 -$scriptblock = { $i=5; Write-Output $i } -& $scriptblock # => 5 +$scriptBlock = { $i=5; Write-Output $i } +& $scriptBlock # => 5 $i # => 2 invoke-expression ' $i=5; Write-Output $i ' # => 5 -- cgit v1.2.3 From ea11ea2444b1e0274805a091958ff2fd6276e386 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Thu, 20 Aug 2020 12:40:18 -0700 Subject: Fixing formatting in published page the markdown powershell checker didn't have a space before it --- powershell.html.markdown | 1 + 1 file changed, 1 insertion(+) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 32d2e667..9087dad8 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -680,6 +680,7 @@ Update-Help # Run as admin ``` If you are uncertain about your environment: + ```Powershell Get-ExecutionPolicy -List Set-ExecutionPolicy AllSigned -- cgit v1.2.3 From 33cd1f57ef49f4ed0817e906b7579fcf33c253a1 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Davis Date: Tue, 6 Oct 2020 18:02:35 -0700 Subject: Adjusting formatting Indentation on function --- powershell.html.markdown | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'powershell.html.markdown') diff --git a/powershell.html.markdown b/powershell.html.markdown index 9087dad8..318bf043 100644 --- a/powershell.html.markdown +++ b/powershell.html.markdown @@ -620,26 +620,27 @@ $area $targetArray = 'a','b','c','d','e','f','g','h','i','j','k','l','m' -function Format-Range ($start, $end) { -[System.Collections.ArrayList]$firstSectionArray = @() -[System.Collections.ArrayList]$secondSectionArray = @() -[System.Collections.Stack]$stack = @() - for ($index = 0; $index -lt $targetArray.Count; $index++) { +function Format-Range ($start, $end, $array) { + [System.Collections.ArrayList]$firstSectionArray = @() + [System.Collections.ArrayList]$secondSectionArray = @() + [System.Collections.Stack]$stack = @() + for ($index = 0; $index -lt $array.Count; $index++) { if ($index -lt $start) { - $firstSectionArray.Add($targetArray[$index]) > $null + $firstSectionArray.Add($array[$index]) > $null } elseif ($index -ge $start -and $index -le $end) { - $stack.Push($targetArray[$index]) + $stack.Push($array[$index]) } else { - $secondSectionArray.Add($targetArray[$index]) > $null + $secondSectionArray.Add($array[$index]) > $null } } $finalArray = $firstSectionArray + $stack.ToArray() + $secondSectionArray - Write-Output $finalArray + return $finalArray } -Format-Range 2 6 # => 'a','b','g','f','e','d','c','h','i','j','k','l','m' +Format-Range 2 6 $targetArray +# => 'a','b','g','f','e','d','c','h','i','j','k','l','m' # The previous method works, but uses extra memory by allocating new arrays. # It's also kind of lengthy. -- cgit v1.2.3