Skip to content

Instantly share code, notes, and snippets.

@jdhitsolutions
Created April 6, 2023 03:19
Show Gist options
  • Save jdhitsolutions/6463ea32d91e3ea21eb8faffeffd5a47 to your computer and use it in GitHub Desktop.
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.
#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
@Gandanetworks
Copy link

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.

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