Get-EPMInfo.ps1

<#PSScriptInfo
.VERSION 1.0.1
.GUID be880b1c-37d3-4349-9fd6-79668387cc88
.DESCRIPTION
 Get-EPMInfo.ps1 gathers the information most commonly required when creating, validating, or troubleshooting EPM elevation rules.
.AUTHOR Jeff Gilbert
.COMPANYNAME Community
.RELEASENOTES
 v1.0.1 08.11.2026 Intitial release
#>

<#
.SYNOPSIS
Collects application metadata, file hash, digital signature, and
publisher certificate information for Microsoft Intune Endpoint
Privilege Management (EPM).
 
The script analyzes a specified executable, installer, or script file
and collects:
 
- SHA256 file hash
- File version information
- Product metadata
- Company information
- Digital signature status
- Publisher certificate details
- Certificate thumbprint
- Certificate chain information
 
For digitally signed files, the signing certificate is exported to a
.CER file for additional analysis, validation, or documentation.
 
If a file path is not provided as a parameter, the script prompts the
user interactively.
 
A detailed report is generated and saved to a dedicated output folder
named after the application's Internal Name when available, or the file
name when Internal Name information is unavailable.
 
The resulting report can be used to support creation of:
 
- Publisher-based EPM rules
- Certificate-based EPM rules
- File Hash-based EPM rules
- Application onboarding documentation
- Security reviews
- Change management records
- Troubleshooting and validation activities
 
.PARAMETER FilePath
Full path to the executable, installer, or script to analyze.
 
If FilePath is not specified, the script prompts for the path
interactively.
 
Supported examples include:
 
- C:\Program Files\Contoso\App.exe
- C:\Installers\Setup.msi
- C:\Scripts\Maintenance.ps1
 
.INPUTS
System.String
 
You can provide a file path using the FilePath parameter.
 
.OUTPUTS
TXT Report
 
    A detailed report containing:
 
    - EPM Quick Reference information
    - Application metadata
    - File hash information
    - Digital signature status
    - Publisher certificate details
    - Complete certificate chain
 
CER Certificate
 
    Exported signing certificate for signed files.
 
.NOTES
File Name : Get-EPMInfo.ps1
Purpose : EPM Application Identity Collection
Version : 1.0
 
Designed for Intune and Endpoint Privilege Management administrators
who need to collect application identity information for elevation
rule creation and documentation purposes.
 
The script performs read-only operations against the specified file and
does not create or modify EPM policies.
 
Artifacts Created:
 
    <ApplicationFolder>\
        <ApplicationName>.txt
            Detailed EPM analysis report
 
        <ApplicationName>.cer
            Exported signing certificate (signed files only)
 
The output folder is created in the same directory as the script.
 
.EXAMPLE
PS> .\Get-EPMInfo.ps1
 
Prompts for a file path and generates an EPM report.
 
.EXAMPLE
PS> .\Get-EPMInfo.ps1 -FilePath 'C:\Program Files\Contoso\App.exe'
 
Collects application identity information, calculates the SHA256 hash,
exports the signing certificate, and generates an EPM report.
 
.EXAMPLE
PS> .\Get-EPMInfo.ps1 -FilePath 'C:\Installers\Setup.msi'
 
Generates a report containing publisher, certificate, version, and
file hash information for EPM rule creation.
 
.EXAMPLE
PS> .\Get-EPMInfo.ps1 -FilePath 'C:\Scripts\Maintenance.ps1'
 
Determines whether the script is digitally signed and creates a
reference report for EPM evaluation.
 
.LINK
Microsoft Intune Endpoint Privilege Management Documentation
 
#>


[CmdletBinding()]
param(
    [Parameter(
        Mandatory = $false,
        Position = 0,
        HelpMessage = 'Full path to the target executable, installer, or script.'
    )]
    [ValidateNotNullOrEmpty()]
    [string]$FilePath
)

