Public/Get-ServiceExecutablePermission.ps1

#requires -Version 2
function Get-ServiceExecutablePermission
{
    <#
            .Synopsis
            Gets file permissions of service executables.
            .DESCRIPTION
            The Get-ServiceExecutablePermissions function uses Powershell remoting to query the file permissions of service executables for those services which are set to automatically start on remote computers. By default, the Get-ServiceExecutablePermissions function is set to query all domain joined computers.
 
            .EXAMPLE
            PS C:\> Get-ServiceExecutablePermissions
 
            This command queries the file permissions of service executables for those services which are set to automatically start on all domain-joined computers. Any permissions which allow a nonpriviledged user to modify a service executable are returned.
 
            .EXAMPLE
            PS C:\> Get-ServiceExecutablePermissions | Export-csv -Path c:\ServiceExePermissions.csv
 
            This command queries the file permissions of service executables for those services which are set to automatically start on all domain-joined computers. Any permissions which allow a nonpriviledged user to modify a service executable are returned. The results are then exported to a CSV file named ServiceExePermissions.csv at the root of the C drive.
 
            .EXAMPLE
            PS C:\> Get-ServiceExecutablePermissions -IncludePriviledgedAccounts
 
            This command queries the file permissions of service executables for those services which are set to automatically start on all domain-joined computers. Any permissions which allow any user (both priviledged and nonpriviledged) to modify a service executable are returned.
 
            .EXAMPLE
            PS C:\> Get-ServiceExecutablePermissions -ShowAllPermissions
 
            This command queries the file permissions of service executables for those services which are set to automatically start on all domain-joined computers. All nonprivileded user permissions are returned
 
            .EXAMPLE
            PS C:\> Get-ServiceExecutablePermissions -IncludePriviledgedAccounts -ShowAllPermissions
 
            This command queries the file permissions of service executables for those services which are set to automatically start on all domain-joined computers. All permissions of any user (both priviledged and nonpriviledged) are returned.
 
            .NOTES
            The Get-ServiceExecutablePermissions function requires administrator rights on the remote computer(s) to be queried.
         
            Powershell remoting must be enabled on the remote computer to properly query service executable permissions.
         
            If Powershell remoting is not enabled on a remote computer it can be enabled by either
            - Running Enable-PSRemoting locally or
            - By running Enable-RemotePSRemoting and specifying the name of the remote computer.
 
            .PARAMETER ComputerName
            Specifies the computers on which the command runs. The default is all domain-joined computers.
         
            Type the NETBIOS name, IP address, or fully-qualified domain name of one or more computers in a comma-separated list. To specify the local computer, type the computer name, "localhost", or a dot (.).
         
            To use an IP address in the value of the ComputerName parameter, the command must include the Credential parameter. Also, the computer must be configured for HTTPS transport or the IP address of the remote computer must be included in the WinRM TrustedHosts list on the local computer. For instructions for adding a computer name to the TrustedHosts list, see "How to Add a Computer to the Trusted Host List" in about_Remote_Troubleshooting.
     
            .PARAMETER Credential
            Specifies a user account that has permission to perform this action. The default is the current user.
     
            Type a user name, such as "User01" or "Domain01\User01", or enter a variable that contains a PSCredential object, such as one generated by the Get-Credential cmdlet. When you type a user name, you will be prompted for a password.
 
            .PARAMETER ShowAllPermissions
            Specifies the function show all permissions for service executables, not just Modify & FullControl rights.
 
            .PARAMETER IncludePriviledgedAccounts
            Specifies the function include priviledged account permissions in the results.
    #>


    
    [CmdletBinding()]
    
    param
    (
        [Parameter(Mandatory = $false,Position = 0)]
        [string[]]$ComputerName = (Get-ADComputer -Filter *).Name,
        
        [Parameter(Mandatory = $false)]
        [pscredential]$Credential = $null,

        [Parameter(Mandatory = $false)]
        [switch]$ShowAllPermissions,

        [Parameter(Mandatory = $false)]
        [switch]$IncludePriviledgedAccounts
    )
  
    Begin{
        If($PSBoundParameters.ContainsKey('Credential'))
        {
            $User = $Credential.UserName
            $Password = $Credential.GetNetworkCredential().Password

            If($User -like "$env:USERDOMAIN*")
            {
                Add-Type -AssemblyName System.DirectoryServices.AccountManagement
                $Domain = $env:USERDOMAIN
                $ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain
                $PrincipalContext = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ContextType, $Domain
                $CredentialValidity = $PrincipalContext.ValidateCredentials($User,$Password)
                If(-not $CredentialValidity)
                {
                    Write-Warning -Message 'Logon failure: Unknown username or bad password.' 
                    Break
                }
            }
        }
    }

    Process{
        $ScriptBlock = {
            $WarningPreference = $Using:WarningPreference
            
            $ServiceExe = Get-WmiObject -Class win32_service -Filter "StartMode='Auto' AND NOT PathName LIKE 'c:\\Windows\\%'"

            Foreach($Exe in $ServiceExe)
            {
                $ExeCommandLine = $($Exe.PathName).Replace('"','')

                $ExePath = $ExeCommandLine -split ' (-|\/)' |
                Where-Object -FilterScript {
                    $_ -Match 'exe'
                }

                If(Test-Path -Path $ExePath)
                {
                    $Info = Get-Acl -Path $ExePath | 
                    Select-Object -ExpandProperty Access |
                    ForEach-Object -Process {
                        If($Using:IncludePriviledgedAccounts)
                        {
                            $_
                        }
                        Else
                        {
                            $_ |
                            Where-Object -FilterScript {
                                $_.IdentityReference -ne 'NT Authority\System' -and $_.IdentityReference -ne 'BUILTIN\Administrators' -and $_.IdentityReference -ne 'APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES' -and $_.IdentityReference -ne 'NT SERVICE\TrustedInstaller'
                            }
                        }
                    } |
                    ForEach-Object -Process {
                        If($Using:ShowAllPermissions)
                        {
                            $_
                        }
                        Else
                        {
                            $_ |
                            Where-Object -FilterScript {
                                $_.FileSystemRights -match 'Modify|FullControl'
                            }
                        }
                    }
     
                    If($Info)
                    {
                        $Info |
                        Select-Object -Property *, @{
                            n = 'Path'
                            e = {
                                $ExePath
                            }
                        }, 
                        @{
                            n = 'Name'
                            e = {
                                $Exe.Name
                            }
                        } |
                        ForEach-Object -Process{
                            $Object = $_
                            $Object.PSObject.Typenames.Insert(0,'ARTools.ServiceExePermissions')
                            $Object
                        }
                    }
                }
                Else
                {
                    Write-Error -Message "Cannont parse file path from commandline. Please evaluate file permissions for service executable with commandline '$ExeCommandLine' on $env:COMPUTERNAME."
                }
            }
        }
        
        $InvokeArgs = @{
            ComputerName = $ComputerName
        }
    
        If($null -ne $Credential)
        {
            $InvokeArgs.Credential = $Credential
        }
        
        $InvokeArgs.ComputerName = Test-PSRemoting @InvokeArgs -WarningAction $WarningPreference
        
        If($null -eq $InvokeArgs.ComputerName)
        {
            Break
        }
        
        $InvokeArgs.ScriptBlock = $ScriptBlock
        
        Invoke-Command @InvokeArgs -HideComputerName
    }

    End{

    }
}