Update specific octet within a IP Address Subnet - powershell

Is there is a shorter way to realise my little tricks?
$ipsubnet is from the following form: X.X.X.0 and I want to add +1 to the third X e.g. X.X.(X+1).0
$tmp = $ipsubnet -replace '..$', ''
$tmp -match '.$'
$tmp2 = [int]$Matches[0]+1
$tmp = $tmp -replace '.$', '$tmp2'
$ipsubnet = $tmp + ".0"

$sm = "255.255.48.0".Split('.')
if([int]$sm[2] -lt 255) { $sm[2]=([int]$sm[2]+1).ToString(); }
$sm = $sm -join "."
$sm
This answer will take into consideration the max value of an octet in a subnet mask (255) in the second lines if statement.
It also allows you to supply a basic string as your input in the first line. This can be substituted with a variable. Please not that this does not 'check' the subnet mask for validity, since only specific values can constitute a valid subnet mask.

Related

powershell (Get-WmiObject win32_physicalmedia).serialnumber output hex

When I used (Get-WmiObject win32_physicalmedia).serialnumber the output was in hex. Example: 31323334353637383930. Then then I used the code below
$pass=""
$t=(Get-WmiObject win32_physicalmedia).serialnumber
$t -split '(.{2})' |%{ if ($_ -ne "") { $pass+=[CHAR]([CONVERT]::toint16("$_",16)) }}
write host $pass
The output was: 1234567890. The problem is that 1234567890 is not the serial number -- the real serial number is 2143658709. I need a script to swap the number $input "1234567890" to $output "214365768709".
this presumes your SN string is an even number of characters, and that the real number simply reverses the character pairs.
$InString = '1234567890'
$OutString = ''
foreach ($Index in 0..($InString.Length / 2))
{
$CurPos = $Index * 2
$OutString += $InString[$CurPos + 1] + $InString[$CurPos]
}
$OutString
output = 2143658709
I think this is called "middle endian" format, where every two bytes are reversed: middle-endian
Coming from a post here: WMI Win32_PhysicalMedia SMART ID in Vista and 7 Permissions

How to get IP Address range from subnet and netmask

Team,
I am new to the forum, also new to the development, i am currently using windows 2016, 2012 & 2008 servers in the environment. The script primarily should work on all the environment.
I wanted to find out the IP start ip address and end ip address.
$params = #{
"ComputerName" = "."
"Class" = "Win32_NetworkAdapterConfiguration"
"Filter" = "IPEnabled=TRUE"
}
$netConfigs = Get-WMIObject #params
foreach ( $netConfig in $netConfigs ) {
for ( $i = 0; $i -lt $netConfig.IPAddress.Count; $i++ ) {
if ( $netConfig.IPAddress[$i] -match '(\d{1,3}\.){3}\d{1,3}' ) {
$ipString = $netConfig.IPAddress[$i]
$ip = [IPAddress] $ipString
$maskString = $netConfig.IPSubnet[$i]
$mask = [IPAddress] $maskString
$netID = [IPAddress] ($ip.Address -band $mask.Address)
"IP address: {0}" -f $ip.IPAddressToString
"Subnet mask: {0}" -f $mask.IPAddressToString
"Network ID: {0}" -f $netID.IPAddressToString
}
}
}
Convert IP address to the subnet
[IPAddress] (([IPAddress] "192.168.100.45").Address -band ([IPAddress] "255.255.255.0").Address)
I am currently using 2016 & i am not getting how to proceed further to get the start ip address and end ip address in a single line of code.
Please advise
You can do the following to get the network and broadcast addresses:
$IP = '192.168.4.5'
$mask = '255.255.0.0'
$IPBits = [int[]]$IP.Split('.')
$MaskBits = [int[]]$Mask.Split('.')
$NetworkIDBits = 0..3 | Foreach-Object { $IPBits[$_] -band $MaskBits[$_] }
$BroadcastBits = 0..3 | Foreach-Object { $NetworkIDBits[$_] + ($MaskBits[$_] -bxor 255) }
$NetworkID = $NetworkIDBits -join '.'
$Broadcast = $BroadcastBits -join '.'
# Output
$NetworkID
192.168.0.0
$Broadcast
192.168.255.255
Explanation:
Since bitwise operators (see About Arithmetic Operators) are only supported on integer types, you must do a string to integer conversion to successfully use the operator[1].
The IP and Mask are split on the . character creating a two string array of the octets. The [int[]] cast converts the array into an Int32 array.
For the network address, we perform a -band (bitwise and) on the same index from each array. Since IPs have four octets, we only need to loop over the 0..3 range. The resulting Int32 array ($NetworkIDBits) items joined by the . character, putting the result in IP address format.
For the broadcast address, we perform a -bxor (bitwise XOR) on the integer array derived from the mask with 255. The goal is to flip all of the ones and zeroes in the mask. The result will be an increment value per octet that can be added to the octets of the network address. The final, calculated result is converted to IP address form using -join.
[1]: You don't always need to explicitly cast strings to integers for the conversion. PowerShell can automatically do this in some cases. For example, in my shell, I do not have to cast with [int[]]
The first ip is just the network address plus 1, although that is usually the gateway. For the broadcast address, I'll just point to this link: https://www.indented.co.uk/powershell-subnet-math/
Getting to the Broadcast Address is a bit more complicated than the
Network Address. A Bitwise Or is executed against an Inverted Subnet
Mask. For example, the Inverted form of 255.255.255.0 is 0.0.0.255.

