Converting VB Script To VB.Net

My Last Post Titled “Event 10 Mystery Solved” (found here.), Left me with a Question about the binary version of the SID, A returned value of  CreatorSID: 1,5,0,0,0,0,0,5,21,0,0,0,190,118,173,34,87,198,105,19,239,226,7,24,244,1,0,0

I started searching the net to see if anyone has posted a conversion tool to go from the the Binary SID:  The Administrators SID in array of bytes format
    CreatorSID = {1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0};

to a String version:  Administrators group  S-1–5-32-544

So far I have not found a formula to do a conversion (that works) but I am getting closer, and learning a few thing in the process.

I ran across a blog article (Located Here) that used Power Shell to search classes by Key Phrase and return a list of Classes that it was located in. The Default search location is Cimv2 (System default).

PS-SID-Search

 

That Gave me Several locations to search for answers.

The Win32_SID does not return any instances. You have to create an instance, as you will see below in the script. It does show BinaryRepresentation as a property.

Then I ran across this Web Page.

How to convert the SDDL form of an SID to a SAM account name ,(Located Here and another KB article here on conversion) Which the code appears to be in VB6 version. The Code still didn’t do what I wanted. They all required you to access the system for some form of information. It did tell me the the SID is actually stored in the binary form to start with so all I had to do is figure out how to get at it., Which brings me to the next web page.

This page is a script that I found at the Microsoft Script Center (Located Here) called, “Create Shared Folder and Set Access Permissions”

After looking thru the code I noted that it had a place where the binary version of the SID was placed into a variable, Which was what I was wanting.

Foldername="c:\KS" 'folder to share sharename="KS_Share" 'Share Name strDesc="Test Share" 'Share Description strUser="mike" 'User to set permissions for Set Services = GetObject("winmgmts:{impersonationLevel=impersonate,(Security)}!\\.\root\cimv2") ' Connects to the WMI service with security privileges Set SecDescClass = Services.Get("Win32_SecurityDescriptor") ' Need an instance of the Win32_SecurityDescriptor so we can create an instance of a Security Descriptor. Set SecDesc = SecDescClass.SpawnInstance_() ' Create an instance of a Security Descriptor. Set colWinAcc = Services.ExecQuery("SELECT * FROM Win32_ACCOUNT WHERE Name='" & strUser & "'") If colWinAcc.Count < 1 Then Wscript.echo("User " & strUser & "Not Found - quitting") wscript.quit End If ' Find the WMI representation of a particular Windows Account For Each refItem in colWinAcc Set refSID = Services.Get("Win32_SID='" & refItem.SID & "'") ' Get the SID for the choosen Windows account. Next Set refTrustee = Services.Get("Win32_Trustee").spawnInstance_() ' Creates an instance of a Windows Security Trustee (usually a user but anything with a SID I guess...) With refTrustee .Domain = refSID.ReferencedDomainName .Name = refSID.AccountName .SID = refSID.BinaryRepresentation .SidLength = refSID.SidLength .SIDString = refSID.SID End With ' Sets the trustee object up with the SID & all that malarkey from the user object we have choosen to work on Set ACE = Services.Get("Win32_Ace").SpawnInstance_ ' Creates an instance of an Access Control Entry Object(this will be one entry on the access list on an object) ACE.Properties_.Item("AccessMask") = 2032127 ' This is full Control ' This is full Control (bitflag) full list here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/win32_ace.asp ACE.Properties_.Item("AceFlags") = 3 ' what to apply ACE to inc inhehitance 3 - means files & folders get permssions & pass onto children ACE.Properties_.Item("AceType") = 0 ' 0=allow access 1=deny access ACE.Properties_.Item("Trustee") = refTrustee ' Set the Trustee (user) that this Access control Entry will refer to. SecDesc.Properties_.Item("DACL") = Array(ACE) ' Get the DACL property of the Security Descriptor object ' Add the ACE to the Dynamic Access Control List on the object (an array) it will overwrite the old entries ' unless you retreive & save 'em first & add them to a big array with the new entry as well as the old ones Set Share = Services.Get("Win32_Share") ' Get a WMI share Object Set InParam = Share.Methods_("Create").InParameters.SpawnInstance_() ' Create an instance of a WMI input Parameters object InParam.Properties_.Item("Access") = SecDesc ' Set the Access Parameter to the Security Descriptor Object we configured above InParam.Properties_.Item("Description") = strDesc InParam.Properties_.Item("Name") = ShareName InParam.Properties_.Item("Path") = FolderName InParam.Properties_.Item("Type") = 0 Set outParams=Share.ExecMethod_("Create", InParam) ' Create the share with all the parameters we have set up wscript.echo("OUT: " & outParams.returnValue) If outParams.returnValue <> 0 Then wscript.echo("Failed to Create Share, return Code:" & outParams.returnValue) Else wscript.echo("Folder " & Foldername & " sucessfully shared as: " & sharename & " with FULL CONTROL Permissions for user " & strUser) End If

