This readme contains the content for the entire course.
whats missing?
- function stuff (near bottom)
- API stuff (near bottom)
- loop stuff(near bottom)
- short explanation of wildcards
The following tools must be installed before the course starts.
- Visual Studio Code - https://code.visualstudio.com/
- GitHub Desktop - https://desktop.github.com/ (unless you allready know git.)
- Powershell 7 - https://github.com/PowerShell/PowerShell#get-powershell
The following should be done before the course starts.
- Create a Github account https://github.com/
- setup my predictive intellisense powershell config
Predictive intellisense does this
uses your previously typed in commands to predict what you want to type in next. Big help in learning.
here is the config
# these are my predictive intellisense settings.
# grabbed the essentials from the link below.
# https://devblogs.microsoft.com/powershell/announcing-psreadline-2-1-with-predictive-intellisense/
Set-PSReadLineOption -PredictionSource History
Set-PSReadLineOption -HistorySearchCursorMovesToEnd
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Set-PSReadLineKeyHandler -Chord "Ctrl+f" -Function ForwardWord
Set-PSReadLineKeyHandler -Chord Shift+Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Chord Ctrl+b -Function BackwardWord
after installing VSCode, Powershell 7+ and Githubdesktop.
open powershell 7(not windows powershell),
type code $profile
. hit enter.
wait for visual studio code to launch and paste in my predictive intellisense config. save this file and it should be good to go.
the powershell profile loads every time you open powershell so this is a nice place to store things you often need in powershell.
this can happen if your system image is lacking shell components. the following solution pasted into a powershell window run as admin should solve it
Get-WindowsCapability -Name "*ShellComponents*" -Online | Add-WindowsCapability -Online
Visual Studio Code vs Notepad++. VSC is just better.
- official editor for powershell. Powershell ISE deprecated
- Github integration
https://code.visualstudio.com/
try the keybindings. spesifically Ctrl+shift+P and alt+click https://code.visualstudio.com/docs/getstarted/keybindings https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf
- version control.
- sharing and collaboration.
https://github.com/PowerShell/PowerShell
- crossplatform
- predictive intellisense
- multithreading
# slow 1 by 1
1..10 | foreach-object { test-connection 195.88.55.$_ -count 1 -quiet}
# all 10 at the same time!
1..10 | foreach-object -ThrottleLimit 10 -Parallel { test-connection 195.88.55.$_ -count 1 -quiet}
- just better than powershell 5
CMD | Powershell | Powershell Alias |
---|---|---|
ping | Test-NetConnection / Test-Connection | tnc |
cd | Set-Location | sl, cd, chdir |
dir | Get-ChildItem | gci,dir,ls |
ipconfig | Get-NetIPConfiguration | gip |
tracert | Test-NetConnection -traceroute | tnc -tr |
shutdown | Stop-Computer / Restart-Computer | |
type | get-content | cat, gc, type |
All powershell functions are built using verb-noun
Verb = get, set, stop, remove, test, invoke...
Noun = cat, london, chair, cleanliness, assignment, computer...
if you are creating your own functions. look at the list approved verbs https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands?view=powershell-7.2
with the verb-noun information we can quickly get more commands
get-command -verb "get" -noun "loc*"
get-command -noun "location"
explore the commands in table above. ping some website
test out predictive intellisense with shift+tab. Try it with
- "
Get-NetIPConfiguration -
" - "
Test-Connection -
" - try out
test-connection -quiet -TargetPath "Your Favorite site"
variable is a way to store something for easy reuse later on.
you have built inn variables like $ErrorActionPreference
# this should display all variables
get-variable
and user defined ones that you make yourself.
$MyGivenName = "David"
$MySurName = "Etternavn"
$MyGivenname + " " + $MySurname
$var1 = "-1"
$var2 = 2
$sum = $var1 + $var2
$sum
$var2.GetType()
[int32]$var1 + $var2
# you also have more datatypes like these or more
$var1 = $true
$var2 = 10L
$var2 = [int64]"10"
Enviromental variables are also quite usefull
$env:
and shift tab will displaythem.
$env:username and $env:userprofile when writing scripts makes them easier to use for multiple users.
explore the different enviromental variables. use them with for example set-location and get-childitem
single quotes is pure text. double quotes can expand variables inside it
$language = 'Powershell'
$color = 'purple'
$sentence = "$language the powershell mascot has $color hair"
$sentence2 = '$language the powershell mascot has $color hair'
# you dont have to store it as a variable to run it. this also works fine
"$language the powershell mascot has $color hair"
represented with @" "@
block with either singlequote or double quote. Since anything inside it is displayed. the ending block has to be without tab or spaces and on a new line to work. otherwise it wont terminate the here string
$date = get-date
$herestring = @"
This is a string
Today's date is : $date
fancy ascii art or whatever
`. ___
__,' __`. _..----....____
__...--.'``;. ,. ;``--..__ .' ,-._ _.-'
_..-''-------' `' `' `' O ``-''._ (,;') _,'
,'________________ \`-._`-','
`._ ```````````------...___ '-.._'-:
```--.._ ,. ````--...__\-.
`.--. `-` ____ | |`
`. `. ,'`````. ; ;`
`._`. __________ `. \'__/`
`-:._____/______/___/____`. \ `
| `._ `. \
`._________`-. `. `.___
SSt `------'`
"@
with command execution $() you can run big chunks of code inside your text if you wanted to or just singular commands.
$date = get-date
$string = "today is $date"
# the above could also be written as
$string = "today is $(get-date)"
store some ascii art as a here-string try shoving in a variable with your name someplace and also running any powershell command you like using command execution.
more on this topic here
$var = "stuff written here", "more stuff written here"
# check these out
$var | get-member
get-member -inputobject $var
- run the
var =
command above, try a $var.count, $var.length - test-netconnection and test-connection your favorite website, and save them as a variable.
- try get-member and access the different properties using $var.InsertPropertyName
- try
$variable | select-object address
on both test-connection and test-netconnection variables.
creation of an empty array
$data = @()
# check the count to see if its empty or not.
$data.count
creation of an array with values in one go
$data = @('Zero','One','Two','Three')
# checking its contents.
$data.count
$data
# or multiline since its easier to read
$data = @(
'Zero'
'One'
'Two'
'Three'
)
comma separated lines can also create an array and work most of the time.
$data = 'Zero','One','Two','Three'
to access individual items use brackets []. remember that the first item is [0]
#
$data[0]
$data[3]
# negative values go from the end. so last item is [-1]
$data[-1]
# multiple also possible
$data[3,0,3]
#or range with the .. operator
$data[1..3]
# or reverse
$data[3..1]
updating values and adding to an array
# updating a value
$data[1] = "fifty"
# adding to an array
$data += "four"
more info on arrays https://docs.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-arrays?view=powershell-7.2
arrays are slow to manipulate when large. adding to an array doesnt append the data, it breaks down the array and stores it again.
Arraylists handles adding items quickly. I personally almost always use arraylists.
# creating an array and adding to it.
$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')
$somevalue ="othervalue"
[void]$myArray.Add($somevalue)
# and removing from array
$everyExistingFolder.Remove('Value')
[void]
is used to supress the return code when adding values. try it without.
$myObject = [PSCustomObject]@{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Illinois'
}
# can be accessed like a normal object
$myObject.Name
# adding new properties to an object
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'McCallister'
# and looking at it
$myObject.ID
# removing a property
$myObject.psobject.Properties.Remove("ID")
#when using objects in strings. funny thing can happen
"hello $myobject"
# this above would print as hello @{Name=Kevin; Language=PowerShell; State=Illinois}
# $() is how you expand on something on an expression in a string
"hello $($myobject.name)"
more info on pscustomobjects https://docs.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-pscustomobject?view=powershell-7.2
super fast but has its limits. if you encounter preformance issues. look into converting your arrays or arraylists if possible to hashtables.
$htable = @{EmpName="Charlie";City="New York";EmpID="001"}
$htable2 = @{
“key1” = “value1”
“key2” = “value2”
}
- create an array and an arraylist.
- add a psCustomObject to each, add one text string and one number(make sure its stored as an int)
- access individual items in the array and array list.
- run .gettype() on the array/arraylist and the individual items.
pipe |
is usefull for oneliners but generaly slower than other methods, using it in the command line is fine. using it in scripts if you hit performance issues might be something to consider removing.
'wuauserv' | Get-Service
'wuauserv' | Get-Service | Stop-Service
'wuauserv' | Get-Service
'wuauserv' | Get-Service | start-service
# you can also get the content of a text file and pipe it along
- find 3 services, store them in a text file and try piping it to get-service.
Get-Content -Path $env:USERPROFILE\Services.txt | Get-Service
more about operators here
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_operators?view=powershell-7.2
or get-help about_operators
there are plenty but the logical and comparison operators are the most used ones.
- 1 -eq 1
- 1 -ne 1
- (0..10) -contains 8
- "burgers are awesome" -like "*are*"
- "burger" -match "burger"
- 1 -gt 2
- 1 -lt 2
- 3 -ge 3
etc.
- 1 -eq 1 -and 1 -eq 2
- 1 -eq 1 -or 1 -eq 2
- 1 -eq 1 -xor 1 -eq 2
- -not(1 -eq 1)
-xor is exclusive or.
try running the operators listed
if(1 -eq 1){"hurray, its true"}
# or more complex
if(test-connection -count 1 -quiet nrk.no){"NRK is online"}
if (-not( 1 -eq 2)) { $true }
# or
if (!( 1 -eq 2)) { $true }
if (test-connection -count 1 -quiet nrk.no) { "NRK is online" }
else { "NRK is not responding" }
if (test-connection -count 1 -quiet nrk.no) { "NRK is online" }
elseif (test-connection bbc.com -count 1 -quiet) { "bbc is online" }
elseif (1-eq 3){"can have many more"}
else { "NRK is not responding" }
switch is like an if statement. but much simpler when it comes to checking multiple conditions.
switch (3)
{
1 {"It is one."}
2 {"It is two."}
3 {"It is three."}
4 {"It is four."}
}
# or multiple, or text.
switch (4, 2, "five")
{
1 {"It is one." }
2 {"It is two." }
3 {"It is three." }
4 {"It is four." }
3 {"Three again."}
"five" {"It is five."}
}
more about switches https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_switch?view=powershell-7.2
- Write something using controll flow that tells you if the current time is after lunch(11:00 local time)
- Write something using controll flow that tells you if you have:
- good ping (less than 30)
- bad ping (more than 100)
- ok ping (somewhere inbetween good and bad)
Remember that switch is a thing.
Good for doing something X amount of times, every other time, basic scripting you probably wont need for loop that much, but if you draw graphics with code its more usable.
# <Init> intialises the counter
# <Condition> for continuing and doing your thing is this.
# <Repeat> adding to your conter, usually $i++(adds 1) or even $i+=2(adds two)
for (<Init>; <Condition>; <Repeat>)
{
<Statement list>
}
# a simple for loop would look like this
for ($i = 0; $i -lt 100; $i++) {
Write-Host "im doing something 100 times, this is #$i"
}
# or you can count the number of things in an array
$list = "Finn","Jake","Princess bubblegum","Steve"
for ($i = 0; $i -lt $list.Count; $i++) {
write-host "$($list[$i]) is a cool person"
}
Probably the easiest to use.
$list = "Finn","Jake","Princess bubblegum","Steve"
foreach($person in $list){
write-host "$person is a cool person"
}
this uses the pipeline which is seen as slower.
$list = "Finn","Jake","Princess bubblegum","Steve"
$list | ForEach-Object {"$_ is a cool person"}
There is one way this can be faster than all other loops in some circumstances. any one remember?
the fastest loop and my favorite.
$list = "Finn","Jake","Princess bubblegum","Steve"
$list.ForEach({"$_ is a cool person"})
there might be some faster but then your probably a c# nerd using .net stuff.
while($val -ne 3)
{
$val++
Write-Host $val
}
# do while
do {<statement list>} while (<condition>)
# do until
do {<statement list>} until (<condition>)
$x = 1,2,78,0
do { $count++; $a++; } while ($x[$a] -ne 0)
$x = 1,2,78,0
do { $count++; $a++; } until ($x[$a] -eq 0)
as you can see -ne(not equal) and -eq(equal) is changed.
where, binarysearch,hashtable, sorting
Take a look at all the approved verbs here: https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands?view=powershell-7.2
You're able to use automatic variables in functions like:
You can have 2 different types, basic- and advanced-functions.
Basic functions would just have the bare minimum in order to create a function.
function Verb-Noun {
param (
[string]$Param1,
[int]$Param2
)
#CODE
}
Advanced functions are a little more complex, but have much more functionality. Therefore we most likely would always want to create an advanced function. Here's a basic version of an advanced function.
function Verb-Noun {
[CmdletBinding()]
param (
[string]$Param1,
[int]$Param2
)
begin {
#CODE
}
process {
#CODE
}
end {
#CODE
}
}
The advantage of using an advanced function is that it has a lot of built-in functionality. You can e.g. create a function that has parameters that are exclusive from one another. You can see more of this in the Get-MrfkUserInfo function.
function Verb-Noun {
[CmdletBinding(DefaultParameterSetName="username")]
param (
[Parameter(ParameterSetName="username")][string]$Username,
[Parameter(ParameterSetName="displayname")][string]$DisplayName,
[Parameter(ParameterSetName="mobilephone")][string]$MobilePhone
)
process {
switch ($PsCmdlet.ParameterSetName) {
"username" {
$filter = "SamAccountName -like `"$Username`""
}
"displayname" {
$filter = "DisplayName -like `"$DisplayName`""
}
"mobilephone" {
$filter = "MobilePhone -like `"$MobilePhone`""
}
}
Get-ADUser -Filter $filter
}
}
You could merge a collection of functions into a module, which you can use to easily import functions across multiple users or devices, and update to new versions of the functions. This would atleast be better than having a bunch of custom functions in your $PROFILE
. You can take NN.MrfkCommands as an example (if one is needed).
should hand out a cheat sheet for this stuff abve. quick look up on the things mentioned above so they can easily look at when doing some ez labwork.
what i usualy do to quickly generate arrays or get stuff from clipboards is this.
# i use this
$stuff = get-clipboard | where-object {$_}
# or this, which is same as above but with shortnames
$stuff = gcb|?{$_}
get-clipboard
gets from your clipboard, whatever you have CTRL+Ced
the above can be saved in a function you put in your profile.
TASK
Some stuff from these modules as they will daily look at AD and SCCM stuff. AD module (get-aduser, get-adgroup etc).
You can run this function in order to get a list of all the functions in the module.
Get-Command -Module "MODULENAME"
https://github.com/dfinke/ImportExcel
Import-Excel -Path "PATH"
Export-Excel -Path "PATH"
The AD-module is installed by default on wintools04
.
You can run the following functions to get either users or groups from AD.
Get-ADUser "USERNAME"
Get-ADGroup "GROUPNAME"
Get-ADComputer "COMPUTERNAME"
MECM module to find deployed computers, who has logged on, their ip etc.
You can import the module by running the following on wintools04
.
Import-Module ConfigurationManager
Set-Location ps1:
You'll have to set the psdrive to ps1 in order to make all the functions work.
If you want to get the computerinfo of a specific computer you can run the following.
Get-CMDevice -Name "LT-SADM-001"
APIs can handle Create, Read, Update and Delete operations.
A webhook is a lightweight API that powers one-way data sharing triggered by events, such as you pushing a button.
Almost all APIS use JSON to structure data.
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
#flat easy json file to grasp
$ip = "1.1.1.1"
Invoke-RestMethod -uri "https://ipinfo.io/$ip/json"
# this weather one has alot more depth with forecast every hour etc. so getting the weather right now requires some more
$lat = "34.05"
$lon = "-118.24"
$weather = Invoke-RestMethod -uri "https://api.met.no/weatherapi/locationforecast/2.0/compact?&lat=$lat&lon=$lon"
$weather.properties.timeseries[0].data.instant.details
- PSkoan
- Interactive learning. try doing 1 PSKoan at work everyday. https://github.com/vexx32/PSKoans
- do stuff with powershell instead of GUI
Install PSkoans by following the link. Go through installation of prereqs and the module. Solve the first Koan.