Chapter 07Lesson 05~140 minutes

Permissions, ACLs, Hashes, Certificates, and Safe File Integrity Workflows

Treat filesystem permissions as platform security policy, use Windows ACL cmdlets only where supported, verify artifact content with hashes, and inspect certificate metadata without unsafe trust-store changes.

Learning objectives

  • Explain Windows ACL and Unix permission concepts without implying they are one identical abstraction.
  • Identify Get-Acl and Set-Acl as Windows-only in current PowerShell 7.6 documentation and use disposable paths for examples.
  • Apply least-privilege thinking and capture original ACL state before any prospective change.
  • Compute SHA-256 hashes with Get-FileHash and distinguish integrity verification from authenticity.
  • Explain X.509 certificates conceptually and navigate the Windows Certificate provider read-only when available.
  • Complete a cross-platform integrity lab with optional Windows-only ACL/certificate inspection.

1. Permissions answer “who can do what,” and the model is platform-specific

Before changing permissions, separate identity, ownership, and access rules. Windows commonly represents file security through security descriptors and access control lists (ACLs). Unix-like systems traditionally use owner/group/other read-write-execute mode bits, with optional POSIX or filesystem ACL extensions. These models overlap conceptually but are not interchangeable.

ConceptWindows-oriented viewUnix-oriented view
IdentityUser/group SIDs and accountsUID/GID mapped to users/groups
Basic accessACL access rulesr/w/x mode bits for owner/group/other
Extended rulesDiscretionary/system ACL entriesPOSIX/filesystem ACL extensions where supported
InheritanceDirectory ACL inheritance rulesDirectory/default ACL and filesystem-specific behavior

The PowerShell provider abstraction does not erase these OS security semantics. Portable tooling must declare which permission model it is inspecting or modifying.

2. Current PowerShell 7.6 documents Get-Acl and Set-Acl as Windows-only

This is an important cross-platform boundary. On Windows, Get-Acl returns an object representing a resource security descriptor, and Set-Acl can apply a supplied descriptor. Current Microsoft documentation explicitly marks both cmdlets as Windows-only. Do not teach them as a universal Linux/macOS permissions abstraction.

if ($IsWindows -and (Get-Command Get-Acl -ErrorAction SilentlyContinue)) {
    $temp = Join-Path ([System.IO.Path]::GetTempPath()) 'acl-readonly-demo.txt'
    Set-Content -LiteralPath $temp -Value 'training'

    Get-Acl -LiteralPath $temp |
        Format-List Path, Owner, AccessToString

    Remove-Item -LiteralPath $temp -Force
}
else {
    'Get-Acl/Set-Acl are Windows-only in current PowerShell.'
}

On Unix-like platforms, use OS-native permission tooling or platform-specific .NET/file APIs according to your operational contract. Chapter 07 does not pretend one command gives identical authorization semantics everywhere.

3. Before changing an ACL, capture the original descriptor and operate only on disposable paths

Permission mistakes can lock out users, expose secrets, or break services. The safe sequence is: identify a disposable target, capture current security state, calculate the desired rule, preview if supported, apply with least privilege, verify, and restore if the lab changed anything.

# Windows-only pattern. This lab intentionally stops at -WhatIf.
if ($IsWindows -and (Get-Command Set-Acl -ErrorAction SilentlyContinue)) {
    $root = Join-Path ([System.IO.Path]::GetTempPath()) 'ps-acl-lab'
    New-Item -ItemType Directory -Path $root -Force | Out-Null

    $fileA = Join-Path $root 'source.txt'
    $fileB = Join-Path $root 'target.txt'
    Set-Content -LiteralPath $fileA -Value 'source'
    Set-Content -LiteralPath $fileB -Value 'target'

    $originalTargetAcl = Get-Acl -LiteralPath $fileB
    $sourceAcl = Get-Acl -LiteralPath $fileA

    Set-Acl -LiteralPath $fileB -AclObject $sourceAcl -WhatIf

    # No ACL changed because -WhatIf was used.
    Remove-Item -LiteralPath $root -Recurse -Force
}

Saving an ACL object in a variable is useful for short-lived recovery inside the same run. For durable production rollback, serialize/document security metadata with an approach appropriate to the OS and policy; do not assume an in-memory object is a backup.

4. Least privilege is a design constraint, not a final cleanup step

Least privilege means a process, user, or automation identity gets only the permissions required for its task. Running every script as Administrator/root hides permission design problems and increases blast radius. Prefer user-owned temporary paths for training and request elevation only when a documented operation genuinely requires it.

$labRoot = Join-Path ([System.IO.Path]::GetTempPath()) 'ps-integrity-lab'
New-Item -ItemType Directory -Path $labRoot -Force | Out-Null
Get-Item -LiteralPath $labRoot |
    Select-Object FullName, Attributes
Rule: Do not use system directories such as Windows, Program Files, /etc, /usr, or service data directories for permission experiments unless the lab explicitly requires and isolates that platform-specific administration.

5. Get-FileHash verifies content integrity across platforms

A cryptographic hash is a fixed-size digest derived from file bytes. If file content changes, its hash should change with overwhelming probability. Get-FileHash computes file hashes and uses SHA-256 by default. Hashing is a practical cross-platform way to verify that an artifact matches an expected digest.

$file = Join-Path ([System.IO.Path]::GetTempPath()) 'artifact.txt'
Set-Content -LiteralPath $file -Value 'release=2026.08'

$hash = Get-FileHash -LiteralPath $file -Algorithm SHA256
$hash | Format-List Algorithm, Hash, Path

A matching hash proves content equality relative to the expected digest; it does not prove who created the file. Authenticity requires a trusted source for the expected digest or a signature/trust mechanism.