The code above as listed on the Script Center.

Next I had to strip out everything to do with working with the folders. Then add a way to show the “refTrustee.* ” information , as you see in the next code listing.

strUser="David" 'User to Get SID For Set Services = GetObject("winmgmts:{impersonationLevel=impersonate,(Security)}!\\.\root\cimv2") ' Connects to the WMI service with security privileges Set SecDescClass = Services.Get("Win32_SecurityDescriptor") ' Need an instance of the Win32_SecurityDescriptor so we can create an instance of a Security Descriptor. Set SecDesc = SecDescClass.SpawnInstance_() ' Create an instance of a Security Descriptor. Set colWinAcc = Services.ExecQuery("SELECT * FROM Win32_ACCOUNT WHERE Name='" & strUser & "'") If colWinAcc.Count < 1 Then Wscript.echo("User " & strUser & "Not Found - quitting") wscript.quit End If ' Find the WMI representation of a particular Windows Account For Each refItem in colWinAcc Set refSID = Services.Get("Win32_SID='" & refItem.SID & "'") ' Get the SID for the choosen Windows account. Next Set refTrustee = Services.Get("Win32_Trustee").spawnInstance_() ' Creates an instance of a Windows Security Trustee (usually a user but anything with a SID I guess...) With refTrustee .Domain = refSID.ReferencedDomainName .Name = refSID.AccountName .SID = refSID.BinaryRepresentation .SidLength = refSID.SidLength .SIDString = refSID.SID End With ' Sets the trustee object up with the SID & all that malarkey from the user object we have choosen to work on Wscript.echo "Domain Name: " & refTrustee.Domain Wscript.echo "User Name: " & refTrustee.Name strSID = Join(refTrustee.SID, ",") WScript.Echo "SID: " & strSID Wscript.echo "SidLength: " & refTrustee.SidLength Wscript.echo "SIDString: " & refTrustee.SIDString

The only thing you will have to change in the modified script to get it to work is the name of a user. You can also save it as a text file and load it into the Scriptomatic V2 to run it.

The output from the BUILTIN Administrators group looks like this:

Domain Name: BUILTIN
User Name: Administrators
SID: 1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0
SidLength: 16
SIDString: S-1-5-32-544

To me, one of the most interesting things is the way to handle the array of Bytes, the script used the join function to pull out all of the Bytes.

strSID = Join(refTrustee.SID, “,”)
         WScript.Echo “SID: ” & strSID

This does not work in VB.Net, you get a this function is not supported error.

Now the conversion :

Below is the VB.Net version of the stripped script above, I started by copying the script into a new project then adding the Import’s and  references , also adding Dim to a few lines and replace the WScript.Echo with a way to get the information to a multi-line Text box.

Here is what the form looks like.

XtraSID1

And here is the code behind the form.

Imports System.Management Imports System.Management.Instrumentation Imports System.Threading Imports System Imports System.IO Imports System.Security Imports System.Security.Permissions Imports System.Text Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim uan As Integer Dim usearcher As New ManagementObjectSearcher( _ "root\CIMV2", _ "SELECT * FROM Win32_UserAccount") For Each queryObj As ManagementObject In usearcher.Get() ComboBoxAllUsers.Items.Add(queryObj("Name")) Next lblUserNumber.Text = "Total Accounts Found: " & ComboBoxAllUsers.Items.Count uan = ComboBoxAllUsers.Items.Count End Sub Private Sub btnGetNfo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetNfo.Click Try 'If ComboBoxAllUsers.SelectedItem = Nothing Then ' MsgBox("Please Select A User Name", MsgBoxStyle.Information, "User Not Selected") 'End If Dim strUser As String = ComboBoxAllUsers.SelectedItem.ToString Dim refSID As System.Object refSID = Nothing Dim Services = GetObject("winmgmts:{impersonationLevel=impersonate,(Security)}!\\.\root\cimv2") ' Connects to the WMI service with security privileges Dim SecDescClass = Services.Get("Win32_SecurityDescriptor") ' Need an instance of the Win32_SecurityDescriptor so we can create an instance of a Security Descriptor. Dim SecDesc = SecDescClass.SpawnInstance_() ' Create an instance of a Security Descriptor. Dim colWinAcc = Services.ExecQuery("SELECT * FROM Win32_ACCOUNT WHERE Name='" & strUser & "'") If colWinAcc.Count < 1 Then MsgBox("User " & strUser & "Not Found ") End If ' Find the WMI representation of a particular Windows Account For Each refItem In colWinAcc refSID = Services.Get("Win32_SID='" & refItem.SID & "'") ' Get the SID for the choosen Windows account. Next Dim refTrustee = Services.Get("Win32_Trustee").spawnInstance_() ' Creates an instance of a Windows Security Trustee (usually a user but anything with a SID I guess...) With refTrustee .Domain = refSID.ReferencedDomainName .Name = refSID.AccountName .SID = refSID.BinaryRepresentation .SidLength = refSID.SidLength .SIDString = refSID.SID End With ' Sets the trustee object up with the SID & all that malarkey from the user object we have choosen to work on Dim strb As New StringBuilder Dim strsid As New StringBuilder Dim nstrSid As String Dim pSid As String For Each pSid In refTrustee.SID strsid.Append(pSid & ",") Next nstrSid = strsid.ToString strb.AppendLine("Domain Name: " & refTrustee.Domain) strb.AppendLine("User Name: " & refTrustee.Name) 'strSID = Join(refTrustee.SID, ",") strb.AppendLine("SID: " & nstrSid) strb.AppendLine("SidLength: " & refTrustee.SidLength) strb.AppendLine("SIDString: " & refTrustee.SIDString) tbSidNFO.Text = strb.ToString Catch ex As Exception If ComboBoxAllUsers.SelectedItem = Nothing Then MsgBox("Please Select A User Name", MsgBoxStyle.Information, "User Not Selected") Else MsgBox("An Error Has Occured : " & vbCrLf & ex.Message) End If End Try End Sub Private Sub lblAbout_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lblAbout.Click My.Forms.AboutBox1.Show() End Sub End Class

