diff options
| -rw-r--r-- | powershell.html.markdown | 871 | 
1 files changed, 610 insertions, 261 deletions
| 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) | 
