Sync-PowerHistory.ps1

function Sync-PowerHistory
{
    <#
    .Synopsis
        Synchronizes PowerHistory with Command History
    .Description
        Synchronizes PowerHistory with information that can be automatically inferred from the command history.
 
        At present, this information is:
 
        |Name |Type | Description |
        |------------|-----------------|--------------------------------------------|
        |Assignments | [string[]] | The variables assigned |
        |Commands | [CommandInfo[]] | The Commands Used |
        |CommandsAST | [CommandAst[]] | The Abstract-Syntax Tree of Commands |
        |Modules | [PSModuleInfo[]]| The Modules Used |
        |Runtime | [TimeSpan] | The RunTime |
        |Variables | [string[]] | The Variables Used |
    .Link
        Get-PowerHistory
    .Example
        Sync-PowerHistory
    #>

    [CmdletBinding(DefaultParameterSetName='All')]
    [OutputType([Nullable])]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', "", Justification = 'Functionality Most Be Global')]
    param(
    # One or more history IDs. If no IDs are provided, the current history will be synchronized.
    [Parameter(Mandatory,ParameterSetName='SpecificItem',ValueFromPipelineByPropertyName)]
    [long[]]
    $ID
    )

    begin {
        $allIds = [Collections.Generic.List[long]]::new()
        $inputObjects = [Collections.Generic.List[PSObject]]::new()
    }
    process {
        #region If No ID Is Provided, Go Call Yourself
        if ($PSCmdlet.ParameterSetName -eq 'All') {
            Get-History | Sync-PowerHistory
            return
        }
        #endregion If No ID Is Provided, Go Call Yourself
        #region If an ID is Provided, Accumulate it
        if ($PSCmdlet.ParameterSetName -eq 'SpecificItem') {
            if ($_) {
                $null = $inputObjects.Add($_)
            }
            $allIds.AddRange($ID)
        }
        #endregion If an ID is Provided, Accumulate it

    }

    end {
        $cmdLookup = @{}
        $t, $progId = $allIds.Count, [Random]::new().Next()
        for ($c =0 ; $c -lt $allIds.Count; $c++) {
            if ($t -gt 1) {
                Write-Progress "Syncing History" "$($allIds[$c])" -PercentComplete ($c * 100 / $t) -Id $progId
            }
            $historyItem = $inputObjects[$c]
            if ($historyItem -isnot [Microsoft.PowerShell.Commands.HistoryInfo]) {
                $historyItem = Get-History -Id $allIds[$c] -ErrorAction Ignore
            }

            if (-not $historyItem) { continue }

            if (-not $Global:PowerHistory[$historyItem.Id]) {
                $Global:PowerHistory[$historyItem.Id] = [Ordered]@{}
            }

            if ($Global:PowerHistory[$historyItem.Id] -isnot [Collections.IDictionary]) {
                continue
            }

            if ($Global:PowerHistory[$historyItem.Id].Synchronized) {
                continue
            }

            $phi = $Global:PowerHistory[$historyItem.Id]



            $phi.RunTime = $historyItem.EndExecutionTime - $historyItem.StartExecutionTime

            $script:_FoundVariables = [Collections.Generic.List[string]]::new()
            $script:_FoundAssignments = [Collections.Generic.List[string]]::new()
            $script:_FoundCommands = [Collections.Generic.List[Management.Automation.Language.CommandAst]]::new()
            try {
                $phiScript = [ScriptBlock]::Create($historyItem.CommandLine)



            } catch {
                continue
            }


            if (-not $phiScript) { continue }

            $phiScript.Ast.FindAll({param($ast)
                if ($ast -is [Management.Automation.Language.CommandAst]) {
                    $null = $script:_FoundCommands.Add($ast)
                }
                if ($ast -is [Management.Automation.Language.VariableExpressionAst]) {
                    $null = $script:_FoundVariables.Add($ast.VariablePath)
                }
                if ($ast -is [Management.Automation.Language.AssignmentStatementAst] -and
                    $ast.Left.VariablePath) {

                    $null = $script:_FoundAssignments.Add($ast.Left.VariablePath)
                }

            }, $true)


            $resolvedCmds = [Collections.Generic.List[PSObject]]::new()
            $foundModules = [Collections.Generic.List[Management.Automation.PSModuleInfo]]::new()

            foreach ($cmdAst in $script:_FoundCommands) {
                $cmdName = $cmdAst.CommandElements[0].Value
                if ($cmdName) {
                    if (-not $cmdLookup[$cmdName]) {
                        $cmdLookup[$cmdName] = $ExecutionContext.SessionState.InvokeCommand.GetCommand($cmdName, 'All')
                    }

                    if ($cmdLookup[$cmdName]) {
                        if ($resolvedCmds -notcontains $cmdLookup[$cmdName]) {
                            $resolvedCmds.Add($cmdLookup[$cmdName])
                        }
                        if ($cmdLookup[$cmdName].Module -and
                            $foundModules -notcontains $cmdLookup[$cmdName].Module) {
                            $foundModules.Add($cmdLookup[$cmdName].Module)
                        }
                    }
                }
            }

            $phi.Commands = $resolvedCmds
            $phi.Modules = $foundModules
            $phi.Variables = $script:_FoundVariables
            $phi.Assignments = $script:_FoundAssignments
            $phi.CommandsAST = $script:_FoundCommands
            $phi.Synchronized = $true
        }

        if ($t -gt 1) {
            Write-Progress "Syncing History" "Complete!" -Completed -Id $progId
        }
    }
}