Tag Archives: $MyInvocation

Adding a Help Parameter to a Function

Edit: There’s a quick addition at the bottom of this post. I tried something else, it worked, and so I decided to include it.

I started writing a PowerShell function to replicate the work of an old executable called ICSWEEP. ICSWEEP “is a command-line utility to clear the Temporary Internet Files Cache and/or the TEMP files folder of ALL user profiles that are NOT in use when this command is executed.” ICSWEEP Information. I may or may not walk through the process of writing this function here; it’s to be determined. What I do want to discuss for sure, however, is the last switch in the above image. It’s /?.

We cannot add ? parameter to a function. Below is an image of the message when we attempt to do that in VS Code.

That’s right, right!? You do remember the $? variable. It stores the execution status of the last command as True or False. Instead of ? as a parameter, I used the value of Help. Therefore, someone can invoke my function and use -Help to get help with the function. But could they?

I sat there, wondering, can you create a parameter of a function so that it’ll return its own, comment-based help? It turns out you can. Here’s the early stage of this function. It consists of the comment-based help, a few parameters, and a small amount of code.

function Clear-UserTemporaryFile {
<#
.SYNOPSIS
    The Clear-UserTemporaryFile command ...
.DESCRIPTION
.PARAMETER <Parameter>
.EXAMPLE
.NOTES
    Name: Clear-UserTemporaryFile
    Author: Tommy Maynard
    Comments: --
    Last Edit: 12/13/2022 [1.0.0]
    Version: 1.0.0
#>
    Param (
        [Parameter()]
        [switch]$ALL,
        [Parameter()]
        [string]$TIF,
        [Parameter()]
        [string]$TMP,
        [Parameter()]
        [string]$SIZE,
        [Parameter()]
        [switch]$HELP
        
    )

    if ($HELP) {
       Get-Help -Name "$($MyInvocation.MyCommand.Name)"
       Exit
    }
}

In the above code, I added a simple if statement. It monitors whether or not the Help parameter is used when the function is invoked. If it is, it runs the Get-Help cmdlet against the name of the executing function—itself—using the $MyInvocation variable and then exits the function.

Clear-UserTemporaryFile -Help
NAME
    Clear-UserTemporaryFile

SYNOPSIS
    The Clear-UserTemporaryFile command ...

SYNTAX
    Clear-UserTemporaryFile [-ALL] [[-TIF] <String>] [[-TMP] <String>] [[-SIZE] <String>] [-HELP] [<CommonParameters>]

DESCRIPTION

RELATED LINKS

REMARKS
    To see the examples, type: "Get-Help Clear-UserTemporaryFile -Examples"
    For more information, type: "Get-Help Clear-UserTemporaryFile -Detailed"
    For technical information, type: "Get-Help Clear-UserTemporaryFile -Full"

At this point, some of you may already know where I’m going to go next. There was something else I had forgotten about every cmdlet and function written. They all have something in common. And what’s that? There is a way to return a command’s help using, of all things, the question mark! Take a look using the built-in Get-Verb and Get-Command cmdlets below.

Get-Verb -?
NAME
    Get-Verb

SYNTAX
    Get-Verb [[-Verb] <string[]>] [[-Group] {Common | Communications | Data | Diagnostic | Lifecycle | Other |
    Security}] [<CommonParameters>]

ALIASES
    None

REMARKS
    Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help.
        -- To download and install Help files for the module that includes this cmdlet, use Update-Help.
        -- To view the Help topic for this cmdlet online, type: "Get-Help Get-Verb -Online" or
           go to https://go.microsoft.com/fwlink/?LinkID=2097026.
Get-Command -?
NAME
    Get-Command

