Indented.ComSecurity.psm1

using namespace System.Management.Automation
using namespace System.Security.Principal
using namespace System.Security.AccessControl
#Region '.\enum\ComRight.ps1' 0
[Flags()]
enum ComRight {
    Read             = 1
    LocalLaunch      = 2
    RemoteLaunch     = 4
    LocalActivation  = 8
    RemoteActivation = 16
    All              = 31
}
#EndRegion '.\enum\ComRight.ps1' 10
#Region '.\enum\ComType.ps1' 0
enum ComType {
    DefaultLaunchPermission = 1
    MachineAccessRestriction
    MachineLaunchRestriction
}
#EndRegion '.\enum\ComType.ps1' 6
#Region '.\class\IdentityTransformationAttribute.ps1' 0
#using namespace System.Management.Automation
#using namespace System.Security.Principal

class IdentityTransformationAttribute : ArgumentTransformationAttribute {
    [Object] Transform(
        [EngineIntrinsics] $engineIntrinsics,
        [Object]           $inputData
    ) {
        if ($inputData -is [SecurityIdentifier]) {
            return $inputData
        } elseif ($inputData -is [NTAccount]) {
            return $inputData.Translate([SecurityIdentifier])
        } elseif ($inputData -is [String]) {
            if ($inputData.StartsWith('S-1-5-')) {
                return [SecurityIdentifier]$inputData
            } else {
                return ([NTAccount]$inputData).Translate([SecurityIdentifier])
            }
        }
        throw '{0} is not a valid identity' -f $inputData
    }
}
#EndRegion '.\class\IdentityTransformationAttribute.ps1' 23
#Region '.\private\GetOlePath.ps1' 0
function GetOlePath {
    <#
    .SYNOPSIS
        Get the path to OLE.
    .DESCRIPTION
        Get the path to OLE depending on the current process and the requested registry view.
    #>


    [CmdletBinding()]
    param (
        # Set to true if the 32-bit registry view should be used to get the ACL.
        [Switch]$Is32Bit
    )

    if (($Is32Bit -and [IntPtr]::Size -eq 8) -or (-not $Is32Bit -and [IntPtr]::Size -eq 4)) {
        return 'HKLM:\Software\Wow6432Node\Microsoft\Ole'
    }
    return 'HKLM:\Software\Microsoft\Ole'
}
#EndRegion '.\private\GetOlePath.ps1' 20
#Region '.\public\Get-ComAcl.ps1' 0
#using namespace System.Security.AccessControl
#using namespace System.Security.Principal

function Get-ComAcl {
    <#
    .SYNOPSIS
        Get security descriptors associated with COM.
    .DESCRIPTION
        Get-ComAcl can be used to read the access control lists which make up COM Security.
    .EXAMPLE
        Get-ComAcl -Type MachineLaunchRestriction
 
        Get the ACL used to describe launch restrictions.
    #>


    [CmdletBinding()]
    [OutputType([System.Security.AccessControl.CommonSecurityDescriptor])]
    param (
        # The permission set which should be retrieved.
        [Parameter(Mandatory, Position = 1)]
        [ComType]$Type,

        # Set to true if the 32-bit registry view should be used to get the ACL.
        [Switch]$Is32Bit
    )

    $path = GetOlePath -Is32Bit:$Is32Bit

    $aclObject = [CommonSecurityDescriptor]::new(
        $false,
        $false,
        (Get-ItemPropertyValue -Path $path -Name $Type),
        0
    )

    $aclObject | Add-Member -NotePropertyName Type -NotePropertyValue $Type
    $aclObject | Add-Member -NotePropertyName Is32Bit -NotePropertyValue $Is32Bit.ToBool()

    $aclObject | Add-Member Access -MemberType ScriptProperty -Value {
        foreach ($ace in $this.DiscretionaryAcl) {
            [PSCustomObject]@{
                ComAccessRights   = [ComRight]$ace.AccessMask
                AccessControlType = [AccessControlType]$ace.AceType
                IdentityReference = $ace.SecurityIdentifier.Translate([NTAccount])
            } | Add-Member ToString -MemberType ScriptMethod -Force -PassThru -Value {
                '{0} {1} {2}' -f @(
                    $this.IdentityReference.ToString().PadRight(32),
                    $this.AccessControlType.ToString().PadRight(10),
                    $this.ComAccessRights
                )
            }
        }
    }

    $aclObject | Add-Member AccessToString -MemberType ScriptProperty -Value {
        ($this.Access | ForEach-Object { $_.ToString() }) -join [Environment]::NewLine
    }

    $aclObject
}
#EndRegion '.\public\Get-ComAcl.ps1' 61
#Region '.\public\Grant-ComPermission.ps1' 0
#using namespace System.Security.Principal

