Logging Variable Types

by Aug 2, 2022

As part of your debugging and quality control you may want to log the data that gets assigned to individual variables. For example, you may want to find out what the actual data types are that are assigned to a given variable, so that you could later strongly-type the variable for added security.

Here is a custom validator class that you can use for such analysis. Simply run the code below as a prerequisite. It does nothing except declaring a new attribute:

# create a new custom validation attribute named "LogVariableAttribute":
class IdentifyTypeAttribute  : System.Management.Automation.ValidateArgumentsAttribute
{
  
    
  # this gets called whenever a new value is assigned to the variable:

  [void]Validate([object]$value, [System.Management.Automation.EngineIntrinsics]$engineIntrinsics)
  {
    # get the global variable that logs all changes:
    [System.Management.Automation.PSVariable]$variable = Get-Variable "loggedTypes" -Scope global -ErrorAction Ignore
    # if the variable exists and does not contain an ArrayList, delete it:
    if ($variable -ne $null -and $variable.Value -isnot [System.Collections.ArrayList]) { $variable = $null }
    # if the variable does not exist, set up an empty new ArrayList:
    if ($variable -eq $null) { $variable = Set-Variable -Name "loggedTypes" -Value ([System.Collections.ArrayList]@()) -Scope global -PassThru }
    
    [string]$line = (Get-PSCallStack)[-1].Position.Text
    $pattern = '\$(\w{1,})'
    $match = [regex]::Match($line, $pattern)
    if ($match.success)
    {
      
      # log the type contained in the variable
      $null = $variable.Value.Add([PSCustomObject]@{
          # use the optional source name that can be defined by the attribute:
          Value = $value.GetType()
          Timestamp = Get-Date
          # use the callstack to find out where the assignment took place:
          Name = [regex]::Match($line, $pattern).Groups[1]
          Position = [regex]::Match($line, $pattern).Groups[1].Index + (Get-PSCallStack)[-1].Position.StartOffset
          Line = (Get-PSCallStack).ScriptLineNumber | Select-Object -Last 1
          Path = (Get-PSCallStack).ScriptName | Select-Object -Last 1
      })

    }
  }
} 

Now in your script, at its beginning, initialize all variables that you want to track by adding the new attribute:

[IdentifyType()]$test = 1
[IdentifyType()]$x = 0

# start using the variables:
for ($x = 1000; $x -lt 3000; $x += 300) 
{
  "Frequency $x Hz"
  [Console]::Beep($x, 500)
}

& {
  $test = Get-Date
}


$test = "Hello"
Start-Sleep -Seconds 1
  $test = 1,2,3

Then run the script normally. The results are logged to the global variable $ from where you can view them:

# looking at the log results:
$loggedTypes | Out-GridView
 
PS C:\> $loggedTypes


Value     : System.Int32
Timestamp : 04.07.2022 09:42:46
Name      : test
Position  : 17
Line      : 1
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:46
Name      : x
Position  : 44
Line      : 2
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:46
Name      : x
Position  : 89
Line      : 5
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:46
Name      : x
Position  : 113
Line      : 5
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:47
Name      : x
Position  : 113
Line      : 5
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:47
Name      : x
Position  : 113
Line      : 5
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:48
Name      : x
Position  : 113
Line      : 5
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:48
Name      : x
Position  : 113
Line      : 5
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:49
Name      : x
Position  : 113
Line      : 5
Path      : 

Value     : System.Int32
Timestamp : 04.07.2022 09:42:49
Name      : x
Position  : 113
Line      : 5
Path      : 

Value     : System.String
Timestamp : 04.07.2022 09:42:49
Name      : test
Position  : 215
Line      : 16
Path      : 

Value     : System.Object[]
Timestamp : 04.07.2022 09:42:50
Name      : test
Position  : 258
Line      : 18
Path      :   
 

Twitter This Tip! ReTweet this Tip!