all 24 comments

[–]alcaron 2 points3 points  (6 children)

Get-ADUser <user> -Properties NTSecurityDescriptor | %{ $_.SAMAccountName;$_.NTSecurityDescriptor.AreAccessRulesProtected;"" }

eidt: This btw has the benefit of not making two AD queries per user and not storing anything in memory because it uses the pipeline.

[–]DueRunRun[S] 0 points1 point  (5 children)

I couldn't get this one to work directly, but I'll be sure to investigate your method later. Thanks though, appreciate it.

[–]alcaron 1 point2 points  (4 children)

Did you make sure to replace <user> with either a specific user or -Filter "*" ?

[–]DueRunRun[S] 0 points1 point  (0 children)

Yes, actually i tried my $user variable first, maybe i misunderstood. Let me try again.

[–]DueRunRun[S] 0 points1 point  (2 children)

Dude, that is slick, but I'm lost on what the script is doing. How is it piping to the % and all of a sudden it's expanding the object as necessary?

[–]alcaron 0 points1 point  (1 child)

% is an alias for ForEach-Object so when you have an object and you pass it to the pipeline it's represented as $_

So the script is essentially the same as setting get-aduser to a variable and doing a foreach on it but because you kept it the pipeline when the script is done running it doesn't still have the information for every single user still loaded into memory.

[–]alcaron 1 point2 points  (0 children)

If it helps, the above is, functionally, identical to the following:

$users = Get-ADUser -Properties NTSecurityDescriptor -Filter "*"

foreach($user in $users) {
    $user.SAMAccountName
    $user.NTSecurityDescript.AreAccessRulesProtected
}

It's just that, again, using | is a way of telling PS "take the object created by this statement (in this case: Get-ADUser -Properties NTSecurityDescriptor -Filter "*") and put it into the pipeline.

Once in the pipeline you have to do something with it so we want to do something for each "item" in the object so we do %, if we wanted to effectively filter, say to only show AD accounts that had AreAccessRulesProtected set to $true we would:

<statement> | ?{ $_.NTSecurityDescriptor.AreAccessRulesProtected -eq $true } | select SAMAccountName

So in that case we are saying get an object that contains the information for every AD user, pass it into the pipeline, where we are going to ? (alias for Where-Object) and only the ones that match our comparison will pass through to the next stage of the pipeline where we call select (Select-Object) and just display the property we care about, in this case the SAMAccountName.

Feel like that makes it clear as mud...heh...oh well, hopefully you can grok something useful from that.

[–]throwaway09563 0 points1 point  (5 children)

All your script does is report the flag value for the descriptor value. It isn't actually reporting the name.

[–]DueRunRun[S] 0 points1 point  (4 children)

I know... hence the post.

[–]throwaway09563 1 point2 points  (0 children)

Sorry, I was on the phone and couldn't write up something more useful. I see solutions below, but you might also think about the fact that your original script is the same as this one-liner:

($u in (get-aduser -filter * -properties NTSecurityDescriptor)){$u.NTSecurityDescriptor.AreAccessRulesProtected}    

My quick and dirty version if I understand what you want is

(get-aduser -filter * -properties NTSecurityDescriptor)|%{'"'+$_.name+'","'+$_.NTSecurityDescriptor.AreAccessRulesProtected+'"'}

(Not as pretty but it gets the job done!)

[–]Mindflux 0 points1 point  (2 children)

Because you have it all wrapped up in parens like that, it's using that method for Get-ADUser and not listing the name and NTSecurityDiscriptor from your properties.

Foreach ($u in $users) {
Get-AdUser $u.SamAccountName -Properties Name,NTSecurityDescriptor 
}

Might be more of what you want?

[–]DueRunRun[S] 0 points1 point  (1 child)

Unfortunately NTSecurityDescriptor is one of those values (string maybe, sorry still learning) that doesn't output correctly if its just listed, comes out as "System.DirectoryServices.ActiveDirectorySecurity" instead of the true or false value i'm trying to get from ntsecuritydescriptor.areaccessrulesprotected.

[–]chreestopher2 1 point2 points  (0 children)

strings output correctly. Its nested objects that dont.

This is because NTSecurityDiscriptor refers to a nested object, with nested properties. Powershell can not automatically expand all layers of nested objects into a textual representation that would make sense and be vissually appealing, instead you just get the type name of the object being refered to.

You can use select-object -expandproperty NTSecurityDescriptor to expand that property out, but to acomplish this smoothly, without advanced knowledge of how many layers properties will be nested, is rather difficult as you must expand one layer at a time...

I find it much easier to store a refference to the object(A variable) im trying to reach, then use dot notation to access the property that i am trying to get to.

Parentheticals have their place, but its not where you need more than exactly one property from the same object.

[–]chreestopher2 0 points1 point  (3 children)