try {
    $ErrorActionPreference = 'Stop'

    $quoteChars = @([char]34, [char]39, [char]0x2018, [char]0x2019, [char]0x201C, [char]0x201D)

    function Normalize-InputPath {
        param(
            [AllowNull()]
            [string]$Value,
            [char[]]$TrimChars
        )

        if ($null -eq $Value) {
            return ""
        }

        return $Value.Trim().Trim($TrimChars)
    }

    Write-Host ""
    Write-Host "========================================" -ForegroundColor Cyan
    Write-Host "EPM Application Identity Collector" -ForegroundColor Cyan
    Write-Host "========================================" -ForegroundColor Cyan
    Write-Host ""

    # Prompt for executable
    if ([string]::IsNullOrWhiteSpace($FilePath)) {
        while ($true) {
            $rawPath = Read-Host 'Enter the full path to the file (.exe, .msi, or script) that this EPM policy will manage (quotes optional)'
            $filePath = Normalize-InputPath -Value $rawPath -TrimChars $quoteChars

            if ([string]::IsNullOrWhiteSpace($filePath)) {
                Write-Warning "No path entered. Please try again."
                continue
            }

            if ($filePath -like 'Write-Error:*') {
                Write-Warning "Input appears to be an error message, not a file path. Paste only the file path and try again."
                continue
            }

            if (Test-Path -LiteralPath $filePath) {
                break
            }

            Write-Warning "File not found: $filePath"
        }
    }
    else {
        $filePath = Normalize-InputPath -Value $FilePath -TrimChars $quoteChars

        if ([string]::IsNullOrWhiteSpace($filePath)) {
            throw "No executable path was provided."
        }

        if ($filePath -like 'Write-Error:*') {
            throw "Input appears to be an error message, not a file path."
        }

        if (-not (Test-Path -LiteralPath $filePath)) {
            throw "File not found: $filePath"
        }
    }

    try {
        $file = Get-Item -LiteralPath $filePath
    }
    catch {
        throw "Unable to access file: $filePath"
    }

    Write-Host ""
    Write-Host "Collecting file information..."
    Write-Host ""

    # File Hash
    try {
        $hash = Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256
    }
    catch {
        throw "Unable to calculate file hash."
    }

    # Signature Information
    try {
        $sig = Get-AuthenticodeSignature -FilePath $file.FullName
    }
    catch {
        throw "Unable to inspect file signature."
    }

    $isSigned = $false
    $cert = $null

    if ($sig.SignerCertificate) {
        $isSigned = $true
        $cert = $sig.SignerCertificate
    }

    # Determine name for output folder
    $commonName = if (-not [string]::IsNullOrEmpty($file.VersionInfo.InternalName)) {
        $file.VersionInfo.InternalName
    }
    else {
        [System.IO.Path]::GetFileNameWithoutExtension($file.Name)
    }

    $commonName = ($commonName -replace '[\\/:*?"<>|]', '_').Trim()

    # Determine script location
    $scriptRoot = if ($PSScriptRoot) {
        $PSScriptRoot
    }
    else {
        (Get-Location).Path
    }

    $outputFolder = Join-Path $scriptRoot $commonName

    New-Item `
        -Path $outputFolder `
        -ItemType Directory `
        -Force | Out-Null

    $txtPath = Join-Path $outputFolder "$commonName.txt"

    if ($isSigned) {
        $certPath = Join-Path $outputFolder "$commonName.cer"

        try {
            $cert | Export-Certificate `
                -FilePath $certPath | Out-Null
        }
        catch {
            Write-Warning "Failed to export certificate."
        }
    }

    # Default values for unsigned executables
    $subjectCN = "N/A"
    $issuerCN  = "N/A"
    $chainText = "No certificate chain available."
    $chainSummaryText = "Unsigned file."

    if ($isSigned) {

        if ($cert.Subject -match 'CN=([^,]+)') {
            $subjectCN = $Matches[1]
        }

        if ($cert.Issuer -match 'CN=([^,]+)') {
            $issuerCN = $Matches[1]
        }

        try {

            $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
            $null = $chain.Build($cert)

            $chainSummary = @()
            $chainDetails = @()

            foreach ($element in $chain.ChainElements) {

                $chainCert = $element.Certificate

                $chainSubjectCN = if ($chainCert.Subject -match 'CN=([^,]+)') {
                    $Matches[1]
                }
                else {
                    ""
                }

                $chainIssuerCN = if ($chainCert.Issuer -match 'CN=([^,]+)') {
                    $Matches[1]
                }
                else {
                    ""
                }

                $chainSummary += $chainSubjectCN

                $chainDetails += @"
 
--------------------------------------------------
Subject CN : $chainSubjectCN
Issuer CN : $chainIssuerCN
 
Subject : $($chainCert.Subject)
Issuer : $($chainCert.Issuer)
 
Thumbprint : $($chainCert.Thumbprint)
Serial : $($chainCert.SerialNumber)
 
Not Before : $($chainCert.NotBefore)
Not After : $($chainCert.NotAfter)
 
"@

            }

            $chainSummaryText = $chainSummary -join " -> "
            $chainText = $chainDetails -join ""

        }
        catch {
            $chainText = "Unable to build certificate chain."
            $chainSummaryText = "Certificate chain unavailable."
        }
    }

    # EPM Summary
    $epmSummary = @"
