file.psm1

function Disable-Access {
    <#
    .SYNOPSIS
        Deny student group permission to a file.
    .DESCRIPTION
        Add an NTFS Deny ACL to a given file for students to block their access.
        A deny rule supercedes any allow rule.
    .EXAMPLE
        PS C:\> \\<server\<share>\<Path> | Disable-Access | Convertto-html | Out-File "Report.html"
        Generate a report that lists the files students have been blocked from using.
    #>

    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline,
                   ValueFromPipelineByPropertyName,
                   Position = 0)]
        [String[]]
        $Path
        , # AD identity
        [Parameter(ValueFromPipelineByPropertyName,
                   Position = 1)]
        [string]
        $Identity = 'AllStudents'
    )
    Begin {
        $Deny = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $Identity, 'FullControl', 'Deny'
    }
    Process {
        $Path | Get-Acl | foreach-object {
            $psitem.SetAccessRule($Deny)
            try { $psitem | Set-acl }
            catch {
                Throw "Failed to set permission: $($psitem.path)"
            }
            Get-Item $psitem.Path | Write-Output
        }
    }
}

function Enable-Access {
    <#
    .SYNOPSIS
        Remove "Deny" permission added by "Deny-Access"
    .DESCRIPTION
        Remove the NTFS Deny ACL for a given item for students access.
        Does not test that users get access permission. See Add-Access
    .EXAMPLE
        PS C:\> \\<server\<share>\<Path> | Enable-Access | Convertto-html | Out-File "Report.html"
        Generate a report that lists the item students have been blocked from using.
    #>

    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline,
                   ValueFromPipelineByPropertyName,
                   Position = 0)]
        [String[]]
        $Path
        , # AD identity
        [Parameter(ValueFromPipelineByPropertyName,
                   Position = 1)]
        [string]
        $Identity = 'AllStudents'
    )
    Begin {
        $Rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $Identity, 'FullControl', 'Deny'
    }
    Process {
        $Path | Get-Acl | foreach-object {
            $psitem.RemoveAccessRule($Rule) > $null
            try { $psitem | Set-acl }
            catch {
                Throw "Failed remove Deny permission: $($psitem.path)"
            }
            Get-Item $psitem.Path | Write-Output
        }
    }
    End {
        Write-Warning "Enable-StudentAccess will remove 'Deny' permission set by Disable-StudentAccess. See Add-Access"
    }
}

function Add-Access {
    <#
    .SYNOPSIS
        Add "Allow" permission to target path.
    .DESCRIPTION
        Add the NTFS Allow ACL for a given item for students access.
        Any deny rule will supercede this. See Enable-Access.
    .EXAMPLE
        Add-Access .\en-US\
        By default allow students to read permission to the folder
    .EXAMPLE
        Add-Access .\en-US\ -Identity '2016 Students'
        Specify the Active Directory identiy name to set access for;
 
            Directory: N:\Documents\src\ps-helper
 
 
        Mode LastWriteTime Length Name
        ---- ------------- ------ ----
        d----- 19/10/2016 15:33 en-US
    .EXAMPLE
        PS C:\> \\<server\<share>\<Path> | Add-Access | Convertto-html | Out-File "Report.html"
        Generate a report that lists the items students have been allowed to aceess.
    #>

    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline,
                   ValueFromPipelineByPropertyName,
                   Position = 0
                   )]
        [String[]]
        $Path
        , # AD identity to grant access
        [Parameter(ValueFromPipelineByPropertyName,
                   Position = 1)]
        [string]
        $Identity = 'AllStudents'
        , # keyword access permission levels
        [ValidateSet('FullControl','Modify','ReadAndExecute')]
        [string]
        $Access = 'ReadAndExecute'
        , # Sets the Applies to contition for child items
        [ValidateSet('All','ThisFolder')]
        [string]
        $Inherit
    )
    Begin {
        switch ($inherit) {
            'ThisFolder' { $Inherritance = @('None') }
            Default { $Inherritance = @('ContainerInherit', 'ObjectInherit') }
        }
        $FolderRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $Identity, $Access, $Inherritance, 'None', 'Allow'
        $FileRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $Identity, $Access, 'Allow'
    }
    Process {
        $Path | Get-Acl | foreach-object {
            if ( (Get-Item $Path) -is [System.IO.DirectoryInfo] ){
                $psitem.SetAccessRule($FolderRule)
            } else {
                $psitem.SetAccessRule($FileRule)
            }
            try { $psitem | Set-acl }
            catch {
                Throw "Failed to add permission: $($psitem.path)"
            }
            Get-Item $psitem.Path | Write-Output
        }
    }
}