The code for the above app. only gets the local User Accounts it finds.

The way I handled the array of Bytes in VB.Net is with a for each loop and a string builder. I’m not sure how others would do it but I kinda like the Stringbuilder now that I have learned how to use it. The other way I used to do it was in 1 long line and several  “&” and “vbCrLf” Mixed in. When you had several properties to pull out then it got harder to read  and handle the code even using line continuation.

This code below is the way to get the information to the text box from the original code.

Dim strb As New StringBuilder 'Stringbuilder to build the complete String to the Textbox Dim strsid As New StringBuilder 'Stringbuilder for the array of bytes Dim nstrSid As String ' string to represent the complete array of bytes Dim pSid As String ' string id to represent each byte in the foreach loop For Each pSid In refTrustee.SID strsid.Append(pSid & ",") ' adds each byte to a string and appends a Comma to each byte Next nstrSid = strsid.ToString strb.AppendLine("Domain Name: " & refTrustee.Domain) strb.AppendLine("User Name: " & refTrustee.Name) 'strSID = Join(refTrustee.SID, ",") strb.AppendLine("SID: " & nstrSid) strb.AppendLine("SidLength: " & refTrustee.SidLength) strb.AppendLine("SIDString: " & refTrustee.SIDString) tbSidNFO.Text = strb.ToString

 

Lets jazz this up a bit and get the System and Group accounts also.

Here is what the final app. looks like.

XtraSID2

In this version I added a group box and the 3 Radio Buttons inside of it for selecting the account type.

I then moved the code to get the  names for the account type to its own sub. Then in the radio button on change event, calls the selected user type sub to fill the combo box.

Now The Final Code:

