Skip to content

Instantly share code, notes, and snippets.

@ninmonkey
Last active April 21, 2023 17:51
Show Gist options
  • Save ninmonkey/47b0978298229a35e517fb200ad0d1ca to your computer and use it in GitHub Desktop.
Save ninmonkey/47b0978298229a35e517fb200ad0d1ca to your computer and use it in GitHub Desktop.
public dump

Experimental dumping starts here Huge TOC.

2022-12-12

Regex tips, answering reddit:

$regex = @'
(?x) # this lets you use padding and comments
     # this is your regex, untouched

    ^
    (\w+)
    =
    (\w*)
    ;   
'@

$regexNamed = @'
(?x) # same thing, Except I named the groups
    ^
    (?<Heading1>\w+)
    =
    (?<Heading2>\w*)
    ;   
'@

Regex parsing variations

$sample = @'
attachmentname=Name1;
Attachmentislarge=False;
Deleteattachment=;
Attachmentispasswordprotected=True;
Attachmentcontainswords=;
'@

$regex = @'
(?x) # this lets you use padding and comments
     # this is your regex, untouched

    ^
    (\w+)
    =
    (\w*)
    ;   
'@

$regexNamed = @'
(?x) # same thing, Except I named the groups
    ^
    (?<Heading1>\w+)
    =
    (?<Heading2>\w*)
    ;   
'@
$RegexLineEnding = '\r?\n' # this means linux or windows act the same

'### Part 0 : $matches'
$results0 = $sample -split $RegexLineEnding | ForEach-Object { 
    if ($_ -match $regexNamed) {     
        $matches.remove(0)
        [pscustomobject]$matches
    }
}
$results0 | Format-Table Heading1, Heading2 -AutoSize

'### Part 1 : [Regex]::Matches()'
$results1 = $sample -split $RegexLineEnding | ForEach-Object { 
    $Line = $_
    $search = [Regex]::Matches( $Line, $regex )
    $search
    # $search | ft  -auto
} 
# $results1 | Format-Table Heading1, Heading2 -AutoSize
$results1 | ft -AutoSize

'### Part 2 : '
$results2 = $sample -split $RegexLineEnding | ForEach-Object { 
    $Line = $_
    "Iter: Line = $Line" | Write-Debug  

    # for this data, $Rest should always be empty
    # Unless you remove the '2', and there is another '='
    # Under those conditions, rest would contain something 
    $Header1, $Header2, $Rest = $Line -split '=', 2 
    if($null -ne $Rest) { 
        write-warning "Unexpected Regex Result: '$Line' => '$Rest' is not null!"
    }
    [pscustomobject]@{ 
        Header1 = $Header1
        Header2 = $Header2 -replace ';$', ''
    }
}
$results2 
# | Format-Table Heading1, Heading2 -AutoSize

-Split has an optional argument to set the max number of segments We can take advantage of that to make parsing text easier. I don't have to add logic for more than 2 segments, it will always have 2 or less

how to verify:

('foo=bar=cat' -split '=', 2).count -eq 2 # true
('foo=bar=cat' -split '=').count -eq 2    # false

2022-12-11

He wanted a way to re-use filters

function filterProcess { 
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        $InputObject,

        [ArgumentCompletions('x64', 'x86')]
        [string]$Architecture,

        [ArgumentCompletions('MSI')]
        [string]$Type
    )
    process {
        # if any condition is not successful, return without emitting anything
        # 'return' should only be used for control flow, like this

        # If the parameter isn't declared, then don't filter by that field
        if ( $Architecture ) {
            if ($InputObject.Architecture -ne $Architecture) {
                return
            }
        }
        if ($Type) { 
            if ($InputObject.Type -ne $Type) {
                return
            }                        
        }

        # All filters, passed, so output
        $InputObject                
    }
}

# ps | get-random -count 20
# hr
$samples = @( 
    [pscustomobject]@{
        Architecture = 'x86'
        Type         = 'other'
    } 
    [pscustomobject]@{
        Architecture = 'x64'
        Type         = 'MSI'
    } 
)

# if using pester:
#   ($samples | filterProcess).count | Should -be 2

$samples | filterProcess  # count is 2
'---'
$samples | filterProcess -Architecture x64 # count is  1
'---'
$samples | filterProcess -Architecture x86 -Type MSI # count is 0

