My Samples
https://tinyurl.com/cbmctsamples
Module 1: Getting started with Windows PowerShell
Understand Windows PowerShell command syntax
Module 2: Windows PowerShell for local systems administration
Active Directory Domain Services administration cmdlets
The -Filter parameter does work with quotes around the entire filter but for consistency we should be using braces (the filter is a PowerShell expression and expressions should be in braces).
Get-ADObject -Filter 'ObjectClass -eq "contact"'
Get-ADObject -Filter {ObjectClass -eq "contact"}
It does require quotes around values inside the filter (either single or double, but not curly ).
Get-ADObject -Filter {ObjectClass -eq contact} # Error
Get-ADObject -Filter {ObjectClass -eq 'contact'}
Get-ADObject -Filter {ObjectClass -eq "contact"}
Network configuration cmdlets
Test-NetConnection has two party tricks that I find useful. First, it has a builtin traceroute. Second, it can connect to ports other than ICMP ECHO.
Test-NetConnection chcstud-fs -TraceRoute
Test-NetConnection chcstud-fs -Port 3389
Get-NetIpAddress allows filtering by IPv4/IPv6 address type.
Get-NetIPAddress -AddressFamily IPv4
Get-NetIPAddress -AddressFamily IPv6
Module 3: Working with the Windows PowerShell pipeline
Select, sort and measure objects - Sorting objects by a property
"It isn't possible in a single command to sort by one property in ascending order and another in descending order."
Yes, it is. It's been possible for the last four versions of this course which all said that it isn't. *sigh*
How? Use a hash table.
Get-Process `
| Sort-Object `
@{expression={$PSItem.Name};descending=$true}, `
@{e={$PSItem.NPM};ascending=$true}
https://craigb-mct.blogspot.com/2016/06/using-powershell-hash-tables-with.html
Filter objects out of the pipeline
No, the principle is filter left, format right.
https://www.youtube.com/watch?v=-LpsPtbcKR0
Skill question
If I runGet-Service -Name "bits" | Start-Process
what is going to happen ?
Lab: Using PowerShell pipeline (the first one, Lab 3)
Exercise 2: Filtering objects
Task 5: Create a report that displays specified Control Panel items
What is this trying to achieve? List all items in the System and Security category and in only that category. One item (Power Options) is in two categories, so should be excluded.
Get-ControlPanelItem -Category "System and Security" `
| where { -not ($PSItem.Category -notlike "*System and Security*") } `
| sort name `
| ft name, category
Since the Category property is a collection (note the braces), there is a much better way of doing this - the Count property.
Get-ControlPanelItem -Category "System and Security" `
| where { $PSItem.Category.count -eq 1 } `
| sort name `
| ft name, category
Note that Get-ControlPanelItem is not in PowerShell 7.
Enumerate objects in the pipeline
PowerShell 7 adds a -Parallel processing option to ForEach-Object.
https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-feature/
Send and pass pipeline data as output - Passing pipeline data
Get-ADComputer -Filter * | Get-Process
This is a bad example because there is a parameter that matches (-Name) however Get-Process binds to -ComputerName first, which errors out (even though -ComputerName is not mandatory).
Why? Who knows? I can't find any information on a global rule for the order that pipeline binding uses the parameters.
Module 5: Querying management information by using CIM and WMI
WMI Explorer (Dec 2020)
https://github.com/vinaypamnani/wmie2/releases
https://devblogs.microsoft.com/scripting/weekend-scripter-announcing-wmi-explorer-2-0/
Query data by using CIM and WMI - Querying instances
In WQL the wildcards are % and _. The percent is the "0-or-more" wildcard (the * in Windows) and the underscore is the "exactly-1" wildcard (the ? in Windows).
Make changes by using CIM and WMI - Discovering methods
You cannot use Get-Member to discover methods. It only shows the methods of .NET classes, not of WMI classes.
Lab 5
Hints for the lab:
gcim -ClassName Win32_Account -Filter "LocalAccount = 'true'"
gcim -ClassName Win32_UserAccount -Filter "LocalAccount = 'true'"
#or
gcim -ClassName Win32_UserAccount -Filter "Domain='LON-CL1'"
Module 6: Working with variables, arrays, and hash tables
Manipulate variables - Working with strings
Note that the methods of the String class are always case-sensitive, regardless of the .NET culture.
[String] $S = "Monday"
$S.Contains("mon") # evaluates to False
Write-Host is bad
Don Jones famously wrote that every time you use Write-Host, you kill a puppy. Why is Write-Host so bad? Because it messes with the output streams.
Single-item arrays
PS > $A = "lon-dc1"
PS > $A.count
1
PS > $A[0]
l
PS > $A = @( "lon-dc1" )
PS > $A.count
1
PS > $A[0]
lon-dc1
Lab: Using variables, arrays, and hash tables in PowerShell (Lab 6)
Exercise 1: Working with variable types
Task 2: Use DateTime variables
Step 6: Either replace "haven't signed in" with "have signed in" in the Lab, or replace "-gt" with "-lt" in the Lab Answer Key.Module 7: Windows PowerShell scripting
Case convention
The convention for the scripting keywords is all lowercase. That is, foreach instead of ForEach, if and elseif and else instead of If and ElseIf and Else. Mixed case will, however, work fine.
Mandatory vs Read-Host
The model answers in the course often use a construct similar to the following for mandatory parameters. Note that the parens are required.
[string] $ComputerName = (Read-Host "Enter computer name")
A better way is to mark the parameter as mandatory.
[Parameter(Mandatory)] [string] $ComputerName
Lab: Using scripts with PowerShell (Lab 7)
Exercise 2: Processing an array with a ForEach loop
Goal: Create a script that sets the ip phone attribute for all members of the IPPhoneTest group. Set the ip phone number to givenname.surname@adatum.com.
Note that Active Directory Administrative Center displays the ipPhone attribute on the Account tab of a user. If you use Active Directory Users and Computers then you will need to enable Advanced Features and use the Attribute Editor tab.
Hint: Get-ADGroupMember returns an ADPrincipal object. This does not include most the attributes we need. Inside the foreach loop we will require a call to Get-ADUser.
Hint: The Set-ADUser cmdlet does not directly support changing the ipphone attribute. Use the -Replace parameter, which takes a hashtable for the attribute/value pair or pairs.
Set-ADUser -Identity "August" -Replace @{ ipPhone="august.toyle@adatum.com" }
Exercise 3: Processing items by using If statements
Goal: Create a script that reads a list of services from a text file. For each service in the list, if the service is not running then start it and display a message "Started service name", and if the service is running then display a message "Service name is already running".
The services.txt file should contain two lines: Spooler, W32Time
Exercise 4: Creating users based on a CSV file
Goal: Create a script that creates user accounts based on information from a csv file. There are no passwords provided, so create disabled accounts.
Extra Credit: Create enabled accounts with a complex password. Save the passwords to a text file.
The users.csv file contains four columns: First, Last, UserID, and Department.
Create the users with the following values.
Name: First Last
Path: OU=Department,DC=Adatum,DC=Com
User principal name: UserID@adatum.com
SAM account name: UserID
Display name: First Last
Given name: First
Surname: Last
Department: Department
Password: (Leave blank)
Exercise 5: Querying disk information from remote computers
Goal: Create a parameterised script that collects disk information from a remote computer.
PS E:\Mod07\Labfiles> .\AZ-040_Mod07_Ex5_LAK.ps1 -ComputerName lon-dc1
Hint: Get-CIMInstance Win32_LogicalDisk.
Exercise 6: Updating the script to use alternate credentials
Goal: Extend the previous script, add a switch parameter to make the script prompt us for a credential.
PS E:\Mod07\Labfiles> .\AZ-040_Mod07_Ex6_LAK.ps1 -ComputerName lon-dc1 -UseAlternateCredential
Hint: New-CimSession.
Module 10: Managing Microsoft 365 services with PowerShell
Manage Microsoft 365 user accounts, licenses, and groups with PowerShell - Managing groups
The MsolGroup cmdlets work with object IDs, not names.
For example:
$MktGrp = Get-MsolGroup | Where-Object {$_.DisplayName -eq "Marketing"}
$Catherine = Get-MsolUser | Where-Object {$_.DisplayName -eq "Catherine Richard"}
Add-MsolGroupMember -GroupObjectId $MktGrp.ObjectId -GroupMemberType "User" -GroupMemberObjectId $Catherine.ObjectId
Module 11: Using background jobs and scheduled jobs
Typo: In multiple places in this module, replace "-IncludeChildJobs" with "-IncludeChildJob".
PSScheduledJob module
Remove all references to the ScheduledTasks module. It was superseded many years ago by the PSScheduledJob module.
Get-Command -Module PSScheduledJob
Note that this module is not available in PowerShell 7.
Job results
Background job results are not persisted. When you close the PowerShell host, all unclaimed results are discarded.
Scheduled job results are persisted to disk.
$HOME\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs\<jobname>