6. Compare hashes with an explicit trusted expectation

$file = Join-Path ([System.IO.Path]::GetTempPath()) 'artifact.txt'
Set-Content -LiteralPath $file -Value 'release=2026.08'

$expected = (Get-FileHash -LiteralPath $file -Algorithm SHA256).Hash

# Later verification:
$actual = (Get-FileHash -LiteralPath $file -Algorithm SHA256).Hash

if ($actual -ne $expected) {
    throw "Integrity check failed. Expected $expected but got $actual"
}

'Integrity check passed.'

In a real release workflow, the expected hash must come from a trusted manifest, signed release metadata, or another trusted channel. If an attacker can replace both the file and the expected hash, the comparison provides no authenticity guarantee.

7. Certificates bind a public key to identity information; the Certificate provider is Windows-only

An X.509 certificate contains a public key plus identity and validity metadata, usually signed by a certificate authority or another issuer. Certificates are used in TLS, code signing, client authentication, and other trust workflows. The private key is separate sensitive material that must be protected.

if ($IsWindows -and (Get-PSDrive -Name Cert -ErrorAction SilentlyContinue)) {
    Get-ChildItem Cert:\CurrentUser\My |
        Select-Object -First 5 Subject, Thumbprint, NotAfter, HasPrivateKey
}
else {
    'The PowerShell Certificate provider is available only on Windows.'
}

This chapter only navigates certificate metadata read-only. Creating certificates, managing trust stores, signing code, and secret/private-key handling belong to the security-focused chapters.

8. Unix permission inspection should remain explicitly Unix-specific

On Linux/macOS, filesystem permission tooling commonly includes native commands such as ls, stat, chmod, chown, and ACL utilities where installed. PowerShell can invoke native tools, but their availability and output differ by OS/distribution. If a production script modifies Unix permissions, define the supported platforms and validate native exit codes as Chapter 02 taught.

if (-not $IsWindows) {
    $item = Get-Item $HOME
    $item | Select-Object FullName, Mode, UnixFileMode -ErrorAction SilentlyContinue

    # Native commands are platform-specific; discover before invoking:
    Get-Command chmod -ErrorAction SilentlyContinue
    Get-Command stat -ErrorAction SilentlyContinue
}

The object properties available for Unix mode information can vary with PowerShell/.NET/platform details, so discovery and explicit support statements are preferable to pretending Windows ACL objects map directly to Unix permissions.

9. Lab: verify artifact integrity everywhere; inspect ACL/certificate metadata only where supported

$root = Join-Path ([System.IO.Path]::GetTempPath()) 'ps-integrity-lab'
New-Item -ItemType Directory -Path $root -Force | Out-Null

$artifact = Join-Path $root 'package.txt'
$copy = Join-Path $root 'package-copy.txt'

Set-Content -LiteralPath $artifact -Encoding utf8 -Value 'build=42'
Copy-Item -LiteralPath $artifact -Destination $copy

$h1 = Get-FileHash -LiteralPath $artifact -Algorithm SHA256
$h2 = Get-FileHash -LiteralPath $copy -Algorithm SHA256

[pscustomobject]@{
    SameContent = ($h1.Hash -eq $h2.Hash)
    SourceHash  = $h1.Hash
    CopyHash    = $h2.Hash
} | Format-List

Add-Content -LiteralPath $copy -Value 'tampered=true'
$h3 = Get-FileHash -LiteralPath $copy -Algorithm SHA256
"Hash changed after content change: $($h3.Hash -ne $h1.Hash)"

if ($IsWindows -and (Get-Command Get-Acl -ErrorAction SilentlyContinue)) {
    Get-Acl -LiteralPath $artifact |
        Format-List Path, Owner, AccessToString
}

if ($IsWindows -and (Get-PSDrive -Name Cert -ErrorAction SilentlyContinue)) {
    Get-ChildItem Cert:\CurrentUser\My |
        Select-Object -First 3 Subject, Thumbprint, NotAfter
}

Remove-Item -LiteralPath $root -Recurse -Force

Verification checklist

10. Common permission and integrity mistakes

Assuming Administrator/root is the normal runtime. Design for least privilege and elevate narrowly.

Applying an ACL without preserving the previous state. Capture, preview, verify, and have a rollback path.

Teaching Get-Acl as cross-platform. Current PowerShell 7.6 documentation marks Get-Acl and Set-Acl as Windows-only.

Calling a hash “proof of authenticity.” It proves equality to an expected digest only when that expectation itself is trusted.

Manipulating the certificate store during an introductory lab. Read metadata only; trust-store changes are security administration.

11. Knowledge check

Question 1. Why can’t Windows ACL semantics simply be treated as Unix mode bits?

Question 2. What platform limitation applies to Get-Acl/Set-Acl in current PowerShell 7.6 documentation?

Question 3. What is the default algorithm used by Get-FileHash?

Question 4. Does a matching SHA-256 hash prove who produced an artifact?

Question 5. What is the purpose of the Windows Cert: provider?

12. Summary

Permissions are security policy, not a generic file attribute. Windows ACLs and Unix permission models must be taught and automated separately. Current PowerShell 7.6 documents Get-Acl/Set-Acl and the Certificate provider as Windows-only. Cross-platform integrity verification with Get-FileHash is broadly useful, but a trusted expected digest is required for meaningful supply-chain assurance. Use least privilege, disposable paths, ACL backup/preview patterns, and read-only certificate inspection until the security chapter introduces deeper trust administration.

13. Further reading

Next chapter

Turn safe provider/file operations into reusable scripts with parameters and scope discipline

Chapter 08 moves from interactive operational workflows into .ps1 scripts, validated parameters, scope, profiles, configuration precedence, and reusable command-line entry points.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.