PowerShell split input and replace/combine?

I want to be able to automatically generate an output if I run a PowerShell script that splits the input by a period "." and adds "DC=" in each item/object that has been split.
$DomainFQDN = "prod.mydomain.com" # This varies depending on the input. It could be "prod.boston.us.mydomain.com" as the input.
$DistinguishedName = $DomainFQDN -split "\."
...
...
...I just don't know how to proceed
How do I get an output of "DC=prod,DC=mydomain,DC=com" for prod.mydomain.com as the input or DC=prod,DC=boston,DC=us,DC=mydomain,DC=com for prod.boston.us.mydomain.com?
Well, you can use foreach construct with $DistinguishedName and use -join like this (if you want to output directly the joined string):
$AddDC = foreach ($e in $DistinguishedName) { "DC=$e" }
Write-Host $($AddDC -join ",")
-join works like -split, you just specify the character that you need to join by.
Other way to do it is to store $AddDC
$AddDC = foreach ($e in $DistinguishedName) { "DC=$e" }
$new_string = $AddDC -join ","
Write-Host $new_string
You can consult this page for more info.
If I got it right, this is what needed:
$fqdn='prod.boston.us.mydomain.com'
$dn="DC=$($fqdn.replace('.',',DC='))"
$dn
$DomainFQDN = "prod.mydomain.com"
$DomainFQDN = $DomainFQDN.Split(".")
For ($i = 0; $i -lt $DomainFQDN.Count; $i++) {
$DomainFQDN[$i] = "DC=" + $DomainFQDN[$i]
}
$DomainFQDN = $DomainFQDN -join ","
Write-Host $DomainFQDN
Output:
DC=prod,DC=mydomain,DC=com
I'm not sure why I couldn't get the -Split "." operator to work. It should function the same as .Split(".") but for some reason it gives a different result. But anyway this should work for you.
I feel like I should mention that a real FQDN would not be DC= on every line. It would look more like:
DC=Com,DC=MyDomain,OU=Prod
I usually do a single replace operation in an expandable to convert from FQDN to distinguished name of the domain root:
$DistinguishedName = "DC=$($DomainFQDN.TrimEnd('.') -replace '\.',',DC=')"
The TrimEnd('.') call strips any dot from rooted FQDNs, and the replace operation replaces each remaining dot with ,DC=

Is there a better way to convert all control characters to entities in PowerShell 5?