2022-11-14

extra "hidden" terminal colors

"workbench.colorCustomizations": {
    // for discord
   "terminal.ansiBlack": "#ff9a04", //"#000000",
   "terminal.ansiBlue": "#ff9a04", //"#2472c8",
   "terminal.ansiBrightBlack": "#ff9a04", //"#666666",
   "terminal.ansiBrightBlue": "#ff9a04", //"#3b8eea",
   "terminal.ansiBrightCyan": "#ff9a04", //"#29b8db",
   "terminal.ansiBrightGreen": "#ff9a04", //"#23d18b",
   "terminal.ansiBrightMagenta": "#ff9a04", //"#d670d6",
   "terminal.ansiBrightRed": "#ff9a04", //"#f14c4c",
   "terminal.ansiBrightWhite": "#ff9a04", //"#e5e5e5",
   "terminal.ansiBrightYellow": "#ff9a04", //"#f5f543",
   "terminal.ansiCyan": "#ff9a04", //"#11a8cd",
   "terminal.ansiGreen": "#ff9a04", //"#0dbc79",
   "terminal.ansiMagenta": "#ff9a04", //"#bc3fbc",
   "terminal.ansiRed": "#ff9a04", //"#cd3131",
   "terminal.ansiWhite": "#ff9a04", //"#e5e5e5",
   "terminal.ansiYellow": "#ff9a04", //"#e5e510",
   "terminal.border": "#ff9a04", //"#80808059",
   "terminal.dropBackground": "#ff9a04", //"#53595d80",
   "terminal.findMatchBackground": "#ff9a04", //"#515c6a",
   "terminal.findMatchHighlightBackground": "#ff9a04", //"#ea5c0055",
   "terminal.foreground": "#ff9a04", //"#cccccc",
   "terminal.selectionBackground": "#ff9a04", //"#264f78",
   "terminalCommandDecoration.defaultBackground": "#ff9a04", //"#ffffff40",
   "terminalCommandDecoration.errorBackground": "#ff9a04", //"#f14c4c",
   "terminalCommandDecoration.successBackground": "#ff9a04", //"#1b81a8",
   "terminalOverviewRuler.cursorForeground": "#ff9a04", //"#a0a0a0cc",
   "terminalOverviewRuler.findMatchForeground": "#ff9a04", //"#d186167e",
   "terminal.inactiveSelectionBackground": "#ff9a04", //"#3a3d41",
   "terminalCursor.background": "#ff9a04", //"#ff9a04",
   "terminal.inactiveSelectionBackground": "#ff9a04", //"#3a3d41",
   "terminal.inactiveSelectionBackground": "#ff9a04", //"#ffff00",
   "terminal.background": "#ff9a04", // null,
   "terminal.findMatchBorder": "#ff9a04", // null,
   "terminal.findMatchHighlightBorder": "#ff9a04", // null,
   "terminal.selectionForeground": "#ff9a04", // null,
   "terminal.tab.activeBorder": "#ff9a04", // null,
   "terminalCursor.background": "#ff9a04", // null,
   "terminalCursor.foreground": "#ff9a04", // null,


   "editorLineNumber.foreground": "#4f4f4f", // subtle 
   "editorLineNumber.foreground": "#4f4f4f69", // subtle 
   // "symbolIcon.numberForeground": "#ff0000",
   // "minimap.background": "#ff000021",
   // "minimap.errorHighlight": "#ff0000",
   "errorForeground": "#bd0e0e9c",
   // "editorGhostText.border": "#c5bb2d7a",
   "problemsErrorIcon.foreground": "#1100ff",
   "editorWarning.foreground": "#c300ff00", // when invis, makes the popup error lens empty
   "editorWarning.background": "#fffb1e21",
   "editorWarning.background": "#fffb1e3b",
   "editorWarning.background": "#fffb1e3a",


   // "minimap.background": ,
   // "editorLineNumber.activeForeground": "#a5a5a5", // bright
   // "editorLineNumber.activeForeground": "#7e7e7e", // subtle
   // "editorLineNumber.activeForeground": "#a0a0a0cc", // subtle
   // "foreground": "#ff0000" // mostly the UI
   // "foreground": "#b6b6b6",
   // "foreground": "#b6b6b681",
   // "foreground": "#b6b6b63d", // crazy affects lots of things
   // "foreground": "#ffffffa6", // crazy affects lots of things
   // "foreground": "#ffffffcc", // crazy affects lots of things
   // "tab.activeModifiedBorder": "#ff0000"
    },