function Remove-Access {
    <#
    .SYNOPSIS
        Remove "Allow" permission added by "Add-StudentAccess"
    .DESCRIPTION
        Remove the NTFS Allow ACL for a given item for students access.
    .EXAMPLE
        PS C:\> \\<server\<share>\<Path> | Remove-StudentAccess | Convertto-html | Out-File "Report.html"
        Generate a report that lists the items students have been blocked from using.
    #>

    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName,
                   Position = 0)]
        [String[]]
        $Path
        , # AD identity to remove access
        [Parameter(ValueFromPipelineByPropertyName,
                   Position = 1)]
        [string]
        $Identity = 'AllStudents'
    )
    Begin {
    }
    Process {
        $Path | Get-Acl | foreach-object {
            $Rule = $psitem.Access | Where-Object { ($_.IdentityReference -like "*$Identity") -and ($_.AccessControlType -eq  'Allow')}
            $psitem.RemoveAccessRule($Rule) > $null
            try { $psitem | Set-acl }
            catch {
                Throw "Failed to remove permission: $($psitem.path)"
            }
            Get-Item $psitem.Path | Write-Output
        }
    }
}

function Show-Access {
    <#
    .SYNOPSIS
        Display the ACL information for given files or folders.
    .DESCRIPTION
        Wraps Get-ACL to select the access list while retaining the file path being inspected.
        Useful for Group-Object inspecting access controls.
 
        This function is intended for interactive use inspecting a network share, as such it breaks best practice of avoiding the use of format-* commands.
    .EXAMPLE
        Show-Access '.\INFO.lnk'
 
        Path IdentityReference IsInherited AccessControlType FileSystemRights
        ---- ----------------- ----------- ----------------- ----------------
        \\ORG\Desktop\Start Menu\INFO.lnk ORG\Office False Allow ReadAndExecute, Synchronize
        \\ORG\Desktop\Start Menu\INFO.lnk ORG\Support True Allow FullControl
        \\ORG\Desktop\Start Menu\INFO.lnk NT AUTHORITY\SYSTEM True Allow FullControl
        \\ORG\Desktop\Start Menu\INFO.lnk NT AUTHORITY\NETWORK SERVICE True Allow FullControl
        \\ORG\Desktop\Start Menu\INFO.lnk BUILTIN\Administrator True Allow FullControl
        \\ORG\Desktop\Start Menu\INFO.lnk ORG\Domain Admin True Allow FullControl
        \\ORG\Desktop\Start Menu\INFO.lnk ORG\Share Administrator True Allow FullControl
 
        Internal use of Format-Table to ease reading at the console.
    .EXAMPLE
        '.\.gitignore','.\asset.psm1' | show-access -NoFormat
 
        Path : N:\Documents\helper\.gitignore
        IdentityReference : ORG\jbennett
        IsInherited : True
        AccessControlType : Allow
        FileSystemRights : FullControl
 
        Path : N:\Documents\helper\.gitignore
        IdentityReference : BUILTIN\Administrator
        IsInherited : True
        AccessControlType : Allow
        FileSystemRights : FullControl
 
        Use the NoFormat switch to bypass internal use of Format-Table for piping objects to further functions.
    .NOTES
        Should refactor the format switch into a custom native cmdlet format document.
    #>

    [CmdletBinding()]
    Param(
        [Parameter(Position = 0,Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [string]
        $Path

        , # Do not automatically pipe output to Format-Table
        [switch]$NoFormat = $false
    )
    Process {
        $output = $path |
            get-acl |
            Foreach {
                $item = $psItem | select-Object -Expandproperty Access
                $item | Add-Member -MemberType NoteProperty -Name Path -Value $psItem.path
                Write-Output $Item
            } |
            select @{
                    name='Path'
                    expression = { $_.path.replace('Microsoft.PowerShell.Core\FileSystem::','') }
                },
                'IdentityReference',
                'IsInherited',
                'AccessControlType',
                'FileSystemRights'

        if($NoFormat){
            Write-Output $output
        } else{
            $output | Format-Table | Write-Output
        }
    }
}

Register-ArgumentCompleter -CommandName 'Add-Access','Remove-Access','Enable-Access','Disable-Access' -ParameterName 'Identity' -ScriptBlock {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
    [System.Collections.ArrayList]$preset = @(
        'AllStudents'
        'AllCAStudents'
        'AllStaff'
        'Office'
        "'Site Management'"
        "'Student Teachers'"
        "'Teaching Staff'"
        'Govenors'
        "'Exam Candidate'"
    )

    [int]$year = (get-date).year
    for( $i = $year; $i -ge ($year -6); $i -= 1){
        "'$i Students'"
    }

    $preset |
        ForEach-Object {
            [System.Management.Automation.CompletionResult]::new($psitem, $psitem, 'ParameterValue', ("AD Name: " + $psitem))
        }
}

Export-ModuleMember -Function "*"