We are constantly learning new things and I like to share a couple of things that I’ve learned that i think all sysadmins need to know.
So I have created a list of my first 17 Powershell tips and tricks.
#1 If you are scripting against an external data source like Azure AD och Exchange Online and want to do large batchjobs you need to cut down on the number of requests. Why?
Well, in exo there is a thing called “microdelay” which is an attack-preventions-thingy (goole it), and number two. This commands is time consuming.
My solution is to download all the things you need and then do all the filter stuff in the script.
$users = Get-MsolUser -All
#2 These huge scripts feeds on three things time, cpu and ram. To save som time you can user the built in index in your arrays to speed up filters like this.
#Old way Measure-Command -Expression { $users.where({$psitem.UserPrincipalName -eq "user1@contoso.net"}) #avg 86 ms } #My way!! Measure-Command -Expression { $users[$users.UserPrincipalName.IndexOf("user1@contoso.net")] #avg 13 ms }
#3 This is also a speed tip, don’t use “like” to do binary decisions. It’s slow!!!
Measure-Command -Expression { $users.where({$psitem.UserPrincipalName -eq "user1@contoso.net"}) #avg 86 ms } Measure-Command -Expression { $users.where({$psitem.UserPrincipalName -like "user1@contoso.net"}) #avg 120 ms }
#4 People is still using XP and PS 2.0 but if you live in the real world, you probably have WMF 4 or 5.
If you do, use the new cool .net where / foreach loops.
#New cool way Measure-Command -Expression { $users.where({$psitem.UserPrincipalName -eq "user1@contoso.net"}) #avg 86 ms } #Old boring way Measure-Command -Expression { $users | % {$_.UserPrincipalName -eq "user1@contoso.net"} #avg 200 ms }
#5 Now you know that indexof() is super cool. But it can screw up, big time! If you don’t do error handling.
#if 0 or more than 1 records are found the indexof() returns -1 $index=$users.UserPrincipalName.IndexOf("user1@contoso.ns") if ($index -eq -1) {throw "Error"} $users[$index] #or use ValidateRange [ValidateRange(0,([int]::MaxValue))]$index=$users.UserPrincipalName.IndexOf("user1@contoso.ns") #The variable cannot be validated because the value -1 is not a valid value for the index variable.
#6 Use “in” & “notin” to find differentials and matches in arrays. It’s there to help you, use it.
$findLicenses = "ENTERPRISEPACK" #Find all users where ENTERPRISEPACK is in the licenses property $HaveE3 = $users.Where({ $findLicenses -in ($PSItem.licenses.accountskuid -split ":")[1] }).count #Find all users where ENTERPRISEPACK is not in the licenses property $HaveNotE3 = $users.Where({ $findLicenses -notin ($PSItem.licenses.accountskuid -split ":")[1] }).count #Find all users from 0 to 10 where UPN is in UPN from users 9 to 20 $users[0..10].where({$psitem.UserPrincipalName -in $users[9..20].UserPrincipalName}).count #2 #Find all users from 0 to 10 where UPN is not in UPN from users 9 to 20 $users[0..10].where({$psitem.UserPrincipalName -notin $users[9..20].UserPrincipalName}).count #9
#7 Use regex in “replace”, it’s like dark magic. If you don’t know regex, visit regexr.com it’s the best.
[string[]]$users2 = @( "john.doe@thisnice.domain.se" "john.doe@thisnice.domain.dk" "john.doe@thisnice.domain.net" "john.doe@internal.thisnice.domain.local" "j.d@thisnice.net" ) #Replace the . (dot) to .mig. where it matches in between thisnice and domain $users2 -replace "(\.)(?=domain)(?<!thisnice)",".mig."
#8 Don’t forget that regex is default in -repace, -match, -split….. escape special charaters \ like . (dot)
#tip 8 dont forget that regex is default, escape special charaters \ like . (dot) "Test.test2" -replace ".","," #,,,,,,,,,, "Test.test2" -replace "\.","," #Test,test2
#9 Tab separation character this is super useful, when exporting to tsv-files.
"test,Test3" -replace ",","`t" "test,Test3" -replace ",",[char]9
#10 int ranges is cool.
0..10
#11 Disable type information in csv export, this crap have hunted me for far to long now.
$users[0..10] | Export-Csv -NoTypeInformation -Path c:\test\test.csv -Delimiter "`t" #this will remove the \/ bullshit from the csv file. #TYPE System.String #Length
#12 Split and join is extremely useful when dealing with external application that uses weird ways to send data. Or things like the old cmd commands 🙂
$splitRegex = "JonJanderIsMyName!!!" -split "(\w{4})" | ? {$_} $splitRegex -join "," $ping = Invoke-Expression -Command "cmd /C ping 1.1.1.1 /n 1" ($ping -split ",").Where({$PSItem -like '*Received*'})
#13 Hex values and bitwise operations exist in Powershell, don’t forget that. I love this one.
(0xFF -band 0xF0) -bxor 0xAA $binaryString = "010111" $int = [convert]::ToInt32($binaryString,2) #Binary to int $shiftleft = $int -shl 1 #shift left [convert]::ToString($shiftleft,2) #Int to binary #010111 # 101110 <<
#14 Get unique values from arrays.
#Sort the values or the get-Unique will fail. $users.licenses.accountskuid | sort | Get-Unique
#15 Group-object is super useful when doing things like usage statistics.
$GroupLicense = $users | group -Property {$_.licenses.accountskuid -join ","} #single property $GroupLicenseCountry = $users | group -Property {$_.licenses.accountskuid -join ","},Country #Multiple properties
#16 One of the first this you learn when doing Powershell is select-object, this is the next level.
#tip 16 Use Select label expression to return calculated parameters $Group | select Count,@{label="Name";expression={($_.Name -replace "(\w+\:)","")}} $GroupLicenseCountry | select Count,@{l="Name";e={($_.Name -replace "(\w+\:)","")}} #Count Name #----- ---- # 528 ENTERPRISEPACK # 406 # 40 DESKLESSPACK # 12 EMS,ENTERPRISEPACK # 6 INTUNE_A_VL,DESKLESSPACK #... #Count Name #----- ---- # 73 ENTERPRISEPACK, Finland # 145 , Sweden # 274 ENTERPRISEPACK, Sweden # 18 , Norway # 47 ENTERPRISEPACK, Denmark #...
#17 Last one is among the latest I’ve learned. I hate myself for not using regions as much as I do today.
#tip 17 use regions #region Code function test1 { 1..2 } function test2 { Write-Host "foobar" } #endregion
“Programming is a creative art form based in logic. Every programmer is different.” – id Software