Listing 1: Whereis.ps1's main Function
function main {
# If -help is present or the -name parameter is missing, output
# the usage message.
if (($Help) -or (-not $Name)) {
usage
}
# Convert $Name to an array. If any array element contains *,
# change the array to $NULL. This is because
# get-childitem c:\* -include *
# recurses to one level even if you don't use -recurse.
$Name = @($Name)
for ($i = 0; $i -lt $Name.Length; $i++) {
if ($Name\[$i] -eq "*") {
$Name = $NULL
break
}
}
#CALLOUT
A
# If no -path parameter, use WMI to collect a list of fixed drives.
if (-not $Path) {
$Path = get-wmiobject Win32_LogicalDisk -filter DriveType=3 | foreach-
object {
$_.DeviceID
}
}
#END CALLOUT A
# Convert $Path into an array so we can iterate it.
$Path = @($Path)
#CALLOUT
B
# If a path ends with "\", append "*". Then, if it doesn't end with
# "\*", append "\*" so each path in the array ends with "\*".
for ($i = 0; $i -lt $Path.Length; $i++) {
if ($Path\[$i].EndsWith("\")) {
$Path\[$i] += "*"
}
if (-not $Path\[$i].EndsWith("\*")) {
$Path\[$i] += "\*"
}
}
#END CALLOUT B
# If no -LastWriteTimeRange parameter, assume all dates.
if (-not $LastWriteTimeRange) {
$LastWriteTimeRange = @([DateTime]::MinValue, [DateTime]::MaxValue)
}
else {
# Convert $LastWriteTimeRange to an array (if it's not already).
$LastWriteTimeRange = @($LastWriteTimeRange)
# If only one element, add max date as second element.
if ($LastWriteTimeRange.Length -eq 1) {
$LastWriteTimeRange += [DateTime]::MaxValue
}
# Zero for first element means [DateTime]::MinValue.
if ($LastWriteTimeRange\[0] -eq 0) {
$LastWriteTimeRange\[0] = [DateTime]::MinValue
}
#CALLOUT
C
# Throw an error if [DateTime]::Parse() fails.
trap [System.Management.Automation.MethodException] {
throw "Error parsing date range. String not recognized as a valid
DateTime."
}
# Parse the first two array elements as DateTimes.
for ($i = 0; $i -lt 2; $i++) {
$LastWriteTimeRange\[$i] = [DateTime]::Parse($LastWriteTimeRange\[$i])
}
#END CALLOUT C
}
# Throw an error if the date range is invalid.
if ($LastWriteTimeRange\[0] -gt $LastWriteTimeRange\[1]) {
throw "Invalid date range. The first date is greater than the second."
}
# If no -sizerange parameter, assume all sizes.
if (-not $SizeRange) {
$SizeRange = @(0, [UInt64]::MaxValue)
}
else {
# Convert $SizeRange to an array (if it's not already).
$SizeRange = @($SizeRange)
# If no second element, add max value as second element.
if ($SizeRange.Length -eq 1) {
$SizeRange += [UInt64]::MaxValue
}
}
#CALLOUT
D
# Ensure the elements in the size range are numeric.
for ($i = 0; $i -lt 2; $i++) {
if (-not (isNumeric $SizeRange\[$i])) {
throw "Size range must contain numeric value(s)."
}
}
#END CALLOUT D
# Throw an error if the size range is invalid.
if ($SizeRange\[0] -gt $SizeRange\[1]) {
throw "Invalid size range. The first size is greater than the second."
}
# If both -files and -dirs are missing, assume -files.
if ((-not $Files) -and (-not $Dirs)) {
$Files = $TRUE
}
# Keep track of the number of files and their sizes.
$count = $sizes = 0
# Use the get-childitem cmdlet to search the file system, and use
# the writeItem function to output matching items. For files, check
# the date and size ranges. For directories, only the date range is
# meaningful.
get-childitem $Path -include $Name -force: $Force -recurse: (-not
$OneLevel) | foreach-object {
if ($Files -and (-not $_.PsIsContainer)) {
if (($_.LastWriteTime -ge $LastWriteTimeRange\[0]) -and
($_.LastWriteTime -le $LastWriteTimeRange\[1]) -and
($_.Length -ge $SizeRange\[0]) -and ($_.Length -le $SizeRange\[1])) {
$count++
$sizes += $_.Length
writeItem $_
}
}
if ($Dirs -and ($_.PsIsContainer)) {
if (($_.LastWriteTime -ge $LastWriteTimeRange\[0]) -and
($_.LastWriteTime -le $LastWriteTimeRange\[1])) {
$count++
writeItem $_
}
}
}
# Output statistics if not using -defaultformat.
if (-not $DefaultFormat) {
"Found {0:N0} item(s), {1:N0} byte(s)" -f $count, $sizes
}
}