src/Set-ItemNixMode.ps1

#!/usr/bin/env pwsh
$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest


function Set-ItemNixMode() {
    [System.Runtime.Versioning.UnsupportedOSPlatform("windows")]
    [CmdletBinding(DefaultParameterSetName="ModeOctal")]
    param(
        [Parameter(Mandatory = $false, Position = 1)]
        [switch] $PassThru,

        [Parameter(Mandatory = $false, Position = 2)]
        [Alias("Recursive")]
        [switch] $Recurse,

        [Parameter(Mandatory = $false, Position = 3)]
        [Alias("f", "silent", "quiet")]
        [switch] $Force,

        [Parameter(Mandatory = $true, Position = 5, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ValueFromRemainingArguments = $true)]
        [Alias("FullName", "PSPath")]
        [string[]]
        $Path
    )
    DynamicParam {
        $RuntimeParameterDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()

        # Add the "ModeOctal" parameter.
        $ParameterAttributesCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
        $ModeOctalParameterAttribute = [System.Management.Automation.ParameterAttribute]::new()
        $ModeOctalParameterAttribute.Mandatory = $true
        $ModeOctalParameterAttribute.ParameterSetName = "ModeOctal"
        $ModeOctalParameterAttribute.Position = 4
        $ModeOctalParameterAttribute.HelpMessage = "The octal mode to set on the file(s)."
        $ParameterAttributesCollection.Add($ModeOctalParameterAttribute)
        if ([Type]::GetType("System.IO.UnixFileMode")) {
            # If the UnixFileMode type is available, add validation for this parameter.
            $ParameterAttributesCollection.Add([System.Management.Automation.ValidateScriptAttribute]::new(
                [ScriptBlock]::Create("ConvertTo-NixMode -FromOctal `$_")
            ))
        }
        $ModeOctalParameter = [System.Management.Automation.RuntimeDefinedParameter]::new("ModeOctal", [string], $ParameterAttributesCollection)
        $RuntimeParameterDictionary.Add($ModeOctalParameter.Name, $ModeOctalParameter)

        if ([Type]::GetType("System.IO.UnixFileMode")) {
            # Add the "Mode" parameter.
            $ParameterAttributesCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
            $ModeParameterAttribute = [System.Management.Automation.ParameterAttribute]::new()
            $ModeParameterAttribute.Mandatory = $true
            $ModeParameterAttribute.ParameterSetName = "Mode"
            $ModeParameterAttribute.Position = 4
            $ModeParameterAttribute.HelpMessage = "The mode to set on the file(s)."
            $ParameterAttributesCollection.Add($ModeParameterAttribute)
            $ModeParameter = [System.Management.Automation.RuntimeDefinedParameter]::new("Mode", [System.IO.UnixFileMode], $ParameterAttributesCollection)
            $RuntimeParameterDictionary.Add($ModeParameter.Name, $ModeParameter)
        }

        return $RuntimeParameterDictionary
    }
    Begin {
        if ($IsWindows) {
            throw [System.PlatformNotSupportedException]::new("This function is not supported on Windows.")
        }
        function do_chmod {
            param(
                [Parameter(Mandatory = $true, Position = 0)]
                [string] $LiteralMode,

                [Parameter(Mandatory = $true, Position = 1)]
                [string] $LiteralPath
            )
            [string[]] $chmodArgs = @($LiteralMode, $LiteralPath)
            if ($Recurse) {
                $chmodArgs += '-R'
            }
            if ($Force) {
                $chmodArgs += '-f'
            }

            if ($PassThru) {
                chmod @chmodArgs | Out-Null
            } else {
                chmod @chmodArgs
            }

            if ($LASTEXITCODE -ne 0) {
                throw "Failed to set mode '$ModeOctal' on '$_', chmod exited with code $LASTEXITCODE."
            }
        }
    }
    Process {
        if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey('ModeOctal')) {
            $ModeOctal = $PSCmdlet.MyInvocation.BoundParameters['ModeOctal']
        } elseif ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey('Mode')) {
            $Mode = ConvertFrom-NixMode -ToOctal $PSCmdlet.MyInvocation.BoundParameters['Mode']
        } else {
            throw [System.ArgumentException]::new("Either the 'ModeOctal' or 'Mode' parameter must be specified.")
        }

        if (Get-Variable -Name Mode -ErrorAction SilentlyContinue) {
            $ModeOctal = ConvertFrom-NixMode -ToOctal $Mode
        }

        @($PSCmdlet.MyInvocation.ExpectingInput ? $PSItem : $Path) | ForEach-Object {
            $parent = Split-Path -Path $_ -Parent
            $leaf = Split-Path -Path $_ -Leaf
            Get-ChildItem -Path $parent -Filter $leaf -Recurse:$Recurse -Force:$Force | ForEach-Object {
                do_chmod -LiteralMode $ModeOctal -LiteralPath $_.FullName
                if ($PassThru) {
                    $_.Refresh()
                    $_
                }
            }
        }
    }
}