Extract part from middle of a string using powershell - powershell

I am working on a code where I need to get the device id from below string
key-vim.host.PlugStoreTopology.Device-0200eb00006000097000029790063053303032344353594d4d4554
device id in this is 60000970000297900630533030323443
Now I wrote the below code where I am getting the index of 6000 and the taking the next 32 chars from there
$strPhrase = $plugs.Device
[int]$check_index = $strPhrase.IndexOf("6000")
$device = "naa."+$strPhrase.Substring($check_index,32)
Most of the cases the index value is 48, so I am able to fetch the proper data. but in few cases(e.g. key-vim.host.PlugStoreTopology.Device-0200e600006000097000029790063053303031343253594d4d4554) the index value is not same, so I am not getting the correct ID.
Please let me know how to get these values

If the string always looks like this (with Device- and then random 10 characters before the actual device id comes), you could do it using the following regex:
$deviceString = 'key-vim.host.PlugStoreTopology.Device-0200eb00006000097000029790063053303032344353594d4d4554'
$deviceString -replace '.*Device-.{10}(.{32}).*', '$1'

You can also get the value going from right to left if the value you're looking for is always the 32 characters long and 12 characters away from the right:
$str = 'key-vim.host.PlugStoreTopology.Device-0200eb00006000097000029790063053303032344353594d4d4554'
$str -replace '^.+(.{32}).{12}$', '$1'
yields 60000970000297900630533030323443
$str = 'key-vim.host.PlugStoreTopology.Device-0200e600006000097000029790063053303031343253594d4d4554'
$str -replace '^.+(.{32}).{12}$', '$1'
yields 60000970000297900630533030313432
or use the string .Substring() method
$str = 'key-vim.host.PlugStoreTopology.Device-0200eb00006000097000029790063053303032344353594d4d4554'
$str.Substring($str.Length - 44).Substring(0,32)
yields 60000970000297900630533030323443

Related

Store everything after second `/`

I have this string in a Powershell Variable:
$buildParametersSourceBranch = refs/heads/pb/31333-test-branch/name
When I run $buildParametersSourceBranch.split('/')[2]
The result is pb. I assumed the split would show everything after the second / but it seems to only show the value between the second / and third /.
String.Split() doesn't "know" that you're only interested in a particular subset of the result and only want the string split in 2 places.
Use the -split operator and specify a max number of resulting substrings:
$rest = ($buildParametersSourceBranch -split '/',3)[2]
# or
$null,$null,$rest = $buildParametersSourceBranch -split '/',3

Error with Substring()

$fileName = "Name of TheFolder_NE_ED"
$lengthFileName = $fileName.length
$shortenLengthFileName = $lengthFileName - 5
Write-Host("Name of TheFolder_NE_ED").Substring($shortenLengthFileName,$lengthFileName)
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
I am having a problem with SubString() function, it errors with:
I tried printing out values of my variables but they seemed fine.
In PowerShell, substring works in a slightly different way.
With your existing code you could try this:
$fileName = "Name of TheFolder_NE_ED"
$lengthFileName = $fileName.length
$shortenLengthFileName = $lengthFileName - 5
Write-Host("Name of TheFolder_NE_ED").Substring($shortenLengthFileName)
Explanation:
The first parameter inside Substring should be the starting index of the character(in this case 18). Now from that letter it will start counting till the character (which you have to pass as a second parameter). Else it will by default go to the end of the string.
So, if you want to pass 2 parameters and do that, then change it to:
Write-Host("Name of TheFolder_NE_ED").Substring($shortenLengthFileName,5)
For further reference, follow Substring Use
Hope it helps.

How to convert hexadecimal encoded string to hexadecimal integer

