IISResetMe / PSProfiler

PowerShell Script Profiler
MIT License
126 stars 9 forks source link

getting exception when trying to analyse my $profile #15

Closed LuanVSO closed 1 year ago

LuanVSO commented 2 years ago
PS C:\Users\luanv
❯ Get-Module

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Manifest   0.1.0                 CompletionPredictor
Manifest   7.0.0.0               Microsoft.PowerShell.Management     {Add-Content, Clear-Content, Clear-Item, Clear-It…
Manifest   7.0.0.0               Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Ob…
Script     1.0.3.0               PSProfiler                          {Measure-Script, WhyScriptNoGoBrrrr}
Script     2.2.6                 PSReadLine                          {Get-PSReadLineKeyHandler, Get-PSReadLineOption, …

PS C:\Users\luanv
❯ Get-Module { curl google.com}
Get-Module: Cannot evaluate parameter 'Name' because its argument is specified as a script block and there is no input.A script block cannot be evaluated without input.
PS C:\Users\luanv
❯ Measure-Script { curl google.com}
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   219  100   219    0     0   1192      0 --:--:-- --:--:-- --:--:--  1209

    Anonymous ScriptBlock

      Count  Line       Time Taken Statement
      -----  ----       ---------- ---------
          1     1    00:00.5812887 { curl google.com}

PS C:\Users\luanv
❯ Measure-Script $profile.CurrentUserAllHosts
MethodInvocationException: C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\AstVisitor7.class.ps1:15
Line |
  15 |          $res = $element.Visit($this)
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Exception calling "Visit" with "1" argument(s): "Method invocation failed because
     | [System.Management.Automation.Language.TokenKind] does not contain a method named 'Visit'."

InvalidOperation: You cannot call a method on a null-valued expression.

InvalidOperation: The expression after '&' in a pipeline element produced an object that was not valid. It must result in a command name,
a script block, or a CommandInfo object.

    C:\Users\luanv\Documents\PowerShell\profile.ps1

      Count  Line       Time Taken Statement
      -----  ----       ---------- ---------
          0     1    00:00.0000000 #source completers
          0     2    00:00.0000000 Get-ChildItem "$(Split-Path $profile -Parent)\completions\" |
          0     3    00:00.0000000 ForEach-Object {
          0     4    00:00.0000000      . $_.FullName
          0     5    00:00.0000000 }
          0     6    00:00.0000000
          0     7    00:00.0000000 function import-OrInstallModule([string[]]$module) {
          0     8    00:00.0000000      Import-Module -Global $module -ErrorAction SilentlyContinue ||
          0     9    00:00.0000000      Install-Module -Name $module -Scope CurrentUser -SkipPublisherCheck -Force &&
          0    10    00:00.0000000      Import-Module -Global $module
          0    11    00:00.0000000 }
          0    12    00:00.0000000
          0    13    00:00.0000000 import-OrInstallModule 'CompletionPredictor'
          0    14    00:00.0000000
          0    15    00:00.0000000 if (Test-Path "~\.vcpkg\") {
          0    16    00:00.0000000      . "~\.vcpkg\vcpkg-init.ps1"
          0    17    00:00.0000000      Import-Module "~\.vcpkg\scripts\posh-vcpkg\"
          0    18    00:00.0000000 }
          0    19    00:00.0000000
          0    20    00:00.0000000 #region helpers
          0    21    00:00.0000000 function Enter-VsDevEnv {
          0    22    00:00.0000000      [CmdletBinding()]
          0    23    00:00.0000000      param(
          0    24    00:00.0000000              [Parameter()]
          0    25    00:00.0000000              [switch]$Prerelease,
          0    26    00:00.0000000              [Parameter()]
          0    27    00:00.0000000              [string]$architecture = "x64"
          0    28    00:00.0000000      )
          0    29    00:00.0000000
          0    30    00:00.0000000      $ErrorActionPreference = 'Stop'
          0    31    00:00.0000000
          0    32    00:00.0000000      import-OrInstallModule 'VSSetup'
          0    33    00:00.0000000
          0    34    00:00.0000000      Write-Verbose 'Searching for VC++ instances'
          0    35    00:00.0000000      $VSInfo = `
          0    36    00:00.0000000              Get-VSSetupInstance  -All -Prerelease:$Prerelease `
          0    37    00:00.0000000      | Select-VSSetupInstance `
          0    38    00:00.0000000              -Latest -Product * `
          0    39    00:00.0000000              -Require 'Microsoft.VisualStudio.VC.Ide.Core'
          0    40    00:00.0000000
          0    41    00:00.0000000      $VSPath = $VSInfo.InstallationPath
          0    42    00:00.0000000
          0    43    00:00.0000000      switch ($env:PROCESSOR_ARCHITECTURE) {
          0    44    00:00.0000000              "amd64" { $hostarch = "x64" }
          0    45    00:00.0000000              "x86" { $hostarch = "x86" }
          0    46    00:00.0000000              "arm64" { $hostarch = "arm64" }
          0    47    00:00.0000000              default { throw "Unknown architecture: $switch" }
          0    48    00:00.0000000      }
          0    49    00:00.0000000
          0    50    00:00.0000000      $devShellModule = "$VSPath\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
          0    51    00:00.0000000
          0    52    00:00.0000000      Import-Module -Global -Name $devShellModule
          0    53    00:00.0000000
          0    54    00:00.0000000      Write-Verbose 'Setting up environment variables'
          0    55    00:00.0000000      Enter-VsDevShell -VsInstanceId $VSInfo.InstanceId  -SkipAutomaticLocation `
          0    56    00:00.0000000              -devCmdArguments "-arch=$architecture -host_arch=$hostarch"
          0    57    00:00.0000000
          0    58    00:00.0000000      Set-Item -Force -path "Env:\Platform" -Value $architecture
          0    59    00:00.0000000
          0    60    00:00.0000000      remove-Module Microsoft.VisualStudio.DevShell, VSSetup
          0    61    00:00.0000000 }
          0    62    00:00.0000000 function la { Get-ChildItem @args | Format-Wide }
          0    63    00:00.0000000 function which($c) {
          0    64    00:00.0000000  $a = get-command $c
          0    65    00:00.0000000      switch ($a.CommandType) {
          0    66    00:00.0000000              'Alias' { $a.Definition }
          0    67    00:00.0000000              'Application' { $a.Path }
          0    68    00:00.0000000              'ExternalScript' { $a.Source }
          0    69    00:00.0000000              Default { $a }
          0    70    00:00.0000000      }
          0    71    00:00.0000000 }
          0    72    00:00.0000000 function take([string]$path) { mkdir $path ; Set-Location $path }
          0    73    00:00.0000000
          0    74    00:00.0000000 function reset { [Console]::write("`ec`e]104`a`e[!p`e[?3;4l`e[4l`e>`e[?69l") }
          0    75    00:00.0000000
          0    76    00:00.0000000 function tabs($tabsize) {
          0    77    00:00.0000000      [console]::Write("`e[?25l`e[3g`r`eH")
          0    78    00:00.0000000      for ($i = 0; $i -lt [System.Console]::BufferWidth; $i += $tabsize) {
          0    79    00:00.0000000              [console]::Write("`e[${tabsize}C`eH")
          0    80    00:00.0000000      }
          0    81    00:00.0000000      [Console]::write("`r`e[?25h")
          0    82    00:00.0000000 }
          0    83    00:00.0000000
          0    84    00:00.0000000 function Search-Alias([String] $name) {
          0    85    00:00.0000000      (get-Alias).DisplayName | Select-String $name
          0    86    00:00.0000000 }
          0    87    00:00.0000000 #endregion
          0    88    00:00.0000000
          0    89    00:00.0000000 #region aliases
          0    90    00:00.0000000 set-Alias sral search-Alias
          0    91    00:00.0000000 Set-Alias grep Select-String
          0    92    00:00.0000000 Set-Alias sudo elevate
          0    93    00:00.0000000 set-Alias vim "C:\Program Files\Git\usr\bin\vim.exe"
          0    94    00:00.0000000 # set-Alias "ping" "Test-NetConnection"
          0    95    00:00.0000000 # set-Alias "ipconfig" "Get-NetIPConfiguration"
          0    96    00:00.0000000 #endregion
          0    97    00:00.0000000
          0    98    00:00.0000000 #region keybindings
          0    99    00:00.0000000 Set-PSReadLineKeyHandler -Key "Ctrl+f" -Function ForwardWord
          0   100    00:00.0000000 Set-PSReadLineKeyHandler -Key "Ctrl+RightArrow" -Function ForwardWord
          0   101    00:00.0000000 Set-PSReadLineKeyHandler -key "Ctrl+d" -Function DeleteCharOrExit
          0   102    00:00.0000000 <#Set-PSReadLineKeyHandler -Key "UpArrow" -Function HistorySearchBackward
          0   103    00:00.0000000 Set-PSReadLineKeyHandler -Key "DownArrow" -Function HistorySearchForward #>
          0   104    00:00.0000000 set-PSReadLineKeyHandler -Key "tab" -Function MenuComplete
          0   105    00:00.0000000 #endregion
          0   106    00:00.0000000

PS C:\Users\luanv
❯ get-error

Exception             :
    Type        : System.Management.Automation.RuntimeException
    ErrorRecord :
        Exception             :
            Type    : System.Management.Automation.ParentContainsErrorRecordException
            Message : The expression after '&' in a pipeline element produced an object that was not valid. It must
result in a command name, a script block, or a CommandInfo object.
            HResult : -2146233087
        CategoryInfo          : InvalidOperation: (:) [], ParentContainsErrorRecordException
        FullyQualifiedErrorId : BadExpression
        InvocationInfo        :
            ScriptLineNumber : 198
            OffsetInLine     : 19
            HistoryId        : -1
            ScriptName       : C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\PSProfiler.psm1
            Line             : $null = & $MeasureScriptblock @Arguments

            PositionMessage  : At C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\PSProfiler.psm1:198
char:19
                               +         $null = & $MeasureScriptblock @Arguments
                               +                   ~~~~~~~~~~~~~~~~~~~
            PSScriptRoot     : C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0
            PSCommandPath    : C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\PSProfiler.psm1
            CommandOrigin    : Internal
        ScriptStackTrace      : at Measure-Script,
C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\PSProfiler.psm1: line 198
                                at <ScriptBlock>, <No file>: line 1
    TargetSite  :
        Name          : AddCommand
        DeclaringType : System.Management.Automation.PipelineOps, System.Management.Automation, Version=7.2.6.500,
Culture=neutral, PublicKeyToken=31bf3856ad364e35
        MemberType    : Method
        Module        : System.Management.Automation.dll
    Message     : The expression after '&' in a pipeline element produced an object that was not valid. It must result
in a command name, a script block, or a CommandInfo object.
    Data        : System.Collections.ListDictionaryInternal
    Source      : System.Management.Automation
    HResult     : -2146233087
    StackTrace  :
   at System.Management.Automation.PipelineOps.AddCommand(PipelineProcessor pipe, CommandParameterInternal[]
commandElements, CommandBaseAst commandBaseAst, CommandRedirection[] redirections, ExecutionContext context)
   at System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput,
CommandParameterInternal[][] pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][]
commandRedirections, FunctionContext funcContext)
   at System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
CategoryInfo          : InvalidOperation: (:) [], RuntimeException
FullyQualifiedErrorId : BadExpression
InvocationInfo        :
    ScriptLineNumber : 198
    OffsetInLine     : 19
    HistoryId        : -1
    ScriptName       : C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\PSProfiler.psm1
    Line             : $null = & $MeasureScriptblock @Arguments

    PositionMessage  : At C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\PSProfiler.psm1:198 char:19
                       +         $null = & $MeasureScriptblock @Arguments
                       +                   ~~~~~~~~~~~~~~~~~~~
    PSScriptRoot     : C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0
    PSCommandPath    : C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\PSProfiler.psm1
    CommandOrigin    : Internal
ScriptStackTrace      : at Measure-Script,
C:\Users\luanv\Documents\PowerShell\Modules\PSProfiler\1.0.3.0\PSProfiler.psm1: line 198
                        at <ScriptBlock>, <No file>: line 1

PS C:\Users\luanv
❯
bedware commented 1 year ago

@LuanVSO I have the same issue. I'm not an expert of pwsh, but a little investigation allowed me to run the script successfully if I removed . (dot) from my functions. I think it somehow connected with that issue https://stackoverflow.com/a/17881960/8413677. I tried to fix it in AstVisitor but I couldn't.

For example this is my function that failed:

 function dotfilesEdit {
     Set-Location $env:DOTFILES && nvim .
 }

@IISResetMe hello 👋 Do you have any idea how to fix it even conceptually?

IISResetMe commented 1 year ago

@bedware can you share the original profile script + the full error message you saw? Please include the version of PowerShell you're using :)

bedware commented 1 year ago

@bedware can you share the original profile script + the full error message you saw? Please include the version of PowerShell you're using :)

PowerShell 7.3.4
Loading personal and system profiles took 1977ms.
╭─ >  pwsh  ~                                                                                                             16:28:14
╰─❯ $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.3.4
PSEdition                      Core
GitCommitId                    7.3.4
OS                             Microsoft Windows 10.0.22621
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

╭─ >  pwsh  ~                                                                                                             16:28:33
╰─❯ measure-Script -Path $PROFILE -Top 5
MethodInvocationException: C:\Users\dmitr\Documents\PowerShell\Modules\PSProfiler\1.0.5\AstVisitor7.class.ps1:15
Line |
  15 |          $res = $element.Visit($this)
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Exception calling "Visit" with "1" argument(s): "Method invocation failed because
     | [System.Management.Automation.Language.TokenKind] does not contain a method named 'Visit'."
InvalidOperation: You cannot call a method on a null-valued expression.
InvalidOperation: The expression after '&' in a pipeline element produced an object that was not valid. It must result in a command name, a script
block, or a CommandInfo object.

    C:\Users\dmitr\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

      Count  Line       Time Taken Statement
      -----  ----       ---------- ---------
          0     1    00:00.0000000 # $OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding =
                                   [System.Text.UTF8Encoding]::new()
          0     2    00:00.0000000 [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
          0     3    00:00.0000000
          0     4    00:00.0000000  $ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
          0     5    00:00.0000000  if (Test-Path($ChocolateyProfile)) {
          0     6    00:00.0000000    Import-Module "$ChocolateyProfile"
          0     7    00:00.0000000  }
          0     8    00:00.0000000
          0     9    00:00.0000000  Import-Module "$env:LOCALAPPDATA\tools\poshgit\dahlbyk-posh-git-9bda399\src\posh-git.psd1"
          0    10    00:00.0000000  oh-my-posh init pwsh --config
                                   "$env:LOCALAPPDATA\Programs\oh-my-posh\themes\bedware.omp.json"| Invoke-Expression
          0    11    00:00.0000000
          0    12    00:00.0000000  # replace 'Ctrl+t' and 'Ctrl+r' with your preferred bindings:
          0    13    00:00.0000000  Set-PsFzfOption `
          0    14    00:00.0000000      -PSReadlineChordProvider 'Ctrl+f' `
          0    15    00:00.0000000      -PSReadlineChordReverseHistory 'Ctrl+r' `
          0    16    00:00.0000000      -PSReadlineChordSetLocation 'Ctrl+g'
          0    17    00:00.0000000
          0    18    00:00.0000000  $env:EDITOR = 'nvim'
          0    19    00:00.0000000  $env:DOTFILES = "$env:USERPROFILE\.dotfiles"
          0    20    00:00.0000000  $env:ChocolateyToolsLocation = "$env:LOCALAPPDATA\tools"
          0    21    00:00.0000000  $env:FZF_CTRL_T_COMMAND = 'fd --type f --path-separator / --hidden'
          0    22    00:00.0000000  $env:FZF_ALT_C_COMMAND = 'fd --type d --path-separator /'
          0    23    00:00.0000000
          0    24    00:00.0000000  Set-Alias -Name vi -Value nvim
          0    25    00:00.0000000  Set-Alias -Name .f -Value dotfiles
          0    26    00:00.0000000  Set-Alias -Name .fe -Value dotfilesEdit
          0    27    00:00.0000000
          0    28    00:00.0000000  function dotfiles {
          0    29    00:00.0000000      Set-Location $env:DOTFILES
          0    30    00:00.0000000  }
          0    31    00:00.0000000  function dotfilesEdit {
          0    32    00:00.0000000      Set-Location $env:DOTFILES && nvim .
          0    33    00:00.0000000  }
          0    34    00:00.0000000

╭─ >  pwsh  ~                                                                                                                                                                                                                16:29:51
╰─❯ vi $profile # comment out "&& nvim."
╭─ >  pwsh  ~                                                                                                                                                                                                                16:30:18
╰─❯ measure-Script -Path $PROFILE -Top 5

    C:\Users\dmitr\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

      Count  Line       Time Taken Statement
      -----  ----       ---------- ---------
          0     1    00:00.0000000 # $OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
          1     2    00:00.0022937 [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
          0     3    00:00.0000000
          1     4    00:00.0005926  $ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
          0     5    00:00.0000000  if (Test-Path($ChocolateyProfile)) {
          1     6    00:00.0008007    Import-Module "$ChocolateyProfile"
          0     7    00:00.0000000  }
          0     8    00:00.0000000
          1     9    00:00.0012642  Import-Module "$env:LOCALAPPDATA\tools\poshgit\dahlbyk-posh-git-9bda399\src\posh-git.psd1"
          1    10    00:00.1799960  oh-my-posh init pwsh --config "$env:LOCALAPPDATA\Programs\oh-my-posh\themes\bedware.omp.json"| Invoke-Expression
          0    11    00:00.0000000
          0    12    00:00.0000000  # replace 'Ctrl+t' and 'Ctrl+r' with your preferred bindings:
          1    13    00:00.0243277  Set-PsFzfOption `
          0    14    00:00.0000000      -PSReadlineChordProvider 'Ctrl+f' `
          0    15    00:00.0000000      -PSReadlineChordReverseHistory 'Ctrl+r' `
          0    16    00:00.0000000      -PSReadlineChordSetLocation 'Ctrl+g'
          0    17    00:00.0000000
          1    18    00:00.0006962  $env:EDITOR = 'nvim'
          1    19    00:00.0006824  $env:DOTFILES = "$env:USERPROFILE\.dotfiles"
          1    20    00:00.0007021  $env:ChocolateyToolsLocation = "$env:LOCALAPPDATA\tools"
          1    21    00:00.0006482  $env:FZF_CTRL_T_COMMAND = 'fd --type f --path-separator / --hidden'
          1    22    00:00.0006952  $env:FZF_ALT_C_COMMAND = 'fd --type d --path-separator /'
          0    23    00:00.0000000
          1    24    00:00.0006434  Set-Alias -Name vi -Value nvim
          1    25    00:00.0006170  Set-Alias -Name .f -Value dotfiles
          1    26    00:00.0006356  Set-Alias -Name .fe -Value dotfilesEdit
          0    27    00:00.0000000
          0    28    00:00.0000000  function dotfiles {
          0    29    00:00.0000000      Set-Location $env:DOTFILES
          0    30    00:00.0000000  }
          0    31    00:00.0000000  function dotfilesEdit {
          0    32    00:00.0000000      Set-Location $env:DOTFILES # && nvim .
          0    33    00:00.0000000  }
          0    34    00:00.0000000

╭─ >  pwsh  ~                                                                                                                                                                                                                16:30:27
╰─❯
IISResetMe commented 1 year ago

Thanks!

I see the problem, the AST Visitor hasn't been updated to handle the short-circuit operators introduced in the latest versions of PowerShell. I'll get it updated and ship a new version sometime next week :)

bedware commented 1 year ago

Thanks! I will be appreciated =)

bedware commented 1 year ago

I just want to mention that in my case it was enough to merge the commands by ; to get around this problem. And that worked, too. But I want to warn you that is not the same as using && which will apply the second command only if the first command was successful.

function dotfilesEdit {
    Set-Location $env:DOTFILES ; nvim .
}
IISResetMe commented 1 year ago

I'm aware they behave differently, it's a question of timing - the chaining operators didn't exist in PowerShell when the latest version of PSProfiler was released :)

IISResetMe commented 1 year ago

@bedware @LuanVSO New release should fix this bug, please give it a spin: https://www.powershellgallery.com/packages/PSProfiler/1.0.5.0 :)

LuanVSO commented 1 year ago

Working fine now, thanks