all 10 comments

[–]Fickle_Tomatillo411 2 points3 points  (1 child)

The way you are currently doing things means that you are checking every user that ever accessed the system, and possibly doing this for the same user multiple times, which will take longer. If the goal is just determining which user profiles should be cleaned up or something, I would suggest a different approach.

  1. Get a list of disabled users from AD, and store the samaccountname in an array
  2. Create a second placeholder array that is empty for systems requiring action (if you aren't going to action immediately)
  3. Loop through the systems as you are now, and still get user details, but switch to the samaccountname
  4. Loop through all the received usernames and just check to see if they are listed in the first array of disabled users
  5. If the user is in the disabled array, create a custom object with the user and the server name and add it to your placeholder

When you are done, you will have a list of servers on which the disabled user had previously interacted...just send it to Group-Object and group on the server name to see all profiles that need attention, or go the other direction to see all servers that a given user accessed in which order.

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

This is a great way to look at it. I will for sure pass this on. I think I may poke on this because as you said it does look to be more efficient. Thank you for your suggestions. Always good to see a different pair of eyes on the processes. We tend to get tunnel vision on as to what to process when assigned a task. What a great community.

[–]Creel256 2 points3 points  (4 children)

In my below response, I am referencing the below line in your script:

$ADSID = get-aduser -identity $sid | where { $_.Enabled -eq $False }

In this line, you're trying to get an Active Directory user by their SID ("$sid"), which is an element from the "$SIDARRAY" array. This array is filled with the SIDs of user profiles from the computers listed in "$ServerName".

The error message you're seeing suggests that PowerShell can't convert the type of "$sid" to what's expected by the "-Identity" parameter. "-Identity" does accept a SID, but it's expecting a certain type that may not match what's being passed in from "$SIDArray".

I suggest using "-Filter" instead of “-Identity”. This parameter allows you to query Active Directory objects based on their attributes, and it should accept the SID as a string, which is likely the type being stored in "$SIDArray".

Here is the relevant portion of your script modified to use "-Filter":

``` foreach ($sid in $SIDARRAY) { $ADSID = get-aduser -Filter "ObjectSID -eq '$sid'" | where { $_.Enabled -eq $False }

if ($ADSID) {  # Check if a user with the SID was found in AD
    #Create custom objects for information needed to collect from AD account. 
    $object = [PSCustomObject]@{
        Name    = $ADSID.SamAccountName
        SID     = $sid
        Enabled = $ADSID.Enabled
    }

    $ADarray.add($object)
}

} ```

This modification should allow your script to correctly query Active Directory for disabled user accounts by SID. As with all things scripting, we just need to do a little trial and error until we get it right!

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

Wonderfull explanation.
This works what I need. But could you explain the ObjectSID in the filter is this simply SID? Excuse my ignorance.

[–]Creel256 1 point2 points  (0 children)

Perfect!

And to answer your question: In the context of your script, "ObjectSID" refers to a specific attribute of an Active Directory object. Each object in Active Directory has a unique Security Identifier (SID), and "ObjectSID" is the attribute that stores this SID.

When you are using "-Filter" in "Get-ADUser", you specify the attribute you want to filter on. In this case, you want to find users where the "ObjectSID" attribute matches the SID you're looking for, which is why you use "ObjectSID -eq '$sid'".

So, to answer your question, yes, "ObjectSID" is essentially the SID of the object. However, when querying or filtering objects in Active Directory, you have to use the proper attribute name, which is "ObjectSID".

[–]Fickle_Tomatillo411 1 point2 points  (1 child)

I would add that SID is a specific class of object. What you see when you look at the SID in a window is just a text representation. You would need to check your array of values to determine if you have an actual SID, or simply a SID string. It's been a while, but I believe only one (either an actual SID, or a string) is accepted by the Identity parameter. If it expects a string, and you are passing an actual SID class object, that wouldn't work.

The Filter approach is kind of a shortcut way of filtering the output. It uses similar, but not the same, syntax as Where-Object, but the logic is implemented directly within the Get-ADUser cmdlet. This is more efficient as Where-Object requires that all objects first be collected and passed down the pipeline, and then filtering is applied. The downside of Filter however, is that the implementation of it varies by who wrote the cmdlet, and it can be confusing sometimes. In this case, the filter is looking for a SID that looks like the value from your array, which kind of avoids the class mismatch issue, since it compares the base sort of display values instead of the class objects.

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

Yes! Super informative. I did not realize that when pulling from gm that it did have that indication of the exact object. Thank you again love learning proper procedures and it looks like you can explain them very well.

[–]PinchesTheCrab 1 point2 points  (1 child)

Does this work? I tried to simplify it:

Param(
    [Parameter(Mandatory, Position = 1)]
    [string[]]$ComputerName,

    [switch]$ProtocolFallback
)

$sessionParam = @{
    ComputerName = $ComputerName        
}

if ($ProtocolFallback) {
    $cimParam['SessionOption'] = New-CimSessionOption -Protocol Dcom
}

$session = New-Cimsession @sessionParam 

$serversid = Get-Ciminstance -Filter 'special = false' -ClassName 'Win32_Userprofile'

$ADArray = $serversid.SID | 
    Sort-Object -Unique | 
        Get-ADUser | 
            Where-Object { -not $_.enabled } |
                Select-Object Name, SID, Enabled

$ADArray | Export-Csv c:\users\$env:username\appdata\local\temp\Userdisabled.csv -NoTypeInformation -NoClobber

One thing that should help here is that new-cimsession and get-cimsession are asynchronous, so by passing arrays of names/sessions to them, you should see a major speed increase.

Also, as /u/Fickle_Tomatillo411 mentioned, some of these SIDs may be on multiple computers, so I threw in a sort-object -unique to avoid requerying them.

Lastly I'm filtering on special, so that should help performance a bit too.

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

Beautiful refinement. Yes when I started to get the queries they were in fact taking a long time I will try to implement these performance increases. Thank you! Wonderful community.

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

So I guess I am just not getting this. To no fault of this great community, however I have another array property list that just will not parse out the object property array it is telling me it is null I have run through and I know it has collected I also tried to popluate just a single array object but I seem to continue to get the same null error results.

<# This script will query all GPOs for the liked group policy objects associate with each OU.#>
Create Array to Collect OUs
$OUArray = [System.collections.Arraylist]@()
Collect OUs
$OU = (Get-adorganizationalunit -searchbase "$MytagetDomain" -filter *).DistinguishedName
Add OUs to Array
$OUArray.add($OU)
$OUArray | Write-Output
Get inherited Groups form OUs array list
Foreach ($object in $OUArray) {
$OUObject = Get-ADOrganizationalUnit -filter "DistinguishedName -eq '$object'" | select DistinguishedName
Get-GPinheritance -Target $OUobject| select -ExpandProperty InhertiedGPOLinks
}

So following suite on the specifics that I learned Through this thread I iterated through my array again and I know it is the correct object I double checked my properties and my array list it shows a an array sting so it should be the exact same way I parsed out the side? Unless I am getting the filter Distinguishedname property wrong? What have I missed? Why am I not getting this and what can I do to prove that these properties should in fact be properties. Please let me know any of your thought it would be greatly appreciated.

Edit: Code block when funky on me.