So basically what I'm trying to achieve is to get a MAC address from a text file and increment the value by one.
Been bashing my head against the Google/StackOverflow wall for a couple of hours, think there's a concept I'm just not getting.
PowerShell:
$Last_MAC_Address = (Get-Content -LiteralPath "\\UNC\Path\Last MAC Address.txt")
Write-Host ($Last_MAC_Address)
# Output: 00155DE10B73
$Next_MAC_Address = (($Last_MAC_Address | Format-Hex) + 1)
This is a 3 step process, and although PetSerAl answered it in the comments as a one liner, I'll break it down slightly for posterity (and use a different class).
The first step is to get the Hex number as a decimal (mathematical base 10, not type).
The Second step is the incrementation of the decimal.
And the final step is converting it back to hexadecimal.
broken down and not a one liner this will accomplish the task at hand:
$asDecimal = [System.Convert]::ToInt64("00155DE10B73", 16)
$asDecimal++
$asHex = [System.Convert]::ToString($asDecimal, 16)
Another option is to prefix the value with 0x and cast it to an int64:
$Next_MAC_Address = ([int64]"0x$Last_MAC_Address"+1).ToString('X12')
You could also use the format operator (-f) instead of the ToString() method:
$Next_MAC_Address = '{0:X12}' -f ([int64]"0x$Last_MAC_Address"+1)
There is, however, one thing that may be worth noting. MAC addresses aren't just random 6-byte numbers without any inner structure. They actually consist of two parts. The first 3 bytes form the Organizationally Unique Identifier (OUI), a vendor-specific prefix (00-15-5D is one of the OUIs belonging to Microsoft). Only the last 3 bytes are a random number, a unique identifier for each card from the vendor identified by the OUI.
Taking that into consideration you may want to split the MAC address accordingly, e.g. like this:
$oui, $nid = $Last_MAC_Address -split '(?<=^[0-9a-f]{6})(?=[0-9a-f]{6}$)'
or like this:
$oui = $Last_MAC_Address.Substring(0, 6)
$nid = $Last_MAC_Address.Substring(6, 6)
and increment only the NIC identifier, and only if it wouldn't overflow:
if ($nid -ne 'ffffff') {
$Next_MAC_Address = "{0}{1:X6}" -f $oui, ([int64]"0x$nid"+1)
} else {
Write-Error 'MAC address overflow.'
}

Write REG_MULTI_SZ with Hex data

I am trying to write to a multi string, but using data gleaned from a REG file, so it's in Hex format. I have managed to convert the string to a byte array using the Convert-HexStringToByteArray here, but that doesn't produce the same result in the registry as loading the REG, so I am thinking that is not actually the right data type to be casting to.
The initial data looks like this
"NavigatorLayoutOrder"=hex(7):31,00,30,00,00,00,31,00,00,00,32,00,00,00,33,00,00,00,30,00,00,00,34,00,00,00,35,00,00,00,36,00,00,00,37,00,00,00,38,00,00,00,39,00,00,00,31,00,31,00,00,00,31,00,32,00,00,00,31,00,33,00,00,00,31,00,34,00,00,00,31,00,35,00,00,00,31,00,36,00,00,00,31,00,37,00,00,00,31,00,38,00,00,00,31,00,39,00,00,00,32,00,30,00,00,00,32,00,31,00,00,00,32,00,32,00,00,00,00,00
and I have removed the hex(7): off the front, then tried it as a pure string and casting to a byte array, and neither seems to work.
I have found reference to REG_MULTI_SZ being UTF-16le, but my understanding is that this is also the default for PowerShell, so I shouldn't need to be changing the encoding, but perhaps I am wrong there?
EDIT: I also tried this, with again a successful write, but the wrong result.
$enc = [system.Text.Encoding]::UTF8
[byte[]]$bytes = $enc.GetBytes($string)
Also tried
$array = $string.Split(',')
$byte = [byte[]]$array
This also puts data into the registry, but the result is not the same as importing the REG. And, everything I am finding keeps pointing at the idea that the REG file is UTF16, so I tried
$enc = [system.Text.Encoding]::Unicode
[byte[]]$bytes = $enc.GetBytes($string)
both with BigEndianUnicode & Unicode. Not only did it not work, the result is the same which I find odd. Seems like changing the endian-ness SHOULD change the result.
EDIT: To clarify, the input string as taken from the REG file is shown above. I simply removed the hex(7): from the front of the data.
The results are seen here, where the second value is what results from PowerShell, while the first is what the REG file produced.
The code used to produce this was
$string = "31,00,30,00,00,00,31,00,00,00,32,00,00,00,33,00,00,00,30,00,00,00,34,00,00,00,35,00,00,00,36,00,00,00,37,00,00,00,38,00,00,00,39,00,00,00,31,00,31,00,00,00,31,00,32,00,00,00,31,00,33,00,00,00,31,00,34,00,00,00,31,00,35,00,00,00,31,00,36,00,00,00,31,00,37,00,00,00,31,00,38,00,00,00,31,00,39,00,00,00,32,00,30,00,00,00,32,00,31,00,00,00,32,00,32,00,00,00,00,00"
$enc = [system.Text.Encoding]::BigEndianUnicode
[byte[]]$bytes = $enc.GetBytes($string)
New-ItemProperty "HKCU:\Software\Synchro\Synchro\ProjectConfig" -name:"NavigatorLayoutOrder2" -value:$bytes -propertyType:MultiString -force
Using Unicode encoding produces a very slightly different, but still wrong, result.
For one thing, the multistring is little endian encoded, so you need [Text.Encoding]::Unicode, not [Text.Encoding]::BigEndianUnicode. Plus, using [Text.Encoding]::Unicode.GetBytes() on the string from the .reg file ("31,00,30,00,...") would give you a byte array of the characters of that string:
'3' → 51, 0
'1' → 49, 0
',' → 44, 0
'0' → 48, 0
…
What you actually want is a byte array of the comma-separated hexadecimal values in that string:
31 → 49 (character '1')
00 → 0 (character NUL)
30 → 48 (character '0')
…
Split the string at commas, convert the hexadecimal number strings to integers, and cast the resulting list of integers to a byte array:
[byte[]]$bytes = $string -split ',' | ForEach-Object { [int]"0x$_" }
Then you can convert that (little endian encoded) byte array to a string:
$ms = [Text.Encoding]::Unicode.GetString($bytes)
and write that to the registry:
$key = 'HKCU:\Software\Synchro\Synchro\ProjectConfig'
$name = 'NavigatorLayoutOrder2'
New-ItemProperty $key -Name $name -Value $ms -PropertyType MultiString -Force

