none
Powershell GUI MultiLine textbox - write data to reg_sz_multi registry value RRS feed

  • Question

  • I'm working on a project where I am reading data from a reg_sz_multi registry value to a multiLine textbox in Powershell. I'm then allowing the end user to modify this data, and I need to write it back to the same registry value. They click the Update button to update the value.

    This reg value is then used to populate another powershell GUI's ComboBox with the lines on data.

    So, for instance, I'm reading the data from the reg value and populating the textbox like this:

    #Get list from registry
    $server = $env:computername
    $Array = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).GetValue("test")
    [string[]]$itemlist = @("")
    foreach ($name in $Array)
    {
    $itemlist += $name + "`r`n"
    }

    $DatabasesTB.Text = $itemlist

    Then, the update button's event handler looks like this:

    $server = $env:computername
    [string[]]$DBList = ($DatabasesTB.Text)
    [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).SetValue('test', $DBList, [Microsoft.Win32.RegistryValueKind]::MultiString)

    Now, the data gets written to the registry, but not right for some reason. When I look at the data in the reg value, it looks right, however, if I open the registry value 'test', change nothing and hit the OK button, I get an error: "Data of type REG_MULTI_SZ cannot contain empty strings. Registry Editor will remove the empty string found."

    This is a problem. If I don't open the value and allow the Registry Editor to "fix" it, when I try to read the data in the GUI, only the first line of the data is read. If I do allow the Registry Editor to "fix" it, it works as expected. The issue here is, how can I get the data to be written properly in the first place. It isn't feasible to have to open regedit every time and fix it. If that were the case, I'd just go in and write the info there! 

    Any ideas?

    Thank you.

    Thursday, September 8, 2016 9:43 PM

Answers

  • Actually there is another issue as the value has to be a "C" array of null terminated strings.

    This should work:
    [string[]]$lines = "one"."two","three"

    When PowerShell sees this it converts it correctly.

    [string[]]regvalue =$DatabasesTB.Lines | ?{$_.Trim()} # remove blank lines

    The key is to force a string array.  The default is object array.


    \_(ツ)_/


    • Edited by jrv Friday, September 9, 2016 2:22 PM
    • Marked as answer by RichMini Friday, September 9, 2016 3:13 PM
    Friday, September 9, 2016 2:21 PM
  • Actually there is another issue as the value has to be a "C" array of null terminated strings.

    This should work:
    [string[]]$lines = "one"."two","three"

    When PowerShell sees this it converts it correctly.

    [string[]]regvalue =$DatabasesTB.Lines | ?{$_.Trim()} # remove blank lines

    The key is to force a string array.  The default is object array.


    \_(ツ)_/


    Yes. I saw that. The original threw an error. 

    I think I have it now!!

    The only thing I had to change was an issue with the textbox. In your example to read the reg and populate the textbox: 

    #Get list from registry
    $server = $env:computername
    $itemlist= [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).GetValue("test")
    # $itemlist is an array
    $DatabasesTB.Text = $itemlist


    This populates the textbox as a single line for some reason. When I read the textbox and wrote it back to the registry, it was just one line.

    I changed it to this:

     
    #Get list from registry
    $server = $env:computername
    $Array= [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).GetValue("test")
    $itemlist = $Array -join "`r`n"
    $DatabasesTB.Text = $itemlist

    Looks like it's working!!!

    @jrv....Thank you so much!

    • Marked as answer by RichMini Friday, September 9, 2016 3:13 PM
    Friday, September 9, 2016 3:13 PM

