PowerShell Script to Check FSLogix Container Permissions

# Check-FSLogixPermissions.ps1
# Script to verify permissions for all FSLogix profile folders and their VHD/VHDX files in a parent folder
# Handles folder names as SID or SID_username

param (
    [Parameter(Mandatory=$true)]
    [string]$ParentFolderPath
)

# Function to check if folder exists
function Test-FolderExists {
    param (
        [string]$Path
    )
    if (-not (Test-Path -Path $Path -PathType Container)) {
        Write-Host "Error: The parent folder '$Path' does not exist." -ForegroundColor Red
        exit 1
    }
}

# Function to extract and validate SID from folder name
function Get-SIDFromFolderName {
    param (
        [string]$FolderName
    )
    # Handle folder names like SID or SID_username
    $parts = $FolderName -split '_'
    $sid = $parts | Where-Object { $_ -match '^S-1-[0-9-]+$' } | Select-Object -First 1
    
    if (-not $sid) {
        Write-Host "Skipping folder '$FolderName': No valid SID found in name." -ForegroundColor Yellow
        return $null
    }
    
    return $sid
}

# Function to get expected permissions for FSLogix folder or VHD/VHDX
function Get-ExpectedPermissions {
    param (
        [string]$UserSID
    )
    $expected = @(
        @{
            Identity = $UserSID
            Access = "FullControl"
            Inherited = $false
        },
        @{
            Identity = "NT AUTHORITY\SYSTEM"
            Access = "FullControl"
            Inherited = $false
        },
        @{
            Identity = "BUILTIN\Administrators"
            Access = "FullControl"
            Inherited = $false
        }
    )
    return $expected
}

# Function to check actual permissions against expected
function Check-Permissions {
    param (
        [string]$Path,
        [array]$ExpectedPermissions,
        [string]$ItemType
    )
    Write-Host "Checking $ItemType permissions for: $Path" -ForegroundColor Cyan
    $acl = Get-Acl -Path $Path
    $results = @()
    $issuesFound = $false

    # Check each expected permission
    foreach ($expected in $ExpectedPermissions) {
        $identity = $expected.Identity
        $expectedAccess = $expected.Access
        $expectedInherited = $expected.Inherited

        $rule = $acl.Access | Where-Object {
            $_.IdentityReference -eq $identity -and 
            $_.FileSystemRights -eq $expectedAccess -and 
            $_.IsInherited -eq $expectedInherited
        }

        if ($rule) {
            $results += [PSCustomObject]@{
                Identity = $identity
                Status = "Correct"
                Details = "Permission '$expectedAccess' is correctly set (Inherited: $expectedInherited)."
            }
        } else {
            $issuesFound = $true
            $actualRule = $acl.Access | Where-Object { $_.IdentityReference -eq $identity }
            if ($actualRule) {
                $results += [PSCustomObject]@{
                    Identity = $identity
                    Status = "Incorrect"
                    Details = "Expected '$expectedAccess' (Inherited: $expectedInherited), but found '$($actualRule.FileSystemRights)' (Inherited: $($actualRule.IsInherited))."
                }
            } else {
                $results += [PSCustomObject]@{
                    Identity = $identity
                    Status = "Missing"
                    Details = "Permission '$expectedAccess' is missing for '$identity'."
                }
            }
        }
    }

    # Check for unexpected permissions
    $unexpected = $acl.Access | Where-Object {
        $_.IdentityReference -notin $ExpectedPermissions.Identity -and
        $_.IsInherited -eq $false
    }

    if ($unexpected) {
        $issuesFound = $true
        foreach ($rule in $unexpected) {
            $results += [PSCustomObject]@{
                Identity = $rule.IdentityReference
                Status = "Unexpected"
                Details = "Unexpected permission '$($rule.FileSystemRights)' found for '$($rule.IdentityReference)'."
            }
        }
    }

    return $results, $issuesFound
}

# Main script
try {
    # Verify parent folder exists
    Test-FolderExists -Path $ParentFolderPath

    # Get all subfolders
    $profileFolders = Get-ChildItem -Path $ParentFolderPath -Directory
    $allResults = @()
    $anyIssuesFound = $false

    foreach ($folder in $profileFolders) {
        $folderPath = $folder.FullName
        $folderName = $folder.Name

        # Extract SID from folder name
        $userSID = Get-SIDFromFolderName -FolderName $folderName
        if (-not $userSID) {
            continue
        }
        Write-Host "`nProcessing profile folder for SID: $userSID" -ForegroundColor Cyan

        # Get expected permissions for the folder
        $expectedPermissions = Get-ExpectedPermissions -UserSID $userSID

        # Check folder permissions
        $folderResults, $folderIssues = Check-Permissions -Path $folderPath -ExpectedPermissions $expectedPermissions -ItemType "Folder"
        $allResults += $folderResults | ForEach-Object { 
            [PSCustomObject]@{
                Item = $folderPath
                Type = "Folder"
                Identity = $_.Identity
                Status = $_.Status
                Details = $_.Details
            }
        }
        if ($folderIssues) { $anyIssuesFound = $true }

        # Check for VHD/VHDX file
        $vhdxFile = Get-ChildItem -Path $folderPath -File | Where-Object { $_.Extension -in @('.vhd', '.vhdx') } | Select-Object -First 1
        if ($vhdxFile) {
            $vhdxPath = $vhdxFile.FullName
            $vhdxResults, $vhdxIssues = Check-Permissions -Path $vhdxPath -ExpectedPermissions $expectedPermissions -ItemType "VHD/VHDX File"
            $allResults += $vhdxResults | ForEach-Object { 
                [PSCustomObject]@{
                    Item = $vhdxPath
                    Type = "VHD/VHDX File"
                    Identity = $_.Identity
                    Status = $_.Status
                    Details = $_.Details
                }
            }
            if ($vhdxIssues) { $anyIssuesFound = $true }
        } else {
            Write-Host "No VHD/VHDX file found in folder: $folderPath" -ForegroundColor Yellow
        }
    }

    # Output consolidated results
    Write-Host "`nConsolidated Permission Check Results:" -ForegroundColor Cyan
    $allResults | Format-Table -Property Item, Type, Identity, Status, Details -AutoSize

    if ($anyIssuesFound) {
        Write-Host "Permission issues detected in one or more folders/files. Please review the output above." -ForegroundColor Yellow
    } else {
        Write-Host "All permissions are correctly set for all FSLogix folders and VHD/VHDX files." -ForegroundColor Green
    }
}
catch {
    Write-Host "An error occurred: $_" -ForegroundColor Red
    exit 1
}

This article was updated on June 22, 2025