Obtain IP address from user input, generates 3 other static IPs

I am looking for a more efficient way to obtain an IP address from a user, splitting the IP address into an array, knocking off the last octet, replacing with a specific number, then joining the array back into a new IP address.
For example: User inputs IP: 10.1.1.50. From this input, I take the first 3 octets, then generate 10.1.1.1, 10.1.1.10 and 10.1.1.11. I can procedurally do this, but seems Im doing the same operations over for 3 iterations, a function could possibly be beneficial, but my attempts are failing.
$ip= $(read-host "Enter any IP Address")
$gateway = $ip.split('.')
$gateway[-1] = 1
$gateway = $ipArray -join '.'
$dns1 = $ip.split('.')
$dns1[-1] = 10
$dns1 = $dns1 -join '.'
$dns2 = $ip.split('.')
$dns2[-1] = 11
$dns2 = $dns2 -join '.'
I've separated out the first 3 octets with $threeOctets = $ip | Select-Object -First 3, which works fine, what any time i operate on it, i just seem to ADD on the 1, then the 10, then the 11 instead of adding on the 1, then going back to the first 3 octets and adding a 10, then going back and adding an 11.
Why are you making the user type in the last octet, only to cut it off and throw it away? And are you sure this is a good design, given that networks aren't all /24?
Anyway, no real need to split and join, you can just:
$ip = (Read-Host "Enter an IP") -replace '\d+$'
$gateway, $dns1, $dns2 = ('1','10','11' | foreach {"$ip$_"})
The replace gets rid of the last digits. The loop puts a string into the pipeline for each of the three numbers in the array. The multiple assignment takes the three values coming out of the pipeline into the three variables.
(PowerShell does have rudimentary IP address types, with [ipaddress]"192.168.0.1", but they're too basic to be of much help here).
I agree with was TessellatingHeckler's answer says. But I wanted to show another way that has some basic error correction as well using [ipaddress].
do{
$ip = $(read-host "Enter any IP Address")
} while(!($ip -as [ipaddress]))
$octets = ([ipaddress]$ip).Getaddressbytes()
$gateway, $dns1, $dns2 = '1','10','11' | ForEach-Object{$octets[3] = $_; $octets -join "."}
This is by no means a better approach. Merely an alternate one. The error correction is not perfect and can break but its better than a kick in the pants in some cases.
Get the ip. Convert it into its octets as an array. replace the last element of the array with the pipeline value. Join again with a period to make it an valid ip again.
It is a shame that the [Ipaddress] class wont let you edit the octets in place. [version] works like this too, which is unfortunate.