Imports System.Management Imports System.Management.Instrumentation Imports System.Threading Imports System Imports System.IO Imports System.Security Imports System.Security.Permissions Imports System.Text Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ComboBoxAllUsers.Items.Clear() Get_userAccount() End Sub Private Sub btnGetNfo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetNfo.Click Try 'If ComboBoxAllUsers.SelectedItem = Nothing Then ' MsgBox("Please Select A User Name", MsgBoxStyle.Information, "User Not Selected") 'End If Dim strUser As String = ComboBoxAllUsers.SelectedItem.ToString Dim refSID As System.Object refSID = Nothing Dim Services = GetObject("winmgmts:{impersonationLevel=impersonate,(Security)}!\\.\root\cimv2") ' Connects to the WMI service with security privileges Dim SecDescClass = Services.Get("Win32_SecurityDescriptor") ' Need an instance of the Win32_SecurityDescriptor so we can create an instance of a Security Descriptor. Dim SecDesc = SecDescClass.SpawnInstance_() ' Create an instance of a Security Descriptor. Dim colWinAcc = Services.ExecQuery("SELECT * FROM Win32_ACCOUNT WHERE Name='" & strUser & "'") If colWinAcc.Count < 1 Then MsgBox("User " & strUser & "Not Found ") End If ' Find the WMI representation of a particular Windows Account For Each refItem In colWinAcc refSID = Services.Get("Win32_SID='" & refItem.SID & "'") ' Get the SID for the choosen Windows account. Next Dim refTrustee = Services.Get("Win32_Trustee").spawnInstance_() ' Creates an instance of a Windows Security Trustee (usually a user but anything with a SID I guess...) With refTrustee .Domain = refSID.ReferencedDomainName .Name = refSID.AccountName .SID = refSID.BinaryRepresentation .SidLength = refSID.SidLength .SIDString = refSID.SID End With ' Sets the trustee object up with the SID & all that malarkey from the user object we have choosen to work on Dim strb As New StringBuilder Dim strsid As New StringBuilder Dim nstrSid As String Dim pSid As String For Each pSid In refTrustee.SID strsid.Append(pSid & ",") Next nstrSid = strsid.ToString strb.AppendLine("Domain Name: " & refTrustee.Domain) strb.AppendLine("User Name: " & refTrustee.Name) 'strSID = Join(refTrustee.SID, ",") strb.AppendLine("SID: " & nstrSid) strb.AppendLine("SidLength: " & refTrustee.SidLength) strb.AppendLine("SIDString: " & refTrustee.SIDString) tbSidNFO.Text = strb.ToString Catch ex As Exception If ComboBoxAllUsers.SelectedItem = Nothing Then MsgBox("Please Select A User Name", MsgBoxStyle.Information, "User Not Selected") Else MsgBox("An Error Has Occured : " & vbCrLf & ex.Message) End If End Try End Sub Private Sub lblAbout_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lblAbout.Click My.Forms.AboutBox1.Show() End Sub Private Sub Get_userAccount() tbSidNFO.Clear() Dim uan As Integer Dim usearcher As New ManagementObjectSearcher( _ "root\CIMV2", _ "SELECT * FROM Win32_UserAccount") For Each queryObj As ManagementObject In usearcher.Get() ComboBoxAllUsers.Items.Add(queryObj("Name")) Next lblUserNumber.Text = "Total User Accounts Found: " & ComboBoxAllUsers.Items.Count uan = ComboBoxAllUsers.Items.Count End Sub Private Sub Get_GroupAccount() tbSidNFO.Clear() Dim uan As Integer Dim usearcher As New ManagementObjectSearcher( _ "root\CIMV2", _ "SELECT * FROM Win32_Group") For Each queryObj As ManagementObject In usearcher.Get() ComboBoxAllUsers.Items.Add(queryObj("Name")) Next lblUserNumber.Text = "Total Group Accounts Found: " & ComboBoxAllUsers.Items.Count uan = ComboBoxAllUsers.Items.Count End Sub Private Sub Get_SystemAccounts() tbSidNFO.Clear() Dim uan As Integer Dim usearcher As New ManagementObjectSearcher( _ "root\CIMV2", _ "SELECT * FROM Win32_SystemAccount") For Each queryObj As ManagementObject In usearcher.Get() ComboBoxAllUsers.Items.Add(queryObj("Name")) Next lblUserNumber.Text = "Total System Accounts Found: " & ComboBoxAllUsers.Items.Count uan = ComboBoxAllUsers.Items.Count End Sub Private Sub RadioButtonUserAccount_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButtonUserAccount.CheckedChanged ComboBoxAllUsers.Items.Clear() 'Need to clear or the usernames will keep stacking up. ComboBoxAllUsers.Text = "Please Select A User Account" ' Changes the text property you see before selecting a user name. Get_userAccount() 'Calls the sub for the account type. End Sub Private Sub RadioButtonGroupAccount_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButtonGroupAccount.CheckedChanged ComboBoxAllUsers.Items.Clear() ComboBoxAllUsers.Text = "Please Select A Group Account" Get_GroupAccount() End Sub Private Sub RadioButtonSystemAccount_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButtonSystemAccount.CheckedChanged ComboBoxAllUsers.Items.Clear() ComboBoxAllUsers.Text = "Please Select A System Account" Get_SystemAccounts() End Sub End Class

Now that I can get several sample versions of the binary/array of bytes version of the SID I can get back to the research of being able to do a conversion of a given binary SID and do the conversion with out having access to the original system it came from.

The best source I could find that explained how the conversion works is (Located Here) at selfadsi.org . Microsoft Security Descriptor(SID)Attributes

So far I can’t get the math & conversion to agree with what this program shows.

Conclusion:

If you have access to the systems and have Admin Authority then this should work for you as an easy way to get the binary and string form for an account. You may also want to check out another tool of mine called All User Account NFO (Located Here) .

Located on my website with a link to download the program.

That’s it for now, hope everyone else learned as much as I did.

Please post any comments or questions.

I think I have figured out the comments control , maybe .

Reposting 11/19/2011 to try and get the RSS to pick it up.

Advertisements

About pcsxcetrasupport3

My part time Business, I mainly do system building and system repair. Over the last several years I have been building system utility's in vb script , HTA applications and VB.Net to be able to better find the information I need to better understand the systems problems in order to get the systems repaired and back to my customers quicker.
This entry was posted in CodeProject, Programming Tools, System Tools, VB.net, VBScript and tagged , , , . Bookmark the permalink.