PSSystemProperties.psm1

Function Find-SystemPropertyName {
    [CmdletBinding(DefaultParameterSetName='UserInput')]
    param (
        [Parameter(Mandatory=$true, ParameterSetName='UserInput')]
        [string]$Name,
        [Parameter(Mandatory=$true, ParameterSetName='List')]
        [switch]$All
    )
    if ($PSCmdlet.ParameterSetName -eq 'List') {
        return (Get-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath 'PropertyList.txt'))
    } else {
        $Regex = switch -Regex ($Name) {
            "([a-zA-Z]+\.)([a-zA-Z]+\.?){1,}" {[regex]::Escape($Name); break}
            "[a-zA-Z]+" {"([a-zA-Z]+\.){1,}([a-zA-Z]+)?$Name([a-zA-Z]+)?"; break}
            default {throw "Value for Parameter 'Name' contains Invalid characters"}
        }
        $Results = (Get-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath 'PropertyList.txt')) -match $Regex
        $ExactMatch = $Results -match "^$Name$"
        if ($ExactMatch) {$ExactMatch} else {$Results}
    }
}

Function Get-SystemPropertyValue {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [System.IO.FileInfo]$Path,
        
        [Parameter(Mandatory=$true)]
        [string[]]$Name
    )
    begin {
        $PropertyList = Find-SystemPropertyName -All
        $Properties = $PropertyList | Where-Object {$_ -in $Name} 
        if (-not $Properties) {throw ("No matching properties found for: {0}" -f ($Name -join ', '))} else {
            if ($Properties.Count -ne $Name.Count) {Write-Warning -Message 'Found {0}/{1} properties' -f $Properties.Count, $Name.Count}
            [System.Collections.ArrayList]$Results = @()
        }
    }
    Process {
        $Path | ForEach-Object {
            if (Test-Path -Path $_.FullName -PathType Leaf) {
                $ObjectPath = $_
                $ObjectResults = [ordered]@{Path=$ObjectPath}
                
                $shellFile = [Microsoft.WindowsAPICodePack.Shell.ShellObject]::FromParsingName($ObjectPath.FullName)
                foreach ($Property in $Properties){  
                    try {$ObjectResults.$Property = $shellFile.Properties.GetProperty($Property).Value}
                    catch {$ObjectResults.$Property = $null}
                }
                [void]$Results.Add([PSCustomObject]$ObjectResults)
            }
        }
    }
    End {return $Results}
}


Function Set-SystemProperty {
    [CmdletBinding(DefaultParameterSetName='Set')]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateScript({if ($_.Exists) {[System.IO.FileInfo]$_} else {throw 'File does not exist.'}})]
        [System.IO.FileInfo]$Path,
        
        [Parameter(Mandatory=$true)]
        [ValidateScript({(Find-SystemPropertyName -Name $_).Count -eq 1})]
        [string]$Name,

        [Parameter(Mandatory=$true, ParameterSetName='Set')]
        [ValidateScript({if ($null -ne $_) {$_} else {throw "Value for parameter 'Value' cannot be null. Use switch '-Remove' instead."}})]
        [object]$Value,
 
        [Parameter(Mandatory=$false, ParameterSetName='Set')]
        [switch]$AllowTruncatedValue,

        [Parameter(Mandatory=$true, ParameterSetName='Remove')]
        [switch]$Remove
    )
    $MatchingProperty = Find-SystemPropertyName -Name $Name
    if ($MatchingProperty.Count -eq 1) {
        $shellFile = [Microsoft.WindowsAPICodePack.Shell.ShellObject]::FromParsingName($Path.FullName)
        try {$ValidProperty = $shellFile.Properties.GetProperty($MatchingProperty)}
        catch {throw "Invalid Property name: '$MatchingProperty' not found for file: '$Path'."}

        if ($ValidProperty.ValueType.ToString() -match ([regex]::Escape($Value.GetType().Name))) {
            $ShellPropertyWriter = $shellFile.Properties.GetPropertyWriter()
            try {
                if ($PSCmdlet.ParameterSetName -eq 'Set'){$ShellPropertyWriter.WriteProperty($MatchingProperty, $Value, $AllowTruncatedValue.IsPresent)}
                else {$ShellPropertyWriter.WriteProperty($MatchingProperty, $null, $false)}
            }
            finally {$ShellPropertyWriter.Close()}
        } else {throw ("Value entered for parameter: 'Value' does not match the ValueType for Property '$MatchingProperty': {0}" -f $ValidProperty.ValueType)}
    } else {throw "A Property which matches the value entered for Parameter 'Property': $Name could not be found."}
}