# 2
$existingRender = @( 
   "${fg:\gray40}${bg:gray25}"
   "Collections.Generic"
   "${fg:\gray80}${bg:gray45}"
   'List' 
   $lastColor
   '['
   "${fg:orange}"
   'Hashtable'
   "${fg:\gray80}${bg:gray45}"
   ']'
   $lastColor  
) -join ''
$existingRender
hr
$lastColor = "${fg:\gray40}${bg:gray25}"
@( 
   "${fg:\gray40}${bg:gray25}"
   "Collections.Generic"
   "${fg:\gray80}${bg:gray45}"
   'List[Hashtable]'
   $lastColor  
   '$hl = ....'
) -join ''
$PSStyle.Reset

2022-10-10

using gh to automatically download all NFL releases

datasets from https://github.com/nflverse/nflverse-data/releases using gh

# Source: <https://gist.github.com/ninmonkey/47b0978298229a35e517fb200ad0d1ca#2022-10-10>

$nativeGH = Get-Command -CommandType Application -Name 'gh' -ea ignore
if(-not $NativeGH) {
    throw "Required 'gh' command not installed, see: <https://cli.github.com/>"
}

function find_releaseNames {
    # autodetect rleases
    $q = & $nativeGH release list --repo nflverse/nflverse-data
    $q | %{ $_ -split '\s+' | s -First 1 }
}

function Hr {
    # horizontal rule
    $w = $host.ui.RawUI.WindowSize.Width
    $chars = '-' * $w -join ''
}

function collect_NFLRelease {
    [CmdletBinding()]
    param(
        <#
        .SYNOPSIS
            sugar to invoke 'gh release download's
        .LINK
            https://cli.github.com/manual/gh_release
        .LINK
            https://stedolan.github.io/jq/manual/v1.6/
        #>
        # 4oot directory, will create subdirectories
        [Alias('Path')][Parameter(Mandatory)]$BasePath
    )
    if( -not (Test-Path $BasePath)) {
        mkdir -path $BasePath
    }

    Set-Location $BasePath

    $items = find_releaseNames
    $items | %{
        $name = $_
        'writing "{0}" from nflverse/nflverse-data release to "{1}"' -f @(
            $name
            Join-Path '.' $Name
        ) | Write-Information
        & $nativeGH release download $name --dir $name --repo nflverse/nflverse-data
    }
}

collect_NFLRelease -infa 'continue' -path 'C:\nin_temp\nfl-src'

2022-10-09

Silly nested format expressions using @()

Write-ConsoleHorizontalRule -fg '#ebcb8b' 1
    $files ??= Get-ChildItem $Env:USERPROFILE\Downloads
    
# for integers with commas, use:   'n0'   or 'n2'
# for decimals with 2 places use:  'f2'  
    $files
    | Sort-Object LastWriteTime -Descending -Top 10
    | ForEach-Object {
        '{0} {1} mb [ {2} bytes ]' -f @(
            $_.Name | Write-ConsoleColorZd -Color '#cc6e6e'
            '{0:f2}' -f @( $_.Length / 1mb  )
                | Write-ConsoleColorZd 'gray95'  -BackgroundColor '7f91b2' #'495366'

            '{0:n0}' -f @( $_.Length ) | Write-ConsoleColorZd 'gray60'  #'#ebcb8b'  

        )
    } | ForEach-Object { $_.ToString().Padleft(90, '-') }

    Write-ConsoleHorizontalRule -fg '#ebcb8b' 1 
ls $Env:UserProfile\Downloads -file
| sort Length -Descending -Top 10
| % { 
    '{0} {1:f2} mb' -f @(
        $_.Name
        $_.Length / 1mb
    )
}
# This line is optional, it right-aligns the text
| %{ $_.ToString().Padleft(90, '-') }

2022-10-09

Autocomplete calculator modes

