Created
April 6, 2023 03:19
-
-
Save jdhitsolutions/6463ea32d91e3ea21eb8faffeffd5a47 to your computer and use it in GitHub Desktop.
The demonstration file from my presentation for the Research Triangle PowerShell User Group on advanced function parameters.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#requires -version 7.3 | |
<# | |
No code in this file should be considered production-ready. | |
All code and explanations should be viewed as educational material. | |
You are free to re-use anything in this file in your own work. | |
#> | |
# FIND ME: https://jdhitsolutions.github.io/ | |
return 'This is a demo script file. Load this file in your scripting editor and execute selected lines.' | |
# Some things will work in Windows PowerShell with a few changes. | |
#region advanced functions defined | |
# [cmdletbinding()] | |
#Begin/Process/End script blocks | |
#typically accept pipeline input | |
#endregion | |
#region Parameter considerations | |
# What needs a parameter? | |
# What's in a name? | |
# - Don't re-invent the wheel with parameter names | |
# - Simple alphabetical names | |
# - Consider a prefix | |
# - User proper case or camel case and be consistent | |
# Do you need a default value? | |
# Type matters | |
Function Get-FolderSize { | |
[cmdletbinding()] | |
[OutputType('folderSize')] | |
[alias('gfs')] | |
Param( | |
[string[]]$Path = '.', | |
[Switch]$Recurse | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
if ($Recurse) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Recursing" | |
$option = 'AllDirectories' | |
} | |
else { | |
$option = 'TopDirectoryOnly' | |
} | |
} #begin | |
Process { | |
foreach ($folder in $path) { | |
$p = Get-Item -Path $folder | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $($p.FullName) and $($p.GetDirectories().count) top-level folders" | |
$stats = $p.GetFiles('*', $option) | Measure-Object -Property length -Sum | |
[PSCustomObject]@{ | |
PSTypeName = 'folderSize' | |
Path = $p.FullName | |
Size = $stats.sum | |
Files = $stats.count | |
Directories = $p.GetDirectories('*', $option).count | |
ComputerName = [System.Environment]::MachineName | |
Date = Get-Date | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Get-FolderSize | |
#alternative | |
Function Get-FolderSize { | |
[cmdletbinding()] | |
[OutputType('folderSize')] | |
[alias('gfs')] | |
Param( | |
#notice the change in parameter type | |
#this type needs additional help to use properly since | |
#it won't work with non-Filesystem paths | |
[System.IO.DirectoryInfo[]]$Path = '.', | |
[Switch]$Recurse | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
if ($recurse) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Recursing" | |
$option = 'AllDirectories' | |
} | |
else { | |
$option = 'TopDirectoryOnly' | |
} | |
} #begin | |
Process { | |
foreach ($folder in $path) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $($folder.FullName) and $($folder.GetDirectories().count) top-level folders" | |
$stats = $folder.GetFiles('*', $option) | Measure-Object -Property length -Sum | |
[PSCustomObject]@{ | |
PSTypeName = 'folderSize' | |
Path = $folder.FullName | |
Size = $stats.sum | |
Files = $stats.count | |
Directories = $folder.GetDirectories('*', $option).count | |
ComputerName = [System.Environment]::MachineName | |
Date = Get-Date | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Get-FolderSize | |
Function Set-SecretFile { | |
[cmdletbinding(SupportsShouldProcess)] | |
[OutputType('None', 'PSCustomObject')] | |
[alias('ssf')] | |
Param( | |
[Parameter()] | |
#not using string type for the file | |
[ValidateScript({ $_.Exists })] | |
[System.IO.FileInfo]$FilePath, | |
#Encrypt or Decrypt | |
[string]$FileOption = 'Encrypt', | |
[switch]$PassThru | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
} #begin | |
Process { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $FilePath" | |
if ($PSCmdlet.ShouldProcess($filepath, $FileOption)) { | |
Switch ($FileOption) { | |
'Encrypt' { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Encrypt" | |
$filePath.Encrypt() | |
} | |
'Decrypt' { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Decrypt" | |
$filePath.Decrypt() | |
} | |
} #Switch | |
if ($PassThru) { | |
$name = $FilePath.FullName.replace('\', '\\') | |
Get-CimInstance -ClassName CIM_DataFile -Filter "name='$Name'" | Select-Object Name, FileSize, LastModified, Encrypted | |
} | |
} #whatIf | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Set-SecretFile | |
# using FileInfo automatically adds tab-completion | |
# BUT --- this won't work with PSDrive file paths | |
#endregion | |
#region Parameter attribute | |
# [Parameter()] | |
# position | |
# mandatory | |
# helpmessage | |
# pipeline values | |
# alias [alias()] | |
Function Get-FolderSize { | |
[cmdletbinding()] | |
[OutputType('folderSize')] | |
[alias('gfs')] | |
Param( | |
[Parameter( | |
Position = 0, | |
ValueFromPipeline, | |
ValueFromPipelineByPropertyName, | |
HelpMessage = 'Specify a folder to analyze.' | |
)] | |
[alias('folder')] | |
[System.IO.DirectoryInfo[]]$Path = '.', | |
[Switch]$Recurse | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
if ($recurse) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Recursing" | |
$option = 'AllDirectories' | |
} | |
else { | |
$option = 'TopDirectoryOnly' | |
} | |
} #begin | |
Process { | |
foreach ($folder in $path) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $($folder.FullName) and $($folder.GetDirectories().count) top-level folders" | |
$stats = $folder.GetFiles('*', $option) | Measure-Object -Property length -Sum | |
[PSCustomObject]@{ | |
PSTypeName = 'folderSize' | |
Path = $folder.FullName | |
Size = $stats.sum | |
Files = $stats.count | |
Directories = $folder.GetDirectories('*', $option).count | |
ComputerName = [System.Environment]::MachineName | |
Date = Get-Date | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Get-FolderSize | |
Get-FolderSize -folder c:\work | |
[PSCustomObject]@{path = 'c:\work' }, [PSCustomObject]@{path = 'c:\windows' } | | |
Get-FolderSize -verbose | |
Get-ChildItem c:\work -Directory | Get-FolderSize | Format-Table | |
#endregion | |
#region Parameter validation | |
#Validate Script | |
Function Get-FolderSize { | |
[cmdletbinding()] | |
[OutputType('folderSize')] | |
[alias('gfs')] | |
Param( | |
[Parameter( | |
Position = 0, | |
ValueFromPipeline, | |
ValueFromPipelineByPropertyName, | |
HelpMessage = 'Specify a folder to analyze.' | |
)] | |
[alias('Folder')] | |
[ValidateScript({ $_.Exists })] # <------ | |
[System.IO.DirectoryInfo[]]$Path = '.', | |
[Switch]$Recurse | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
if ($recurse) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Recursing" | |
$option = 'AllDirectories' | |
} | |
else { | |
$option = 'TopDirectoryOnly' | |
} | |
} #begin | |
Process { | |
foreach ($folder in $path) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $($folder.FullName) and $($folder.GetDirectories().count) top-level folders" | |
$stats = $folder.GetFiles('*', $option) | Measure-Object -Property length -Sum | |
[PSCustomObject]@{ | |
PSTypeName = 'folderSize' | |
Path = $folder.FullName | |
Size = $stats.sum | |
Files = $stats.count | |
Directories = $folder.GetDirectories('*', $option).count | |
ComputerName = [System.Environment]::MachineName | |
Date = Get-Date | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Get-FolderSize | |
Function Get-FolderSize { | |
[cmdletbinding()] | |
[OutputType('folderSize')] | |
[alias('gfs')] | |
Param( | |
[Parameter( | |
Position = 0, | |
ValueFromPipeline, | |
ValueFromPipelineByPropertyName, | |
HelpMessage = 'Specify a folder to analyze.' | |
)] | |
[alias('Folder')] | |
#PowerShell 7 | |
[ValidateScript({ $_.Exists }, ErrorMessage = 'Cannot validate that {0} is a valid directory object.')] | |
[System.IO.DirectoryInfo[]]$Path = '.', | |
[Switch]$Recurse | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
if ($recurse) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Recursing" | |
$option = 'AllDirectories' | |
} | |
else { | |
$option = 'TopDirectoryOnly' | |
} | |
} #begin | |
Process { | |
foreach ($folder in $path) { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $($folder.FullName) and $($folder.GetDirectories().count) top-level folders" | |
$stats = $folder.GetFiles('*', $option) | Measure-Object -Property length -Sum | |
[PSCustomObject]@{ | |
PSTypeName = 'folderSize' | |
Path = $folder.FullName | |
Size = $stats.sum | |
Files = $stats.count | |
Directories = $folder.GetDirectories('*', $option).count | |
ComputerName = [System.Environment]::MachineName | |
Date = Get-Date | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Get-FolderSize | |
#with custom error in PowerShell 7 | |
Get-FolderSize C:\work\a.ps1 | |
Get-FolderSize Z:\foo | |
#validate set | |
Function Set-SecretFile { | |
[cmdletbinding(SupportsShouldProcess)] | |
[OutputType('None', 'PSCustomObject')] | |
[alias('ssf')] | |
Param( | |
[Parameter( | |
Position = 0, | |
Mandatory, | |
ValueFromPipeline, | |
ValueFromPipelineByPropertyName, | |
HelpMessage = 'Specify the file to encrypt or decrypt' | |
)] | |
#not using string type for the file | |
[ValidateScript({ $_.Exists }, ErrorMessage = "Can't find or verify {0} exists as a file.")] | |
[alias('FullName')] | |
[System.IO.FileInfo]$FilePath, | |
[Parameter(Position = 1)] | |
[ValidateSet('Encrypt', 'Decrypt')] #<----- | |
[string]$FileOption = 'Encrypt', | |
[Switch]$PassThru | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
} #begin | |
Process { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $FilePath" | |
if ($PSCmdlet.ShouldProcess($filepath, $FileOption)) { | |
Switch ($FileOption) { | |
'Encrypt' { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Encrypt" | |
$filePath.Encrypt() | |
} | |
'Decrypt' { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Decrypt" | |
$filePath.Decrypt() | |
} | |
} #Switch | |
if ($PassThru) { | |
$name = $FilePath.FullName.replace('\', '\\') | |
Get-CimInstance -ClassName CIM_DataFile -Filter "name='$Name'" | Select-Object Name, FileSize, LastModified, Encrypted | |
} | |
} #whatIf | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Set-SecretFile | |
help Set-SecretFile | |
Set-SecretFile -FileOption <tab> | |
Get-ChildItem c:\work\*.txt | Set-SecretFile -FileOption Encrypt -WhatIf | |
#validatePattern | |
Function Get-PSScriptStat { | |
[cmdletbinding()] | |
[OutputType('psScriptStat')] | |
Param( | |
[Parameter( | |
Position = 0, | |
Mandatory, | |
ValueFromPipeline, | |
HelpMessage = 'Specify a PowerShell script file.' | |
)] | |
[ValidateNotNullOrEmpty()] | |
#I could integrate the pattern with the test | |
[ValidateScript({ Test-Path $_ }, ErrorMessage = 'Cannot find or validate {0}.')] | |
[ValidatePattern('\.ps(m)?1$')] #<----- | |
[string]$Path | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
} #begin | |
Process { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $Path" | |
$stat = Get-Content $Path -Raw | Measure-Object -Word -Line | |
$item = Get-Item $Path | |
[PSCustomObject]@{ | |
Path = $item.FullName | |
Size = $item.Length | |
Modified = $item.LastWriteTime | |
Words = $stat.Words | |
Lines = $stat.Lines | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Get-PSScriptStat | |
Get-ChildItem c:\scripts\ -File | Get-Random -Count 10 | Get-PSscriptStat | Format-Table | |
#validateRange and ValidateCount | |
Function New-TestData { | |
[cmdletbinding(SupportsShouldProcess)] | |
[OutputType('System.IO.FileInfo')] | |
Param( | |
[Parameter( | |
Position = 0, | |
Mandatory, | |
ValueFromPipeline, | |
HelpMessage = 'Specify the path for the test data files.' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[ValidateScript({ Test-Path $_ }, ErrorMessage = 'Cannot validate that {0} is a valid directory.')] | |
[string]$Path, | |
[Parameter(HelpMessage = 'Specify a collection of extensions like foo or bar, without the period. The limit is 5.')] | |
[ValidateCount(1, 5)] | |
[string[]]$Extension = @('dat', 'txt', 'log'), | |
[Parameter(HelpMessage = 'Specify the maximum size in bytes between 10 and 5MB')] | |
[ValidateRange(10, 5242880)] #<----- | |
[int32]$MaximumSize = 10, | |
[Parameter(HelpMessage = 'Specify the number of test files to create between 1 and 25')] | |
[ValidateRange(1, 25)] #<----- | |
[int]$Count = 10 | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
} #begin | |
Process { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Creating $Count test files in $Path " | |
1..$Count | ForEach-Object { | |
$Size = ($MaximumSize -gt 10) ? ( Get-Random -Minimum 10 -Maximum $MaximumSize) : 10 | |
$ext = $Extension | Get-Random -Count 1 | |
$FileName = [System.IO.Path]::GetRandomFileName() -replace '\w{3}$', $ext | |
$OutPut = Join-Path -Path $Path -ChildPath $FileName | |
#get a random creation time | |
$Created = (Get-Date).AddHours( - (Get-Random -min 1 -Maximum 1000)) | |
#get a random LastWriteTime | |
$Modified = $Created.AddHours((Get-Random -Minimum 1 -Maximum 995)) | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] ... $Output [$size]" | |
if ($PSCmdlet.ShouldProcess("$Output [$size]")) { | |
$stream = New-Object System.IO.FileStream("$Output", [System.IO.FileMode]::CreateNew) | |
[void]$stream.Seek($Size, [System.IO.SeekOrigin]::Begin) | |
$stream.WriteByte(0) | |
$Stream.Close() | |
Start-Sleep -Milliseconds 500 | |
$f = Get-Item -Path $OutPut | |
$f.CreationTime = $Created | |
$f.CreationTimeUtc = $Created.ToUniversalTime() | |
$f.LastWriteTime = $Modified | |
$f.LastWriteTimeUTC = $modified.ToUniversalTime() | |
$f.LastAccessTime = $Modified | |
$f.LastAccessTimeUTC = $modified.ToUniversalTime() | |
$f | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close New-TestData | |
New-TestData d:\temp -Count 100 -MaximumSize 1mb -WhatIf | |
New-TestData d:\temp -Count 5 -MaximumSize 1mb -WhatIf | |
New-TestData d:\temp -Count 10 -Extension 'foo', 'bar', 'dat' -MaximumSize 10kb | |
#endregion | |
#region ArgumentCompleter | |
#using ValidateSet gives you auto-complete | |
Function Get-LogInfo { | |
[CmdletBinding()] | |
Param( | |
[Parameter(Position = 0, HelpMessage = 'Specify a log name')] | |
[ValidateSet('System', 'Application', 'Windows PowerShell')] #<----- | |
[string]$Log = 'System', | |
[ValidateRange(1, 1000)] | |
[alias('max')] | |
[int]$Count = 100 | |
) | |
Get-WinEvent -FilterHashtable @{ | |
LogName = $log | |
Level = 2, 3 | |
} -MaxEvents $count | Group-Object -Property ProviderName -NoElement | | |
Sort-Object -Property Count -Descending | |
} #end function | |
# Get-LogInfo <tab> | |
#creating a custom argument completer | |
Function Get-PSScriptStat { | |
[cmdletbinding()] | |
[OutputType('psScriptStat')] | |
Param( | |
[Parameter( | |
Position = 0, | |
ValueFromPipeline, | |
HelpMessage = 'Specify a PowerShell script file.' | |
)] | |
[ValidateNotNullOrEmpty()] | |
#this should run quickly | |
[ArgumentCompleter({ (Get-ChildItem .\*.ps1, .\*.psm1).Name | Sort-Object })] | |
#I could integrate the pattern with the test | |
[ValidateScript({ Test-Path $_ }, ErrorMessage = 'Cannot find or validate {0}.')] | |
[ValidatePattern('\.ps(m)?1$')] | |
[string]$Path | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" | |
} #begin | |
Process { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $Path" | |
$stat = Get-Content $Path -Raw | Measure-Object -Word -Line | |
$item = Get-Item $Path | |
[PSCustomObject]@{ | |
Path = $item.FullName | |
Size = $item.Length | |
Modified = $item.LastWriteTime | |
Words = $stat.Words | |
Lines = $stat.Lines | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Get-PSScriptStat | |
#Get-PSScriptStat <tab> | |
# show PSReadline completions | |
#endregion | |
#region Parameter sets | |
Function Get-LogInfo { | |
[CmdletBinding(DefaultParameterSetName = 'computer')] | |
[OutputType('WinEventLogInfo')] | |
Param( | |
[Parameter(Position = 0, HelpMessage = 'Specify a log name')] | |
[ValidateSet('System', 'Application', 'Windows PowerShell')] | |
[string]$Log = 'System', | |
[ValidateRange(1, 1000)] | |
[alias('max')] | |
[int]$Count = 100, | |
[Parameter(ValueFromPipeline, ParameterSetName = 'computer')] | |
[string]$Computername = $env:COMPUTERNAME, | |
[Parameter(ParameterSetName = 'computer')] | |
[PSCredential]$Credential, | |
[Parameter(ValueFromPipeline, ParameterSetName = 'session')] | |
[ValidateNotNullOrEmpty()] | |
[alias('session')] | |
[System.Management.Automation.RunSpaces.PSSession]$PSSession | |
) | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
$scriptblock = { | |
Write-Host "Querying $using:log on $env:computername for $using:count errors and warnings" -ForegroundColor cyan | |
Get-WinEvent -FilterHashtable @{ | |
LogName = $using:log | |
Level = 2, 3 | |
} -MaxEvents $using:count | Group-Object -Property ProviderName -NoElement | | |
Sort-Object -Property Count -Descending | |
} | |
#parameters to splat to Invoke-Command | |
$icm = @{ | |
scriptblock = $scriptblock | |
} | |
if ($Credential) { | |
$icm.Add('Credential', $Credential) | |
} | |
} #begin | |
Process { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Detected parameter set $($PSCmdlet.ParameterSetName)" | |
if ($PSCmdlet.ParameterSetName -eq 'computer') { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $Log on $Computername" | |
$icm['Computername'] = $Computername | |
} | |
else { | |
$icm['Session'] = $PSSession | |
} | |
Invoke-Command @icm | ForEach-Object { | |
[PSCustomObject]@{ | |
PSTypeName = 'WinEventLogInfo' | |
LogName = $Log | |
Count = $_.Count | |
Source = $_.Name | |
Computername = $_.PSComputername.ToUpper() | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #end function | |
help Get-LogInfo | |
Get-LogInfo | |
get-loginfo Application -Verbose -Count 1000 -computername win10 #-Credential company\artd | |
New-PSSession srv1, srv2, dom1 #-Credential company\artd | |
$r = Get-PSSession | Get-LogInfo System -Count 500 -verbose | |
$r | Format-Table -GroupBy Computername -Property Count, Source | |
#endregion | |
#region advanced voodoo if time | |
#this is a proof-of-concept, not production-ready. | |
Function Get-LogInfo { | |
[CmdletBinding(DefaultParameterSetName = 'computer')] | |
[OutputType('WinEventLogInfo')] | |
Param( | |
[ValidateRange(1, 1000)] | |
[alias('max')] | |
[int]$Count = 100, | |
[Parameter(ValueFromPipeline, ParameterSetName = 'computer')] | |
[ValidateNotNullOrEmpty()] | |
[string]$Computername = $env:COMPUTERNAME, | |
[Parameter(ParameterSetName = 'computer')] | |
[PSCredential]$Credential, | |
[Parameter(ValueFromPipeline, ParameterSetName = 'session')] | |
[ValidateNotNullOrEmpty()] | |
[alias('session')] | |
[System.Management.Automation.RunSpaces.PSSession]$PSSession | |
) | |
DynamicParam { | |
# Query for classic event logs on the specified computer | |
If ($True) { | |
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary | |
# Defining parameter attributes | |
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute] | |
$attributes = New-Object System.Management.Automation.ParameterAttribute | |
$attributes.Position = 0 | |
$attributes.Mandatory = $True | |
$attributes.HelpMessage = 'Select a classic event log' | |
# Adding ValidateNotNullOrEmpty parameter validation | |
$v = New-Object System.Management.Automation.ValidateNotNullOrEmptyAttribute | |
$AttributeCollection.Add($v) | |
$attributeCollection.Add($attributes) | |
# Adding ValidateSet parameter validation | |
$splat = @{ | |
ListLog = '*' | |
ErrorAction = 'SilentlyContinue' | |
} | |
if ($PSBoundParameters.ContainsKey('ComputerName')) { | |
$splat.Add('Computername', $PSBoundParameters['Computername']) | |
if ($PSBoundParameters.ContainsKey('Credential')) { | |
$splat.Add('credential', $PSBoundParameters['credential']) | |
} | |
} | |
$Value = (Get-WinEvent @splat).where({ $_.IsClassicLog -AND $_.RecordCount -gt 0 -AND $_.LogName -ne 'Security' }).LogName | |
$vs = New-Object System.Management.Automation.ValidateSetAttribute($value) | |
$AttributeCollection.Add($vs) | |
# Defining the runtime parameter | |
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('Log', [String], $attributeCollection) | |
#$dynParam1.Value = 'System' | |
$paramDictionary.Add('Log', $dynParam1) | |
return $paramDictionary | |
} # end if | |
} #end DynamicParam | |
Begin { | |
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" | |
$scriptblock = { | |
Param($LogName, $Max) | |
Write-Host "Querying $LogName on $env:computername for $Max errors and warnings" -ForegroundColor cyan | |
Get-WinEvent -FilterHashtable @{ | |
LogName = $LogName | |
Level = 2, 3 | |
} -MaxEvents $Max | Group-Object -Property ProviderName -NoElement | | |
Sort-Object -Property Count -Descending | |
} | |
#parameters to splat to Invoke-Command | |
$icm = @{ | |
ScriptBlock = $scriptblock | |
ArgumentList = @($PSBoundParameters['log'], $Count) | |
} | |
if ($Credential) { | |
$icm.Add('Credential', $Credential) | |
} | |
} #begin | |
Process { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Detected parameter set $($PSCmdlet.ParameterSetName)" | |
$PSBoundParameters | Out-String | Write-Verbose | |
if ($PSCmdlet.ParameterSetName -eq 'computer') { | |
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $count $log on $($Computername.ToUpper())" | |
$icm['Computername'] = $Computername | |
} | |
else { | |
$icm['Session'] = $PSSession | |
} | |
Invoke-Command @icm | ForEach-Object { | |
[PSCustomObject]@{ | |
PSTypeName = 'WinEventLogInfo' | |
LogName = $PSBoundParameters['log'] | |
Count = $_.Count | |
Source = $_.Name | |
Computername = $_.PSComputername.ToUpper() | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #end function | |
# Get-LogInfo -computername dom1 -log <tab> | |
#endregion | |
#region learn more | |
Install-Module PSScriptTools | |
Get-ParameterInfo Get-LogInfo | Sort-Object ParameterSet | |
<# Read the Help! | |
about_Functions_Advanced | |
about_Functions_Advanced_Methods | |
about_Functions_Advanced_Parameters | |
about_Functions_Argument_Completion | |
about_Functions_CmdletBindingAttribute | |
about_Functions_OutputTypeAttribute | |
#> | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am not that skilled. Used a copy en paste. Wish to get to this stage and upgrade to write my own codes.....i like Powershell.