All replies

  • Remove empty lines from the input data before writing back to the registry.


    -- Bill Stewart [Bill_Stewart]

    Thursday, September 8, 2016 9:49 PM
    Moderator
  • Multi string values are zero terminated with two xeros at the end.  "zeros" being the "null" character.

    See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724884(v=vs.85).aspx


    \_(ツ)_/

    Thursday, September 8, 2016 10:06 PM
  • Yeah. I saw that and tried to put the /0 and /0/0 characters, but it just wrote them.  Looking here: 

    https://technet.microsoft.com/en-us/library/hh847835.aspx

    it looks like the "null" character is the `0. So, with that, where would you suggest I put the null character? I would think it would be when I'm building the text for the textbox, right?

    When I grab the data that's in the textbox to put back into the registry, it reads the textbox's data as a single element of data. 

    I tried to do this when writing data TO the textbox:

    #Get list from registry
    $server = $env:computername
    $Array = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\7-Zip", $true).GetValue("test")
    [string[]]$itemlist = @("")
    foreach ($name in $Array)
    {
    $itemlist +=$name + "`0`r`n"
    }
    $itemlist += "`0`0"
    $DatabasesTB.Text = $itemlist

    but this only gives me the first line of data. I assume that the `0 in the $itemlist +=$name + "`0`r`n" is messing that up. I then tried to remove the `0 in that line and I get all the data, but it still doesn't write back right.

    Would it be possible to give me an example? I really hate just asking someone to do it for me, but I've been at this little snippet for days and can't move forward until I get it.

    Friday, September 9, 2016 1:39 PM
  • $regvalue = ($names -join [char]0)+[char]0

    $names cannot have any blank lines.


    \_(ツ)_/



    • Edited by jrv Friday, September 9, 2016 1:48 PM
    Friday, September 9, 2016 1:47 PM
  • Assuming a multiline textbox.

    Here is how to acquire a multistring array and write it back.

    #Get list from registry
    $server = $env:computername
    $itemlist = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).GetValue("test")
    # $itemlist is an array
    $DatabasesTB.Lines = $itemlist
    # $DatabasesTB.Lines is an array
    [string[]]regvalue = $DatabasesTB.Lines | ?{$_.Trim()} # remove blank lines
    [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).SetValue('test',$regvalue)


    \_(ツ)_/



    • Edited by jrv Friday, September 9, 2016 3:16 PM
    Friday, September 9, 2016 2:05 PM
  • $regvalue = ($names -join [char]0)+[char]0

    $names cannot have any blank lines.


    \_(ツ)_/



    Wow! I'm now way over my head here! Where would I put that? I'm assuming you're talking about where I am populating the textbox, right? 

    If so, since I'm reading the registry value into the $Array, and then reading the $array to $itemlist, wouldn't it be $itemlist = ($Array -join [char]0) + [char] 0?

    Sorry for the noobness here! 

    Friday, September 9, 2016 2:09 PM
  • Sorry...replied before you sent the next entry. I'll try what you wrote above. 

    Thank you so much for your help.

    I will let you know what the outcome is.

    Friday, September 9, 2016 2:16 PM
  • Actually there is another issue as the value has to be a "C" array of null terminated strings.

    This should work:
    [string[]]$lines = "one"."two","three"

    When PowerShell sees this it converts it correctly.

    [string[]]regvalue =$DatabasesTB.Lines | ?{$_.Trim()} # remove blank lines

    The key is to force a string array.  The default is object array.


    \_(ツ)_/


    • Edited by jrv Friday, September 9, 2016 2:22 PM
    • Marked as answer by RichMini Friday, September 9, 2016 3:13 PM
    Friday, September 9, 2016 2:21 PM
  • Actually there is another issue as the value has to be a "C" array of null terminated strings.

    This should work:
    [string[]]$lines = "one"."two","three"

    When PowerShell sees this it converts it correctly.

    [string[]]regvalue =$DatabasesTB.Lines | ?{$_.Trim()} # remove blank lines

    The key is to force a string array.  The default is object array.


    \_(ツ)_/


    Yes. I saw that. The original threw an error. 

    I think I have it now!!

    The only thing I had to change was an issue with the textbox. In your example to read the reg and populate the textbox: 

    #Get list from registry
    $server = $env:computername
    $itemlist= [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).GetValue("test")
    # $itemlist is an array
    $DatabasesTB.Text = $itemlist


    This populates the textbox as a single line for some reason. When I read the textbox and wrote it back to the registry, it was just one line.

    I changed it to this:

     
    #Get list from registry
    $server = $env:computername
    $Array= [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).GetValue("test")
    $itemlist = $Array -join "`r`n"
    $DatabasesTB.Text = $itemlist

    Looks like it's working!!!

    @jrv....Thank you so much!

    • Marked as answer by RichMini Friday, September 9, 2016 3:13 PM
    Friday, September 9, 2016 3:13 PM
  • You don't need to or want to do that:

    This is how to load a testbox from an array:

    $server = $env:computername
    $Array= [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server).OpenSubKey("SOFTWARE\TestApp", $true).GetValue("test")
    $DatabasesTB.Lines = $array

    The TextBox control is smart.  It works correctly and cooperatively with the Net Framework.

    ( I fixed the mistake in my earlier post above. )


    \_(ツ)_/



    • Edited by jrv Friday, September 9, 2016 3:17 PM
    Friday, September 9, 2016 3:16 PM
  • Oh...I see. Instead of setting the $DatabasesTB.text to a list...you are setting the $DatabasesTB.lines to the array. Very interesting. I will try that. 

    Again...thank you. You are a lifesaver (and possibly a job saver!!)

    Friday, September 9, 2016 3:45 PM
  • You are welcome.

    Yes - skill with PowerShell is becoming a pre-requisite for techs.


    \_(ツ)_/

    Friday, September 9, 2016 4:06 PM