Public/Get-UnixFileMode.ps1
|
#!/usr/bin/env pwsh Set-StrictMode -Version Latest if ($IsLinux) { function Get-UnixFileMode { <# .SYNOPSIS Finds files or directories whose Unix mode has any of the given bits set. .DESCRIPTION Recurses the path and returns every file, or every directory with -ItemType Directory, whose UnixFileMode includes at least one bit of -Mode. Use it to find SUID and SGID binaries, world-writable files, and world-writable directories. Directories whose name is in -Exclude are skipped entirely. The defaults skip the proc, sys, dev, and run pseudo filesystems, and mnt, where WSL mounts the Windows drives with every file world-writable. Directories that cannot be read are skipped, so run as root for a complete scan. Symbolic links are not followed. The path itself is not checked, only the items below it. Returns the raw .NET objects, which list as a flat table of names. Select FullName and UnixFileMode to see the path and mode. Linux only. .PARAMETER Path The directories to search. Wildcards are accepted. Accepts paths from the pipeline. .PARAMETER Mode The mode bits to look for, such as SetUser, SetGroup, or OtherWrite. An item matches when any of the bits is set. .PARAMETER ItemType File returns files, Directory returns directories. Defaults to File. .PARAMETER Exclude Directory names to skip, matched against the name only, not the path. Defaults to proc, sys, dev, run, and mnt. .PARAMETER Parallel Recurses the subdirectories of the path in parallel thread jobs. Faster on large or slow trees, slower on small ones. .PARAMETER ThrottleLimit With -Parallel, the number of subdirectories recursed at once, from 1 through 255. Defaults to 75% of the processors, rounded down, and at least 1. .INPUTS System.String. You can pipe directory paths to this function. .OUTPUTS System.IO.FileInfo, or System.IO.DirectoryInfo with -ItemType Directory. One object for each matching item. .EXAMPLE Get-UnixFileMode -Path / -Mode SetUser, SetGroup | Select-Object FullName, UnixFileMode Lists the SUID and SGID files on the system. .EXAMPLE Get-UnixFileMode -Path / -Mode OtherWrite -Parallel Lists the world-writable files on the system, searching in parallel. .EXAMPLE Get-UnixFileMode -Path /home, /var -Mode OtherWrite -ItemType Directory | Select-Object FullName, UnixFileMode Lists the world-writable directories under /home and /var. .EXAMPLE Get-UnixFileMode -Path / -Mode OtherWrite -ItemType Directory | Add-UnixFileMode -Mode StickyBit Adds the sticky bit to every world-writable directory that lacks it (CIS 1.1.21). #> [CmdletBinding()] [OutputType([System.IO.FileInfo], [System.IO.DirectoryInfo])] param( [Parameter(Mandatory, ValueFromPipeline, HelpMessage = 'Enter the directories to search. Wildcards are accepted. Accepts paths from the pipeline.')] [ValidateNotNullOrEmpty()] [string[]]$Path, [Parameter(Mandatory, HelpMessage = 'Enter the mode bits to look for, such as SetUser, SetGroup, or OtherWrite.')] [System.IO.UnixFileMode]$Mode, [Parameter(HelpMessage = 'Enter File to return files or Directory to return directories.')] [ValidateSet('File', 'Directory')] [string]$ItemType = 'File', [Parameter(HelpMessage = 'Enter the directory names to skip.')] [string[]]$Exclude = @('proc', 'sys', 'dev', 'run', 'mnt'), [Parameter(HelpMessage = 'Recurse the subdirectories in parallel thread jobs.')] [switch]$Parallel, [Parameter(HelpMessage = 'Enter the maximum number of workers (1-255).')] [ValidateRange(1, 255)] [int]$ThrottleLimit ) begin { if (-not $PSBoundParameters.ContainsKey('ThrottleLimit')) { $ThrottleLimit = Get-DefaultThrottleLimit } } process { # -Path can name several directories, and each wildcard can match several. foreach ($resolvedPath in (Resolve-Path -Path $Path -ErrorAction Stop).ProviderPath) { $directory = [System.IO.DirectoryInfo]::new($resolvedPath) if ($ItemType -eq 'Directory') { $searchCommand = 'Get-DirectoryThreaded' $searchParams = @{ Directory = $directory Exclude = $Exclude Parallel = $Parallel ThrottleLimit = $ThrottleLimit } } elseif ($Parallel) { $searchCommand = 'Get-FileMultiThreaded' $searchParams = @{ Directory = $directory Include = '*' Exclude = $Exclude ThrottleLimit = $ThrottleLimit } } else { $searchCommand = 'Get-FileSingleThreaded' $searchParams = @{ Directory = $directory Include = '*' Exclude = $Exclude Recurse = $true } } & $searchCommand @searchParams | Where-Object { ($_.UnixFileMode -band $Mode) -ne 0 } } } } } |