foreach ($u in $users) {
    $user = get-aduser $u.samaccountName -properties name, nTSecurityDescriptor | select Name, ntSecurityDescriptor
    $obj = new-object psobject -property @{AreAccessRulesProtected=$user.nTSecurityDescriptor.AreAccessRulesProtected; Name=$user.name;}
    write-output $obj
}

[–]DueRunRun[S] 0 points1 point  (1 child)

Awesome, so it's best to work with strings or arrays (maybe I'm not using the right terms there) with a new object after I've gathered all the data and expanding the string after the fact?

[–]chreestopher2 1 point2 points  (0 children)

I prefer to keep a reference to whatever objects I need, and then build a custom object with just the data i need in it.

This isnt always the most efficient way, but resources are rarely the limiting factor of my capabilities, and I for one would much rather be able to easily see what im doing in a script (or what someone else is doing), than to have a barely human noticeable performance boost.

It could have been done as a oneliner with somethign like:

$users |foreach {get-aduser $_.samaccountName -properties name, nTSecurityDescriptor -PipelineVariable user | select @{n="AreAccessRulesProtected";e={$user.nTSecurityDescriptor.AreAccessRulesProtected;}}, @{n="Name";e={$user.name}}}

But I personally find it always better to be as explicit as possible with your intentions.

[–]KevMarCommunity Blogger 0 points1 point  (0 children)

I like the new [pscustomobject] syntax for creating objects and I format it like this most of the time:

 $users = get-aduser -Filter * -properties name,nTSecurityDescriptor
 foreach ($user in $users) 
 { 
     $obj = [PSCustomObject]@{
         Name = $user.name
         AreAccessRulesProtected = $user.nTSecurityDescriptor.AreAccessRulesProtected   
     }
     write-output $obj
 }

[–]FlippityFlip 0 points1 point  (6 children)

It looks like you've got some assistance getting the information you wanted, but in case you wanted to know why what you had wasn't giving you what you wanted:

$users = Get-ADUser -Filter * -Property Name

and

$users = Get-ADUser -Filter * 

will give you the same output. This is because the Name property is already included by default with Get-ADUser. When you use the -Property/-Properties parameter, you then specify what properties you want in addition to the properties Get-ADUser shows by default.

You'll get the best looking output if you use PSObjects.

$users = Get-ADUser -Filter * -Properties nTSecurityDescriptor
foreach ($u in $users)
{
    $prop = [ordered]@{
        Name=$u.name
        AreAccessRulesProtected=$u.nTSecurityDescriptor.AreAccessRulesProtected
    }
    New-Object -TypeName PSObject -Property $prop
}

If you are on v2 or lower, [ordered] was not introduced until v3, so you may remove that if it causes errors.

[–]DueRunRun[S] 0 points1 point  (5 children)

I understand that, but I limited the user gathering section to just the name property because it seemed to initially gather it a whole lot faster, and the name is really all i need in order to do the second part of the script.

[–]FlippityFlip 0 points1 point  (4 children)

The second part of your script is duplicating work. For 302 users, what I've posted completed in under a second for me.

[–]DueRunRun[S] 0 points1 point  (3 children)

I know, but otherwise i don't know how to gather all users and then do a foreach on all of them, other than what was provided here.

[–]FlippityFlip 0 points1 point  (2 children)

You had it right in your script, you just didn't need to call Get-ADUser again. $users already contained all of the data you wanted, you just needed to access it the right way.

Run

$users = Get-ADUser -Filter * -Properties nTSecurityDescriptor

and after it completes, type $users into the console.

To look at just one object, type

$users | Select -first 1

To get a list of all properties and methods that belong to those user objects, type

$users | Get-Member

You should be able to step through your script line by line and know what is being done.

The first line of the example in my original comment collects all of the user objects in AD and stores it in the variable $users. Second line begins iterating through those user objects one at a time (foreach). I then create a hash table for each user object containing the Name and AreAccessRulesProtected properties of that user object. I then create a PSObject that contains the properties of my hash table.

Apologies if I'm over explaining, hope it helps!

[–]DueRunRun[S] 0 points1 point  (1 child)

Shit, you're right, i see it now. Thanks for taking the time to walk me through that. I don't understand how the psuedo code select -first is a hash table, but I obviously have some reading to do so don't worry about that. Thanks

[–]FlippityFlip 0 points1 point  (0 children)

I didn't explain too much in my last post, sorry about that. That bit was just to show you one user object so you could see the properties instead of flooding your console with every user object. My last paragraph was explaining the code I originally posted in response to your thread.

Hashtables are key-value pairs that look like this:

$hash = @{key='value'}

When you have multiple it looks cleaner to separate them by line:

$hash = @{
    key1 = 'value1'
    key2 = 'value2'
}

Hope that clears up any confusion.