Publisher CN : $($subjectCN)
Product Name : $($file.VersionInfo.ProductName)
File Name : $($file.Name)
File Path : $($filePath)
Internal Name: $($file.VersionInfo.InternalName)
Version : $($file.VersionInfo.FileVersion)
SHA256 : $($hash.Hash)
Issuer CN : $($issuerCN)
Issuer : $($cert.Issuer)
Thumbprint : $($cert.Thumbprint)
"@


    # Report
    $report = @"
==================================================
EPM QUICK REFERENCE
==================================================
 
$epmSummary
 
Certificate Chain
==================================================
 
$chainSummaryText
 
 
==================================================
APPLICATION INFORMATION
==================================================
 
File Name : $($file.Name)
Product Name : $($file.VersionInfo.ProductName)
Internal Name : $($file.VersionInfo.InternalName)
File Description : $($file.VersionInfo.FileDescription)
File Version : $($file.VersionInfo.FileVersion)
Original Filename : $($file.VersionInfo.OriginalFilename)
Company Name : $($file.VersionInfo.CompanyName)
File Path : $($file.FullName)
 
==================================================
FILE HASH INFORMATION
==================================================
 
Algorithm : $($hash.Algorithm)
SHA256 : $($hash.Hash)
 
==================================================
SIGNATURE INFORMATION
==================================================
 
Signature Status : $($sig.Status)
Is OS Binary : $($sig.IsOSBinary)
 
==================================================
CERTIFICATE INFORMATION
==================================================
 
Subject CN : $subjectCN
Issuer CN : $issuerCN
 
$(
if ($isSigned) {
@"
Subject : $($cert.Subject)
Issuer : $($cert.Issuer)
Thumbprint : $($cert.Thumbprint)
Serial Number : $($cert.SerialNumber)
 
Not Before : $($cert.NotBefore)
Not After : $($cert.NotAfter)
 
Friendly Name : $($cert.FriendlyName)
 
Signature Algorithm: $($cert.SignatureAlgorithm.FriendlyName)
Public Key Algo : $($cert.PublicKey.Oid.FriendlyName)
"@
}
else {
"Executable is not digitally signed."
}
)
 
==================================================
FULL CERTIFICATE CHAIN
==================================================
 
$chainText
 
"@


    $report | Set-Content -Path $txtPath -Encoding UTF8

    Write-Host ""
    Write-Host "========================================" -ForegroundColor Green
    Write-Host "EPM QUICK REFERENCE" -ForegroundColor Green
    Write-Host "========================================" -ForegroundColor Green
    Write-Host $epmSummary

    Write-Host ""
    Write-Host "Certificate Chain:" -ForegroundColor Cyan
    Write-Host $chainSummaryText

    Write-Host ""
    Write-Host "Output Folder:" -ForegroundColor Green
    Write-Host " $outputFolder"

    if ($isSigned) {
        Write-Host ""
        Write-Host "Certificate Export:"
        Write-Host " $certPath"
    }

    Write-Host ""
    Write-Host "Report:"
    Write-Host " $txtPath"
    Write-Host ""

}
catch {
    Write-Error $_.Exception.Message
}