Integrity Inspection
In this issue:
- Not Everything Has To Be a String
- Parameter Transformations
- Getting Integrity Info
- Testing Integrity Info
- Managing Profiles
- Summary
Last time I started sharing code that I can use to insert into my PowerShell scripts to ensure the file hasn't changed. Eventually, I want to inject this into my profile scripts so I can know if the file has changed without my knowledge.
So far, I am generating what I'm calling an integrity information object like this:
Path : C:\Scripts\sample-function.ps1
Name : sample-function.ps1
Size : 302
Hash : C8CC55C2E2265395DDCA62B09BCBB840
Date : 5/5/2026 4:06:58 PM
Computername : PROSPERO
And storing them in a JSON file. Eventually I will need code that I can insert into my scripts that will look for this information from the JSON data and test if the file hashes match.
Before we get too far, I want to revisit my function that creates the integrity info object.
Not Everything Has To Be a String
I glossed over the New-integrityInfo last time and I also realized there were a few shortcomings in the original code. One thing that I was doing differently from past work, is that instead of casting the file path as [String], I was using [System.IO.FileInfo].
param(
[Parameter(
Position = 0,
Mandatory,
ValueFromPipeline,
HelpMessage = 'Specify a PowerShell script file'
)]
[Alias('Name', 'FullName')]
[System.IO.FileInfo]$FilePath
)
Eventually, I need to get the file size which means using the string to get the file. Making the parameter use a [FileInfo] object saves a step. The user can still type a string, but it will be coerced into a file object. In other words, setting the parameter type is similar to this manual process.
PS C:\> "C:\scripts\sample-script.ps1" -as [System.IO.FileInfo]
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 5/5/2026 9:26 AM 1616 sample-script.ps1
Of course, if I pipe the output of Get-Item or Get-ChildItem, that will automatically give my file objects.
Parameter Transformations
However, this is one potential pitfall. If I used a [String] type, I could pass a relative path like .\sample-script.ps1, although I might need to process that path. I can't use a relative path with [System.IO.FileInfo].
PS C:\Scripts> ".\sample-script.ps1" -as [System.IO.FileInfo]
Mode LastWriteTime Length Name
---- ------------- ------ ----
larhs 12/31/1600 7:00 PM
I don't get an error, but I also don't get the expected file. This creates an object for the file name but it uses the filesystem's detected working directory which is not necessarily the current location.
To keep the desired parameter design, I need a way to transform the parameter value if a relative path is detected. This means diving into the deep end.
Deep within PowerShell is a .NET class called System.Management.Automation.ArgumentTransformationAttribute. Even though this class can be applied to a parameter, it has no constructor so you can't use it directly. However, we can derive a class from it using inheritance.
class ResolvePathTransform : System.Management.Automation.ArgumentTransformationAttribute {
#define a class method that returns an object
[object]Transform([System.Management.Automation.EngineIntrinsics]$engineIntrinsics, [object]$inputData) {
if ($inputData -is [string]) {
# Validate first: check if path exists before attempting transformation
if (-not (Test-Path -Path $inputData)) {
throw "Failed to find or validate '$inputData' as a valid path."
}
try {
return [System.IO.FileInfo](Convert-Path $inputData)
}
catch {
#this should never get called
throw "Unable to resolve path '$inputData': $($_.Exception.Message)"
}
}
#This will be the new parameter value
return $inputData
}
}
This will define an attribution class I can use on the parameter.
[ResolvePathTransform()]
[System.IO.FileInfo]$FilePath
This is a transformation attribute which is applied before any validation parameters. That's why I incorporated the Test-Path validation into the class. I can test this from a prompt.