Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VBScript and ACLs - Please Help

Status
Not open for further replies.

twdeveloper

Programmer
Mar 8, 2011
19
US
Hello,

I have been tasked to Create a Script to check DP's. Here is the take list:

1.) Determine Domain, DOM1 or DOM2. (That was easy enough)

2.) If DOM1 then Check for existence of share TEST1$ and folder D:\TEST1 (again got this working)

3.) If Share and folder doesn't exist exit with 1 as result. (Okay so far)

Okay so here is where I run into my problem.

5.) If exists, make sure ACL on TEST1& and D:\TEST1 contains the following ACE entries

Authenticated Users - Full Control

FakeUserName& - Full Control

Administators - Full Control

Users - Read, List, Read & Execute

6.) If ACEs don't match exit with 1 as a result

7.) If ACEs match exit with a 0 as a result.

8>) ELSE DOM2 and repeat

So as you see I am not quite sure the best way to do Step 5.) I have gather the SID for Authenticated Users but can't seem to get them for the others. Also didn't know if a program like ICacls or SubinAcl would be in my best interest.

Any help would be much appreciated.

Thank You,

TW

 

If you need further help, make sure to post your code.

-Geates



"I hope I can feel and see the change - stop the bleed inside a feel again. Cut the chain of lies you've been feeding my veins; I've got nothing to say to you!"
-Infected Mushroom

"I do not offer answers, only considerations."
- Geates's Disclaimer
 
I will post my VBScript if that will help but basically

The Script will be used to scan DP's on Servers.

I really just need something that will Display the ACLs and if all of the ACEs and Permissions are correct, return 0.

So say Cacls.exe can be used to list all ACLs on share TEST1$ and folder D:\TEST1. I just need some line(s) of code that states:

IF (for share TEST1$ & folder D:\TEST1)

Authenticated Users - Full Control

FakeUserName& - Full Control

Administators - Full Control

Users - Read, List, Read & Execute

is TRUE

WScript.Echo 0

Else

WScript.Echo 1

 
You'll have to exec cacls to a stream. Then read and parse the stream. Something like...

Code:
function getACL(strFolder)
	set objShell = CreateObject("WScript.Shell")
	set objStream = objShell.Exec("%comspec% /c cacls.exe " & strFolder)
	
	do until objStream.Stdout.AtEndOfStream
		strLine = trim(replace(lcase(objStream.StdOut.ReadLine), lcase(strFolder), ""))
		if (len(strLine)) then
			strUser = left(strLine, inStr(strLine, ":"))
			strPermission = right(strLine, 1)
		
			select case lcase(strPermission)
				case "c" : strPermission = "Change"
				case "f" : strPermission = "Full control"
				case "n" : strPermission = "None"
				case "r" : strPermission = "Read"
				case "w" : strPermission = "Write"
				case else : strPermission = "Unknown"
			end select
			strCACLS = strCACLS & strUser & " - " & strPermission & vbNewLine
		end if
	loop
	getACL = strCACLS
end function

msgbox getACL("C:\windows\system32")

use this function to get the permissions of a folder and them compare the output what you want.

-Geates

"I hope I can feel and see the change - stop the bleed inside a feel again. Cut the chain of lies you've been feeding my veins; I've got nothing to say to you!"
-Infected Mushroom

"I do not offer answers, only considerations."
- Geates's Disclaimer
 
Okay Geates,

Here is what I got so far.

I took your GETACL function, thank you.
I added my parsing code below the function.
This outputs the ACLs of the Folder then I parsed in by line with strName and then StrPermission.

Now if the part I am stuck on. The IF Statement that allows me to check whether strName = "authenticated users" & strPermissions = Full Control and WScript.Echo 0
else
WScript.Echo 1

If you can lend advice on the IF Statement I would appreciate it.

Thanks Again,

TW




function getACL(strFolder)
set objShell = CreateObject("WScript.Shell")
set objStream = objShell.Exec("%comspec% /c cacls.exe " & strFolder)