Context: Azure, Windows Server 2012, PowerShell 5
I've got the following code to convert all control characters (ascii and unicode whitespace other than \x20 itself) to their ampersand-hash equivalents.
function ConvertTo-AmpersandHash {
param ([Parameter(Mandatory)][String]$Value)
# there's got to be a better way of doing this.
$AMPERHASH = '&#'
$SEMICOLON = ';'
for ($i = 0x0; $i -lt 0x20; $i++) {
$value = $value -replace [char]$i,($AMPERHASH + $i + $SEMICOLON)
}
for ($i = 0x7f; $i -le 0xa0; $i++) {
$value = $value -replace [char]$i,($AMPERHASH + $i + $SEMICOLON)
}
return $Value
}
As can be seen by the embedded comment, I'm sure there's a better way to do this. As it stands, one does some 65 iterations for each incoming string. Would regular expressions work better/faster?
LATER
-replace '([\x00-\x1f\x7f-\xa0])',('&#' + [byte][char]$1 + ';')
looks promising but the $1 is evaluating to zero all the time, giving me  all the time.
LATER STILL
Thinking that -replace couldn't internally iterate, I came up with
$t = [char]0 + [char]1 + [char]2 + [char]3 + [char]4 + [char]5 + [char]6
$r = '([\x00-\x1f\x7f-\xa0])'
while ($t -match [regex]$r) {
$t = $t -replace [regex]$r, ('&#' + [byte][char]$1 + ';')
}
echo $t
However out of that I still get

FINALLY
function ConvertTo-AmpersandHash {
param ([Parameter(Mandatory)][String]$Value)
$AMPERHASH = '&#'
$SEMICOLON = ';'
$patt = '([\x00-\x1f\x7f-\xa0]{1})'
while ($Value -match [regex]$patt) {
$Value = $Value -replace $Matches[0], ($AMPERHASH + [byte][char]$Matches[0] + $SEMICOLON)
}
return $Value
}
That works better. Faster too. Any advances on that?
Kory Gill's answer with the library call is surely a better approach, but to address your regex question, you can't evaluate code in the replacement with the -replace operator.
To do that, you need to use the .Net regex replace method, and pass it a scriptblock to evaluate the replacement, which takes a parameter of the match. e.g.
PS C:\> [regex]::Replace([string][char]2,
'([\x00-\x20\x7f-\xa0])',
{param([string]$m) '&#' + [byte][char]$m + ';'})

Your question is a little unclear to me, and could be a duplicate of What is the best way to escape HTML-specific characters in a string (PowerShell)?.
It would be nice if you explicitly stated the exact string you have and what you want it to converted to. One has to read the code to try to guess.
I am guessing one or more of these functions will do what you want:
$a = "http://foo.org/bar?baz & also <value> conversion"
"a"
$a
$b = [uri]::EscapeDataString($a)
"b"
$b
$c = [uri]::UnescapeDataString($b)
"c"
$c
Add-Type -AssemblyName System.Web
$d = [System.Web.HttpUtility]::HtmlEncode($a)
"d"
$d
$e = [System.Web.HttpUtility]::HtmlDecode($d)
"e"
$e
Gives:
a
http://foo.org/bar?baz & also <value> conversion
b
http%3A%2F%2Ffoo.org%2Fbar%3Fbaz%20%26%20also%20%3Cvalue%3E%20conversion
c
http://foo.org/bar?baz & also <value> conversion
d
http://foo.org/bar?baz & also <value> conversion
e
http://foo.org/bar?baz & also <value> conversion
I have one small function which helps me replacing as per my requirement:
$SpecChars are all the characters that are going to be replaced with nothing
Function Convert-ToFriendlyName
{param ($Text)
# Unwanted characters (includes spaces and '-') converted to a regex:
$SpecChars = '\', ' ','\\'
$remspecchars = [string]::join('|', ($SpecChars | % {[regex]::escape($_)}))
# Convert the text given to correct naming format (Uppercase)
$name = (Get-Culture).textinfo.totitlecase(“$Text”.tolower())
# Remove unwanted characters
$name = $name -replace $remspecchars, ""
$name
}
Example: Convert-ToFriendlyName "My\Name\isRana\Dip " will result me "MyNameIsranaDip".
Hope it helps you.

