StrictAclTools.psm1
|
<# .SYNOPSIS Utilities for inspecting and enforcing strict Windows ACLs. .DESCRIPTION Provides commands to inspect filesystem ACLs and to enforce strict, single-user ownership and access on files and directory trees. This is particularly useful for Windows OpenSSH scenarios where private keys and config fragments must not be accessible by other users or inherited from parent folders. .NOTES Author: DJ Stomp <85457381+DJStompZone@users.noreply.github.com> GitHub: https://github.com/DJStompZone/StrictAclTools License: MIT #> function Get-CustomAclForFile { <# .SYNOPSIS Returns a simplified view of a file or directory ACL. .DESCRIPTION Retrieves the owner and access rules for the specified filesystem item and returns them in a simplified custom object for easier inspection or export. .PARAMETER File File or directory to inspect. .EXAMPLE Get-Item "$HOME\.ssh\id_rsa" | Get-CustomAclForFile .NOTES Author: DJ Stomp <85457381+DJStompZone@users.noreply.github.com> GitHub: https://github.com/DJStompZone/StrictAclTools License: MIT #> [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [System.IO.FileSystemInfo]$File ) process { $acl = Get-Acl -LiteralPath $File.FullName [PSCustomObject]@{ FilePath = $File.FullName Owner = $acl.Owner Access = $acl.Access | Select-Object IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags, PropagationFlags } } } function Set-StrictFileAcl { <# .SYNOPSIS Replaces all ACL entries on a file or directory with a single allow rule for one user. .DESCRIPTION Disables inheritance, sets the owner, removes all existing access rules, adds a single FullControl allow rule for the specified account, and writes the ACL back to disk. .PARAMETER Path File or directory path to update. .PARAMETER Username Account that should own and exclusively control the target. .EXAMPLE Set-StrictFileAcl -Path "$HOME\.ssh\csb\config" -Username 'DESKTOP\MyUsername' .EXAMPLE Set-StrictFileAcl -Path "$HOME\.ssh\id_rsa" -Username [System.Security.Principal.NTAccount]"$env:USERDOMAIN\$env:USERNAME" .EXAMPLE Get-ChildItem "$HOME\.ssh" -File | Set-StrictFileAcl -Username 'DESKTOP\MyUsername' -WhatIf .NOTES Author: DJ Stomp <85457381+DJStompZone@users.noreply.github.com> GitHub: https://github.com/DJStompZone License: MIT #> [CmdletBinding(SupportsShouldProcess = $true)] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true)] [Alias('FullName')] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(Mandatory = $true, Position = 1)] [System.Security.Principal.NTAccount]$Username ) process { $resolvedPath = (Resolve-Path -LiteralPath $Path).Path if ($PSCmdlet.ShouldProcess($resolvedPath, "Set strict ACL for $Username")) { $acl = Get-Acl -LiteralPath $resolvedPath $acl.SetAccessRuleProtection($true, $false) $acl.SetOwner($Username) foreach ($rule in @($acl.Access)) { $null = $acl.RemoveAccessRule($rule) } $newRule = [System.Security.AccessControl.FileSystemAccessRule]::new( $Username, [System.Security.AccessControl.FileSystemRights]::FullControl, [System.Security.AccessControl.AccessControlType]::Allow ) $acl.AddAccessRule($newRule) Set-Acl -LiteralPath $resolvedPath -AclObject $acl } } } function Set-StrictAclTree { <# .SYNOPSIS Applies a strict single-user ACL to a directory and everything under it. .DESCRIPTION Updates the root directory first, then recursively updates all child files and directories so the specified account is the sole owner and access holder. .PARAMETER RootPath Root directory to process. .PARAMETER Username Account that should own and exclusively control the tree. .EXAMPLE Set-StrictAclTree -RootPath "$HOME\.ssh" -Username 'DESKTOP\MyUsername' .EXAMPLE Set-StrictAclTree -RootPath "$HOME\.ssh" -Username [System.Security.Principal.NTAccount]"$env:USERDOMAIN\$env:USERNAME" -WhatIf .NOTES Author: DJ Stomp <85457381+DJStompZone@users.noreply.github.com> GitHub: https://github.com/DJStompZone/StrictAclTools License: MIT #> [CmdletBinding(SupportsShouldProcess = $true)] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string]$RootPath, [Parameter(Mandatory = $true, Position = 1)] [System.Security.Principal.NTAccount]$Username ) $resolvedRoot = (Resolve-Path -LiteralPath $RootPath).Path Set-StrictFileAcl -Path $resolvedRoot -Username $Username Get-ChildItem -LiteralPath $resolvedRoot -Force -Recurse | ForEach-Object { Set-StrictFileAcl -Path $_.FullName -Username $Username } } Export-ModuleMember -Function Get-CustomAclForFile, Set-StrictFileAcl, Set-StrictAclTree |