Um momento
0x100Lesson 17 of 17

Capstone: the sanctuary feeding report

Combine CSV import, grouping, hashtables, advanced functions and formatting into a real reporting tool.

45 min 6-question quiz 3 code exercises
By the end of this lesson you can
  • Turn a raw CSV log into typed, summarized objects
  • Compare results against limits stored in a hashtable
  • Package the logic as an advanced function that returns an object, and format it at the edge

A note pinned to the feeding-room door:

Whoever is the new automation keeper: every evening I add up the feeding log with a pencil to see who’s been overfed. Vesper keeps getting seconds. Please make the computer do it. - Head Keeper Ada

The log is a CSV file with one row per meal:

1Time,Dragon,Food,Kg
207:00,Ember,goats,20
307:30,Glim,moths,1
4...

and every dragon has a daily limit in kilograms. By the end, your script prints:

1=== EMBERFALL FEEDING REPORT ===
2Meals: 9 (07:00-18:30)
3Total: 155 kg
4Hungriest: Vesper (54 kg)
5Over limit: Ember, Vesper
6Status: ALERT

Step 1: load it and check the types

ConvertFrom-Csv (or Import-Csv for a file) gives you objects - but every property is a string. Check with Get-Member before trusting any arithmetic:

step1.ps1
1$log = @'
2Time,Dragon,Food,Kg
307:00,Ember,goats,20
411:00,Ember,goats,22
507:30,Glim,moths,1
6'@ | ConvertFrom-Csv
7$log.Count
8($log | Get-Member -Name Kg).Definition
9($log | Measure-Object -Property Kg -Sum).Sum
Output
3
string Kg=20
43

Measure-Object converts strings to numbers when it adds them, so sums are safe. Sorting and comparing are not - convert with [int] or a calculated property first.

Step 2: one row per dragon

Group-Object Dragon collects each dragon’s meals in the group’s Group property. Turn each group into a tidy summary object with [pscustomobject] - objects keep the data usable for the next step, whereas formatted text would be a dead end.

step2.ps1
1$log = @'
2Time,Dragon,Food,Kg
307:00,Ember,goats,20
411:00,Ember,goats,22
507:30,Glim,moths,1
6'@ | ConvertFrom-Csv
7$perDragon = $log | Group-Object Dragon | ForEach-Object {
8  [pscustomobject]@{
9    Dragon = $_.Name
10    Meals  = $_.Count
11    Kg     = ($_.Group | Measure-Object -Property Kg -Sum).Sum
12  }
13}
14$perDragon | Sort-Object Kg -Descending | ForEach-Object { '{0}: {1} kg in {2}' -f $_.Dragon, $_.Kg, $_.Meals }
Output
Ember: 42 kg in 2
Glim: 1 kg in 1

Step 3: compare against limits

A hashtable is the natural home for per-dragon limits: $limits[$dragon] looks one up instantly. Guard against dragons that have no limit yet with .ContainsKey() - visitors arrive all the time.

step3.ps1
1$limits = @{ Ember = 45; Glim = 2 }
2$totals = @{ Ember = 52; Glim = 1; Nimbus = 70 }
3foreach ($dragon in $totals.Keys | Sort-Object) {
4  if (-not $limits.ContainsKey($dragon)) {
5    "$dragon has no limit yet"
6  } elseif ($totals[$dragon] -gt $limits[$dragon]) {
7    '{0} is {1} kg over' -f $dragon, ($totals[$dragon] - $limits[$dragon])
8  } else {
9    "$dragon is fine"
10  }
11}
Output
Ember is 7 kg over
Glim is fine
Nimbus has no limit yet

Step 4: objects in, objects out

The final tool is an advanced function that takes meals from the pipeline and returns one report object. Formatting it into text happens outside the function. That separation pays off: the same function can feed a console report today, ConvertTo-Json for a dashboard tomorrow, and a Pester test the day after.

Import-Csv feeding.csv | Get-FeedingReport -Limit $limits | ConvertTo-Json

Collect the pipeline objects in process, and do all the summarizing in end, once everything has arrived.

Where to go next

  • Schedule it: register the script with Task Scheduler (or cron) to run every evening at 20:00.
  • Send it: post the report to a chat channel with Invoke-RestMethod -Method Post and a webhook URL, or save it as JSON for a dashboard.
  • Test it: write Pester tests for Get-FeedingReport with tiny fake logs.
  • Go further: the Az and Microsoft.Graph modules bring the same skills to Azure and Microsoft 365; Invoke-Command brings them to every server you manage.

Key takeaways

  • Check types with Get-Member; convert text to numbers before sorting or comparing.

  • Group-Object plus [pscustomobject] turns raw rows into one summary per thing.

  • Hashtables hold lookups like limits; guard missing keys with .ContainsKey().

  • Return objects from functions and format at the edge - the same data can then go anywhere.

Lesson quiz

6 questions · pass with 5 correct · up to 50 XP

Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.

Practice: write PowerShell scripts

Write a script in the editor and run it for real against sample input, which is piped into your script as $input. Scripts run on PowerShell 6.2 through Try It Online (tio.run), a free public service, so these exercises avoid PowerShell 7-only syntax; your script and test input are sent there.

Exercise 1

Meals per dragon

+25 XP

The input is the feeding log CSV. Print one line per dragon, most kilograms first: Vesper: 54 kg (2 meals) - and (1 meal), singular, when there was only one.

  • A busy day
  • A quiet day
script.ps1
Loading editor…

Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.

Exercise 2

Over the limit

+25 XP

The input is the feeding log CSV; the starter defines $limits. For each dragon that ate more than its limit, in alphabetical order, print Ember ate 52 kg - 7 kg over the limit of 45. Dragons with no limit are never over. If nobody is over, print Everyone ate sensibly.

  • A busy day
  • A quiet day
  • A visitor
script.ps1
Loading editor…

Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.

Exercise 3

The feeding report

+25 XP

Write the advanced function Get-FeedingReport. It takes meals from the pipeline (-Meal) and a -Limit hashtable, and returns one object with these properties:

  • Meals (the count), First and Last (the first and last meal times, in log order)
  • TotalKg, and Hungriest - an object with the Dragon and Kg of the dragon that ate the most
  • OverLimit - the alphabetical names of the dragons over their limit (an empty array if none)

The starter formats your object into the report - keep that part as it is:

1=== EMBERFALL FEEDING REPORT ===
2Meals: 9 (07:00-18:30)
3Total: 155 kg
4Hungriest: Vesper (54 kg)
5Over limit: Ember, Vesper
6Status: ALERT
  • A busy day
  • A quiet day
  • A visitor
script.ps1
Loading editor…

Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.

Questions about this lesson

Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.

Loading posts…

Gostou da aula? 😆👍
Apoie nosso trabalho com uma doação: