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, 0What 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