function Grant-ComPermission {
    <#
    .SYNOPSIS
        Grant a COM right.
    .DESCRIPTION
        Grant a right to an identity in a COM ACL.
    .EXAMPLE
        Grant-ComPermission -Type MachineLaunchRestriction -Right RemoteLaunch -Identity (whoami)
 
        Grant the RemoteLaunch right to the current user.
    .EXAMPLE
        Grant-ComPermission -Type MachineLaunchRestriction -Right RemoteLaunch, RemoteActivation -Identity EVERYONE
 
        Grant the RemoteLaunch and RemoteActivation rights to everyone.
    #>


    [CmdletBinding(SupportsShouldProcess)]
    param (
        # The ACL to modify. Must be one of DefaultLaunchPermission, MachineAccessRestriction, or MachineLaunchRestriction.
        [Parameter(Mandatory, Position = 1)]
        [ComType]$Type,

        # The access type which should be granted. The value can be Allow or Deny, by default AccessType is set to Allow.
        [Parameter(ValueFromPipelineByPropertyName)]
        [AccessControlType]$AccessType = 'Allow',

        # The identity which should have rights granted.
        [Parameter(ValueFromPipelineByPropertyName)]
        [IdentityTransformationAttribute()]
        [SecurityIdentifier]$Identity,

        # The right to grant. One or more of Read, LocalLaunch, RemoteLaunch, LocalActivation, RemoteActivation, or All.
        [Parameter(ValueFromPipelineByPropertyName)]
        [ComRight]$Right,

        # Set to true if the 32-bit registry view should be used to set the ACL.
        [Switch]$Is32Bit
    )

    begin {
        $aclObject = Get-ComAcl -Type $Type -Is32Bit:$Is32Bit
    }

    process {
        try {
            $aclObject.DiscretionaryAcl.AddAccess(
                $AccessType,
                $Identity,
                [Int]$Right,
                'None',
                'None'
            )
        } catch {
            Write-Error -ErrorRecord $_
        }
    }

    end {
        if ($pscmdlet.ShouldProcess('Applying changes to discretionary ACL for {0}' -f $Type)) {
            $aclObject | Set-ComAcl
        }
    }
}
#EndRegion '.\public\Grant-ComPermission.ps1' 66
#Region '.\public\Revoke-ComPermission.ps1' 0
#using namespace System.Security.Principal

function Revoke-ComPermission {
    <#
    .SYNOPSIS
        Revoke a COM right.
    .DESCRIPTION
        Revoke a right granted to an identity in a COM ACL.
 
        Entries may be added to the ACL if the revoked rights describe less than the rights assigned to a principal.
    .EXAMPLE
        Revoke-ComPermission -Type MachineLaunchRestriction -Right All -Identity $env:USERNAME
 
        Revoke all rights which have been explicitly granted to the current user.
    #>


    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'FromFields')]
    param (
        # The ACL to modify. Must be one of DefaultLaunchPermission, MachineAccessRestriction, or MachineLaunchRestriction.
        [Parameter(Mandatory)]
        [ComType]$Type,

        # The access type which should be removed. Allow or Deny.
        [Parameter(ValueFromPipelineByPropertyName, ParameterSetname = 'FromFields')]
        [AccessControlType]$AccessType = 'Allow',

        # The identity for which rights should be revoked.
        [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetname = 'FromFields')]
        [IdentityTransformationAttribute()]
        [SecurityIdentifier]$Identity,

        # The rights to revoke. One or more of Read, LocalLaunch, RemoteLaunch, LocalActivation, RemoteActivation, or All.
        [Parameter(ValueFromPipelineByPropertyName, ParameterSetname = 'FromFields')]
        [ComRight]$Right,

        # A CommonAce object from the DiscretionaryACL.
        [Parameter(ValueFromPipeline, ParameterSetName = 'FromACE')]
        [CommonAce]$Ace,

        # Set to true if the 32-bit registry view should be used to set the ACL.
        [Switch]$Is32Bit
    )

    begin {
        $aclObject = Get-ComAcl -Type $Type -Is32Bit:$Is32Bit
    }

    process {
        try {
            if ($pscmdlet.ParameterSetName -eq 'FromFields') {
                $aceRemoved = $aclObject.DiscretionaryAcl.RemoveAccess(
                    $AccessType,
                    $Identity,
                    [Int]$Right,
                    'None',
                    'None'
                )
                try {
                    $name = $Identity.Translate([NTAccount])
                } catch {
                    $name = $Identity
                }
            } else {
                try {
                    $name = $ace.IdentityReference.Translate([NTAccount])
                } catch {
                    $name = $ace.IdentityReference
                }
                $aceRemoved = $aclObject.DiscretionaryAcl.RemoveAccess($ace)
            }

            if (-not $aceRemoved) {
                throw 'Failed to remove {0} from {1} ACL' -f $name, $Type
            }
        } catch {
            Write-Error -ErrorRecord $_
        }
    }

    end {
        if ($pscmdlet.ShouldProcess('Applying changes to discretionary ACL for {0}' -f $Type)) {
            $aclObject | Set-ComAcl
        }
    }
}
#EndRegion '.\public\Revoke-ComPermission.ps1' 86
#Region '.\public\Set-ComAcl.ps1' 0
#using namespace System.Security.AccessControl

function Set-ComAcl {
    <#
    .SYNOPSIS
        Set a COM Security ACL.
    .DESCRIPTION
        Apply an updated ACL to COM Security.
    .EXAMPLE
        Set-ComAcl -Type MachineLaunchRestriction -AclObject $aclObject
 
        Set a modified ACL for MachineLaunchRestriction.
    #>


    [CmdletBinding(SupportsShouldProcess)]
    param (
        # The permission set which should be changed.
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [ComType]$Type,

        # The ACL object to apply.
        [Parameter(Mandatory, ValueFromPipeline)]
        [CommonSecurityDescriptor]$AclObject,

        # Set to true if the 32-bit registry view should be used to set the ACL.
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [Switch]$Is32Bit
    )

    begin {
        $path = GetOlePath -Is32Bit:$Is32Bit
    }

    process {
        try {
            $bytes = [Byte[]]::new($AclObject.BinaryLength)
            $AclObject.GetBinaryForm($bytes, 0)

            $existingBytes = Get-ItemPropertyValue -Path $path -Name $Type
            if (Compare-Object $bytes $existingBytes -SyncWindow 0) {
                if ($pscmdlet.ShouldProcess('Setting the {0} ACL' -f $Type)) {
                    Set-ItemProperty -Path $path -Name $Type -Value $bytes
                }
            }
        } catch {
            $pscmdlet.ThrowTerminatingError($_)
        }
    }
}
#EndRegion '.\public\Set-ComAcl.ps1' 50