2020-03-24 12:41:00 -07:00
|
|
|
# This module is a collection of things I find useful while working
|
|
|
|
|
# interactively with PowerShell. Because contents may be updated significantly,
|
|
|
|
|
# or moved to more appropriate locations as they mature, its contents should
|
|
|
|
|
# *only* be used interactively and not in scripts.
|
|
|
|
|
#
|
|
|
|
|
# These may also have additional dependencies such as non-PowerShell utilities
|
|
|
|
|
# and filesystem structure.
|
|
|
|
|
#
|
|
|
|
|
# TODO: Add function to automatically format a file with line numbers and then compare the input and output with diffmerge
|
2020-09-16 13:03:47 -07:00
|
|
|
# TODO: not suck
|
2020-03-24 12:41:00 -07:00
|
|
|
|
|
|
|
|
function PrintXml([xml]$xml) {
|
|
|
|
|
$xml.Save([Console]::Out)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
|
.SYNOPSIS
|
|
|
|
|
Return an ISO 8601 timestamp (UTC) string in long format
|
|
|
|
|
#>
|
|
|
|
|
function Get-8601Long {
|
|
|
|
|
(Get-Date).ToUniVersalTime().ToString("s") + "Z"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
|
.SYNOPSIS
|
|
|
|
|
Return an ISO 8601 timestamp (UTC) string in short format
|
|
|
|
|
#>
|
|
|
|
|
function Get-8601 {
|
|
|
|
|
(Get-8601Long).Replace("-", "").Replace(":", "")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
|
A text search function meant to be comparable to grep
|
|
|
|
|
|
|
|
|
|
The main advantage is that the encoding of input files will automatically be inferred, and matching
|
|
|
|
|
will be performed on the resulting unicode, instead of naively just doing ascii matching
|
|
|
|
|
|
|
|
|
|
TODO: Might be better to do incremental matching (match by lines instead of doing gc -raw)
|
|
|
|
|
#>
|
|
|
|
|
function Select-StringGrep {
|
|
|
|
|
Param(
|
|
|
|
|
[Parameter(Mandatory = $True, Position = 0)]
|
|
|
|
|
$Expression,
|
|
|
|
|
[Parameter(ValueFromRemainingArguments = $True)]
|
|
|
|
|
[string[]]
|
|
|
|
|
$File,
|
|
|
|
|
[Parameter(ValueFromPipeline = $True)]
|
|
|
|
|
$InputObject,
|
|
|
|
|
[switch]
|
|
|
|
|
$Recursive,
|
|
|
|
|
[switch]
|
|
|
|
|
$Matches,
|
|
|
|
|
[switch]
|
|
|
|
|
[alias("N")]
|
|
|
|
|
$LineNumbers,
|
|
|
|
|
[switch]
|
|
|
|
|
$OnlyMatching,
|
|
|
|
|
[switch]
|
|
|
|
|
$Count,
|
|
|
|
|
$MaxCount,
|
|
|
|
|
[switch]
|
|
|
|
|
$CaseSensitive
|
|
|
|
|
|
|
|
|
|
)
|
|
|
|
|
Begin {
|
|
|
|
|
$rgx = [regex]$Expression
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Process {
|
|
|
|
|
ls $File -File | % {
|
|
|
|
|
$filename = (Resolve-Path -Relative $_.FullName)
|
|
|
|
|
$content = (gc $filename -raw)
|
|
|
|
|
if ($content) {
|
|
|
|
|
$rgx.Matches((gc $filename -raw)) |
|
|
|
|
|
% {
|
|
|
|
|
if ($Matches) {
|
|
|
|
|
$_
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$filename + ":" + $_.Value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
New-Alias psgrep Select-StringGrep
|
|
|
|
|
|
|
|
|
|
function New-TempDir() {
|
|
|
|
|
$time = (Get-Date).ToUniversalTime().ToString("yyyyMMddTHHmmss.ffffZ")
|
|
|
|
|
$tempDir = mkdir "~/temp/$time"
|
|
|
|
|
$tempDir.FullName
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Out-FileNoBom {
|
|
|
|
|
Param(
|
|
|
|
|
[Parameter(ValueFromPipeline = $True)]
|
|
|
|
|
$InputObject,
|
|
|
|
|
[Parameter(Position = 0)]
|
|
|
|
|
$Path
|
|
|
|
|
)
|
|
|
|
|
# Output file as UTF-8 with no BOM; see http://stackoverflow.com/questions/5596982/using-powershell-to-write-a-file-in-utf-8-without-the-bom
|
|
|
|
|
Begin {
|
|
|
|
|
New-Item -ItemType File -Path $Path -Force
|
|
|
|
|
$streamWriter = New-Object System.IO.StreamWriter $Path
|
|
|
|
|
$streamWriter.AutoFlush = $True
|
|
|
|
|
}
|
|
|
|
|
Process {
|
|
|
|
|
$streamWriter.WriteLine($InputObject)
|
|
|
|
|
}
|
|
|
|
|
End {
|
|
|
|
|
$streamWriter.Close()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
|
.DESCRIPTION
|
|
|
|
|
Given a Fanuc macro file, normalize it by removing some extraneous whitespace and renaming it to it's program name.
|
|
|
|
|
|
|
|
|
|
This allows comparison between files that have been loaded on a machine and files that have not.
|
|
|
|
|
|
2020-09-16 13:03:47 -07:00
|
|
|
TODO: attempt to remove parentheses inside parentheses (regex can't handle arbitraty nesting depth)
|
2020-03-24 12:41:00 -07:00
|
|
|
#>
|
|
|
|
|
function NormalizeFanucMacroFile {
|
|
|
|
|
Param($InputFile, $OutputDirectory)
|
|
|
|
|
$re = ([regex]"^([^()]+)(\(.*\))$")
|
|
|
|
|
|
|
|
|
|
Write-Verbose "Normalizing $InputFile"
|
|
|
|
|
|
|
|
|
|
$fileContents = gc $InputFile -raw
|
|
|
|
|
$programName = ([regex]"O\d+").Matches($fileContents)[0].Value
|
|
|
|
|
|
|
|
|
|
$fileContents = $fileContents -replace ' ', ''
|
|
|
|
|
$fileContents = $fileContents -replace '`t', ''
|
|
|
|
|
$fileContents = $fileContents -replace '((\r)?\n){3,}', "`r`n`r`n"
|
|
|
|
|
$fileContents = $fileContents -replace '(\r?\n)+$', ''
|
|
|
|
|
|
|
|
|
|
Out-FileNoBom -InputObject $fileContents (Join-Path $OutputDirectory $programName) | Out-Null
|
|
|
|
|
unix2dos (Join-Path $OutputDirectory $programName) | Out-Null
|
|
|
|
|
(Join-Path $OutputDirectory $programName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function NormalizeAndCompareFanucMacros($InputFile1, $InputFile2) {
|
|
|
|
|
$tempDir1 = New-TempDir
|
|
|
|
|
$tempDir2 = New-TempDir
|
|
|
|
|
|
|
|
|
|
$file1 = NormalizeFanucMacroFile -InputFile1 $InputFile1 -OutputDirectory $tempDir1
|
|
|
|
|
$file2 = NormalizeFanucMacroFile -InputFile2 $InputFile2 -OutputDirectory $tempDir2
|
|
|
|
|
sgdm $file1 $file2 /t1=$InputFile1 /t2=$InputFile2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# TODO: Display informative names in the comparison
|
|
|
|
|
function NormalizeAndCompareFanucMacroDirs($Directory1, $Directory2) {
|
|
|
|
|
$Output1 = New-TempDir
|
|
|
|
|
$Output2 = New-TempDir
|
|
|
|
|
|
|
|
|
|
ls -file $Directory1 | % {NormalizeFanucMacroFile -InputFile $_.FullName -OutputDirectory $Output1} | Out-Null
|
|
|
|
|
ls -file $Directory2 | % {NormalizeFanucMacroFile -InputFile $_.FullName -OutputDirectory $Output2} | Out-Null
|
|
|
|
|
sgdm $Output1 $Output2 /t1=$Directory1 /t2=$Directory2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function New-EIModuleManifest($Path) {
|
|
|
|
|
New-ModuleManifest -CompanyName Electroimpact -Copyright "(c) $((Get-Date).Year) Electroimpact inc. All Rights reserved." -Path $Path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$NewlineRegex = [regex]"\r?\n"
|
|
|
|
|
# Create a newline index that is used with regex results and the
|
|
|
|
|
# MatchIndexToLine to get the line number of a match.
|
|
|
|
|
function CreateNewlineIndexList($Text) {
|
|
|
|
|
$NewlineRegex.Matches($Text).Index
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Get the line number of an index (character offset in text)
|
|
|
|
|
function GetLineNumberOfIndex([int]$MatchIndex, $NewlineIndexList) {
|
|
|
|
|
[Math]::Abs([Array]::BinarySearch($NewlineIndexList, $MatchIndex))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Function FormatPSFile($Path) {
|
|
|
|
|
PSScriptAnalyzer\Invoke-Formatter (Get-Content $Path -Raw) > $Path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-PSFileFunctions($file) {
|
|
|
|
|
[System.Management.Automation.Language.Parser]::ParseFile($file, [ref]$null, [ref]$null).endblock.statements.name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function NewNotepadPlusPlusNote() {
|
|
|
|
|
new-item ~/temp/$(get-8601) | % {npp -multiInst -notabbar $_.fullname}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
|
Generates hashes for a set of files and stores them in a csv file.
|
|
|
|
|
|
|
|
|
|
They can later be validated against the generated file using ValidateHashList
|
|
|
|
|
#>
|
|
|
|
|
function GenerateHashList {
|
|
|
|
|
Param(
|
|
|
|
|
[Parameter(ValueFromRemainingArguments = $True, Position = 0)]
|
|
|
|
|
$Paths,
|
|
|
|
|
$OutputFile = "hashes.csv",
|
|
|
|
|
$Algorithm = "SHA256"
|
|
|
|
|
)
|
|
|
|
|
$hashes = @()
|
|
|
|
|
foreach ($Path in $Paths) {
|
|
|
|
|
$hashes += Get-FileHash $Path -Algorithm $Algorithm
|
|
|
|
|
}
|
|
|
|
|
$hashes | % { $_.Path = (Resolve-Path $_.Path -Relative); $_} | ConvertTo-Csv -NoTypeInformation > $OutputFile
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
|
A function to test hash lists generated like:
|
|
|
|
|
Get-FileHash * | %{ $_.Path = (Resolve-Path $_.Path -Relative); $_} | ConvertTo-Csv -NoTypeInformation > hashes.csv
|
|
|
|
|
ValidateHashList hashes.csv
|
|
|
|
|
|
|
|
|
|
Returns boolean
|
|
|
|
|
#>
|
|
|
|
|
function ValidateHashList {
|
|
|
|
|
[CmdLetBinding()]
|
|
|
|
|
Param(
|
|
|
|
|
$HashFile
|
|
|
|
|
)
|
|
|
|
|
$hashes = gc $HashFile | ConvertFrom-Csv
|
|
|
|
|
|
|
|
|
|
$allMatch = $True
|
|
|
|
|
foreach ($hashEntry in $hashes) {
|
|
|
|
|
if ((Get-FileHash $hashEntry.Path -Algorithm $hashEntry.Algorithm).Hash -ne $hashEntry.Hash) {
|
|
|
|
|
Write-Error "Hashes do not match for $($hashEntry.Path)"
|
|
|
|
|
$allMatch = $False
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$allMatch
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Attempt to format files as XML before Vault Comparison
|
|
|
|
|
# Use like: Compare-VaultItems '.\Sub2 Resynch.xml' -ScriptBlock $FormatXmlTemp
|
|
|
|
|
$FormatXmlTemp = {
|
|
|
|
|
$ItemTempFile = [System.IO.Path]::GetRandomFileName()
|
|
|
|
|
$tempPath = (Join-Path $Env:TEMP $ItemTempFile)
|
|
|
|
|
([xml](gc $args[0])).Save($tempPath)
|
|
|
|
|
$tempPath
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
|
.SYNOPSIS
|
|
|
|
|
For the given module(s), look for an examples directory in its installed location, then run all the examples
|
|
|
|
|
#>
|
|
|
|
|
function Invoke-ModuleExamples {
|
|
|
|
|
[CmdletBinding()]
|
|
|
|
|
Param(
|
|
|
|
|
$Module,
|
|
|
|
|
$Repository = "EIPowerShellRepo"
|
|
|
|
|
)
|
|
|
|
|
if ($Module) {
|
|
|
|
|
$installedModules = Get-InstalledModule $Module
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$installedModules = Get-InstalledModule
|
|
|
|
|
}
|
|
|
|
|
$modules = $installedModules | ? {$_.Repository -eq $Repository}
|
|
|
|
|
|
|
|
|
|
foreach ($module in $modules) {
|
|
|
|
|
echo "Executing examples for $($module.Name)"
|
|
|
|
|
|
|
|
|
|
$examplesDir = (Join-Path $module.InstalledLocation examples)
|
|
|
|
|
if (-not (Test-Path $examplesDir)) {
|
|
|
|
|
Write-Error "No examples directory for $($module.Name)"
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Push-Location $examplesDir
|
|
|
|
|
$exampleScripts = Get-ChildItem *.ps1
|
|
|
|
|
foreach ($scriptFile in $exampleScripts) {
|
|
|
|
|
echo "Executing $(Resolve-Path $scriptFile)"
|
|
|
|
|
gc $scriptFile | ? {$_ -and $_ -ne ""} | % {Write-Host "`r`n$(Prompt)$_"; invoke-expression $_}
|
|
|
|
|
}
|
|
|
|
|
Pop-Location
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-16 13:03:47 -07:00
|
|
|
|
|
|
|
|
Import-Module PSEverything
|
|
|
|
|
# I care about the path
|
|
|
|
|
[PSEverything.Everything]::SetMatchPath($true)
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
|
Do a quick 'Everything' search and store the results in $pse.
|
|
|
|
|
Also print out the results.
|
|
|
|
|
|
|
|
|
|
TODO: Why is 'less' text display sometimes black?
|
|
|
|
|
#>
|
|
|
|
|
$global:pse = [string[]]@()
|
|
|
|
|
function pse{
|
|
|
|
|
Param(
|
|
|
|
|
[Alias('l')]
|
2021-09-03 11:51:29 -07:00
|
|
|
[switch]$Local,
|
2020-09-16 13:03:47 -07:00
|
|
|
[switch]$NoPage
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[PSEverything.Everything]::SetMatchPath($true)
|
|
|
|
|
|
|
|
|
|
if($Local){
|
2021-09-03 11:51:29 -07:00
|
|
|
$global:pse = Search-Everything @($args) | fzf --multi --bind ctrl-a:toggle-all,ctrl-d:page-down,ctrl-u:page-up,ctrl-t:toggle
|
2020-09-16 13:03:47 -07:00
|
|
|
} else {
|
2021-09-03 11:51:29 -07:00
|
|
|
$global:pse = Search-Everything -Global @($args) | fzf --multi --bind ctrl-a:toggle-all,ctrl-d:page-down,ctrl-u:page-up,ctrl-t:toggle
|
2020-09-16 13:03:47 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-03 11:51:29 -07:00
|
|
|
$pse
|
2020-09-16 13:03:47 -07:00
|
|
|
}
|
2020-03-24 12:41:00 -07:00
|
|
|
�
|