Skip to content

Commit db3d0b7

Browse files
more 2.13 updates
1 parent 2bf5d6e commit db3d0b7

14 files changed

+523
-140
lines changed

PSScriptTools.psd1

-1.43 KB
Binary file not shown.

PSScriptTools.psm1

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ if ($myinvocation.line -match "-verbose") {
44
}
55
Write-Verbose "Loading public functions"
66

7-
Get-ChildItem -path $PSScriptRoot\functions\*.ps1 | foreach-object -process {
8-
write-verbose $_.fullname
7+
Get-ChildItem -path $PSScriptRoot\functions\*.ps1 | ForEach-Object -process {
8+
Write-Verbose $_.fullname
99
. $_.FullName
1010
}
1111

1212
#add ToDo options to the ISE or VS Code
1313
if ($psEditor) {
14-
write-verbose "Defining VSCode additions"
14+
Write-Verbose "Defining VSCode additions"
1515
$sb = {
1616
Param(
1717
[Microsoft.PowerShell.EditorServices.Extensions.EditorContext]$context
@@ -27,18 +27,20 @@ if ($psEditor) {
2727

2828
}
2929
elseif ($psise) {
30-
write-verbose "Defining ISE additions"
31-
$action = {
30+
Write-Verbose "Defining ISE additions"
3231

33-
$prompt = "What do you need to do?"
34-
$title = "To Do"
35-
$item = Invoke-Inputbox -Title $title -Prompt $prompt
36-
$todo = "# [$(Get-Date)] TODO: $item"
37-
$psise.CurrentFile.Editor.InsertText($todo)
38-
#jump cursor to the end
39-
$psise.CurrentFile.editor.SetCaretPosition($psise.CurrentFile.Editor.CaretLine, $psise.CurrentFile.Editor.CaretColumn)
40-
}
32+
if ($psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.DisplayName -notcontains "ToDo") {
4133

42-
#add the action to the Add-Ons menu
43-
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("ToDo", $Action, "Ctrl+Alt+2" ) | Out-Null
34+
$action = {
35+
$prompt = "What do you need to do?"
36+
$title = "To Do"
37+
$item = Invoke-Inputbox -Title $title -Prompt $prompt
38+
$todo = "# [$(Get-Date)] TODO: $item"
39+
$psise.CurrentFile.Editor.InsertText($todo)
40+
#jump cursor to the end
41+
$psise.CurrentFile.editor.SetCaretPosition($psise.CurrentFile.Editor.CaretLine, $psise.CurrentFile.Editor.CaretColumn)
42+
}
43+
#add the action to the Add-Ons menu
44+
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("ToDo", $Action, "Ctrl+Alt+2" ) | Out-Null
45+
}
4446
}

README.md

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ You can get the current release from this repository or install this from the Po
1212
Install-Module PSScriptTools
1313
```
1414

15-
or in PowerShell Core:
15+
or in PowerShell 7:
1616

1717
```powershell
1818
Install-Module PSScriptTools -scope CurrentUser
1919
```
2020

21-
Starting in v2.2.0, the module was restructured to better support Desktop and Core editions. It is recommended that you uninstall any version older than 2.2.0 and then install the latest version from the PowerShell Gallery.
21+
Starting in v2.2.0, the module was restructured to better support Desktop and Core editions. But starting with version 2.13.0, the module design has reverted. All commands will be exported. Anything that is platform specific should be handled on a per command basis. It is assumed you will be running this module in Windows PowerShell 5.1 or PowerShell 7.
2222

2323
```powershell
2424
Uninstall-Module PSScriptTools -allversions
@@ -30,6 +30,38 @@ Please post any questions, problems or feedback in [Issues](https://github.com/j
3030

3131
## General Tools
3232

33+
### [Convert-EventLogRecord](docs/Convert-EventLogRecord.md)
34+
35+
When you use Get-WinEvent, the results are objects you can work with in PowerShell.
36+
However, often times there is additional information that is part of the eventlog record, such as replacement strings, that are used to construct a message.
37+
This additional information is not readily exposed.
38+
You can use this command to convert results of a Get-WinEvent command into a PowerShell custom object with additional information.
39+
40+
```powershell
41+
PS C:\> get-winevent -FilterHashtable @{Logname='System';ID=7045} -MaxEvents 1 | Convert-EventLogRecord
42+
43+
44+
LogName : System
45+
RecordType : Information
46+
TimeCreated : 1/21/2020 3:49:46 PM
47+
ID : 7045
48+
ServiceName : Netwrix Account Lockout Examiner
49+
ImagePath : "C:\Program Files (x86)\Netwrix\Account Lockout Examiner\ALEService.exe"
50+
ServiceType : user mode service
51+
StartType : auto start
52+
AccountName : bovine320\jeff
53+
Message : A service was installed in the system.
54+
55+
Service Name: Netwrix Account Lockout Examiner
56+
Service File Name: "C:\Program Files (x86)\Netwrix\Account Lockout Examiner\ALEService.exe"
57+
Service Type: user mode service
58+
Service Start Type: auto start
59+
Service Account: bovine320\jeff
60+
Keywords : {Classic}
61+
Source : Service Control Manager
62+
Computername : Bovine320
63+
```
64+
3365
### [Get-WhoIs](docs/Get-WhoIs.md)
3466

3567
This command will retrieve WhoIs information from the ARIN database for a given IPv4 address.
@@ -331,7 +363,7 @@ PS /mnt/c/scripts> new-randomfilename -home -Extension tmp
331363

332364
### [ConvertTo-Markdown](docs/ConvertTo-Markdown.md)
333365

334-
This command is designed to accept pipelined output and create a markdown document. The pipeline output will formatted as a text block. You can optionally define a title, content to appear before the output and content to appear after the output. You can run a command like this:
366+
This command is designed to accept pipelined output and create a markdown document. The pipeline output will formatted as a text block or a table You can optionally define a title, content to appear before the output and content to appear after the output. You can run a command like this:
335367

336368
```powershell
337369
Get-Service Bits,Winrm | Convertto-Markdown -title "Service Check" -precontent "## $($env:computername)" -postcontent "_report $(Get-Date)_"
@@ -352,7 +384,7 @@ which generates this markdown:
352384
Running Winrm Windows Remote Management (WS-Manag...
353385
```
354386

355-
_report 09/25/2018 09:57:12_
387+
_report 09/25/2019 09:57:12_
356388
```
357389

358390
Because the function writes markdown to the pipeline you will need to pipe it to a command `Out-File` to create a file.
@@ -566,7 +598,7 @@ Convert a hashtable object to a string equivalent that you can copy into your sc
566598
This command will take an object and create a hashtable based on its properties. You can have the hashtable exclude some properties as well as properties that have no value.
567599

568600
```powershell
569-
PS C:\> get-process -id $pid | select name,id,handles,workingset | ConvertTo-HashTable
601+
PS C:\> Get-Process -id $pid | select name,id,handles,workingset | ConvertTo-HashTable
570602
571603
Name Value
572604
---- -----
@@ -576,7 +608,7 @@ Id 3456
576608
Handles 958
577609
```
578610

579-
### [Join-Hashtable](docs/Join-Hashtable.md)
611+
### [Join-HashTable](docs/Join-HashTable.md)
580612

581613
This command will combine two hashtables into a single hashtable.Join-Hashtable will test for duplicate keys. If any of the keys from the first, or primary hashtable are found in the secondary hashtable, you will be prompted for which to keep. Or you can use -Force which will always keep the conflicting key from the first hashtable.
582614

@@ -599,6 +631,39 @@ Computer HAL
599631
Count 3
600632
```
601633

634+
### [Rename-Hashtable](docs/Rename-HashTable.md)
635+
636+
This command allows you to rename a key in an existing hashtable or ordered dictionary object.
637+
638+
```powershell
639+
PS C:\> $h = Get-Service Spooler | ConvertTo-HashTable
640+
```
641+
642+
The hashtable in $h has Machinename property which can be renamed.
643+
644+
```powershell
645+
PS C:\> Rename-HashTable -Name h -Key Machinename -NewKey Computername -Passthru
646+
647+
Name Value
648+
---- -----
649+
ServiceType Win32OwnProcess, InteractiveProcess
650+
ServiceName Spooler
651+
Container
652+
CanPauseAndContinue False
653+
RequiredServices {RPCSS, http}
654+
ServicesDependedOn {RPCSS, http}
655+
Computername .
656+
CanStop True
657+
StartType Automatic
658+
Site
659+
ServiceHandle SafeServiceHandle
660+
DisplayName Print Spooler
661+
CanShutdown False
662+
Status Running
663+
Name Spooler
664+
DependentServices {Fax}
665+
```
666+
602667
## Select Functions
603668

604669
The module contains 2 functions which simplify the use of `Select-Object`. The commands are intended to make it easier to select the first or last X number of objects. The commands include features so that you can sort the incoming objects on a given property first.
@@ -993,6 +1058,6 @@ Begin {
9931058

9941059
## Compatibility
9951060

996-
Where possible these commands have been tested with PowerShell Core, but not every platform. If you encounter problems, have suggestions or other feedback, please post an issue.
1061+
Where possible these commands have been tested with PowerShell 7, but not every platform. If you encounter problems, have suggestions or other feedback, please post an issue. It is assumed you will not be running this commands on any edition of PowerShell Core or any beta releases of PowerShell 7.
9971062

998-
last Updated 2019-08-20 19:20:40Z UTC
1063+
last Updated 2020-01-22 16:15:55Z UTC

changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55
+ Added `New-RunspaceCleanupJob` command to be used with WPF commands running in a new runspace
66
+ Modified `ConvertTo-WPFGrid` to clean up runspace when closed. (Issue #25)
77
+ Modified `ConvertTo-WPFGrid` to attempt to run on all platforms and gracefully fail where it won't work. (Issue $56)
8+
+ Added 'Convert-EventLogRecord' function and its alias `clr`
9+
+ Added `Rename-Hashtable` function and its alias `rht`
10+
+ Updated `Convertto-Markdown` to include options to format as a table
811
+ Updated module manifest to export `ConvertTo-WPFGrid` to all hosts. Code in the command will determine compatibility.
12+
+ Updated `Find-FileItem` to work better cross-platform
13+
+ Updated `New-WPFMessagebox` to work on PowerShell 7 on Windows platforms.
914
+ Help Updates
15+
+ Modified module and manifest to export all functions regardless of edition. Any OS limitations will be handled on a per command basis.
1016
+ Updated `README.md`
1117

1218
## v2.12.0
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
2+
Function Convert-EventLogRecord {
3+
4+
[cmdletbinding()]
5+
[alias("clr")]
6+
7+
Param(
8+
[Parameter(Position = 0, Mandatory, ValueFromPipeline)]
9+
[ValidateNotNullorEmpty()]
10+
[System.Diagnostics.Eventing.Reader.EventLogRecord[]]$LogRecord
11+
)
12+
13+
Begin {
14+
Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)"
15+
} #begin
16+
17+
Process {
18+
foreach ($record in $LogRecord) {
19+
Write-Verbose "[PROCESS] Processing event id $($record.ID) from $($record.logname) log on $($record.machinename)"
20+
Write-Verbose "[PROCESS] Creating XML data"
21+
[xml]$r = $record.ToXml()
22+
23+
$h = [ordered]@{
24+
LogName = $record.LogName
25+
RecordType = $record.LevelDisplayName
26+
TimeCreated = $record.TimeCreated
27+
ID = $record.Id
28+
}
29+
30+
if ($r.Event.EventData.Data.Count -gt 0) {
31+
Write-Verbose "[PROCESS] Parsing event data"
32+
if ($r.Event.EventData.Data -is [array]) {
33+
<#
34+
I only want to enumerate with the For loop if the data is an array of objects
35+
If the data is just a single string like Foo, then when using the For loop,
36+
the data value will be the F and not the complete string, Foo.
37+
#>
38+
for ($i = 0; $i -lt $r.Event.EventData.Data.count; $i++) {
39+
40+
$data = $r.Event.EventData.data[$i]
41+
#test if there is structured data or just text
42+
if ($data.name) {
43+
$Name = $data.name
44+
$Value = $data.'#text'
45+
}
46+
else {
47+
Write-Verbose "[PROCESS] No data property name detected"
48+
$Name = "RawProperties"
49+
#data will likely be an array of strings
50+
[string[]]$Value = $data
51+
}
52+
53+
if ($h.Contains("RawProperties")) {
54+
Write-Verbose "[PROCESS] Appending to RawProperties"
55+
$h.RawProperties += $value
56+
}
57+
else {
58+
Write-Verbose "[PROCESS] Adding $name"
59+
$h.add($name, $Value)
60+
}
61+
} #for data
62+
} #data is an array
63+
else {
64+
$data = $r.Event.EventData.data
65+
if ($data.name) {
66+
$Name = $data.name
67+
$Value = $data.'#text'
68+
}
69+
else {
70+
Write-Verbose "[PROCESS] No data property name detected"
71+
$Name = "RawProperties"
72+
#data will likely be an array of strings
73+
[string[]]$Value = $data
74+
}
75+
76+
if ($h.Contains("RawProperties")) {
77+
Write-Verbose "[PROCESS] Appending to RawProperties"
78+
$h.RawProperties += $value
79+
}
80+
else {
81+
Write-Verbose "[PROCESS] Adding $name"
82+
$h.add($name, $Value)
83+
}
84+
}
85+
} #if data
86+
else {
87+
Write-Verbose "[PROCESS] No event data to process"
88+
}
89+
90+
$h.Add("Message", $record.Message)
91+
$h.Add("Keywords", $record.KeywordsDisplayNames)
92+
$h.Add("Source", $record.ProviderName)
93+
$h.Add("Computername", $record.MachineName)
94+
95+
Write-Verbose "[PROCESS] Creating custom object"
96+
New-Object -TypeName PSObject -Property $h
97+
} #foreach record
98+
} #process
99+
100+
End {
101+
Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)"
102+
} #end
103+
}

functions/ConvertTo-Markdown.ps1

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ Function ConvertTo-Markdown {
1313
[string[]]$PreContent,
1414
[string[]]$PostContent,
1515
[ValidateScript( {$_ -ge 10})]
16-
[int]$Width = 80
16+
[int]$Width = 80,
17+
#display results as a markdown table
18+
[switch]$AsTable
1719
)
1820

1921
Begin {
@@ -36,7 +38,6 @@ Function ConvertTo-Markdown {
3638
}
3739

3840
} #begin
39-
4041
Process {
4142
#add incoming objects to data array
4243
Write-Verbose "[PROCESS] Adding processed object"
@@ -46,26 +47,56 @@ Function ConvertTo-Markdown {
4647
End {
4748
#add the data to the text
4849
if ($data) {
49-
#convert data to strings and trim each line
50-
Write-Verbose "[END ] Converting data to strings"
51-
[string]$trimmed = (($data | Out-String -Width $width).split("`n")).ForEach( {"$($_.trimend())`n"})
52-
Write-Verbose "[END ] Adding to markdown"
53-
$text += @"
50+
if ($AsTable) {
51+
Write-Verbose "[END ] Formatting as a table"
52+
$names = $data[0].psobject.Properties.name
53+
$head = "| $($names -join " | ") |"
54+
$text += $head
55+
$text += "`n"
56+
57+
$bars = "| $(($names -replace '.','-') -join " | ") |"
58+
59+
$text += $bars
60+
$text += "`n"
61+
62+
foreach ($item in $data) {
63+
$line = "| "
64+
$values = @()
65+
for ($i = 0; $i -lt $names.count; $i++) {
66+
# $line += $item.($names[$i])
67+
$values += $item.($names[$i])
68+
}
69+
$line += $values -join " | "
70+
$line += " |"
71+
$text += $line
72+
$text += "`n"
73+
}
74+
75+
}
76+
else {
77+
#convert data to strings and trim each line
78+
Write-Verbose "[END ] Converting data to strings"
79+
[string]$trimmed = (($data | Out-String -Width $width).split("`n")).ForEach( { "$($_.trim())`n" })
80+
Write-Verbose "[END ] Adding to markdown"
81+
$clean = $($trimmed.trimend())
82+
$text += @"
5483
``````text
55-
$($trimmed.trimend())
84+
$clean
5685
``````
5786
5887
"@
59-
}
6088

89+
} #else as text
90+
} #if $data
6191
If ($postcontent) {
6292
Write-Verbose "[END ] Adding postcontent"
6393
$text += "`n"
6494
$text += $postcontent
6595
}
6696
#write the markdown to the pipeline
67-
$text
97+
$text.TrimEnd()
6898
Write-Verbose "[END ] Ending $($myinvocation.MyCommand)"
6999
} #end
70100

101+
71102
} #close ConvertTo-Markdown

0 commit comments

Comments
 (0)