I have to extrapolate student year of graduation based on their grade number. Their student ID number has the 2-digit year of graduation in it, however this has proven to be inaccurate sometimes due to students who have been held back and other ID number based anomalies.
I wrote a powershell script to do this for me as part of a larger script to take a CSV exported from powerschool and check their location in active directory based on their graduation year. The portion of the script I'm having trouble with is as follows:
function GradeToYog($grade){ # converts grade number to year of grad because IDNUM is not a reliable indicator of grad year
if($grade -ne $null){
# get current date
$date = Get-Date
# account for time of year, add 1yr offset to grad year if september or later
$offset = 0
if($date.month -ge 9){
$offset = 1
}
# Account for placement of extended-stay students such as SPED kids
if($grade -gt 12){
$grade = 12
}
return ($date.year 12 $offset - $grade)
} else {
return "Invalid entry."
}
}
This works for grades -1 (pre-K) through 12, however it breaks when I test it against -2:
PS C:\> GradeToYog 12
2022
PS C:\> GradeToYog 9
2025
PS C:\> GradeToYog 6
2028
PS C:\> GradeToYog 3
2031
PS C:\> GradeToYog 1
2033
PS C:\> GradeToYog 0
2034
PS C:\> GradeToYog -1
2035
PS C:\> GradeToYog -2
2022
The weird thing is that if I test the expected values against the same logic in powershell it works:
PS C:\> 2022 12 0 - -2
2036
I searched for similar questions but either I'm not searching for it correctly or there doesn't seem to be an instance of powershell incorrectly subtracting '-2'
CodePudding user response:
Note: I can't reproduce your specific symptom, but the following advice is still worth heeding.
Type-constrain your $grade
parameter to ensure that it is a number:
# Make sure that $grade is an [int] (System.Int32) value
function GradeToYog([int] $grade) { # ...
# Alternative syntax, with a param(...) block,
# which makes it easier to use validation attributes.
function GradeToYog {
param(
[ValidateRange(-2, 15)] # Constrain the range of allowable numbers.
[int] $grade
)
# ...
}
An unconstrained parameter is effectively the same as [object] $grade
, i.e. it can receive an object of any type.
PowerShell infers certain types from unquoted arguments such as 2
and -2
and, perhaps surprisingly, 2
becomes an [int]
, whereas -2
becomes a [string]
(to force the latter to be interpreted as an [int]
ad hoc, pass it as (-2)
).
Many PowerShell operators, such as -eq
/ ne
and -lt
/ -le
/ -gt
/ ge
can operate on both strings and numbers, and it is usually the type of the LHS operand that determines the data type of the operation overall.
Here's an example of where this would make a difference:
2 -lt 10 # $true
'2' -lt 10 # !! $false, due to *lexical* comparison