function Calculate {
    [Alias('Add', 'Sub', 'Div', 'Pow')]
    [CmdletBinding()]
    param(

       [Parameter(Mandatory)][object]$LeftOperand,
       [Parameter(Mandatory)][object]$RightOperand,

       [ValidateSet('+', '/', '-', '^')]
       [Parameter()][string]$Operation
    )

    $curOp =  switch ($PSCmdlet.MyInvocation.InvocationName) {
        'Add' { '+' }
        'Sub' { '-' }
        'Div' { '/' }
        'Pow' { '^' }
        default { $Operation }
    }
    switch($curOp) {
        '+' { $LeftOperand + $RightOperand }
        '/' { $LeftOperand / $RightOperand }
        '-' { $LeftOperand - $RightOperand }
        '^' {  [math]::pow( $LeftOperand, $RightOperand ) }
        default { throw "Unhandled Operation: $Operation"}
    }
}

Add 2 3
pow 2 9
Sub 9 10
Div 2 3

sugar for invoking and sorting find-member, used to find excel

Excel

$Import = gi -ea stop .\input-bold-text.xlsx
$pkg = Open-ExcelPackage $Import

$t = [ordered]@{}
$t.Sheet = $pkg.Sheet1
$t.Table = $pkg.Sheet1.Tables['Table1']
$t.cols = $t.Table.Columns
$t.col2 = $t.table.Columns[1]
$t.cellQuery = $t.Sheet.Cells | ? text -Match 'cat.*cat'
$t.cellQuery | ft

[OfficeOpenXml.ExcelRangeBase]$c = $t.cellQuery
$t.rich = $c.RichText

[OfficeOpenXml.Style.ExcelRichTextCollection]$rich = $t.rich
[OfficeOpenXml.Style.ExcelRichText]$firstRich = $t.rich[0]

$rich | select bold, text
| Join-String { $_.Bold, $_.Text }

function basicHtml {
    <#
    .SYNOPSIS
    .EXAMPLE
        Pwsh>
        basicHtml -RichCollection $rich

        # or
        $c | basicHtml

        # output: 'cat <b>dog</b> cat'


    #>
    [CmdletBinding()]
    param(
        <#
        You can pipe a
            [OfficeOpenXml.ExcelRangeBase] , or
            [OfficeOpenXml.Style.ExcelRichTextCollection]
        #>
        [Alias('RichText')]
        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)]
        [OfficeOpenXml.Style.ExcelRichTextCollection]$RichCollection
    )
    process {
        foreach($item in $RichCollection) {
            @(
                $item.Bold ? '<b>' : ''
                $item.Text
                $item.Bold ? '<b>' : ''
            ) -join ''
        }
    }
}

Close-ExcelPackage -ExcelPackage $pkg

wrapper

function Inspect {
    # pipe things to me
    process {
        hr 1
        $_.GetType().FullName
        | label 'Type'
        $_ | b.fm
        hr
        $_ | iot2

    }
}

Sugar to find and sort find-member

import-module ClassExplorer -ea stop
function b.wrapLikeWildcard {
    <#
    .SYNOPSIS
        converts like-patterns to always wrap wildcards
    .example
        'cat', 'CAT*' | b.wrapLikeWildcard
        '*cat*', '*cat*
    #>
   process {
    @( '*', $_.ToLower(), '*') -join '' -replace '\^\*{2}', '*' -replace '\*{2}$', '*'
   }
}

function b.fm {
    <#
    .SYNOPSIS
        Find member, sugar to show full name, and enforce wildcard
    .EXAMPLE
        Pwsh> $eis | b.fm fetch
    #>
   param( [string]$Pattern )
   process {
      $pattern = $pattern | b.wrapLikeWildcard
      # $pattern = @( '*', $patter.ToLower(), '*') -join '' -replace '\^\*{2}', '*'

        if($Pattern) {
            $_ | ClassExplorer\Find-Member $Pattern | Sort  Name | ft Name, DisplayString
        } else {
            $_ | ClassExplorer\Find-Member | Sort  Name | ft Name, DisplayString
        }
   }
}

2022-10-05

fd native command usage

sort: directory, then length

