I am trying to convert IP Address range into single CIDR notation, but unable to find any method using Powershell which converts it into CIDR notation.
startIP = '4.249.240.6'
endIP = '4.249.255.255'
Output: '4.249.241.0/24'
You can use this function. Not exactly what you are expecting because it has few other subnet information.
#------------------------------------------------------------------------------
# Subroutine ip_range_to_prefix
# Purpose : Return all prefixes between two IPs
function Get-IpSubnetsBetween {
param(
[ipaddress]$StartIp,
[ipaddress]$EndIp
)
if ($StartIp.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork -or
$EndIp.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) {
Write-Error -Message 'Function only works for IPv4 addresses'
}
# Get the IPs in 32-bit unsigned integers (big-endian)
# The .Address property is little-endian, or host-endian, so avoid that.
[uint32[]]$octets = $StartIp.GetAddressBytes()
[uint32]$startIpAddress = ($octets[0] -shl 24) + ($octets[1] -shl 16) + ($octets[2] -shl 8) + $octets[3]
[uint32[]]$octets = $EndIp.GetAddressBytes()
[uint32]$EndIpAddress = ($octets[0] -shl 24) + ($octets[1] -shl 16) + ($octets[2] -shl 8) + $octets[3]
Remove-Variable -Name octets -ErrorAction SilentlyContinue
while ($startIpAddress -le $endIPAddress -and $startIpAddress -ne [uint32]::MaxValue) {
# Bitwise shift-right in a loop,
# to find how many trailing 0 bits there are
$numTrailingZeros = 0
while ([uint32]($startIpAddress -shr $numTrailingZeros) % 2 -eq 0) {
$numTrailingZeros++
}
# switch all those bits to 1,
# see if that takes us past the end IP address.
# Try one fewer in a loop until it doesn't pass the end.
do {
[uint32]$current = $startIpAddress -bor ([math]::Pow(2, $numTrailingZeros)-1)
$numTrailingZeros--
} while ($current -gt $endIpAddress)
# Now compare this new address with the original,
# and handwave idk what this is for
$prefixLen = 0
while (([uint32]($current -band [math]::Pow(2, $prefixLen))) -ne ([uint32]($startIpAddress -band [math]::Pow(2, $prefixLen)))) {
$prefixLen++
}
$prefixLen = 32 - $prefixLen
# add this subnet to the output
[byte[]]$bytes = #(
(($startIpAddress -band [uint32]4278190080) -shr 24),
(($startIpAddress -band [uint32]16711680) -shr 16),
(($startIpAddress -band [uint32]65280) -shr 8),
($startIpAddress -band [uint32]255)
)
[ipaddress]::new($bytes).IpAddressToString + "/$prefixLen"
# Add 1 to current IP
[uint32]$startIpAddress = [uint32]($current + 1)
}
}
Usage:
Get-IpSubnetsBetween -StartIp '4.249.240.6' -EndIp '4.249.255.255'
Output
Reference Link: r/Powershell - Reddit
Just for fun a friend and I are trying to find a creative way to send coded messages to eachother using steganography.I stumbled upon doing something like whats shown below and I have been struggling trying to write a function to automate the process.
this is a secret message
can be turned into:
("{2}{1}{0}{3}"-f'ecret m','is a s','this ','essage')
splitting the string and using reordering seems to be the way to go.
So the string needs to be split in random splits between 5-10 characters
.
The index of the original positions need to be saved
the splits need to be swapped around
and the new indexes sorted as to reorder the message properly
i've just really been struggling
help is appreciated
Just for fun .... 😉🤡
$InputMessage = 'this is a secret message'
$SplittedString = $InputMessage -split '' | Select-Object -Skip 1 | Select-Object -SkipLast 1
[array]::Reverse($SplittedString)
foreach ($Character in $SplittedString) {
if ($Character -notin $CharacterList) {
[array]$CharacterList += $Character
}
}
foreach ($Character in ($InputMessage -split '' | Select-Object -Skip 1 | Select-Object -SkipLast 1)) {
$Index = [array]::indexof($CharacterList, $Character)
$Output += "{$Index}"
}
$Result = "'$Output' -f $(($CharacterList | ForEach-Object {"'$_'"}) -join ',')"
$Result
And the output of this would be:
'{6}{10}{9}{3}{5}{9}{3}{5}{2}{5}{3}{0}{8}{7}{0}{6}{5}{4}{0}{3}{3}{2}{1}{0}' -f 'e','g','a','s','m',' ','t','r','c','i','h'
And the output of this would be:
this is a secret message
And now if you want to go fancy with it you remove the curly braces and the quotes and the commas and the -f and add only the numbers and characters to the data. ;-)
Not exactly what you're looking for but this might give you something to start with:
class Encode {
[string] $EncodedMessage
[int[]] $Map
[int] $EncodingComplexity = 3
Encode ([string] $Value) {
$this.Shuffle($Value)
}
Encode ([string] $Value, [int] $Complexity) {
$this.EncodingComplexity = $Complexity
$this.Shuffle($Value)
}
[void] Shuffle([string] $Value) {
$set = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!##$%^&*()_-+=[{]};:<>|./?'
$ref = [Collections.Generic.HashSet[int]]::new()
$ran = [random]::new()
$enc = [char[]]::new($Value.Length * $this.EncodingComplexity)
for($i = 0; $i -lt $enc.Length; $i++) {
$enc[$i] = $set[$ran.Next($set.Length)]
}
for($i = 0; $i -lt $Value.Length; $i++) {
do {
$x = $ran.Next($enc.Length)
} until($ref.Add($x))
$enc[$x] = $Value[$i]
}
$this.EncodedMessage = [string]::new($enc)
$this.Map = $ref
}
}
class Decode {
static [string] DecodeMessage ([Encode] $Object) {
return [Decode]::DecodeMessage($Object.EncodedMessage, $Object.Map, $Object.EncodingComplexity)
}
static [string] DecodeMessage ([string] $EncodedMessage, [int[]] $Map) {
return [Decode]::DecodeMessage($EncodedMessage, $Map, 3)
}
static [string] DecodeMessage ([string] $EncodedMessage, [int[]] $Map, [int] $Complexity) {
$decoded = [char[]]::new($EncodedMessage.Length / $Complexity)
for($i = 0; $i -lt $decoded.Length; $i++) {
$decoded[$i] = $EncodedMessage[$Map[$i]]
}
return [string]::new($decoded)
}
}
Encoding a message:
PS /> $message = 'this is a secret message'
PS /> $encoded = [Encode] $message
PS /> $encoded
EncodingComplexity EncodedMessage Map
------------------ -------------- ---
3 B$h^elu2w#CeeHH^qa siQJ)t}es:.a3 ema=eN(GiIcsO;tst1 .fsg}eSUk7ms4 N>rfe# {49, 2, 41, 27…}
For decoding the message you can either use the object of the type Encode or you can give your friend the Encoded Message and the Map to decode it ;)
PS /> [Decode]::DecodeMessage($encoded)
this is a secret message
PS /> [Decode]::DecodeMessage('B$h^elu2w#CeeHH^qa siQJ)t}es:.a3 ema=eN(GiIcsO;tst1 .fsg}eSUk7ms4 N>rfe#', $encoded.Map)
this is a secret message
I have the following variable defined
$A = New-Object -TypeName "System.Collections.ArrayList"
Now I add n elements to it :
$A.Add(1..n)
Now I want to divide $A into p parts of k elements each(The last one might have lesser elements if p*k>$A.count).
How do I do that?
You can use a function to split an array into several smaller arrays.
Below a slighty adapted version of that function found here:
function Split-Array {
[CmdletBinding(DefaultParametersetName = 'ByChunkSize')]
Param(
[Parameter(Mandatory = $true, Position = 0)]
$Array,
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'ByChunkSize')]
[ValidateRange(1,[int]::MaxValue)]
[int]$ChunkSize,
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'ByParts')]
[ValidateRange(1,[int]::MaxValue)]
[int]$Parts
)
$items = $Array.Count
switch ($PsCmdlet.ParameterSetName) {
'ByChunkSize' { $Parts = [Math]::Ceiling($items / $ChunkSize) }
'ByParts' { $ChunkSize = [Math]::Ceiling($items / $Parts) }
default { throw "Split-Array: You must use either the Parts or the ChunkSize parameter" }
}
# when the given ChunkSize is larger or equal to the number of items in the array
# use TWO unary commas to return the array as single sub array of the result.
if ($ChunkSize -ge $items) { return ,,$Array }
$result = for ($i = 1; $i -le $Parts; $i++) {
$first = (($i - 1) * $ChunkSize)
$last = [Math]::Min(($i * $ChunkSize) - 1, $items - 1)
,$Array[$first..$last]
}
return ,$result
}
In your case you could use it like:
$p = 4 # the number of parts you want
$subArrays = Split-Array $A.ToArray() -Parts $p
or
$k = 4 # the max number items in each part
$subArrays = Split-Array $A.ToArray() -ChunkSize $k
Here is a function I came up with to chunk your System.Collections.ArrayList into a nested array list of p parts. It uses a System.Collections.Specialized.OrderedDictionary to group the size k chunks by index / chunksize, which is then rounded down to the nearest integer using System.Math.Floor. It then only fetches the groups with keys from 0 to $Parts.
function Split-ArrayList {
[CmdletBinding()]
param (
# Arraylist to slice
[Parameter(Mandatory=$true)]
[System.Collections.ArrayList]
$ArrayList,
# Chunk size per part
[Parameter(Mandatory=$true)]
[ValidateRange(1, [int]::MaxValue)]
[int]
$ChunkSize,
# Number of parts
[Parameter(Mandatory=$true)]
[ValidateRange(1, [int]::MaxValue)]
[int]
$Parts
)
# Group chunks into hashtable
$chunkGroups = [ordered]#{}
for ($i = 0; $i -lt $ArrayList.Count; $i++) {
# Get the hashtable key by dividing the index by the chunk size
# Round down to nearest integer using Math.Floor
[int]$key = [Math]::Floor($i / $ChunkSize)
# Add new arraylist for key if it doesn't exist
# ContainsKey is not supported for ordered dictionary
if ($chunkGroups.Keys -notcontains $key) {
$chunkGroups.Add($key, [System.Collections.ArrayList]::new())
}
# Add number to hashtable
[void]$chunkGroups[$key].Add($ArrayList[$i])
}
# Create nested ArrayList of parts
$result = [System.Collections.ArrayList]::new()
for ($key = 0; $key -lt $Parts; $key++) {
[void]$result.Add($chunkGroups[$key])
}
$result
}
Usage:
$A = [System.Collections.ArrayList]::new(1..10)
Split-ArrayList -ArrayList $A -ChunkSize 4 -Parts 1 |
ForEach-Object { "{ " + ($_ -join ", ") + " }" }
# { 1, 2, 3, 4 }
Split-ArrayList -ArrayList $A -ChunkSize 4 -Parts 2 |
ForEach-Object { "{ " + ($_ -join ", ") + " }" }
# { 1, 2, 3, 4 }
# { 5, 6, 7, 8 }
Split-ArrayList -ArrayList $A -ChunkSize 4 -Parts 3 |
ForEach-Object { "{ " + ($_ -join ", ") + " }" }
# { 1, 2, 3, 4 }
# { 5, 6, 7, 8 }
# { 9, 10 }
Note: I didn't really account for the cases where you might want to exclude Parts, so I made every parameter mandatory. You can amend the function to be more flexible with different inputs.
I have this code:
[string]$emailBody = getEmailBody $firstName $emailTemplateFileContent
function getEmailBody($firstName, $emailTemplateFileContent)
{
$sb = New-Object Text.StringBuilder
for ($i = 1; $i -lt $emailTemplateFileContent.Length; $i++)
{
$sb.AppendLine($emailTemplateFileContent[$i])
}
$emailTemplateText = $sb.ToString()
$emailTemplateTextCustomised = $emailTemplateText.Replace("#name", $firstName)
return $emailTemplateTextCustomised
}
When I type $emailTemplateTextCustomised.getType() I can see that it is a string.
However when I type $emailBody.getType() I can see that it is an Array.
I can also see that the array has 8 strings, each string containing the output from getEmailBody().
UPDATE:
Powershell seems really buggy, it is no longer a String[] but just a String with 8 repetitions of the output from getEmailBody().
Why is it doing this?
Thanks in advance.
PowerShell isn't buggy, well at least not in this case. :-) You have to understand that in PowerShell the "output" of a function is anything that is not captured to a variable. The line that does the StringBuilder.AppendLine() returns the StringBuilder and that is added to the output of your function. Try this:
function getEmailBody($firstName, $emailTemplateFileContent)
{
$sb = New-Object Text.StringBuilder
for ($i = 1; $i -lt $emailTemplateFileContent.Length; $i++)
{
$sb.AppendLine($emailTemplateFileContent[$i]) > $null
}
$emailTemplateText = $sb.ToString()
$emailTemplateText.Replace("#name", $firstName)
}
If you are on V3 (maybe V2) you can use the -replace operator as well:
function getEmailBody($firstName, $emailTemplateFileContent)
{
$sb = New-Object Text.StringBuilder
for ($i = 1; $i -lt $emailTemplateFileContent.Length; $i++)
{
$sb.AppendLine($emailTemplateFileContent[$i]) > $null
}
$emailTemplateText = $sb.ToString() -replace '#name',$firstName
$emailTemplateText
}
For example, given a list 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8 and a number 4, it returns a list of list with length of 4, that is
(1, 2, 3, 4), (5, 6, 7, 8), (1, 2, 3, 4), (5, 6, 7, 8).
Basically I want to implement the following Python code in Powershell.
s = 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8
z = zip(*[iter(s)]*4) # Here N is 4
# z is (1, 2, 3, 4), (5, 6, 7, 8), (1, 2, 3, 4), (5, 6, 7, 8)
The following script returns 17 instead of 5.
$a = 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,0
$b = 0..($a.Length / 4) | % { #($a[($_*4)..($_*4 + 4 - 1)]) }
$b.Length
This is a bit old, but I figured I'd throw in the method I use for splitting an array into chunks. You can use Group-Object with a constructed property:
$bigList = 1..1000
$counter = [pscustomobject] #{ Value = 0 }
$groupSize = 100
$groups = $bigList | Group-Object -Property { [math]::Floor($counter.Value++ / $groupSize) }
$groups will be a collection of GroupInfo objects; in this case, each group will have exactly 100 elements (accessible as $groups[0].Group, $groups[1].Group, and so on.) I use an object property for the counter to avoid scoping issues inside the -Property script block, since a simple $i++ doesn't write back to the original variable. Alternatively, you can use $script:counter = 0 and $script:counter++ and get the same effect without a custom object.
Wrote this in 2009 PowerShell Split-Every Function
Probably can be improved.
Function Split-Every($list, $count=4) {
$aggregateList = #()
$blocks = [Math]::Floor($list.Count / $count)
$leftOver = $list.Count % $count
for($i=0; $i -lt $blocks; $i++) {
$end = $count * ($i + 1) - 1
$aggregateList += #(,$list[$start..$end])
$start = $end + 1
}
if($leftOver -gt 0) {
$aggregateList += #(,$list[$start..($end+$leftOver)])
}
$aggregateList
}
$s = 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8
$r = Split-Every $s 4
$r[0]
""
$r[1]
""
$r[2]
""
$r[3]
PS> $a = 1..16
PS> $z=for($i=0; $i -lt $a.length; $i+=4){ ,($a[$i]..$a[$i+3])}
PS> $z.count
4
PS> $z[0]
1
2
3
4
PS> $z[1]
5
6
7
8
PS> $z[2]
9
10
11
12
PS> $z[3]
13
14
15
16
Providing a solution using select. It doesn't need to worry whether $list.Count can be divided by $chunkSize.
function DivideList {
param(
[object[]]$list,
[int]$chunkSize
)
for ($i = 0; $i -lt $list.Count; $i += $chunkSize) {
, ($list | select -Skip $i -First $chunkSize)
}
}
DivideList -list #(1..17) -chunkSize 4 | foreach { $_ -join ',' }
Output:
1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16
17
#Shay Levy Answer: if you change the value of a to 1..15 then your solution not working anymore ( Peter Reavy comment )
So this worked for me:
$a = 1..15
$z=for($i=0; $i -lt $a.length; $i+=4){if ($a.length -gt ($i+3)) { ,($a[$i]..$a[$i+3])} else { ,($a[$i]..$a[-1])}}
$z.count
$a = 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,0
$b = 0..([Math]::ceiling($a.Length / 4) - 1) |
% { #(, $a[($_*4)..($_*4 + 4 - 1)]) }
Don't know why I had to put a comma after (.
Clear-Host
$s = 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
$count = $s.Length
$split = $count/2
$split --
$b = $s[0..$split]
$split ++
$a = $s[$split..$count]
write-host "first array"
$b
write-host "next array"
$a
#clean up
Get-Variable -Exclude PWD,*Preference | Remove-Variable -EA 0