do until objStream.Stdout.AtEndOfStream
strLine = trim(replace(lcase(objStream.StdOut.ReadLine), lcase(strFolder), ""))
if (len(strLine)) then
strUser = left(strLine, inStr(strLine, ":"))
strPermission = right(strLine, 1)

select case lcase(strPermission)
case "c" : strPermission = "Change"
case "f" : strPermission = "Full control"
case "n" : strPermission = "None"
case "r" : strPermission = "Read"
case "w" : strPermission = "Write"
case else : strPermission = "Unknown"
end select
strCACLS = strCACLS & strUser & " - " & strPermission & vbNewLine
end if
loop
getACL = strCACLS
end function

Dim strResults
strResults = getACL("C:\Test")
WScript.Echo strResults
aryResults = Split (strResults,vbcrlf)

For Each Line in aryResults
strName = Left(line,InStr(line,":"))
WScript.Echo strName
strPermissions = Right(line,LEN(line)-InStr(line,"-"))
WScript.Echo strPermissions
Next

IF ?


 
1. Create an array to store the permissions you want to check

2. Get the folders ACL and compare the name and permission is each line with the name and permission in each element in the arrPerm.

3. If they are all there then ACL is verified.

I tweaked the getACL function a little bit. I also wrote a verifyACL function. The two functions work together to accomplish your goal.

Code:
function getACL(strFolder)
	set objShell = CreateObject("WScript.Shell")
	set objStream = objShell.Exec("%comspec% /c cacls.exe " & strFolder)
	
	do until objStream.Stdout.AtEndOfStream
		strLine = trim(replace(lcase(objStream.StdOut.ReadLine), lcase(strFolder), ""))
		if (len(strLine)) then
			strUser = left(strLine, inStr(strLine, ":"))
			strPermission = right(strLine, 1)
		
			select case lcase(strPermission)
				case "c" : strPermission = "Change"
				case "f" : strPermission = "Full control"
				case "n" : strPermission = "None"
				case "r" : strPermission = "Read"
				case "w" : strPermission = "Write"
				case else : strPermission = "Unknown"
			end select
			strCACLS = strCACLS & strUser & strPermission & vbNewLine
		end if
	loop
	getACL = split(strCACLS, vbNewLine)
end function