Reading strings from text files using switch -regex returns null element

Question:
The intention of my script is to filter out the name and phone number from both text files and add them into a hash table with the name being the key and the phone number being the value.
The problem I am facing is
$name = $_.Current is returning $null, as a result of which my hash is not getting populated.
Can someone tell me what the issue is?
Contents of File1.txt:
Lori
234 east 2nd street
Raleigh nc 12345
9199617621
lori#hotmail.com
=================
Contents of File2.txt:
Robert
2531 10th Avenue
Seattle WA 93413
2068869421
robert#hotmail.com
Sample Code:
$hash = #{}
Switch -regex (Get-content -Path C:\Users\svats\Desktop\Fil*.txt)
{
'^[a-z]+$' { $name = $_.current}
'^\d{10}' {
$phone = $_.current
$hash.Add($name,$phone)
$name=$phone=$null
}
default
{
write-host "Nothing matched"
}
}
$hash
Remove the current property reference from $_:
$hash = #{}
Switch -regex (Get-content -Path C:\Users\svats\Desktop\Fil*.txt)
{
'^[a-z]+$' {
$name = $_
}
'^\d{10}' {
$phone = $_
$hash.Add($name, $phone)
$name = $phone = $null
}
default {
Write-Host "Nothing matched"
}
}
$hash
Mathias R. Jessen's helpful answer explains your problem and offers an effective solution:
it is automatic variable $_ / $PSItem itself that contains the current input object (whatever its type is - what properties $_ / $PSItem has therefore depends on the input object's specific type).
Aside from that, there's potential for making the code both less verbose and more efficient:
# Initialize the output hashtable.
$hash = #{}
# Create the regex that will be used on each input file's content.
# (?...) sets options: i ... case-insensitive; m ... ^ and $ match
# the beginning and end of every *line*.
$re = [regex] '(?im)^([a-z]+|\d{10})$'
# Loop over each input file's content (as a whole, thanks to -Raw).
Get-Content -Raw File*.txt | foreach {
# Look for name and phone number.
$matchColl = $re.Matches($_)
if ($matchColl.Count -eq 2) { # Both found, add hashtable entry.
$hash.Add($matchColl.Value[0], $matchColl.Value[1])
} else {
Write-Host "Nothing matched."
}
}
# Output the resulting hashtable.
$hash
A note on the construction of the .NET [System.Text.RegularExpressions.Regex] object (or [regex] for short), [regex] '(?im)^([a-z]+|\d{10})$':
Embedding matching options IgnoreCase and Multiline as inline options i and m directly in the regex string ((?im) is convenient, in that it allows using simple cast syntax ([regex] ...) to construct the regular-expression .NET object.
However, this syntax may be obscure and, furthermore, not all matching options are available in inline form, so here's the more verbose, but easier-to-read equivalent:
$re = New-Object regex -ArgumentList '^([a-z]+|\d{10})$', 'IgnoreCase, Multiline'
Note that the two options must be specified comma-separated, as a single string, which PowerShell translates into the bit-OR-ed values of the corresponding enumeration values.
other solution, use convertfrom-string
$template=#'
{name*:Lori}
{street:234 east 2nd street}
{city:Raleigh nc 12345}
{phone:9199617621}
{mail:lori#hotmail.com}
{name*:Robert}
{street:2531 10th Avenue}
{city:Seattle WA 93413}
{phone:2068869421}
{mail:robert#hotmail.com}
{name*:Robert}
{street:2531 Avenue}
{city:Seattle WA 93413}
{phone:2068869421}
{mail:robert#hotmail.com}
'#
Get-Content -Path "c:\temp\file*.txt" | ConvertFrom-String -TemplateContent $template | select name, phone