PowerShell: Ctrl+space won't work in any code declared within a function

Markus Johnsson 21 Reputation points
2022-09-26T08:38:16.58+00:00

Hello, friends!

This is my first post on this forum and I am fairly new to PowerShell and have been experimenting with it on and off in the past and I have recently started doing a bit of scripting so my knowledge isn't that solid yet so, please, bare with me. (However, please know that I've read all relevant documentation I could find without finding any answers to my little problem.)

My problem is very trivial but oh so disturbing: I like the PowerShell feature Ctrl+Space and when I write scripts with parameters but where the code is not declared within a function, Ctrl+Space works just fine. However, when I wrap the code in a function body then simply nothing at all happens when I press Ctrl+Space. No parameter options show up any longer. I mean surely this should work in functions?

I take a most minimal example that works with Ctrl+Space just to make clear what works and not, while sticking to the simplest possible (almost):

param (  
    [Parameter()]  
    [string]  
    $Var = "Test"  
)  
    $ParamValue = $Var  
    $ParamValue  
  

But as soon as this snippet is wrapped in a function...

Function FunctionName {  
    param (  
        [Parameter()]  
        [string]  
        $Var = "Test"  
    )  
        $ParamValue = $Var  
        $ParamValue  
}  
FunctionName  

...Ctrl+Space will simply not show any parameters. Also, this means that my parameter variables are NOT recognized either so I can't complete or cycle through mine and the systems parameter names with TAB either, which is a horrible ordeal! :D

On Windows 10 and Server 2019 I am working with PowerShell Version 7.2.6 as my standard engine but I also use the latest Preview build and Windows PowerShell 5.1 for testing purposes. I have the same issues in all of these environments when it comes to this issue.

Have any of you experienced this behavior as well and do you know what I'm doing wrong?

I understand that this is not a significant problem but I felt it is still a feature that simply should work - no matter who wrote the script - since the feature is there for a reason, right? And it should work in any case.

I'm prepared for that, whatever the cause for this issue may be, it is most certainly located on my side but I'm at a total loss as to what it may be, but I would really like to know why this won't work and I would really appreciate any kind of helping hands here: links to or names of documents that will explain why it won't work in functions (which is extremely disturbing) or that will treat the subject so I can get some sleep tonight ; )

(note: I'm couldn't provide the tags I wanted because I was forced to choose among existing ones but sure this question must be valid even here?)

Windows 10
Windows 10
A Microsoft operating system that runs on personal computers and tablets.
10,618 questions
Windows Server PowerShell
Windows Server PowerShell
Windows Server: A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.PowerShell: A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
5,364 questions
0 comments No comments
{count} votes

Accepted answer
  1. Rich Matheisen 44,776 Reputation points
    2022-10-04T18:56:14.16+00:00

    Well, yes, the Ctrl+Space works with a script that contains no functions. But consider this: if the SCRIPT file contains a function, the FUNCTIONS parameters aren't exposed until the function is loaded into the session. Thus, the need to use dot-sourcing unless it's you intention to use the function in the current PowerShell session.

    But if your intention is to run a script and not pollute your PowerShell sessions memory with functions that make no sense to retain (e.g., they specific the script in which they reside and are of no use outside the script), then you don't dot-source the script.

    #This using the file Get-TestBBB which contains a function  
    #  
    #  
    # When run as a script (without dot-sourcing), the parameter is passed,  
    # but within the script the function Get-TestBBB is invoked with no parameter.  
    # The result? The default value of the Test parameter (an empty string)  
    # is used.  
    PS C:\junk> .\get-testbbb.ps1 -Test "Blah"  
    It doesn't work  
    PS C:\junk>  
      
    # The same thing happens because the function is invoked with no value  
    # from within the ps1 file.  
    PS C:\junk> . .\get-testbbb.ps1 -Test "Blah"  
    It doesn't work  
      
    # But NOW, becasue the script was dot-sourced, the funtion Get-TestBBB  
    # is preserved in this session's "memory"  
      
    PS C:\junk> gci function:get-*  
      
    CommandType     Name                                               Version    Source  
    -----------     ----                                               -------    ------  
    Function        Get-Verb  
    Function        Get-FileHash                                       3.1.0.0    Microsoft.PowerShell.Utility  
    Function        Get-TestBBB  
      
    # NOW, we only have to invoke the function. The function invokation WITHIN  
    # the script isn't part of the function.  
      
    PS C:\junk> get-testbbb -test "It Works!"  
    It Works!  
      
    # And, so does Ctrl+Space  
    PS C:\junk> get-testbbb -Test  
    Test                 Debug                WarningAction        ErrorVariable        InformationVariable  OutBuffer  
    Verbose              ErrorAction          InformationAction    WarningVariable      OutVariable          PipelineVariable  
      
    [string] Test  
    

11 additional answers