SYNTAX
    Get-Command [[-ArgumentList] <Object[]>] [-Verb <string[]>] [-Noun <string[]>] [-Module <string[]>]
    [-FullyQualifiedModule <ModuleSpecification[]>] [-TotalCount <int>] [-Syntax] [-ShowCommandInfo] [-All]
    [-ListImported] [-ParameterName <string[]>] [-ParameterType <PSTypeName[]>] [<CommonParameters>]

    Get-Command [[-Name] <string[]>] [[-ArgumentList] <Object[]>] [-Module <string[]>] [-FullyQualifiedModule
    <ModuleSpecification[]>] [-CommandType {Alias | Function | Filter | Cmdlet | ExternalScript | Application | Script
    | Configuration | All}] [-TotalCount <int>] [-Syntax] [-ShowCommandInfo] [-All] [-ListImported] [-ParameterName
    <string[]>] [-ParameterType <PSTypeName[]>] [-UseFuzzyMatching] [-UseAbbreviationExpansion] [<CommonParameters>]

ALIASES
    gcm

REMARKS
    Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help.
        -- To download and install Help files for the module that includes this cmdlet, use Update-Help.
        -- To view the Help topic for this cmdlet online, type: "Get-Help Get-Command -Online" or
           go to https://go.microsoft.com/fwlink/?LinkID=2096579.

This means I don’t even need a Help parameter. PowerShell already has this covered, and here’s the proof.

Clear-UserTemporaryFile -?
NAME
    Clear-UserTemporaryFile

SYNOPSIS
    The Clear-UserTemporaryFile command ...

SYNTAX
    Clear-UserTemporaryFile [-ALL] [[-TIF] <String>] [[-TMP] <String>] [[-SIZE] <String>] [-HELP] [<CommonParameters>]

DESCRIPTION

RELATED LINKS

REMARKS
    To see the examples, type: "Get-Help Clear-UserTemporaryFile -Examples"
    For more information, type: "Get-Help Clear-UserTemporaryFile -Detailed"
    For technical information, type: "Get-Help Clear-UserTemporaryFile -Full"

Edit: We know that we were able to use this PowerShell to return the help for our function,

Get-Help -Name "$($MyInvocation.MyCommand.Name)"

but we could’ve just as easily done this:

Invoke-Expression -Command "$($MyInvocation.MyCommand.Name) -?"

The first option invokes the Get-Help cmdlet against our function. The second option invokes the same function that’s already being invoked, adding a -? to the end of the complete command.

Command Type and Name

Sometimes I just need to write something down somewhere. That way, I might be able to find what I need when I need it. Have you been to my website? If so, then just maybe you already know this. Over the last many years, I’ve done this repeatedly. It’s basically why this place exists. Best part, it’s not just for me. It’s for me and the 196.5 people that have visited daily over the last 20 days, and those before them. That excludes weekends, of course, as only some of us PowerShell on the weekend.

As you may know, we have way to determine a command type and command name (think function and function name), from within a command itself, as it executes. I’m tired of looking for this code inside something I’ve already written, or figuring out again, and so here we are. I’ve given myself another chance to “remember” it sooner. Here’s how it’s done.

Function Get-CommandInfo {
    $CmdType = "$($MyInvocation.MyCommand.CommandType)"
    $CmdName = "$($MyInvocation.MyCommand.Name)"
    "The name of this $($CmdType.ToLower()) is $CmdName."
} # End Get-CommandInfo.

In the above function, we create two variables — $CmdType and $CmdName. These hold, as you might expect, the type of command we’re executing and the name of it, as well. These variables are made possible due to the $MyInvocation automatic variable. This variable holds a great deal of information. As you can tell, we’ve used the CommandType and Name nested properties that reside inside the MyCommand property. We then echo a string to include the two values we’ve derived from this variable.

PS > Get-CommandInfo
The name of this function is Get-CommandInfo.

And, there it is; the type and name returned. Now to remember that I’ve written about it here, for that next time I don’t feel like exploring the $MyInvocation variable again, or tracking down the use of these properties somewhere else. Enjoy your Wednesday.

Self-Destruction Script

As a part of some work I’m doing, I’ve decided that I need a specific script to do some final configuration for me. More to come on that in time, perhaps. The point here, however, is that a PowerShell script completes my final configuration, and when this final configuration is complete, I have no need for my script any longer. Can a PowerShell script delete itself? Sure it can.

