Skip to content

Commit

Permalink
v1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
TobiasPSP committed Nov 11, 2019
1 parent 2ddb294 commit 533ee46
Show file tree
Hide file tree
Showing 22 changed files with 1,516 additions and 0 deletions.
53 changes: 53 additions & 0 deletions PSOneTools/1.4/Expand-PSOneToken.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
function Expand-PSOneToken
{
<#
.SYNOPSIS
Expands all nested token from a token of type "StringExpandable"
.DESCRIPTION
Recursively emits all tokens embedded in a token of type "StringExpandable"
The original token is also emitted.
.EXAMPLE
Get-PSOneToken -Code '"Hello $host"' -TokenKind StringExpandable | Expand-PSOneToken
Emits all tokens, including the embedded (nested) tokens
.LINK
https://powershell.one/powershell-internals/parsing-and-tokenization/advanced-tokenizer
https://github.com/TobiasPSP/Modules.PSOneTools/blob/master/PSOneTools/1.4/Expand-PSOneToken.ps1
#>

# use the most specific parameter as default:
[CmdletBinding(DefaultParameterSetName='ExpandableString')]
param
(
# binds a token of type "StringExpandableToken"
[Parameter(Mandatory,ParameterSetName='ExpandableString',
Position=0,ValueFromPipeline)]
[Management.Automation.Language.StringExpandableToken]
$StringExpandable,

# binds all tokens
[Parameter(Mandatory,ParameterSetName='Token',
Position=0,ValueFromPipeline)]
[Management.Automation.Language.Token]
$Token
)

process
{
switch($PSCmdlet.ParameterSetName)
{
# recursively expand token of type "StringExpandable"
'ExpandableString' {
$StringExpandable
$StringExpandable.NestedTokens |
Where-Object { $_ } |
Expand-PSOneToken
}
# return regular token as-is:
'Token' { $Token }
# should never occur:
default { Write-Warning $_ }
}
}
}
102 changes: 102 additions & 0 deletions PSOneTools/1.4/Foreach-ObjectFast.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
function Foreach-ObjectFast
{
<#
.SYNOPSIS
Faster Foreach-Object
.DESCRIPTION
Foreach-ObjectFast can replace the built-in Foreach-Object and improves pipeline speed considerably.
Foreach-ObjectFast supports only the most commonly used parameters -Begin, -Process, and -End, so you can replace
1..100 | Foreach-Object { 'Server{0:d3}' -f $_ }
with
1..100 | Foreach-ObjectFast { 'Server{0:d3}' -f $_ }
but you cannot currently replace instances of Foreach-Object that uses the less commonly used parameters,
like -RemainingScripts, -MemberNames, and -ArgumentList
Foreach-ObjectFast has a performance benefit per iteration, so the more objects
you send through the pipeline, the more significant performace benefits you will see.
Foreach-ObjectFast is using a steppable pipeline internally which performs better.
However because of this, the debugging experience will be different, and internal
variables such as $MyInvocation may yield different results. For most every-day tasks,
these changes are not important.
A complete explanation of what Where-ObjectFast does can be found here:
https://powershell.one/tricks/performance/pipeline
.EXAMPLE
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$result = 1..1000000 | Foreach-ObjectFast -Process {
"I am at $_"
}
$report = '{0} elements in {1:n2} seconds'
$report -f $result.Count, $stopwatch.Elapsed.TotalSeconds
Demos the speed improvements. Run this script to see how well it performs,
then replace Foreach-ObjectFast with the default Foreach-Object, and check out
the performace difference. $result is the same in both cases.
.LINK
https://powershell.one/tricks/performance/pipeline
https://github.com/TobiasPSP/Modules.PSOneTools/blob/master/PSOneTools/1.2/Foreach-ObjectFast.ps1
#>

param
(
# executes for each pipeline element
[ScriptBlock]
$Process,

# executes once before the pipeline is started.
# can be used for initialization routines
[ScriptBlock]
$Begin,

# executes once after all pipeline elements have been processed
# can be used to do cleanup work
[ScriptBlock]
$End
)

begin
{
# construct a hard-coded anonymous simple function from
# the submitted scriptblocks:
$code = @"
& {
begin
{
$Begin
}
process
{
$Process
}
end
{
$End
}
}
"@
# turn code into a scriptblock and invoke it
# via a steppable pipeline so we can feed in data
# as it comes in via the pipeline:
$pip = [ScriptBlock]::Create($code).GetSteppablePipeline($myInvocation.CommandOrigin)
$pip.Begin($true)
}
process
{
# forward incoming pipeline data to the custom scriptblock:
$pip.Process($_)
}
end
{
$pip.End()
}
}
166 changes: 166 additions & 0 deletions PSOneTools/1.4/Get-PSOneToken.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@


