Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Using PowerShell Your Way

Posted on June 6, 2022June 7, 2022

I've often told people that I spend my day in a PowerShell prompt. I run almost my entire day with PowerShell. I've shared many of the tools I use daily on Github. Today, I want to share another way I have PowerShell work the way I need it, with minimal effort. This specific task centers on files and folders.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

As you might expect, I am constantly creating, editing, and managing files. I do all of this from a PowerShell prompt. I rarely use the start menu to find a program to launch. My challenge has always been finding the files and folders I've recently been using. Get-ChildItem is naturally the PowerShell tool of choice, but I've finally gotten around to making it work the way I need.

Get-ChildItem Defaults

The default behavior for Get-ChildItem has always been to sort by name.

Get-ChildItem defaults

Directories are listed first, sorted by name, and then files, also sorted by name. Often, I'm trying to remember what folder I was using, and this output doesn't make that easy for me. What I need is a sort by the LastWriteTime property. But I still want folders listed first, followed by files.

Creating a New Command

I can't use a custom format view because that won't do the sorting. In addition, I want to make this an easy process. I know I can run a PowerShell expression like this to get the desired result.

Get-ChildItem | Sort-Object -Property { -Not $_.psiscontainer }, LastWritetime

Sort-Object is sorting pipeline input on two properties. The first is a custom property defined on-the-fly by the scriptblock. The scriptblock looks at the PSIsContainer property, a Boolean value. Files will have a value of True and folders a value of False. I want folders to display first, so I'm using the -Not operator to invert the value. After items are sorted on this property, they are sorted on the LastWriteTime. This makes my life much, much easier. But I'm lazy. I don't want to remember to type all of this, even with auto-completion via PSReadline.

How about a function?

Function Get-MyFolderItem {
    [cmdletbinding()]
    [alias("dl")]
    Param(
        [Parameter(Position = 0)]
        [string]$Path,
        [Parameter(Position = 1)]
        [string]$Flter,
        [switch]$File,
        [switch]$Directory,
        [string[]]$Exclude,
        [string[]]$Include,
        [switch]$Recurse
    )
    #Run Get-Childitem with whatever parameters are specified.
    Get-ChildItem @psboundparameters | Sort-Object -Property { -Not $_.psiscontainer }, LastWritetime
}

This function is nothing more than a wrapper around Get-ChildItem. My function parameters mirror those of Get-ChildItem. I'm splatting $PSBoundParameters to Get-ChildItem and then performing my sort.

using my Get-ChildItem wrapper function

$PSBoundParameters is an intrinsic variable. It is a specialized hashtable that contains every parameter with a value. I also added an alias to my function to make this even easier to use. I can put this function in my PowerShell profile script, and I am set.

Listing by Proxy

But there is another way I can create this command. I could make a proxy function. This is a particular type of function. Proxy functions often replace original commands. Typically, you use proxy functions to add or remove parameters or customize a command's behavior. You often see proxy functions with Just Enough Administration (JEA) deployments. But I could use a proxy function built on Get-ChildItem.

The easiest way to get started is with Copy-Command from my PSScriptTools module.

Copy-Command Get-Childitem -AsProxy -UseForwardHelp -IncludeDynamic

Run this command in the VS Code integrated editor, and it will load a new file into the editor.

If you are building proxy functions, pay attention to your PowerShell version. I created my file in PowerShell 7. Fortunately, the parameters are unchanged in Windows PowerShell, so that I can use my proxy function in both versions. But that may always not be the case.

Here's the proxy function with one addition.

#requires -version 5.1

<#
This is a copy of:

CommandType Name          Version Source
----------- ----          ------- ------
Cmdlet      Get-ChildItem 7.0.0.0 Microsoft.PowerShell.Management

Created: 06 June 2022
Author : Jeff Hicks

Created with Copy-Command from the PSScriptTools module
https://github.com/jdhitsolutions/PSScriptTools

Copy-Command Get-Childitem -AsProxy -UseForwardHelp -IncludeDynamic

#>