function verifyACL(arrACL, arrPerms)
	intMatches = 0
	verifyACL = false
	
	for each strACL in arrACL
		if (len(strACL)) then
			'strip the domain from strACL so the format of strACL is "user:permission"
			strACL = mid(strACL, inStr(strACL, "\") + 1)
			for each strPermission in arrPerms
				if (lcase(strACL) = lcase(strPermission)) then intMatches = intMatches + 1
			next
		if (intMatches = ubound(arrPerms)) then verifyACL = true
		end if
	next
end function



dim arrPerms(1)
arrPerms(0) = "Administrators:Full Control"
arrPerms(1) = "Users:Read"

strFolder = "C:\windows\system32"
arrACL = getACL(strFolder)

if (verifyACL(arrACL, arrPerms)) then
	msgbox strFolder & " has the necessary permissions"
else
	msgbox strFolder & " does not have the necessary permissions"
end if

Do you understand the code?

-Geates

"I hope I can feel and see the change - stop the bleed inside a feel again. Cut the chain of lies you've been feeding my veins; I've got nothing to say to you!"
-Infected Mushroom

"I do not offer answers, only considerations."
- Geates's Disclaimer
 
Geates,

Thank You again, yes I understand the code and this works great. Now if I wanted to run this on Shares does it work the same way?

As a Test, I set up some Shares in Computer Management- TEST1$ and TEST2$. I was testing before with SubinAcl.

Does the code you provided work the same with Shares? Just instead of strfolder = "C:\Test" it would be StrShare = "TEST1$" or something similar?

Todd
 
yes, it the share is mapped to a drive letter.

-Geates

"I hope I can feel and see the change - stop the bleed inside a feel again. Cut the chain of lies you've been feeding my veins; I've got nothing to say to you!"
-Infected Mushroom

"I do not offer answers, only considerations."
- Geates's Disclaimer
 
Hey Geates,

Thanks for all the help. I am really learning this stuff now, which is good. Just trying to wrap my head around this last piece of information. So my script works as planned for checking the Folders and get parsing thru and Verifying the ACL Permissions.

Now I am trying to understand how to get it check the Share$ for the Permissions instead of the Folder.

Okay, I am going to break it down so you can see exactly what I getting at, incase I am not being clear enough.

So when I go to Start-Computer-(right click)-Manage....I get the Computer Management Screen. Now Under Shared Folders and Shares, I create a New share, ex. TEST1$ and Test2$ and I link them to the folders C:\Test1 and C:\Test2.

So in my Script I have the Function getACL(strFolder) doing the following:

function getACL(strFolder)
set objShell = CreateObject("WScript.Shell")
set objStream = objShell.Exec("%comspec% /c cacls.exe " & strFolder)

do until objStream.Stdout.AtEndOfStream
strLine = trim(replace(lcase(objStream.StdOut.ReadLine), lcase(strFolder), ""))
if (len(strLine)) then
strUser = left(strLine, inStr(strLine, ":"))
strPermission = right(strLine, 1)

select case lcase(strPermission)
case "c" : strPermission = "Change"
case "f" : strPermission = "Full control"
case "n" : strPermission = "None"
case "r" : strPermission = "Read"
case "w" : strPermission = "Write"
case else : strPermission = "Unknown"
end select
strCACLS = strCACLS & strUser & strPermission & vbNewLine
end if
loop
getACL = split(strCACLS, vbNewLine)
end function

function verifyACL(arrACL, arrPerms)
intMatches = 0
verifyACL = false

for each strACL in arrACL
if (len(strACL)) then
'strip the domain from strACL so the format of strACL is "user:permission"
strACL = mid(strACL, inStr(strACL, "\") + 1)
for each strPermission in arrPerms
if (lcase(strACL) = lcase(strPermission)) then intMatches = intMatches + 1
next
if (intMatches = ubound(arrPerms)) then verifyACL = true
end if
next
end function



dim arrPerms(1)
arrPerms(0) = "Administrators:Full Control"
arrPerms(1) = "Users:Read"

strFolder = "C:\TEST1"
arrACL = getACL(strFolder)

if (verifyACL(arrACL, arrPerms)) then
msgbox strFolder & " has the necessary permissions"
else
msgbox strFolder & " does not have the necessary permissions"
end if


Now this Function works great for strFolder = "C:\TEST1".

How would I go about using this Function for the Share that is linked to "C:\TEST1".... TEST1$ that I described above.

It is my understanding that just because the Share TEST1$ is created with no Permissions it doesn't mean that the C:\TEST1 folder won't be given security permissions. So I need to check the Share TEST1$ instead.

Thank You,

TW


 
A quick Google search turned up an example by tek-tipper, dm4ever, suggesting the use of Win32_LogicalShareSecuritySetting.

Bare in mind that Share permissions are different from NTFS (regular folder) permissons. Below is an adaptation of dm4ever's example.

NOTE: the '$' at the end of the share name means 'hidden', not share. Names containing a '$' will not show up in Win32_LogicalShareSecuritySetting.

Code:
function getShareACL(strShareName)
	set objWMI = GetObject("winmgmts:\\.\root\cimv2")
	set colShares = objWMI.ExecQuery("SELECT * FROM Win32_LogicalShareSecuritySetting")

	for each objShare in colShares
		if (lcase(objShare.Name) = lcase(strShareName)) then
			intRtn = objShare.GetSecurityDescriptor(wmiSecurityDescriptor)
			colDACLs = wmiSecurityDescriptor.DACL
			for each objACE in colDACLs
				set objUserGroup = objACE.Trustee
				strUser = objUserGroup.Name
				select case objACE.AccessMask
					case 1179817 : strPermission = "Read"
					case 1245631 : strPermission = "Change"
					case 2032127 : strPermission = "Full Control"
					case else : strPermission = "Unknown"
				end select
			next
		end if
	next
	strCACLS = strCACLS & strUser & ":" & strPermission & vbNewLine
	getShareACL = split(strCACLS, vbNewLine)
end function

arrACL = getShareACL("test")

-Geates


"I hope I can feel and see the change - stop the bleed inside a feel again. Cut the chain of lies you've been feeding my veins; I've got nothing to say to you!"
-Infected Mushroom

"I do not offer answers, only considerations."
- Geates's Disclaimer
 
Hey Geates,

Okay I have 2 questions/issues. After doing some testing with the following Functions:

function getACL(strFolder)
set objShell = CreateObject("WScript.Shell")
set objStream = objShell.Exec("%comspec% /c cacls.exe " & strFolder)

do until objStream.Stdout.AtEndOfStream
strLine = trim(replace(lcase(objStream.StdOut.ReadLine), lcase(strFolder), ""))
if (len(strLine)) then
strUser = left(strLine, inStr(strLine, ":"))
strPermission = right(strLine, 1)

select case lcase(strPermission)
case "c" : strPermission = "Change"
case "f" : strPermission = "Full control"
case "n" : strPermission = "None"
case "r" : strPermission = "Read"
case "w" : strPermission = "Write"
case else : strPermission = "Unknown"
end select
strCACLS = strCACLS & strUser & strPermission & vbNewLine
end if
loop
getACL = split(strCACLS, vbNewLine)
end function

function verifyACL(arrACL, arrPerms)
intMatches = 0
verifyACL = false

for each strACL in arrACL
if (len(strACL)) then
'strip the domain from strACL so the format of strACL is "user:permission"
strACL = mid(strACL, inStr(strACL, "\") + 1)
for each strPermission in arrPerms
if (lcase(strACL) = lcase(strPermission)) then intMatches = intMatches + 1
next
if (intMatches = ubound(arrPerms)) then verifyACL = true
end if
next
end function



dim arrPerms(2)
arrPerms(0) = "Administrators:Full Control"
arrPerms(1) = "Users:Read"

strFolder = "C:\TEST1"
arrACL = getACL(strFolder)

if (verifyACL(arrACL, arrPerms)) then
msgbox strFolder & " has the necessary permissions"
else
msgbox strFolder & " does not have the necessary permissions"
end if


It looks as if the "verifyACL" function is reporting accurate if it even finds only one of the two "arrPerms". Can you confirm this by any chance?

Also, if I go to use the function "getShareACL(strShareName)", from the previous reply, can I then use the same "VerifyACL" function with arrPerms assuming it indeed works correctly?

Thank You Again.

TW



 
1.
The problem is likely with the ubound(). ubound() returns the upper dimension of the array, not number of elements. Because arrays are indexed cardinally (starting from zero, not one) ubound returns one less than the number of elements.

array(0) = "first element"
array(1) = "second element"
array(2) = "third element"

there are 3 elements but ubound(array) = 2

Easy fix!
Code:
if (intMatches = ubound(arrPerms) [red]+ 1[/red]) then verifyACL = true

2. Yes

-Geates

"I hope I can chill and see the change - stop the bleed inside and feel again. Cut the chain of lies you've been feeding my veins; I've got nothing to say to you!"
-Infected Mushroom

"I do not offer answers, only considerations."
- Geates's Disclaimer
 
Okay getting some what closer. However, still a little off.

So I updated the following line:

if (intMatches = ubound(arrPerms) + 1) then verifyACL = true

It still seems to return:

if (verifyACL(arrACL, arrPerms)) then
msgbox strFolder & " has the necessary permissions"

even if it finds only 1 of the arrPerms to be Accurate. It doesn't seem to be checking each element in the array and failing if 1 if not there.

Also, when I used the function:

function getShareACL(strShareName)

and typed in at the end:

strShareName = "test"

arrACL = getShareACL(strShareName)

WSCript.echo arrACL

It gives me a runtime error:Type MisMatch

However I commented out the following line of the function:

' getShareACL = split(strCACLS, vbNewLine)

AND inserted in its place: getShareACL = strCACLS

it at least returns 1 username and permission but only 1. I had placed 3 ACLs in the test share.

UGH!










 
arrACL = getShareACL(strShareName)

WSCript.echo arrACL

It gives me a runtime error:Type MisMatch

Well, of course. getShareACL() returns an array. wscript.echo only works with strings.

However I commented out the following line of the function:

' getShareACL = split(strCACLS, vbNewLine)

AND inserted in its place: getShareACL = strCACLS

doing this makes getShareACL() return a strCACLS (a string) instead of split(strCACLS, vbNewLine) (an array).

It only returns 1 because it is outside of the for..loop and if..then and thus only happens once. Move the line "strCACLS = strCACLS & strUser & ":" & strPermission & vbNewLine" inside the if..then.

-Geates

"I hope I can chill and see the change - stop the bleed inside and feel again. Cut the chain of lies you've been feeding my veins; I've got nothing to say to you!"
-Infected Mushroom

"I do not offer answers, only considerations."
- Geates's Disclaimer
 
Geates,

Thanks again for all your help with this Script and my learning curve. Everything seems to be in place and working great.

One more minor issue/question though. Turns out that one the Permissions needed has been changed from:

Users:Read to Builtin\users:Full Control

Now I know with the function, "verifyACL", it's using the line "strACL = mid(strACL, inStr(strACL, "\") + 1)" to strip the domain and just check for User and then (Permission) Read.

What would be the best way to keep the domain so that it reads builtin\User instead of just user, which could be the domain user? I know I need change the function name, remove the strACL = mid line. Just trying to figure out the best way to make this work.

Thanks Again.

TW



function getACL(strFolder)
set objShell = CreateObject("WScript.Shell")
set objStream = objShell.Exec("%comspec% /c cacls.exe " & strFolder)

do until objStream.Stdout.AtEndOfStream
strLine = trim(replace(lcase(objStream.StdOut.ReadLine), lcase(strFolder), ""))
if (len(strLine)) then
strUser = left(strLine, inStr(strLine, ":"))
strPermission = right(strLine, 1)

select case lcase(strPermission)
case "c" : strPermission = "Change"
case "f" : strPermission = "Full control"
case "n" : strPermission = "None"
case "r" : strPermission = "Read"
case "w" : strPermission = "Write"
case else : strPermission = "Unknown"
end select
strCACLS = strCACLS & strUser & strPermission & vbNewLine
end if
loop
getACL = split(strCACLS, vbNewLine)
end function

function verifyACL(arrACL, arrPerms)
intMatches = 0
verifyACL = false

for each strACL in arrACL
if (len(strACL)) then
'strip the domain from strACL so the format of strACL is "user:permission"
strACL = mid(strACL, inStr(strACL, "\") + 1)
for each strPermission in arrPerms
if (lcase(strACL) = lcase(strPermission)) then intMatches = intMatches + 1
next
if (intMatches = ubound(arrPerms)) then verifyACL = true
end if
next
end function



dim arrPerms(1)
arrPerms(0) = "Administrators:Full Control"
arrPerms(1) = "Users:Read"

strFolder = "C:\windows\system32"
arrACL = getACL(strFolder)

if (verifyACL(arrACL, arrPerms)) then
msgbox strFolder & " has the necessary permissions"
else
msgbox strFolder & " does not have the necessary permissions"
end if



 
For the previous post I meant to post the GetShareACL function.

Not that it makes too much of a difference.

 
Nevermind I got it. I found that there is a objUserGroup.Domain.

So I did strDomain = objUserGroup.Domain

Added & strDomain & "\" to the strCACLS line.
 
wouldn't have to do much. getACL/getShareACL return the ACL list with domains. The domains get stripped in verifyACL. As you said, remove the line that strips the domain

Code:
strACL = mid(strACL, inStr(strACL, "\") + 1)

and make sure your custom arrPerm() array contains domains.

Code:
arrPerms(0) = "[red]builtin\[/red]Administrators:Full Control"
arrPerms(1) = "[red]builtin\[/red]Users:Read"
arrPerms(2) = "[red]mydomain\[/red]twdeveloper:Full Control"

-Geates

"I hope I can chill and see the change - stop the bleed inside and feel again. Cut the chain of lies you've been feeding my veins; I've got nothing to say to you!"
-Infected Mushroom

"I do not offer answers, only considerations."
- Geates's Disclaimer
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top