Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Archives
May 8, 2026

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.

Want to read the full issue?
GitHub
Bluesky
LinkedIn
Mastodon
jdhitsolutions.github.io
Powered by Buttondown, the easiest way to start and grow your newsletter.