How does a script delete itself? Easy. It’s a single line, really. However, I have a mildly more interesting example. Before you take a look at the included gif — this really does lend itself to a visual — here are the contents of my self-destruction script. It echos an indication that the script will self-destruct. At this point, it begins a countdown in seconds, from 5 to 1, before removing itself — the script file — from the file system. Take a look, and maybe, just maybe, you’ll find yourself in need of something like this sometime, too.

Write-Output -InputObject 'This script will self-destruct in 5 seconds.'

5..1 | ForEach-Object {
    If ($_ -gt 1) {
        "$_ seconds"
    } Else {
        "$_ second"
    } # End If.
    Start-Sleep -Seconds 1
} # End ForEach-Object.

Write-Output -InputObject 'Self destruction.'

# Here's the command to delete itself.
Remove-Item -Path $MyInvocation.MyCommand.Source

And here’s, the visual representation. It’s a bit small, but you should be able to determine what’s happening. The script executes on the left, and once the countdown is over, DeleteSelfScript.ps1 is removed on the right. It’s deleted itself.

Enjoy the week, and learn something new!

Determine if the Alias, or Function Name was Used

As a Windows PowerShell enthusiast, I am often thinking about PowerShell. Seems logical. Can I do this? What will happen if I do that? Why doesn’t this work!? Well, I had one of those thoughts recently. Can I determine if a function was called using an alias, or if it was called using the function name?

This thought occurred to me because of a change I considered adding to one of my functions. The idea was, that I wanted to prompt the user for confirmation to run a function (within the function), if an alias was used, and not prompt the user when the full function name was used. This lined up with the assumption that an alias could be accidentally entered more easily than the function name, and that we may want to take precautions when the alias was used.

My first consideration was to get the last command entered by the user, by using: (Get-History -Count 1).CommandLine. The problem with that “option,” is that the history isn’t updated until after the function has ended. This means that I wouldn’t know what was entered by the user while the function was running. Take a look at the example below. When I run the function Get-TMHistory the first time, nothing is displayed (in a fresh console), but something is displayed after the second run.

Function Get-TMHistory {
	Get-History -Count 1
}

PS C:\> Get-TMHistory
PS C:\> Get-TMHistory

  Id CommandLine
  -- -----------
   1 Get-TMHistory

I came up with a another idea. Let’s start by creating a new function called Get-TMHowCalled. In addition, we’ll need to create an alias for the function – let’s use ghc. I’ve included the New-Alias cmdlet’s -Force parameter in case there’s already an alias with that name. If there is, then New-Alias acts like Set-Alias, and updates the alias (instead of throwing an error). Note: This option could be problematic if it replaced ghc, and ghc was used for a different purpose.

New-Alias -Name ghc -Value Get-TMHowCalled -Force

Function Get-TMHowCalled {

}

The next thing to do is to construct the logic that will check and determine if the alias was used, or if the full function name was used. This is simple function: check, and echo what was entered by the user.

Function Get-TMHowCalled {
    If () {
        Write-Output -Verbose 'Alias was used.'
    } ElseIf () {
        Write-Output -Verbose 'Function name was used.'
    }
}

The secret here is the $MyInvocation automatic variable and its Line property. This stores what was entered, and so it can be used to determine how the function was called – by alias or by name. The best part, is that the variable is populated when the function is called and can, therefore, be queried inside the function. This variable can only be used in “scripts, functions, and script blocks.” You can read more about it using this command: Get-Help about_Automatic_Variables.

Function Get-TMHowCalled {
    If ($MyInvocation.Line -eq 'ghc') {
        Write-Output -Verbose 'Alias was used.'
    } ElseIf ($MyInvocation.Line -eq 'Get-TMHowCalled') {
        Write-Output -Verbose 'Function name was used.'
    }
}

Hope this proves to be helpful for someone. It might be for me.