function Get-PSOneToken
{
<#
.SYNOPSIS
Parses a PowerShell Script (*.ps1, *.psm1, *.psd1) and returns the token
.DESCRIPTION
Invokes the advanced PowerShell Parser and returns tokens and syntax errors
.EXAMPLE
Get-PSOneToken -Path c:\test.ps1
Parses the content of c:\test.ps1 and returns tokens and syntax errors
.EXAMPLE
Get-ChildItem -Path $home -Recurse -Include *.ps1,*.psm1,*.psd1 -File |
Get-PSOneToken |
Out-GridView
parses all PowerShell files found anywhere in your user profile
.EXAMPLE
Get-ChildItem -Path $home -Recurse -Include *.ps1,*.psm1,*.psd1 -File |
Get-PSOneToken |
Where-Object Errors
parses all PowerShell files found anywhere in your user profile
and returns only those files that contain syntax errors
.LINK
https://powershell.one/powershell-internals/parsing-and-tokenization/advanced-tokenizer
https://github.com/TobiasPSP/Modules.PSOneTools/blob/master/PSOneTools/1.4/Get-PSOneToken.ps1
#>

[CmdletBinding(DefaultParameterSetName='Path')]
param
(
# Path to PowerShell script file
# can be a string or any object that has a "Path"
# or "FullName" property:
[String]
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='Path')]
[Alias('FullName')]
$Path,

# PowerShell Code as ScriptBlock
[ScriptBlock]
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='ScriptBlock')]
$ScriptBlock,


# PowerShell Code as String
[String]
[Parameter(Mandatory, ValueFromPipeline,ParameterSetName='Code')]
$Code,

# the kind of token requested. If neither TokenKind nor TokenFlag is requested,
# a full tokenization occurs
[System.Management.Automation.Language.TokenKind[]]
$TokenKind = $null,

# the kind of token requested. If neither TokenKind nor TokenFlag is requested,
# a full tokenization occurs
[System.Management.Automation.Language.TokenFlags[]]
$TokenFlag = $null,

# include nested token that are contained inside
# ExpandableString tokens
[Switch]
$IncludeNestedToken

)

begin
{
# create variables to receive tokens and syntax errors:
$errors =
$tokens = $null

# return tokens only?
# when the user submits either one of these parameters, the return value should
# be tokens of these kinds:
$returnTokens = ($PSBoundParameters.ContainsKey('TokenKind')) -or
($PSBoundParameters.ContainsKey('TokenFlag'))
}
process
{
# if a scriptblock was submitted, convert it to string
if ($PSCmdlet.ParameterSetName -eq 'ScriptBlock')
{
$Code = $ScriptBlock.ToString()
}

# if a path was submitted, read code from file,
if ($PSCmdlet.ParameterSetName -eq 'Path')
{
$code = Get-Content -Path $Path -Raw -Encoding Default
$name = Split-Path -Path $Path -Leaf
$filepath = $Path

# parse the file:
$ast = [System.Management.Automation.Language.Parser]::ParseFile(
$Path,
[ref] $tokens,
[ref]$errors)
}
else
{
# else the code is already present in $Code
$name = $Code
$filepath = ''

# parse the string code:
$ast = [System.Management.Automation.Language.Parser]::ParseInput(
$Code,
[ref] $tokens,
[ref]$errors)
}

if ($IncludeNestedToken)
{
# "unwrap" nested token
$tokens = $tokens | Expand-PSOneToken
}

if ($returnTokens)
{
# filter token and use fast scriptblock filtering instead of Where-Object:
$tokens |
& { process { if ($TokenKind -eq $null -or
$TokenKind -contains $_.Kind)
{ $_ }
}} |
& { process {
$token = $_
if ($TokenFlag -eq $null) { $token }
else {
$TokenFlag |
Foreach-Object {
if ($token.TokenFlags.HasFlag($_))
{ $token } } |
Select-Object -First 1
}
}
}

}
else
{
# return the results as a custom object
[PSCustomObject]@{
Name = $name
Path = $filepath
Tokens = $tokens
# "move" nested "Extent" up one level
# so all important properties are shown immediately
Errors = $errors |
Select-Object -Property Message,
IncompleteInput,
ErrorId -ExpandProperty Extent
Ast = $ast
}
}
}
}
Binary file added PSOneTools/1.4/PSOneTools.psd1
Binary file not shown.
60 changes: 60 additions & 0 deletions PSOneTools/1.4/Test-PSOnePing.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

function Test-PSOnePing
{
<#
.SYNOPSIS
Sends a ping (ICMP) to a computer
.DESCRIPTION
Sends a ping (ICMP) to a computer
.EXAMPLE
Test-PSOnePing -ComputerName 127.0.0.1, microsoft.com, powershell.one -Timeout 2000
Pings three computers with a maximum timeout of 2000 milliseconds
.EXAMPLE
'127.0.0.1', 'microsoft.com', 'powershell.one' | Test-PSOnePing -Timeout 2000
Pings three computers with a maximum timeout of 2000 milliseconds
.EXAMPLE
Get-ADComputer -Filter * | Select-Object -ExpandProperty Name | Test-PSOnePing -Timeout 2000
Pings all computers received from Get-ADComputer with a maximum timeout of 2000 milliseconds
Module "ActiveDirectory" required for Get-ADComputer
.LINK
https://powershell.one/tricks/network/ping
#>


param
(
# Computername or IP address to ping
[Parameter(Mandatory,ValueFromPipeline)]
[string[]]
$ComputerName,

# Timeout in milliseconds
[int]
[ValidateRange(100,50000)]
$Timeout = 2000
)

begin
{
$Online = @{
Name = 'Online'
Expression = { $_.Status -eq 'Success' }
}
$obj = New-Object System.Net.NetworkInformation.Ping
}

process
{
$ComputerName |
ForEach-Object {
$obj.Send($_, $timeout) |
Select-Object -Property $Online, Status, Address |
Add-Member -MemberType NoteProperty -Name Name -Value $_ -PassThru
}
}
}
Loading

0 comments on commit 533ee46

Please sign in to comment.