Created
April 6, 2023 03:19
-
-
Save jdhitsolutions/6463ea32d91e3ea21eb8faffeffd5a47 to your computer and use it in GitHub Desktop.
Revisions
-
jdhitsolutions created this gist
Apr 6, 2023 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,809 @@ #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