pf-string.ps1
function Get-CharRange([char]$Start = 'A', [char]$End = 'Z') { $startLetter = [int]$Start $endLetter = [int]$End for ( $letter = $startLetter; $letter -le $endLetter; $letter++) { [char]$letter } } function Get-Chars([switch]$word,[switch]$number,[switch]$symbol, [switch]$UpperCase, [switch]$LowerCase) { if ($word -or $UpperCase) { Get-CharRange 'A' 'Z' } if ($word -or $LowerCase) { Get-CharRange 'a' 'z' } if ($number) { Get-CharRange '0' '9' } if ($symbol) { $symbolSet = '!%()[]{}@#=*+-_?|' # & not included as not easy include in xml configurations for($i = $symbolSet.Length - 1; $i -ge 0; $i--) { $symbolSet[$i] } } } function Get-Chars:::Test { ( Get-Chars -UpperCase ).count -eq 26 | assert ( Get-Chars -LowerCase ).count -eq 26 | assert ( Get-Chars -word ).count -eq 26*2 | assert ( Get-Chars -number ).count -eq 10 | assert ( Get-Chars -symbol ).count -gt 8 | assert } function Get-RandomString ($length = 20, $seed = [Guid]::NewGuid(), $validChars) { if ($validChars) { $valid = $validChars } else { $valid = Get-Chars -word -number -symbol } if ($seed) { $seed = $seed.GetHashCode() $randomizer = New-Object 'System.Random' -ArgumentList $seed } [string]$result = '' for ($i = $length; $i -gt 0; $i --) { $ch = $randomizer.Next($valid.Length) $ch = $valid[$ch] $result += $ch } $result } function Get-RandomString:::Example { Get-RandomString -seed 'AnyObject' -length 23 -validChars (Get-Chars -LowerCase -number ) } function Get-HeadAndTail{ Param( [Parameter(ValueFromPipeline=$true)] [String]$string, $fieldSeparator = ':', [Switch]$RightToLeft, [String]$FieldHead = 'Head', [String]$FieldTail = 'Tail' ) process { if (-not $string) { return } $pos = if ($RightToLeft) { $string.LastIndexOf($fieldSeparator) } else { $string.IndexOf($fieldSeparator) } if ($pos -eq -1) { return [PSCustomObject]@{ $FieldHead = $string; $FieldTail = "" } } $head = $string.Substring(0,$pos) $tail = $string.Substring($pos+1) $result = [PSCustomObject]@{ $FieldHead = $head; $FieldTail = $tail } if ($RightToLeft) { return [PSCustomObject]@{ $FieldHead = $result.Tail; $FieldTail = $result.Head } $string.LastIndexOf($fieldSeparator) } return $result } } function Get-HeadAndTail:::Test{ Get-HeadAndTail -string 'A:B:C' Get-HeadAndTail -string 'A:B' Get-HeadAndTail -string 'A' Get-HeadAndTail -string '' Get-HeadAndTail -RightToLeft -string 'A:B:C' Get-HeadAndTail -RightToLeft -string 'A:B' Get-HeadAndTail -RightToLeft -string 'A' Get-HeadAndTail -RightToLeft -string '' } function Get-Regex_Match { [CmdLetBinding()] param( [Parameter(Mandatory=$true)] [String]$regex, [Parameter(Mandatory=$true, ValueFromPipeline=$true)] $value ) process { if ( [String]::IsNullOrEmpty($value) ) { return } $value = $value.ToString() $match = $value -match $regex if ( $match ) { return New-Object PsObject -Property $Matches } } } function Get-Regex_Match:::Test { $expected = @{a = 'ABC'; b = 'Commit'; '0' = "ABC_Commit" } "ABC_Commit" | Get-Regex_Match "(?<a>.+)_(?<b>.+)" | ConvertFrom-PSObject_ToHashtable | Assert $expected } function Get-Like_Match { [CmdLetBinding()] param( [Parameter(Mandatory=$true)] [String]$like, [Parameter(ValueFromPipeline=$true)] $value, [string[]]$ProperyNames ) begin { $TokenReplace = [Guid]::NewGuid().ToString().Replace('-','') $regex = $like.Replace('*',$TokenReplace) $regex = [RegEx]::Escape($regex) $regex = $regex.Replace($TokenReplace,'*') if ( $regex.EndsWith('*') ) { $regex += '$' } $regex = $regex.Replace('*', '(.*?)') } process { if ( [String]::IsNullOrEmpty($value) ) { return } $value = $value.ToString() $match = $value -match $regex if ( $match ) { if ($ProperyNames) { $propObj = [Ordered]@{} $propcount = 1 $ProperyNames | ForEach-Object { $propObj.Add($_ , $Matches[$propcount] ) $propcount++ } if ($ProperyNames -notcontains 'match') { $propObj.Add('match' , $Matches[0] ) } return New-Object PsObject -Property $propObj } return New-Object PsObject -Property $Matches -ErrorAction SilentlyContinue } } } function Get-Like_Match:::Test { "File_(123)_(ABC).xml" | Get-Like_Match "file_(*)_(*).xml" "File_(123)_(ABC).xml" | Get-Like_Match "file_(*)_(*).*" "File_(123)_(ABC).xml" | Get-Like_Match "file_(*)_(*).*" -ProperyNames 'Number','string','ext','more' } function Get-RegEx_MatchGroup ( $src, $regex, $groupName ) { $match = $src -match $regex if ( -not $match ) { throw "Cannot find '$groupName' using format '$regex' in '$src'" } return $matches[$groupName] } function Get-RegEx_MatchGroup:::Test { Get-RegEx_MatchGroup "ABC_Commit" "(?<Package>.+)_(?<buildname>.+)" -groupName "Package" | Should -Be 'ABC' { Get-RegEx_MatchGroup "ABCCommit" "(?<Package>.+)_(?<buildname>.+)" -groupName "Package" } | Should -throw 'Cannot find*' } function Join-String_Ex ( [string]$join, [string]$beforeItem, [string]$AfterItem, $whenEmpty ) { end { $items = $input | ForEach-Object { $_ } if ( ( -not $items ) -and $whenEmpty ) { $items = $whenEmpty } $strItems = $items | ForEach-Object { $beforeItem + "$_" + $AfterItem } if (-not $strItems) { return } [String]::Join($join, $strItems) } } function Join-String_Ex:::Test { {$a -eq $b} , {$b -eq $c}, {$c -eq $d} | Join-String_Ex ' -and ' '( ' ' )' | Should -be '( $a -eq $b ) -and ( $b -eq $c ) -and ( $c -eq $d )' {$a -eq $b} | Join-String_Ex ' -and ' '( ' ' )' | Should -be '( $a -eq $b )' Join-String_Ex ' -and ' '( ' ' )' { $true } | Should -be '( $true )' Join-String_Ex ' -and ' '( ' ' )' | Should -be $null } function Join-Script ( [string]$join, $whenEmpty ) { end { $result = $input | Join-String_Ex " $join " '(' ')' $whenEmpty return [scriptblock]::Create($result) } } function Join-Script:::Examples { {$a -eq $b} , {$b -eq $c}, {$c -eq $d} | Join-Script '-and' {$a -eq $b} | Join-Script '-and' Join-Script '-and' Join-Script '-and' {$true} } function Split-StringInColumns ($columns, [switch]$Trim) { begin { $colDefList = $columns.GetEnumerator() | ForEach-Object { [PSCustomObject]@{ Column = $_.Key; Width = $_.Value } } } process { [string]$line = $_ $startPos = 0 $result = [Ordered]@{} foreach ($colDef in $colDefList) { if ($startPos -gt $line.Length) { $result.Add($colDef.Column, $null) continue } $width = [Math]::Min($line.Length - $startPos, $colDef.Width) $value = $line.Substring($startPos, $width) if ($Trim) { $value = $value.Trim() } $result.Add($colDef.Column, $value) $startPos += $colDef.Width } [PSCustomObject]$result } } function Split-StringInColumns:::Test { $columns = [Ordered]@{ Current = 1; SessionName = 15; USERNAME = 20; ID = 11; State = 7; Type = 11; Device = 10} $line = '>rdp-tcp#5 Administrator 2 Active' $line | Split-StringInColumns -columns $columns } function Update-String_Enclose { param ( $prefix, $suffix = $prefix, $escape, [Switch]$conditional ) process { [string]$value = $_ if (-not $value) { return "$prefix$suffix" } if ( $conditional -and $value.StartsWith($prefix) -and $value.EndsWith($suffix)) { return $value } if ($escape -and $value.Contains($prefix)) { $value = $value.Replace($prefix,"$escape$prefix") } return $prefix + $value + $suffix } } function Update-String_Enclose:::Test { 'ab"c' | Update-String_Enclose '"' -escape '`' | assert '"ab`"c"' $null | Update-String_Enclose '"' | assert '""' '' | Update-String_Enclose '"' | assert '""' 'abc' | Update-String_Enclose '"' | assert '"abc"' 'abc' | Update-String_Enclose "'" | assert "'abc'" "'ddd'" | Update-String_Enclose '"' | assert "`"'ddd'`"" "'ddd'" | Update-String_Enclose "'" -conditional | assert "'ddd'" "'ddd'" | Update-String_Enclose "'" | assert "''ddd''" } function Get-LongestPrefix ( $value, $property ) { begin { $match = $null $matchLength = 0 } process { [string]$prefix = if ( $property ) { $_ | Select-Object -ExpandProperty $property } else { $_ } if ( ( $prefix.Length -gt $matchLength ) -and $value.StartsWith($prefix) ) { $matchLength = $prefix.Length; $match = $_ } } end { if ( $null -ne $match ) { return $match } } } function Get-LongestPrefix:::Test { 'C:\', 'd:','C:\abc' | Get-LongestPrefix 'C:\abc\def\ghi' | Assert 'C:\abc' } function Get-RootPrefix { param( $prefixList ) process { $sortedPrefixList = $prefixList | Sort-Object -Descending | Select-Object -Unique $lastPosition = $sortedPrefixList.Length - 1 for ($i = 0; $i -le $lastPosition; $i++) { $current = $sortedPrefixList[$i] for( $j = $i+1; $j -le $lastPosition; $j++) { $prefix = $sortedPrefixList[$j] if ( $current -like "$prefix*" ) { $current = $null break } } if ($current) { $current } } } } function Get-RootPrefix:::Test { $prefixList = @' D:\BuildDrop\Level_VM\CORP_Level_VM_QA-GR2_17449\VM-Corp.SysApp.CORP.QA-GR2.5.0.0.17446\VM\Virtual Machines D:\BuildDrop\Level_VM\CORP_Level_VM_QA-GR2_17449\VM-Corp.SysApp.CORP.QA-GR2.5.0.0.17446 D:\BuildDrop\Level_VM\CORP_Level_VM_QA-GR2_17449 D:\BuildDrop\Level_VM\CORP_Level_VM_QA-GR2_17437\VM-Corp.SysApp.CORP.QA-GR2.5.0.0.17436\VM\Virtual Machines D:\BuildDrop\Level_VM\CORP_Level_VM_QA-GR2_17437\VM-Corp.SysApp.CORP.QA-GR2.5.0.0.17436 D:\BuildDrop\Level_VM\CORP_Level_VM_QA-GR2_17437 '@ $prefixList = $prefixList -split "`r`n" $expected = @' D:\BuildDrop\Level_VM\CORP_Level_VM_QA-GR2_17449 D:\BuildDrop\Level_VM\CORP_Level_VM_QA-GR2_17437 '@ -split "`r`n" $actual = Get-RootPrefix -prefixList $prefixList $actual.Count | assert -eq $expected.Count } function Test-Number ($varValue) { if ( $null -eq $varValue ) { return $false } $type = $varValue.GetType() switch ($type) { [Decimal] { return $true } [Char] { return $false } [Bool] { return $false } default { $type.IsPrimitive } } # The following can be used to see all .Net primitiveTypes # [object].GetType().Assembly.getTypes() | ? { $_.IsPrimitive } } function Test-Number:::Test { Test-Number $null | Assert $false Test-Number ( -1 ) | Assert $true Test-Number 1 | Assert $true Test-Number 'a' | Assert $false } function convert-bool ( [string] $value, [string[]] $trueStrings, [string[]] $falseStrings ) { if (-not $value) { return $false } if (-not $trueStrings) { $trueStrings = "1","Y","TRUE" } if (-not $falseStrings) { $falseStrings = "0","N","FALSE" } [STRING] $valueUpperCase = $value.ToUpperInvariant() foreach ($trueValue in $trueStrings) { if ( $valueUpperCase -eq $trueValue.ToUpperInvariant() ) { return $true } } foreach ($falseValue in $falseStrings) { if ( $valueUpperCase -eq $falseValue.ToUpperInvariant() ) { return $false } } throw [System.ArgumentException] "Not found a converto from $value to boolean." } function convert-bool:::Test { convert-bool 'Y' | Assert $true } function Get-NewName_Preextension { param( [string]$fullname, $PreExtension = 'Generated' ) $parts = $fullname.Split('.') $templateSufix = $parts[-1] $ext = $parts[-2] $fullname | Update-Suffix -Suffix ".$ext.$templateSufix" -replace ".$PreExtension.$ext" } function Get-NewName_Preextension:::Test { $filename = "$env:TEMP\Get-NewName_Preextension\input.sql.PSTemplate" $expected = "$env:TEMP\Get-NewName_Preextension\input.Generated.sql" Get-NewName_Preextension -fullname $filename | assert -eq $expected } function Get-Abbreviation([string]$str) { [string]$result = '' foreach ($ch in $str.GetEnumerator() ) { if ($ch -ge 'A' -and $ch -le 'Z') { $result += $ch } } return $result } function Get-Abbreviation:::Test { Get-Abbreviation 'KiloBytes' | Assert 'KB' } function Get-SizeText([double]$size, [int]$decimalPlaces = 2, [switch]$reduce) { $sizes = @("Bytes", 'KiloBytes','MegaBytes','GigaBytes','TeraBytes','PetaBites') $magnitud = 0; while ( $size -gt 1KB ) { $size = $size / 1KB $magnitud++ } if ( $decimalPlaces -eq 0 ) { $size = [int]$size } else { $size = $size * ( 10 * $decimalPlaces ) $size = [int]$size $size = [double]$size / ( 10 * $decimalPlaces ) } $magnitudText = $sizes[$magnitud] if ($reduce) { $magnitudText = Get-Abbreviation $magnitudText } return "$size $magnitudText" } function Get-SizeText:::Test { Get-SizeText 512 | Assert '512 Bytes' Get-SizeText 10000mb 1 | Assert '9.8 GigaBytes' } function Get-TimeStamp { get-date -f 'yyyyMMdd_HHmmss_ffffff' } function Get-RandomPassword ($length = 20, $seed = [Guid]::NewGuid(), $validChars) { if ($validChars) { $valid = $validChars } else { $valid = Get-Chars -word -number -symbol } if (-not $randomizer) { $seed = $seed.GetHashCode() $global:randomizer = New-Object 'System.Random' -ArgumentList $seed } if ($seed) { $seed = $seed.GetHashCode() $randomizer = New-Object 'System.Random' -ArgumentList $seed } [string]$result = '' for ($i = $length; $i -gt 0; $i --) { $ch = $randomizer.Next($valid.Length) $ch = $valid[$ch] $result += $ch } $result } function Get-RandomPassword:::Example { Get-RandomPassword -seed 'AnyObject' } # Add a section to a file after the indicated line function Add-Section { [CmdletBinding()] param ( [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] $file, $newContentsection, $afterLineThatContains ) process { $path = Get-Path $file if ($path) { $enc = Get-FileEncoding -FullName $path $content = ( Get-Content -Raw -Path $path ) $pos = $content.IndexOf($afterLineThatContains, [System.StringComparison]::InvariantCultureIgnoreCase) if ($pos -lt 0 ) { throw "file '$path' does not have a line with '$afterLineThatContains' " } # Determine new line sequence used in the file $posNewLine = $content.IndexOf("`n", $pos) $newline = $content.Substring($posNewLine-1,2) if ( $newline -ne "`r`n" ) { $newline = "`n" } $sb = New-Object 'System.Text.StringBuilder' -ArgumentList $content if ( $posNewLine -lt 0 ) { $sb.Append("`n" + $newContentsection); } else { $sb.Insert( $posNewLine, "`n" + $newContentsection ) } $newContent = $sb.ToString() if ($newContent -ne $content) { Write-Verbose "Replacing in '$path' , '$find' -> '$replacement' " Set-Content -Path $path $newContent -Encoding $enc -NoNewline } } } } function Add-Section:::Example { $testfile = "$env:TEMP\Add-Section.txt" function GenTestContent ($lines = 10) { begin { @(1..$lines) } process { '<<< ADD AFTER THIS >>>' } end { @(1..$lines) } } $newSection = "START SECTION`nINTERMEDIATE CONTENT`nEND SECTION" GenTestContent > $testfile $testfile | Add-Section -newContentsection $newSection -afterLineThatContains 'ADD AFTER THIS' $newContent = Get-Content $testfile -Raw $newContent.Contains($newSection) | Assert $true Remove-Item $testfile -Force } function Test-Like { [CmdletBinding()] Param( $right, [Switch]$not, [ScriptBlock]$pattern = { "*$_*" }, [Parameter(ValueFromPipeline=$true)] $left ) begin { if ( -not $pattern ) { $pattern = { "$_" } } # Remove empty elements $right = $right | Where-Object { $_ } if ( -not $right ) { $matchToList = $null } else { $matchToList = $right | ForEach-Object { Invoke-Command -ScriptBlock $pattern } } } process { $matched = $false foreach ($matchTo in $matchToList) { $matched = $left -like $matchTo if ($matched) { if (-not $not) { return $left } break } } if ($not -and -not $matched) { return $left } } } function Test-Like:::Test { 'AA', 'BB', 'CC' | Test-Like 'b' | assert -eq 'BB' 'AA', 'BB', 'CC' | Test-Like 'b','x' | assert -eq 'BB' 'AA', 'BB', 'CC' | Test-Like -not #| assert -eq 'AA', 'BB' 'AA', 'BB', 'CC' | Test-Like 'b' -not #| assert -eq 'AA', 'CC' 'AA', 'BB', 'CC' | Test-Like 'b','x' -not #| assert -eq 'AA', 'CC' } function Test-SubString { [CmdletBinding()] Param( $right, [Switch]$not, [Parameter(ValueFromPipeline=$true)] $left ) begin { $right = $right | Where-Object { $_ } if ( -not $right ) { $matchToList = $null } else { [string[]]$matchToList = $right | ForEach-Object { $_.ToLowerInvariant() } } } process { $matched = $false $value = $left if ($value) { $value = $value.ToLowerInvariant() foreach ($matchTo in $matchToList) { $matched = $matchTo.Contains($value) if ($matched) { if (-not $not) { return $left } break } } if ($not -and -not $matched) { return $left } } } } function Test-SubString:::Test { 'AA', 'BB', 'CC' | Test-SubString 'bbb' | should -be 'BB' 'AA', 'BB', 'CC' | Test-SubString 'bbb','xxx' | should -be 'BB' 'AA', 'BB', 'CC' | Test-SubString 'bbb' -not | should -be @('AA','CC') 'AA', 'BB', 'CC' | Test-SubString 'bbb', 'xxx' -not | should -be @('AA', 'CC') } function Get-ListRecords { Param( [Parameter(ValueFromPipeline=$true)] [string]$line, $fieldSeparator = ':' ) process { $line = $line.Trim() if (-not $line) { if ( $result.Count ) { [PSCustomObject]$result } $result = @{} } else { $parts = $line | Get-HeadAndTail -fieldSeparator $fieldSeparator $field = $parts.Head; $value = if ($line.Length -eq $field.Length) { $true } else { $parts.Tail.Trim() } $result.$field = $value } } end { if ( $result.Count ) { [PSCustomObject]$result } } } function Get-ListRecords:::Example { $lines = @' Target: LegacyGeneric:target=MicrosoftAccount:user=test@hotmail.com Type: Generic User: test@hotmail.com Local machine persistence Target: LegacyGeneric:target=msteams_adalsso/adal_context_14 Type: Generic Local machine persistence '@ -split "`n" $results = $lines | Get-ListRecords $results.count | assert -eq 2 $results[0].User | assert -eq test@hotmail.com } |