Function Get-ChildItem {
    <#
.ForwardHelpTargetName Microsoft.PowerShell.Management\Get-ChildItem
.ForwardHelpCategory Cmdlet

#>
    [CmdletBinding(DefaultParameterSetName = 'Items', SupportsTransactions = $true, HelpUri = 'https://go.microsoft.com/fwlink/?LinkID=113308')]
    Param(

        [Parameter(ParameterSetName = 'Items', Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string[]]$Path,

        [Parameter(ParameterSetName = 'LiteralItems', Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('PSPath')]
        [string[]]$LiteralPath,

        [Parameter(Position = 1)]
        [string]$Filter,

        [switch]$File,

        [switch]$Directory,

        [string[]]$Include,

        [string[]]$Exclude,

        [Alias('s')]
        [switch]$Recurse,

        [uint32]$Depth,

        [switch]$Force,

        [switch]$Name
    )

    Begin {

        Write-Verbose "[BEGIN  ] Starting $($MyInvocation.Mycommand)"
        Write-Verbose "[BEGIN  ] Using parameter set $($PSCmdlet.ParameterSetName)"
        Write-Verbose ($PSBoundParameters | Out-String)

        try {
            $outBuffer = $null
            if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) {
                $PSBoundParameters['OutBuffer'] = 1
            }
            $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-ChildItem', [System.Management.Automation.CommandTypes]::Cmdlet)
            #sort the output with directories first and then sorted by last write time
            $scriptCmd = { & $wrappedCmd @PSBoundParameters | Sort-Object -Property { -Not $_.psiscontainer }, LastWritetime }
            $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
            $steppablePipeline.Begin($PSCmdlet)
        }
        catch {
            throw
        }

    } #begin

    Process {

        try {
            $steppablePipeline.Process($_)
        }
        catch {
            throw
        }


    } #process

    End {

        try {
            $steppablePipeline.End()
        }
        catch {
            throw
        }
        Write-Verbose "[END    ] Ending $($MyInvocation.Mycommand)"

    } #end

} #end function Get-ChildItem

The proxy function is also "wrapping" Get-ChildItem.

 $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-ChildItem', [System.Management.Automation.CommandTypes]::Cmdlet)

All I'm doing is sorting the output.

$scriptCmd = { & $wrappedCmd @PSBoundParameters | Sort-Object -Property { -Not $_.psiscontainer }, LastWritetime }

All I have to do is dot-source the proxy function script. From now on, whenever I run Get-Childitem, it will use my proxied version.

In my proxy function, I haven't changed anything about how the underlying command, Get-ChildItem, runs. All I've done is add sorting. I can continue to use Get-Childitem as I always have. But now, in the file system, I get the desired output.

Summary

Get-Command confirms I am running a custom version of Get-Childitem.

To be honest, I'm not sure which approach I'll use long-term. For now, I'm loading my wrapper function with the dl alias and the proxy function in my PowerShell profile script. I'll have to see if there are any limitations to the proxy function that I haven't considered yet.

If you need to bend a PowerShell command to meet your needs, I hope my examples can serve as templates for solutions.

Update

After using my proxy function for a bit, I realized I neglected to include the dynamic parameters -File and -Directory. I updated the code samples.


Behind the PowerShell Pipeline

Share this:

  • Share on X (Opens in new window) X
  • Share on Facebook (Opens in new window) Facebook
  • Share on Mastodon (Opens in new window) Mastodon
  • Share on LinkedIn (Opens in new window) LinkedIn
  • Share on Reddit (Opens in new window) Reddit
  • Print (Opens in new window) Print
  • Email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

3 thoughts on “Using PowerShell Your Way”

  1. Pingback: Using PowerShell Your Way - The Lonely Administrator - Syndicated Blogs - IDERA Community
  2. Pingback: Changing Default Powershell Behavior via Commands or Proxies – Curated SQL
  3. Pingback: Windows Powershell Tips and Tutorial

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2026 The Lonely Administrator | Powered by SuperbThemes!
%d