Sort by: Most helpful
  1. Rich Matheisen 44,776 Reputation points
    2022-09-26T15:04:06.027+00:00

    Do you encounter the same problem if you add [CmdletBinding()] between the "Function . . . {" and the "param" lines?

    function A{  
        [CmdletBinding()]  
        param (  
            [Parameter()]  
            [string]  
            $Var1  
        )  
    }  
      
    

    Is the problem happening in an editor, or at the prompt in a PowerShell session?

    You may be encountering a problem with PSReadLine. See here: https://learn.microsoft.com/en-us/powershell/module/psreadline/about/about_psreadline?view=powershell-7.2


  2. Limitless Technology 43,941 Reputation points
    2022-09-26T15:09:33.523+00:00

    Hello there,

    I guess this is by design, the CTRL + Space doesn't work only when declared in function because when it comes to the Function-Calls, PowerShell is fairly different from other programming.

    PowerShell sequentially processes line-by-line in top-down order, hence the function must be defied before that function is called.

    In Windows PowerShell ISE (or Visual Studio Code) if a function-call appears to be working even though the function-definition is defined below the function-call, (beware) this is because it's cached in memory from a previous execution(s), which too will fail as soon as you update the function-definition.

    May be you can request for an feature addition. Send feedback to Microsoft with the Feedback Hub app https://support.microsoft.com/en-us/windows/send-feedback-to-microsoft-with-the-feedback-hub-app-f59187f8-8739-22d6-ba93-f66612949332

    I hope this information helps. If you have any questions please let me know and I will be glad to help you out.

    ----------------------------------------------------------------------------------------------------------------------------------

    --If the reply is helpful, please Upvote and Accept it as an answer--


  3. Markus Johnsson 21 Reputation points
    2022-09-28T07:05:35.317+00:00

    I would also like to add a fact that might be obvious to you but for the sake of clarity: when I define my parameters inside a function body I cannot not only cycle through the parameters but worse, I can't even use my parameters! If I have a parameter called ComputerName and I run the script like we normally do:

    PS> ScriptName.ps1 -ComputerName COMPUTER1  
    

    Then the script can't find my parameter variable(s) and either fail or continue without the value I supplied in the prompt. Nor can I use the -Verbose switch and its friends even if I have declared [CmdletBinding] correctly. It all only works outside a function. This is weird to me. I use different editors and different shells and versions of Powershell to test my scripts but no go when a functions shows its head and I really need them! : )


  4. Markus Johnsson 21 Reputation points
    2022-09-30T09:46:24.133+00:00

    I want to show you what the most disturbing thing - and the most important thing here - is with this. It is not only the fact that I can't list the parameters using CTRL + SPACE - it is the fact that I can't use the parameters at all when I run the script and if the code is inside a function! It's as if they don't exist and that is what made me start this thread, to begin with.

    Let me show you what happens to me when I have code inside a function. I put a bit of code, with one mandatory parameter named -ComputerName, in a script and it works if I just run the script using its name, but when I run the script with the parameter -ComputerName and supply it with a value then this is what happens:

    246398-failing-function.png

    As you can see, PowerShell disregards the parameter -ComputerName and its value and immediately asks me to supply it with a computer name even though this parameter is defined in the script with the default value of 'localhost'.

    Here is the script too so you can have a look:

    Function Get-PhysicalAdapter {      
        [CmdletBinding()]  
        param (  
            [Parameter(Mandatory=$true,HelpMessage="Enter the computer name to query")]  
            [string]$ComputerName = 'localhost'  
        )  
        if ($ComputerName -eq 'localhost')  
        {  
        Write-Verbose "Getting physical network adapters from localhost"  
        Get-CimInstance win32_networkadapter |  
            Where-Object { $_.PhysicalAdapter } |  
            Select-Object MACAddress,AdapterType,DeviceID,Name,Speed  
            Write-Verbose "Finished running command"  
        }  
        else  
        {  
            $creden = Get-Credential              
            $session = New-CimSession -ComputerName $ComputerName -Credential $creden  
            Invoke-Command -ScriptBlock {   
                Write-Verbose "Getting physical network adapters from $ComputerName"  
                Get-CimInstance win32_networkadapter -CimSession $session |  
                    Where-Object { $_.PhysicalAdapter } |  
                    Select-Object MACAddress,AdapterType,DeviceID,Name,Speed  
                Write-Verbose "Removing CimSession."  
                Remove-CimSession $session  
            }  
        Write-Verbose "Finished running command"  
        }  
    } Get-PhysicalAdapter  
    

    But if I remove the function statement here:

    Function Get-PhysicalAdapter {  
    } Get-PhysicalAdapter  
    

    It will both take my parameter values successfully AND show me the list of all parameters when I hit CTRL + SPACE.

    Even if you find flaws in the script it doesn't really matter because what's relevant here is that parameters won't work for me if used inside a function, without the function it'll work.

    I'm very grateful for you trying to help me solve this but it seems this will remain a headscratcher. And thank you for trying out the functions in your environment for me. Now I know that something definitely is wrong on my side but figuring out what will be difficult for me. It's just so disturbing and it makes no sense at all.

    0 comments No comments