fd -d2 --changed-within 2days --search-path (get-item $env:APPDATA) --color=always
| Sort { 
    $item = $_ | StripAnsi | Get-Item
    $kind =  $item.Extension
    $isDir = Test-IsDirectory $Item    

    $isDir, $item.Length
} -Descending

group: files or folders

Pwsh>
    fd -d2 --changed-within 2days --search-path (get-item $env:APPDATA) --color=always
    | group {
        $item = $_ | StripAnsi | Get-Item
        $isDir = Test-IsDirectory $item
        return $isDir
    } | ft -AutoSize

Count Name  Group
----- ----  -----
   41 False {C:\Users\cppmo_000\AppData\Roaming\Code\Preferences, C:\Users\cppmo_000\A
   31 True  {C:\Users\cppmo_000\AppData\Roaming\Apple Computer\Logs\, C:\Users\cppmo_0


fd -d2 --changed-within 2days --search-path (get-item $env:APPDATA) --color=always
| sort { 
    $item = $_ | StripAnsi | Get-Item
    $isType = $item.Extension -in @('.ini', '.png')
    $when = [datetime]::Now -gt $item.LastWriteTime.AddHours(-2)
    return ($when, $isType, $item.Name)    
}

resolveAliasedCommand alias to FunctionInfo

Minimum use
function resolveAliasedCommand {
    param( [string]$Name, [string]$Module = 'utility' )
    (get-alias | ? Source -match $Module | ? Name -match $Name).ReferencedCommand
}
Fancy
function resolveAliasedCommand {
    <#
    .SYNOPSIS
        converts patterns and aliases, resolving to the actual functions
    .example
        Pwsh> from->Alias '.' -Module Ninmonkey | sort Name, Source -Unique

        Pwsh> (Get-Alias 'at').ReferencedCommand | editFunc -infa Continue
        loading:... <G:\2021-github-downloads\dotfiles\SeeminglyScience\PowerShell\Utility.psm1>
    #>
    # [Alias('to->Func')]
    [Alias('from->Alias')]  
    [OutputType('System.Management.Automation.FunctionInfo')]
    [CmdletBinding()]
    param(
        # name/alias
        [Parameter(Mandatory, Position = 0)][string]$Name = '.',

        # suggest some common ones
        [Parameter(Position = 1)][ArgumentCompletions(
            'ClassExplorer', 'Utility', 'Microsoft.PowerShell', 'Ninmonkey',
            'PSReadLine', 'PSScriptAnalyzer', 'ImportExcel', 'ugit'
        )][string]$Module = '',

        # default is regex, switch to 'normal' wildcards
        [Alias('Like')][switch]$UsingLike
    )
    if ($UsingLike) {
        # change empty regexes to match everything
        if( $Name -eq '.' ) {  $Name = '*' }
        if( [string]::IsNullOrWhiteSpace( $Module ) ) {
             $Module = '*'
        }
        (Get-Alias | ? Source -like $Module | ? Name -Like $Name).ReferencedCommand
       return
    }

    (Get-Alias | ? Source -Match $Module | ? Name -Match $Name).ReferencedCommand
}

format-clip : Invoke-Formatter Paste

Minimum use
function formatClip { 
   # PSScriptAnalyzer 1.21 supports pipeline input
   # the current version Invoke-Formatter added pipeline support
   Get-Clipboard | Invoke-Formatter | Set-Clipboard
}
with -FancyPants
function formatClip { 
    <#
    .EXAMPLE
        Pwsh>   # format, then copy the result
                formatClip

        Pwsh>   # format, then copy the result
                formatClip -PassThru
                        
                    <prints formatted results to console>

        Pwsh>   # format, then copy the result
                formatClip -FancyPants

                    <prints syntax highlighted, and formatted results to console>
    .NOTES
        future: Set-ClipBoard should write-info; user can use -Infa Continue; accept pipeline input
    #>
    # PSScriptAnalyzer 1.21 supports pipeline input
    # either [1] by default save to clipboard [2] else print 
    param(
        [switch]$PassThru, [switch]$Fancy )

    $render = Get-Clipboard | Invoke-Formatter    

    if ($fancy) { $Render | Bat -l ps1 --force-colorization ; return }
    if ($PassThru) { $render; return }
    $render | Set-Clipboard
    
}

formatClip -Fancy

Toc

↰ Back To Top

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment